1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   cons_sos1.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief  constraint handler for SOS type 1 constraints
19  * @author Tobias Fischer
20  * @author Marc Pfetsch
21  *
22  * A specially ordered set of type 1 (SOS1) is a sequence of variables such that at most one
23  * variable is nonzero. The special case of two variables arises, for instance, from equilibrium or
24  * complementary conditions like \f$x \cdot y = 0\f$. Note that it is in principle allowed that a
25  * variables appears twice, but it then can be fixed to 0.
26  *
27  * This implementation of this constraint handler is based on classical ideas, see e.g.@n
28  *  "Special Facilities in General Mathematical Programming System for
29  *  Non-Convex Problems Using Ordered Sets of Variables"@n
30  *  E. Beale and J. Tomlin, Proc. 5th IFORS Conference, 447-454 (1970)
31  *
32  *
33  * The order of the variables is determined as follows:
34  *
35  * - If the constraint is created with SCIPcreateConsSOS1() and weights are given, the weights
36  *   determine the order (decreasing weights). Additional variables can be added with
37  *   SCIPaddVarSOS1(), which adds a variable with given weight.
38  *
39  * - If an empty constraint is created and then variables are added with SCIPaddVarSOS1(), weights
40  *   are needed and stored.
41  *
42  * - All other calls ignore the weights, i.e., if a nonempty constraint is created or variables are
43  *   added with SCIPappendVarSOS1().
44  *
45  * The validity of the SOS1 constraints can be enforced by different branching rules:
46  *
47  * - If classical SOS branching is used, branching is performed on only one SOS1 constraint.
48  *   Depending on the parameters, there are two ways to choose this branching constraint. Either
49  *   the constraint with the most number of nonzeros or the one with the largest nonzero-variable
50  *   weight. The later version allows the user to specify an order for the branching importance of
51  *   the constraints. Constraint branching can also be turned off.
52  *
53  * - Another way is to branch on the neighborhood of a single variable @p i, i.e., in one branch
54  *   \f$x_i\f$ is fixed to zero and in the other its neighbors from the conflict graph.
55  *
56  * - If bipartite branching is used, then we branch using complete bipartite subgraphs of the
57  *   conflict graph, i.e., in one branch fix the variables from the first bipartite partition and
58  *   the variables from the second bipartite partition in the other.
59  *
60  * - In addition to variable domain fixings, it is sometimes also possible to add new SOS1
61  *   constraints to the branching nodes. This results in a nonstatic conflict graph, which may
62  *   change dynamically with every branching node.
63  *
64  *
65  * @todo Possibly allow to generate local cuts via strengthened local cuts (would need to modified coefficients of rows).
66  *
67  * @todo Check whether we can avoid turning off multi-aggregation (it is sometimes possible to fix a multi-aggregated
68  * variable to 0 by fixing the aggregating variables to 0).
69  */
70 
71 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
72 
73 #include "blockmemshell/memory.h"
74 #include "scip/cons_linear.h"
75 #include "scip/cons_setppc.h"
76 #include "scip/cons_sos1.h"
77 #include "scip/pub_cons.h"
78 #include "scip/pub_event.h"
79 #include "scip/pub_heur.h"
80 #include "scip/pub_lp.h"
81 #include "scip/pub_message.h"
82 #include "scip/pub_misc.h"
83 #include "scip/pub_misc_sort.h"
84 #include "scip/pub_tree.h"
85 #include "scip/pub_var.h"
86 #include "scip/scip_branch.h"
87 #include "scip/scip_conflict.h"
88 #include "scip/scip_cons.h"
89 #include "scip/scip_copy.h"
90 #include "scip/scip_cut.h"
91 #include "scip/scip_datastructures.h"
92 #include "scip/scip_event.h"
93 #include "scip/scip_general.h"
94 #include "scip/scip_lp.h"
95 #include "scip/scip_mem.h"
96 #include "scip/scip_message.h"
97 #include "scip/scip_numerics.h"
98 #include "scip/scip_param.h"
99 #include "scip/scip_prob.h"
100 #include "scip/scip_probing.h"
101 #include "scip/scip_sol.h"
102 #include "scip/scip_solvingstats.h"
103 #include "scip/scip_tree.h"
104 #include "scip/scip_var.h"
105 #include "tclique/tclique.h"
106 #include <ctype.h>
107 #include <stdlib.h>
108 #include <string.h>
109 
110 
111 /* constraint handler properties */
112 #define CONSHDLR_NAME          "SOS1"
113 #define CONSHDLR_DESC          "SOS1 constraint handler"
114 #define CONSHDLR_SEPAPRIORITY      1000 /**< priority of the constraint handler for separation */
115 #define CONSHDLR_ENFOPRIORITY       100 /**< priority of the constraint handler for constraint enforcing */
116 #define CONSHDLR_CHECKPRIORITY      -10 /**< priority of the constraint handler for checking feasibility */
117 #define CONSHDLR_SEPAFREQ            10 /**< frequency for separating cuts; zero means to separate only in the root node */
118 #define CONSHDLR_PROPFREQ             1 /**< frequency for propagating domains; zero means only preprocessing propagation */
119 #define CONSHDLR_EAGERFREQ          100 /**< frequency for using all instead of only the useful constraints in separation,
120                                          *   propagation and enforcement, -1 for no eager evaluations, 0 for first only */
121 #define CONSHDLR_MAXPREROUNDS        -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
122 #define CONSHDLR_DELAYSEPA        FALSE /**< should separation method be delayed, if other separators found cuts? */
123 #define CONSHDLR_DELAYPROP        FALSE /**< should propagation method be delayed, if other propagators found reductions? */
124 #define CONSHDLR_NEEDSCONS         TRUE /**< should the constraint handler be skipped, if no constraints are available? */
125 #define CONSHDLR_PROP_TIMING       SCIP_PROPTIMING_BEFORELP
126 #define CONSHDLR_PRESOLTIMING      SCIP_PRESOLTIMING_MEDIUM
127 
128 /* adjacency matrix */
129 #define DEFAULT_MAXSOSADJACENCY   10000 /**< do not create an adjacency matrix if number of SOS1 variables is larger than predefined value
130                                          *   (-1: no limit) */
131 
132 /* presolving */
133 #define DEFAULT_MAXEXTENSIONS         1 /**< maximal number of extensions that will be computed for each SOS1 constraint */
134 #define DEFAULT_MAXTIGHTENBDS         5 /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */
135 #define DEFAULT_PERFIMPLANALYSIS  FALSE /**< if TRUE then perform implication graph analysis (might add additional SOS1 constraints) */
136 #define DEFAULT_DEPTHIMPLANALYSIS    -1 /**< number of recursive calls of implication graph analysis (-1: no limit) */
137 
138 /* propagation */
139 #define DEFAULT_CONFLICTPROP      TRUE /**< whether to use conflict graph propagation */
140 #define DEFAULT_IMPLPROP          TRUE /**< whether to use implication graph propagation */
141 #define DEFAULT_SOSCONSPROP      FALSE /**< whether to use SOS1 constraint propagation */
142 
143 /* branching rules */
144 #define DEFAULT_BRANCHSTRATEGIES  "nbs" /**< possible branching strategies (see parameter DEFAULT_BRANCHINGRULE) */
145 #define DEFAULT_BRANCHINGRULE       'n' /**< which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique)
146                                          *   (note: in some cases an automatic switching to SOS1 branching is possible) */
147 #define DEFAULT_AUTOSOS1BRANCH     TRUE /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */
148 #define DEFAULT_FIXNONZERO        FALSE /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the
149                                          *   feasibility tolerance */
150 #define DEFAULT_ADDCOMPS          FALSE /**< if TRUE then add complementarity constraints to the branching nodes (can be used in combination with
151                                          *   neighborhood or bipartite branching) */
152 #define DEFAULT_MAXADDCOMPS          -1 /**< maximal number of complementarity constraints added per branching node (-1: no limit) */
153 #define DEFAULT_ADDCOMPSDEPTH        30 /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */
154 #define DEFAULT_ADDCOMPSFEAS       -0.6 /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */
155 #define DEFAULT_ADDBDSFEAS          1.0 /**< minimal feasibility value for bound inequalities in order to be added to the branching node */
156 #define DEFAULT_ADDEXTENDEDBDS     TRUE /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */
157 
158 /* selection rules */
159 #define DEFAULT_NSTRONGROUNDS         0 /**< maximal number of strong branching rounds to perform for each node (-1: auto)
160                                          *   (only available for neighborhood and bipartite branching) */
161 #define DEFAULT_NSTRONGITER       10000 /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */
162 
163 /* separation */
164 #define DEFAULT_BOUNDCUTSFROMSOS1 FALSE /**< if TRUE separate bound inequalities from SOS1 constraints */
165 #define DEFAULT_BOUNDCUTSFROMGRAPH TRUE /**< if TRUE separate bound inequalities from the conflict graph */
166 #define DEFAULT_AUTOCUTSFROMSOS1   TRUE /**< if TRUE then automatically switch to separating from SOS1 constraints if the SOS1 constraints do not overlap */
167 #define DEFAULT_BOUNDCUTSFREQ        10 /**< frequency for separating bound cuts; zero means to separate only in the root node */
168 #define DEFAULT_BOUNDCUTSDEPTH       40 /**< node depth of separating bound cuts (-1: no limit) */
169 #define DEFAULT_MAXBOUNDCUTS         50 /**< maximal number of bound cuts separated per branching node */
170 #define DEFAULT_MAXBOUNDCUTSROOT    150 /**< maximal number of bound cuts separated per iteration in the root node */
171 #define DEFAULT_STRTHENBOUNDCUTS   TRUE /**< if TRUE then bound cuts are strengthened in case bound variables are available */
172 #define DEFAULT_IMPLCUTSFREQ          0 /**< frequency for separating implied bound cuts; zero means to separate only in the root node */
173 #define DEFAULT_IMPLCUTSDEPTH        40 /**< node depth of separating implied bound cuts (-1: no limit) */
174 #define DEFAULT_MAXIMPLCUTS          50 /**< maximal number of implied bound cuts separated per branching node */
175 #define DEFAULT_MAXIMPLCUTSROOT     150 /**< maximal number of implied bound cuts separated per iteration in the root node */
176 
177 /* event handler properties */
178 #define EVENTHDLR_NAME         "SOS1"
179 #define EVENTHDLR_DESC         "bound change event handler for SOS1 constraints"
180 
181 #define EVENTHDLR_EVENT_TYPE   (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_GBDCHANGED)
182 
183 /* defines */
184 #define DIVINGCUTOFFVALUE     1e6
185 
186 
187 /** constraint data for SOS1 constraints */
188 struct SCIP_ConsData
189 {
190    int                   nvars;              /**< number of variables in the constraint */
191    int                   maxvars;            /**< maximal number of variables (= size of storage) */
192    int                   nfixednonzeros;     /**< number of variables fixed to be nonzero */
193    SCIP_Bool             local;              /**< TRUE if constraint is only valid locally */
194    SCIP_VAR**            vars;               /**< variables in constraint */
195    SCIP_ROW*             rowlb;              /**< row corresponding to lower bounds, or NULL if not yet created */
196    SCIP_ROW*             rowub;              /**< row corresponding to upper bounds, or NULL if not yet created */
197    SCIP_Real*            weights;            /**< weights determining the order (ascending), or NULL if not used */
198 };
199 
200 
201 /** node data of a given node in the conflict graph */
202 struct SCIP_NodeData
203 {
204    SCIP_VAR*             var;                /**< variable belonging to node */
205    SCIP_VAR*             lbboundvar;         /**< bound variable @p z from constraint \f$x \geq \mu \cdot z\f$ (or NULL if not existent) */
206    SCIP_VAR*             ubboundvar;         /**< bound variable @p z from constraint \f$x \leq \mu \cdot z\f$ (or NULL if not existent) */
207    SCIP_Real             lbboundcoef;        /**< value \f$\mu\f$ from constraint \f$x \geq \mu z \f$ (0.0 if not existent) */
208    SCIP_Real             ubboundcoef;        /**< value \f$\mu\f$ from constraint \f$x \leq \mu z \f$ (0.0 if not existent) */
209    SCIP_Bool             lbboundcomp;        /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to
210                                               *   all have the same lower bound variable */
211    SCIP_Bool             ubboundcomp;        /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to
212                                               *   all have the same lower bound variable */
213 };
214 typedef struct SCIP_NodeData SCIP_NODEDATA;
215 
216 
217 /** successor data of a given nodes successor in the implication graph */
218 struct SCIP_SuccData
219 {
220    SCIP_Real             lbimpl;             /**< lower bound implication */
221    SCIP_Real             ubimpl;             /**< upper bound implication */
222 };
223 typedef struct SCIP_SuccData SCIP_SUCCDATA;
224 
225 
226 /** tclique data for bound cut generation */
227 struct TCLIQUE_Data
228 {
229    SCIP*                 scip;               /**< SCIP data structure */
230    SCIP_CONSHDLR*        conshdlr;           /**< SOS1 constraint handler */
231    SCIP_DIGRAPH*         conflictgraph;      /**< conflict graph */
232    SCIP_SOL*             sol;                /**< LP solution to be separated (or NULL) */
233    SCIP_Real             scaleval;           /**< factor for scaling weights */
234    SCIP_Bool             cutoff;             /**< whether a cutoff occurred */
235    int                   ncuts;              /**< number of bound cuts found in this iteration */
236    int                   nboundcuts;         /**< number of bound cuts found so far */
237    int                   maxboundcuts;       /**< maximal number of clique cuts separated per separation round (-1: no limit) */
238    SCIP_Bool             strthenboundcuts;   /**< if TRUE then bound cuts are strengthened in case bound variables are available */
239 };
240 
241 
242 /** SOS1 constraint handler data */
243 struct SCIP_ConshdlrData
244 {
245    /* conflict graph */
246    SCIP_DIGRAPH*         conflictgraph;      /**< conflict graph */
247    SCIP_DIGRAPH*         localconflicts;     /**< local conflicts */
248    SCIP_Bool             isconflocal;        /**< if TRUE then local conflicts are present and conflict graph has to be updated for each node */
249    SCIP_HASHMAP*         varhash;            /**< hash map from variable to node in the conflict graph */
250    int                   nsos1vars;          /**< number of problem variables that are part of the SOS1 conflict graph */
251    /* adjacency matrix */
252    int                   maxsosadjacency;    /**< do not create an adjacency matrix if number of SOS1 variables is larger than predefined
253                                               *   value (-1: no limit) */
254    /* implication graph */
255    SCIP_DIGRAPH*         implgraph;          /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
256    int                   nimplnodes;         /**< number of nodes in the implication graph */
257    /* tclique graph */
258    TCLIQUE_GRAPH*        tcliquegraph;       /**< tclique graph data structure */
259    TCLIQUE_DATA*         tcliquedata;        /**< tclique data */
260    /* event handler */
261    SCIP_EVENTHDLR*       eventhdlr;          /**< event handler for bound change events */
262    SCIP_VAR**            fixnonzerovars;     /**< stack of variables fixed to nonzero marked by event handler */
263    int                   maxnfixnonzerovars; /**< size of stack fixnonzerovars */
264    int                   nfixnonzerovars;    /**< number of variables fixed to nonzero marked by event handler */
265    /* presolving */
266    int                   cntextsos1;         /**< counts number of extended SOS1 constraints */
267    int                   maxextensions;      /**< maximal number of extensions that will be computed for each SOS1 constraint */
268    int                   maxtightenbds;      /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */
269    SCIP_Bool             perfimplanalysis;   /**< if TRUE then perform implication graph analysis (might add additional SOS1 constraints) */
270    int                   depthimplanalysis;  /**< number of recursive calls of implication graph analysis (-1: no limit) */
271    /* propagation */
272    SCIP_Bool             conflictprop;       /**< whether to use conflict graph propagation */
273    SCIP_Bool             implprop;           /**< whether to use implication graph propagation */
274    SCIP_Bool             sosconsprop;        /**< whether to use SOS1 constraint propagation */
275    /* branching */
276    char                  branchingrule;      /**< which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique)
277                                               *   (note: in some cases an automatic switching to SOS1 branching is possible) */
278    SCIP_Bool             autosos1branch;     /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */
279    SCIP_Bool             fixnonzero;         /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the
280                                               *   feasibility tolerance */
281    SCIP_Bool             addcomps;           /**< if TRUE then add complementarity constraints to the branching nodes additionally to domain fixings
282                                               *   (can be used in combination with neighborhood or bipartite branching) */
283    int                   maxaddcomps;        /**< maximal number of complementarity cons. and cor. bound ineq. added per branching node (-1: no limit) */
284    int                   addcompsdepth;      /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */
285    SCIP_Real             addcompsfeas;       /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */
286    SCIP_Real             addbdsfeas;         /**< minimal feasibility value for bound inequalities in order to be added to the branching node */
287    SCIP_Bool             addextendedbds;     /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */
288    SCIP_Bool             branchsos;          /**< Branch on SOS condition in enforcing? This value can only be set to false if all SOS1 variables are binary */
289    SCIP_Bool             branchnonzeros;     /**< Branch on SOS cons. with most number of nonzeros? */
290    SCIP_Bool             branchweight;       /**< Branch on SOS cons. with highest nonzero-variable weight for branching - needs branchnonzeros to be false */
291    SCIP_Bool             switchsos1branch;   /**< whether to switch to SOS1 branching */
292    /* selection rules */
293    int                   nstrongrounds;      /**< maximal number of strong branching rounds to perform for each node (-1: auto)
294                                               *   (only available for neighborhood and bipartite branching) */
295    int                   nstrongiter;        /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */
296    /* separation */
297    SCIP_Bool             boundcutsfromsos1;  /**< if TRUE separate bound inequalities from SOS1 constraints */
298    SCIP_Bool             boundcutsfromgraph; /**< if TRUE separate bound inequalities from the conflict graph */
299    SCIP_Bool             autocutsfromsos1;   /**< if TRUE then automatically switch to separating SOS1 constraints if the SOS1 constraints do not overlap */
300    SCIP_Bool             switchcutsfromsos1; /**< whether to switch to separate bound inequalities from SOS1 constraints */
301    int                   boundcutsfreq;      /**< frequency for separating bound cuts; zero means to separate only in the root node */
302    int                   boundcutsdepth;     /**< node depth of separating bound cuts (-1: no limit) */
303    int                   maxboundcuts;       /**< maximal number of bound cuts separated per branching node */
304    int                   maxboundcutsroot;   /**< maximal number of bound cuts separated per iteration in the root node */
305    int                   nboundcuts;         /**< number of bound cuts found so far */
306    SCIP_Bool             strthenboundcuts;   /**< if TRUE then bound cuts are strengthened in case bound variables are available */
307    int                   implcutsfreq;       /**< frequency for separating implied bound cuts; zero means to separate only in the root node */
308    int                   implcutsdepth;      /**< node depth of separating implied bound cuts (-1: no limit) */
309    int                   maximplcuts;        /**< maximal number of implied bound cuts separated per branching node */
310    int                   maximplcutsroot;    /**< maximal number of implied bound cuts separated per iteration in the root node */
311 };
312 
313 
314 
315 /*
316  * local methods
317  */
318 
319 /** returns whether two vertices are adjacent in the conflict graph */
320 static
isConnectedSOS1(SCIP_Bool ** adjacencymatrix,SCIP_DIGRAPH * conflictgraph,int vertex1,int vertex2)321 SCIP_Bool isConnectedSOS1(
322    SCIP_Bool**           adjacencymatrix,    /**< adjacency matrix of conflict graph (lower half) (or NULL if an adjacencymatrix is not at hand) */
323    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph (or NULL if an adjacencymatrix is at hand) */
324    int                   vertex1,            /**< first vertex */
325    int                   vertex2             /**< second vertex */
326    )
327 {
328    assert( adjacencymatrix != NULL || conflictgraph != NULL );
329 
330    /* we do not allow self-loops */
331    if ( vertex1 == vertex2 )
332       return FALSE;
333 
334    /* for debugging */
335    if ( adjacencymatrix == NULL )
336    {
337       int succvertex;
338       int* succ;
339       int nsucc1;
340       int nsucc2;
341       int j;
342 
343       nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex1);
344       nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, vertex2);
345 
346       if ( nsucc1 < 1 || nsucc2 < 1 )
347          return FALSE;
348 
349       if ( nsucc1 > nsucc2 )
350       {
351          SCIPswapInts(&vertex1, &vertex2);
352          SCIPswapInts(&nsucc1, &nsucc2);
353       }
354 
355       succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1);
356       SCIPsortInt(succ, nsucc1);
357 
358       for (j = 0; j < nsucc1; ++j)
359       {
360          succvertex = succ[j];
361          if ( succvertex == vertex2 )
362             return TRUE;
363          else if ( succvertex > vertex2 )
364             return FALSE;
365       }
366    }
367    else
368    {
369       if ( vertex1 < vertex2 )
370          return adjacencymatrix[vertex2][vertex1];
371       else
372          return adjacencymatrix[vertex1][vertex2];
373    }
374 
375    return FALSE;
376 }
377 
378 
379 /** checks whether a variable violates an SOS1 constraint w.r.t. sol together with at least one other variable */
380 static
isViolatedSOS1(SCIP * scip,SCIP_DIGRAPH * conflictgraph,int node,SCIP_SOL * sol)381 SCIP_Bool isViolatedSOS1(
382    SCIP*                 scip,               /**< SCIP data structure */
383    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph (or NULL if an adjacencymatrix is at hand) */
384    int                   node,               /**< node of variable in the conflict graph */
385    SCIP_SOL*             sol                 /**< solution, or NULL to use current node's solution */
386    )
387 {
388    SCIP_Real solval;
389    SCIP_VAR* var;
390 
391    assert( scip != NULL );
392    assert( conflictgraph != NULL );
393    assert( node >= 0 );
394 
395    var = SCIPnodeGetVarSOS1(conflictgraph, node);
396    assert( var != NULL );
397    solval = SCIPgetSolVal(scip, sol, var);
398 
399    /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */
400    if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) )
401    {
402       int* succ;
403       int nsucc;
404       int s;
405 
406       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
407       succ = SCIPdigraphGetSuccessors(conflictgraph, node);
408 
409       /* check whether a neighbor variable is nonzero w.r.t. sol */
410       for (s = 0; s < nsucc; ++s)
411       {
412          var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
413          assert( var != NULL );
414          solval = SCIPgetSolVal(scip, sol, var);
415          if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) )
416             return TRUE;
417       }
418    }
419 
420    return FALSE;
421 }
422 
423 
424 /** returns solution value of imaginary binary big-M variable of a given node from the conflict graph */
425 static
nodeGetSolvalBinaryBigMSOS1(SCIP * scip,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,int node)426 SCIP_Real nodeGetSolvalBinaryBigMSOS1(
427    SCIP*                 scip,               /**< SCIP pointer */
428    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
429    SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
430    int                   node                /**< node of the conflict graph */
431    )
432 {
433    SCIP_Real bound;
434    SCIP_VAR* var;
435    SCIP_Real val;
436 
437    assert( scip != NULL );
438    assert( conflictgraph != NULL );
439    assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
440 
441    var = SCIPnodeGetVarSOS1(conflictgraph, node);
442    val = SCIPgetSolVal(scip, sol, var);
443 
444    if ( SCIPisFeasNegative(scip, val) )
445    {
446       bound = SCIPvarGetLbLocal(var);
447       assert( SCIPisFeasNegative(scip, bound) );
448 
449       if ( SCIPisInfinity(scip, -val) )
450          return 1.0;
451       else if ( SCIPisInfinity(scip, -bound) )
452          return 0.0;
453       else
454          return (val/bound);
455    }
456    else if ( SCIPisFeasPositive(scip, val) )
457    {
458       bound = SCIPvarGetUbLocal(var);
459       assert( SCIPisFeasPositive(scip, bound) );
460       assert( SCIPisFeasPositive(scip, val) );
461 
462       if ( SCIPisInfinity(scip, val) )
463          return 1.0;
464       else if ( SCIPisInfinity(scip, bound) )
465          return 0.0;
466       else
467          return (val/bound);
468    }
469    else
470       return 0.0;
471 }
472 
473 
474 /** gets (variable) lower bound value of current LP relaxation solution for a given node from the conflict graph */
475 static
nodeGetSolvalVarboundLbSOS1(SCIP * scip,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,int node)476 SCIP_Real nodeGetSolvalVarboundLbSOS1(
477    SCIP*                 scip,               /**< SCIP pointer */
478    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
479    SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
480    int                   node                /**< node of the conflict graph */
481    )
482 {
483    SCIP_NODEDATA* nodedata;
484 
485    assert( scip != NULL );
486    assert( conflictgraph != NULL );
487    assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
488 
489    /* get node data */
490    nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
491    assert( nodedata != NULL );
492 
493    /* if variable is not involved in a variable upper bound constraint */
494    if ( nodedata->lbboundvar == NULL || ! nodedata->lbboundcomp )
495       return SCIPvarGetLbLocal(nodedata->var);
496 
497    return nodedata->lbboundcoef * SCIPgetSolVal(scip, sol, nodedata->lbboundvar);
498 }
499 
500 
501 /** gets (variable) upper bound value of current LP relaxation solution for a given node from the conflict graph */
502 static
nodeGetSolvalVarboundUbSOS1(SCIP * scip,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,int node)503 SCIP_Real nodeGetSolvalVarboundUbSOS1(
504    SCIP*                 scip,               /**< SCIP pointer */
505    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
506    SCIP_SOL*             sol,                /**< primal solution, or NULL for current LP/pseudo solution */
507    int                   node                /**< node of the conflict graph */
508    )
509 {
510    SCIP_NODEDATA* nodedata;
511 
512    assert( scip != NULL );
513    assert( conflictgraph != NULL );
514    assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
515 
516    /* get node data */
517    nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
518    assert( nodedata != NULL );
519 
520    /* if variable is not involved in a variable upper bound constraint */
521    if ( nodedata->ubboundvar == NULL || ! nodedata->ubboundcomp )
522       return SCIPvarGetUbLocal(nodedata->var);
523 
524    return nodedata->ubboundcoef * SCIPgetSolVal(scip, sol, nodedata->ubboundvar);
525 }
526 
527 
528 /** returns whether variable is part of the SOS1 conflict graph */
529 static
varIsSOS1(SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var)530 SCIP_Bool varIsSOS1(
531    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< SOS1 constraint handler */
532    SCIP_VAR*             var                 /**< variable */
533    )
534 {
535    assert( conshdlrdata != NULL );
536    assert( var != NULL );
537 
538    if ( conshdlrdata->varhash == NULL || ! SCIPhashmapExists(conshdlrdata->varhash, var) )
539       return FALSE;
540 
541    return TRUE;
542 }
543 
544 
545 /** returns SOS1 index of variable or -1 if variable is not part of the SOS1 conflict graph */
546 static
varGetNodeSOS1(SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var)547 int varGetNodeSOS1(
548    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< SOS1 constraint handler */
549    SCIP_VAR*             var                 /**< variable */
550    )
551 {
552    assert( conshdlrdata != NULL );
553    assert( var != NULL );
554    assert( conshdlrdata->varhash != NULL );
555 
556    if ( ! SCIPhashmapExists(conshdlrdata->varhash, var) )
557       return -1;
558 
559    return SCIPhashmapGetImageInt(conshdlrdata->varhash, var);
560 }
561 
562 
563 /** fix variable in given node to 0 or add constraint if variable is multi-aggregated
564  *
565  *  @todo Try to handle multi-aggregated variables as in fixVariableZero() below.
566  */
567 static
fixVariableZeroNode(SCIP * scip,SCIP_VAR * var,SCIP_NODE * node,SCIP_Bool * infeasible)568 SCIP_RETCODE fixVariableZeroNode(
569    SCIP*                 scip,               /**< SCIP pointer */
570    SCIP_VAR*             var,                /**< variable to be fixed to 0*/
571    SCIP_NODE*            node,               /**< node */
572    SCIP_Bool*            infeasible          /**< if fixing is infeasible */
573    )
574 {
575    /* if variable cannot be nonzero */
576    *infeasible = FALSE;
577    if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) )
578    {
579       *infeasible = TRUE;
580       return SCIP_OKAY;
581    }
582 
583    /* if variable is multi-aggregated */
584    if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
585    {
586       SCIP_CONS* cons;
587       SCIP_Real val;
588 
589       val = 1.0;
590 
591       if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
592       {
593          SCIPdebugMsg(scip, "creating constraint to force multi-aggregated variable <%s> to 0.\n", SCIPvarGetName(var));
594          /* we have to insert a local constraint var = 0 */
595          SCIP_CALL( SCIPcreateConsLinear(scip, &cons, "branch", 1, &var, &val, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
596                TRUE, FALSE, FALSE, FALSE, FALSE) );
597          SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) );
598          SCIP_CALL( SCIPreleaseCons(scip, &cons) );
599       }
600    }
601    else
602    {
603       if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) )
604          SCIP_CALL( SCIPchgVarLbNode(scip, node, var, 0.0) );
605       if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
606          SCIP_CALL( SCIPchgVarUbNode(scip, node, var, 0.0) );
607    }
608 
609    return SCIP_OKAY;
610 }
611 
612 
613 /** try to fix variable to 0
614  *
615  *  Try to treat fixing by special consideration of multiaggregated variables. For a multi-aggregation
616  *  \f[
617  *  x = \sum_{i=1}^n \alpha_i x_i + c,
618  *  \f]
619  *  we can express the fixing \f$x = 0\f$ by fixing all \f$x_i\f$ to 0 if \f$c = 0\f$ and the lower bounds of \f$x_i\f$
620  *  are nonnegative if \f$\alpha_i > 0\f$ or the upper bounds are nonpositive if \f$\alpha_i < 0\f$.
621  */
622 static
fixVariableZero(SCIP * scip,SCIP_VAR * var,SCIP_Bool * infeasible,SCIP_Bool * tightened)623 SCIP_RETCODE fixVariableZero(
624    SCIP*                 scip,               /**< SCIP pointer */
625    SCIP_VAR*             var,                /**< variable to be fixed to 0*/
626    SCIP_Bool*            infeasible,         /**< if fixing is infeasible */
627    SCIP_Bool*            tightened           /**< if fixing was performed */
628    )
629 {
630    assert( scip != NULL );
631    assert( var != NULL );
632    assert( infeasible != NULL );
633    assert( tightened != NULL );
634 
635    *infeasible = FALSE;
636    *tightened = FALSE;
637 
638    if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
639    {
640       SCIP_Real aggrconst;
641 
642       /* if constant is 0 */
643       aggrconst = SCIPvarGetMultaggrConstant(var);
644       if ( SCIPisZero(scip, aggrconst) )
645       {
646          SCIP_VAR** aggrvars;
647          SCIP_Real* aggrvals;
648          SCIP_Bool allnonnegative = TRUE;
649          int naggrvars;
650          int i;
651 
652          SCIP_CALL( SCIPflattenVarAggregationGraph(scip, var) );
653 
654          /* check whether all variables are "nonnegative" */
655          naggrvars = SCIPvarGetMultaggrNVars(var);
656          aggrvars = SCIPvarGetMultaggrVars(var);
657          aggrvals = SCIPvarGetMultaggrScalars(var);
658          for (i = 0; i < naggrvars; ++i)
659          {
660             if ( (SCIPisPositive(scip, aggrvals[i]) && SCIPisNegative(scip, SCIPvarGetLbLocal(aggrvars[i]))) ||
661                  (SCIPisNegative(scip, aggrvals[i]) && SCIPisPositive(scip, SCIPvarGetUbLocal(aggrvars[i]))) )
662             {
663                allnonnegative = FALSE;
664                break;
665             }
666          }
667 
668          if ( allnonnegative )
669          {
670             /* all variables are nonnegative -> fix variables */
671             for (i = 0; i < naggrvars; ++i)
672             {
673                SCIP_Bool fixed;
674                SCIP_CALL( SCIPfixVar(scip, aggrvars[i], 0.0, infeasible, &fixed) );
675                if ( *infeasible )
676                   return SCIP_OKAY;
677                *tightened = *tightened || fixed;
678             }
679          }
680       }
681    }
682    else
683    {
684       SCIP_CALL( SCIPfixVar(scip, var, 0.0, infeasible, tightened) );
685    }
686 
687    return SCIP_OKAY;
688 }
689 
690 
691 /** fix variable in local node to 0, and return whether the operation was feasible
692  *
693  *  @note We do not add a linear constraint if the variable is multi-aggregated as in
694  *  fixVariableZeroNode(), since this would be too time consuming.
695  */
696 static
inferVariableZero(SCIP * scip,SCIP_VAR * var,SCIP_CONS * cons,int inferinfo,SCIP_Bool * infeasible,SCIP_Bool * tightened,SCIP_Bool * success)697 SCIP_RETCODE inferVariableZero(
698    SCIP*                 scip,               /**< SCIP pointer */
699    SCIP_VAR*             var,                /**< variable to be fixed to 0*/
700    SCIP_CONS*            cons,               /**< constraint */
701    int                   inferinfo,          /**< info for reverse prop. */
702    SCIP_Bool*            infeasible,         /**< if fixing is infeasible */
703    SCIP_Bool*            tightened,          /**< if fixing was performed */
704    SCIP_Bool*            success             /**< whether fixing was successful, i.e., variable is not multi-aggregated */
705    )
706 {
707    *infeasible = FALSE;
708    *tightened = FALSE;
709    *success = FALSE;
710 
711    /* if variable cannot be nonzero */
712    if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) )
713    {
714       *infeasible = TRUE;
715       return SCIP_OKAY;
716    }
717 
718    /* directly fix variable if it is not multi-aggregated */
719    if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR )
720    {
721       SCIP_Bool tighten;
722 
723       /* fix lower bound */
724       SCIP_CALL( SCIPinferVarLbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
725       *tightened = *tightened || tighten;
726 
727       /* fix upper bound */
728       SCIP_CALL( SCIPinferVarUbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
729       *tightened = *tightened || tighten;
730 
731       *success = TRUE;
732    }
733 
734    return SCIP_OKAY;
735 }
736 
737 
738 /** add lock on variable */
739 static
lockVariableSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)740 SCIP_RETCODE lockVariableSOS1(
741    SCIP*                 scip,               /**< SCIP data structure */
742    SCIP_CONS*            cons,               /**< constraint */
743    SCIP_VAR*             var                 /**< variable */
744    )
745 {
746    assert( scip != NULL );
747    assert( cons != NULL );
748    assert( var != NULL );
749 
750    /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
751    SCIP_CALL( SCIPlockVarCons(scip, var, cons, SCIPisFeasNegative(scip, SCIPvarGetLbGlobal(var)),
752          SCIPisFeasPositive(scip, SCIPvarGetUbGlobal(var))) );
753 
754    return SCIP_OKAY;
755 }
756 
757 
758 /** remove lock on variable */
759 static
unlockVariableSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)760 SCIP_RETCODE unlockVariableSOS1(
761    SCIP*                 scip,               /**< SCIP data structure */
762    SCIP_CONS*            cons,               /**< constraint */
763    SCIP_VAR*             var                 /**< variable */
764    )
765 {
766    assert( scip != NULL );
767    assert( cons != NULL );
768    assert( var != NULL );
769 
770    /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
771    SCIP_CALL( SCIPunlockVarCons(scip, var, cons, SCIPisFeasNegative(scip, SCIPvarGetLbGlobal(var)),
772          SCIPisFeasPositive(scip, SCIPvarGetUbGlobal(var))) );
773 
774    return SCIP_OKAY;
775 }
776 
777 
778 /** ensures that the vars and weights array can store at least num entries */
779 static
consdataEnsurevarsSizeSOS1(SCIP * scip,SCIP_CONSDATA * consdata,int num,SCIP_Bool reserveWeights)780 SCIP_RETCODE consdataEnsurevarsSizeSOS1(
781    SCIP*                 scip,               /**< SCIP data structure */
782    SCIP_CONSDATA*        consdata,           /**< constraint data */
783    int                   num,                /**< minimum number of entries to store */
784    SCIP_Bool             reserveWeights      /**< whether the weights array is handled */
785    )
786 {
787    assert( consdata != NULL );
788    assert( consdata->nvars <= consdata->maxvars );
789 
790    if ( num > consdata->maxvars )
791    {
792       int newsize;
793 
794       newsize = SCIPcalcMemGrowSize(scip, num);
795       SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->maxvars, newsize) );
796       if ( reserveWeights )
797          SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->maxvars, newsize) );
798       consdata->maxvars = newsize;
799    }
800    assert( num <= consdata->maxvars );
801 
802    return SCIP_OKAY;
803 }
804 
805 
806 /** handle new variable */
807 static
handleNewVariableSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_CONSDATA * consdata,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var,SCIP_Bool transformed)808 SCIP_RETCODE handleNewVariableSOS1(
809    SCIP*                 scip,               /**< SCIP data structure */
810    SCIP_CONS*            cons,               /**< constraint */
811    SCIP_CONSDATA*        consdata,           /**< constraint data */
812    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
813    SCIP_VAR*             var,                /**< variable */
814    SCIP_Bool             transformed         /**< whether original variable was transformed */
815    )
816 {
817    SCIP_DIGRAPH* conflictgraph;
818    int node;
819 
820    assert( scip != NULL );
821    assert( cons != NULL );
822    assert( consdata != NULL );
823    assert( conshdlrdata != NULL );
824    assert( var != NULL );
825 
826    /* if we are in transformed problem, catch the variable's events */
827    if ( transformed )
828    {
829       assert( conshdlrdata->eventhdlr != NULL );
830 
831       /* catch bound change events of variable */
832       SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
833             (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/
834 
835       /* if the variable if fixed to nonzero */
836       assert( consdata->nfixednonzeros >= 0 );
837       if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) )
838          ++consdata->nfixednonzeros;
839    }
840 
841    /* install the rounding locks for the new variable */
842    SCIP_CALL( lockVariableSOS1(scip, cons, var) );
843 
844    /* branching on multiaggregated variables does not seem to work well, so avoid it */
845    SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) );
846 
847    /* add the new coefficient to the upper bound LP row, if necessary */
848    if ( consdata->rowub != NULL && ! SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetUbGlobal(var)) )
849    {
850       SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowub, var, 1.0/SCIPvarGetUbGlobal(var)) );
851    }
852 
853    /* add the new coefficient to the lower bound LP row, if necessary */
854    if ( consdata->rowlb != NULL && ! SCIPisInfinity(scip, SCIPvarGetLbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetLbGlobal(var)) )
855    {
856       SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowlb, var, 1.0/SCIPvarGetLbGlobal(var)) );
857    }
858 
859    /* return if the conflict graph has not been created yet */
860    conflictgraph = conshdlrdata->conflictgraph;
861    if ( conflictgraph == NULL )
862       return SCIP_OKAY;
863 
864    /* get node of variable in the conflict graph (or -1) */
865    node = varGetNodeSOS1(conshdlrdata, var);
866    assert( node < conshdlrdata->nsos1vars );
867 
868    /* if the variable is not already a node of the conflict graph */
869    if ( node < 0 )
870    {
871       /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph
872        * @todo: maybe recompute the conflict graph, implication graph and varhash instead */
873       SCIPdebugMsg(scip, "Switched to SOS1 branching rule, since conflict graph could be infeasible.\n");
874       conshdlrdata->switchsos1branch = TRUE;
875       return SCIP_OKAY;
876    }
877 
878    /* if the constraint is local, then there is no need to act, since local constraints are handled by the local conflict graph in the
879     * function enforceConflictgraph() */
880    if ( ! consdata->local )
881    {
882       SCIP_VAR** vars;
883       int nvars;
884       int v;
885 
886       vars = consdata->vars;
887       nvars = consdata->nvars;
888 
889       for (v = 0; v < nvars; ++v)
890       {
891          int nodev;
892 
893          if ( var == vars[v] )
894             continue;
895 
896          /* get node of variable in the conflict graph (or -1) */
897          nodev = varGetNodeSOS1(conshdlrdata, vars[v]);
898          assert( nodev < conshdlrdata->nsos1vars );
899 
900          /* if the variable is already a node of the conflict graph */
901          if ( nodev >= 0 )
902          {
903             int nsucc;
904             int nsuccv;
905 
906             nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
907             nsuccv = SCIPdigraphGetNSuccessors(conflictgraph, nodev);
908 
909             /* add arcs if not existent */
910             SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, nodev, node, NULL) );
911             SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, node, nodev, NULL) );
912 
913             /* in case of new arcs: sort successors in ascending order */
914             if ( nsucc < SCIPdigraphGetNSuccessors(conflictgraph, node) )
915             {
916                SCIPdebugMsg(scip, "Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]));
917                SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, node), SCIPdigraphGetNSuccessors(conflictgraph, node));
918             }
919 
920             if ( nsuccv < SCIPdigraphGetNSuccessors(conflictgraph, nodev) )
921             {
922                SCIPdebugMsg(scip, "Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(vars[v]), SCIPvarGetName(var));
923                SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, nodev), SCIPdigraphGetNSuccessors(conflictgraph, nodev));
924             }
925          }
926          else
927          {
928             /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph
929              * @todo: maybe recompute the conflict graph, implication graph and varhash instead */
930             SCIPdebugMsg(scip, "Switched to SOS1 branching rule, since conflict graph could be infeasible.\n");
931             conshdlrdata->switchsos1branch = TRUE;
932             return SCIP_OKAY;
933          }
934       }
935    }
936 
937    return SCIP_OKAY;
938 }
939 
940 
941 /** adds a variable to an SOS1 constraint, at position given by weight - ascending order */
942 static
addVarSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var,SCIP_Real weight)943 SCIP_RETCODE addVarSOS1(
944    SCIP*                 scip,               /**< SCIP data structure */
945    SCIP_CONS*            cons,               /**< constraint */
946    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
947    SCIP_VAR*             var,                /**< variable to add to the constraint */
948    SCIP_Real             weight              /**< weight to determine position */
949    )
950 {
951    SCIP_CONSDATA* consdata;
952    SCIP_Bool transformed;
953    int pos;
954    int j;
955 
956    assert( var != NULL );
957    assert( cons != NULL );
958    assert( conshdlrdata != NULL );
959 
960    consdata = SCIPconsGetData(cons);
961    assert( consdata != NULL );
962 
963    if ( consdata->weights == NULL && consdata->maxvars > 0 )
964    {
965       SCIPerrorMessage("cannot add variable to SOS1 constraint <%s> that does not contain weights.\n", SCIPconsGetName(cons));
966       return SCIP_INVALIDCALL;
967    }
968 
969    /* are we in the transformed problem? */
970    transformed = SCIPconsIsTransformed(cons);
971 
972    /* always use transformed variables in transformed constraints */
973    if ( transformed )
974    {
975       SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
976    }
977    assert( var != NULL );
978    assert( transformed == SCIPvarIsTransformed(var) );
979 
980    SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, TRUE) );
981    assert( consdata->weights != NULL );
982    assert( consdata->maxvars >= consdata->nvars+1 );
983 
984    /* find variable position */
985    for (pos = 0; pos < consdata->nvars; ++pos)
986    {
987       if ( consdata->weights[pos] > weight )
988          break;
989    }
990    assert( 0 <= pos && pos <= consdata->nvars );
991 
992    /* move other variables, if necessary */
993    for (j = consdata->nvars; j > pos; --j)
994    {
995       consdata->vars[j] = consdata->vars[j-1];
996       consdata->weights[j] = consdata->weights[j-1];
997    }
998 
999    /* insert variable */
1000    consdata->vars[pos] = var;
1001    consdata->weights[pos] = weight;
1002    ++consdata->nvars;
1003 
1004    /* handle the new variable */
1005    SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) );
1006 
1007    return SCIP_OKAY;
1008 }
1009 
1010 
1011 /** appends a variable to an SOS1 constraint */
1012 static
appendVarSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var)1013 SCIP_RETCODE appendVarSOS1(
1014    SCIP*                 scip,               /**< SCIP data structure */
1015    SCIP_CONS*            cons,               /**< constraint */
1016    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
1017    SCIP_VAR*             var                 /**< variable to add to the constraint */
1018    )
1019 {
1020    SCIP_CONSDATA* consdata;
1021    SCIP_Bool transformed;
1022 
1023    assert( var != NULL );
1024    assert( cons != NULL );
1025    assert( conshdlrdata != NULL );
1026 
1027    consdata = SCIPconsGetData(cons);
1028    assert( consdata != NULL );
1029    assert( consdata->nvars >= 0 );
1030 
1031    /* are we in the transformed problem? */
1032    transformed = SCIPconsIsTransformed(cons);
1033 
1034    /* always use transformed variables in transformed constraints */
1035    if ( transformed )
1036    {
1037       SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1038    }
1039    assert( var != NULL );
1040    assert( transformed == SCIPvarIsTransformed(var) );
1041 
1042    if ( consdata->weights != NULL )
1043    {
1044       SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, TRUE) );
1045    }
1046    else
1047    {
1048       SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, FALSE) );
1049    }
1050 
1051    /* insert variable */
1052    consdata->vars[consdata->nvars] = var;
1053    if ( consdata->weights != NULL )
1054    {
1055       if ( consdata->nvars > 0 )
1056          consdata->weights[consdata->nvars] = consdata->weights[consdata->nvars-1] + 1.0;
1057       else
1058          consdata->weights[consdata->nvars] = 0.0;
1059    }
1060    ++consdata->nvars;
1061 
1062    /* handle the new variable */
1063    SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) );
1064 
1065    return SCIP_OKAY;
1066 }
1067 
1068 
1069 /** deletes a variable of an SOS1 constraint */
1070 static
deleteVarSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_CONSDATA * consdata,SCIP_EVENTHDLR * eventhdlr,int pos)1071 SCIP_RETCODE deleteVarSOS1(
1072    SCIP*                 scip,               /**< SCIP data structure */
1073    SCIP_CONS*            cons,               /**< constraint */
1074    SCIP_CONSDATA*        consdata,           /**< constraint data */
1075    SCIP_EVENTHDLR*       eventhdlr,          /**< corresponding event handler */
1076    int                   pos                 /**< position of variable in array */
1077    )
1078 {
1079    int j;
1080 
1081    assert( 0 <= pos && pos < consdata->nvars );
1082 
1083    /* remove lock of variable */
1084    SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[pos]) );
1085 
1086    /* drop events on variable */
1087    SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/
1088 
1089    /* delete variable - need to copy since order is important */
1090    for (j = pos; j < consdata->nvars-1; ++j)
1091    {
1092       consdata->vars[j] = consdata->vars[j+1]; /*lint !e679*/
1093       if ( consdata->weights != NULL )
1094          consdata->weights[j] = consdata->weights[j+1]; /*lint !e679*/
1095    }
1096    --consdata->nvars;
1097 
1098    return SCIP_OKAY;
1099 }
1100 
1101 
1102 /* ----------------------------- presolving --------------------------------------*/
1103 
1104 /** extends a given clique of the conflict graph
1105  *
1106  *  Implementation of the Bron-Kerbosch Algorithm from the paper:
1107  *  Algorithm 457: Finding all Cliques of an Undirected Graph, Bron & Kerbosch, Commun. ACM, 1973
1108  */
1109 static
extensionOperatorSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_Bool ** adjacencymatrix,SCIP_DIGRAPH * vertexcliquegraph,int nsos1vars,int nconss,SCIP_CONS * cons,SCIP_VAR ** vars,SCIP_Real * weights,SCIP_Bool firstcall,SCIP_Bool usebacktrack,int ** cliques,int * ncliques,int * cliquesizes,int * newclique,int * workingset,int nworkingset,int nexts,int pos,int * maxextensions,int * naddconss,SCIP_Bool * success)1110 SCIP_RETCODE extensionOperatorSOS1(
1111    SCIP*                 scip,               /**< SCIP pointer */
1112    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
1113    SCIP_Bool**           adjacencymatrix,    /**< adjacencymatrix of the conflict graph (only lower half filled) */
1114    SCIP_DIGRAPH*         vertexcliquegraph,  /**< graph that contains the information which cliques contain a given vertex
1115                                               *   vertices of variables = 0, ..., nsos1vars-1; vertices of cliques = nsos1vars, ..., nsos1vars+ncliques-1*/
1116    int                   nsos1vars,          /**< number of SOS1 variables */
1117    int                   nconss,             /**< number of SOS1 constraints */
1118    SCIP_CONS*            cons,               /**< constraint to be extended */
1119    SCIP_VAR**            vars,               /**< variables of extended clique */
1120    SCIP_Real*            weights,            /**< weights of extended clique */
1121    SCIP_Bool             firstcall,          /**< whether this is the first call of extension operator */
1122    SCIP_Bool             usebacktrack,       /**< whether backtracking is needed for the computation */
1123    int**                 cliques,            /**< all cliques found so far */
1124    int*                  ncliques,           /**< number of clique found so far */
1125    int*                  cliquesizes,        /**< number of variables of current clique */
1126    int*                  newclique,          /**< clique we want to extended*/
1127    int*                  workingset,         /**< set of vertices that already served as extension and set of candidates that probably will lead to an extension */
1128    int                   nworkingset,        /**< length of array workingset */
1129    int                   nexts,              /**< number of vertices that already served as extension */
1130    int                   pos,                /**< position of potential candidate */
1131    int*                  maxextensions,      /**< maximal number of extensions */
1132    int*                  naddconss,          /**< number of added constraints */
1133    SCIP_Bool*            success             /**< pointer to store if at least one new clique was found */
1134    )
1135 {
1136    int* workingsetnew = NULL;
1137    int nextsnew;
1138    int nworkingsetnew;
1139    int mincands;
1140    int btriter = 0; /* backtrack iterator */
1141    int selvertex;
1142    int selpos = -1;
1143    int fixvertex = -1;
1144    int i;
1145    int j;
1146 
1147    assert( scip != NULL );
1148    assert( conshdlrdata != NULL );
1149    assert( adjacencymatrix != NULL );
1150    assert( vertexcliquegraph != NULL );
1151    assert( cons != NULL );
1152    assert( cliques != NULL );
1153    assert( cliquesizes != NULL );
1154    assert( newclique != NULL );
1155    assert( workingset != NULL );
1156    assert( maxextensions != NULL );
1157    assert( naddconss != NULL );
1158    assert( success != NULL );
1159 
1160    if ( firstcall )
1161       *success = FALSE;
1162 
1163    mincands = nworkingset;
1164    if ( mincands < 1 )
1165       return SCIP_OKAY;
1166 
1167    /* allocate buffer array */
1168    SCIP_CALL( SCIPallocBufferArray(scip, &workingsetnew, nworkingset) );
1169 
1170 #ifdef SCIP_DEBUG
1171    for (i = 0; i < nexts; ++i)
1172    {
1173       for (j = nexts; j < nworkingset; ++j)
1174       {
1175          assert( isConnectedSOS1(adjacencymatrix, NULL, workingset[i], workingset[j]) );
1176       }
1177    }
1178 #endif
1179 
1180    /* determine candidate with minimum number of disconnections */
1181    for (i = 0; i < nworkingset; ++i)
1182    {
1183       int vertex;
1184       int cnt = 0;
1185 
1186       vertex = workingset[i];
1187 
1188       /* count disconnections */
1189       for (j = nexts; j < nworkingset && cnt < mincands; ++j)
1190       {
1191          if ( vertex != workingset[j] && ! isConnectedSOS1(adjacencymatrix, NULL, vertex, workingset[j]) )
1192          {
1193             cnt++;
1194 
1195             /* save position of potential candidate */
1196             pos = j;
1197          }
1198       }
1199 
1200       /* check whether a new minimum was found */
1201       if ( cnt < mincands )
1202       {
1203          fixvertex = vertex;
1204          mincands = cnt;
1205          if ( i < nexts )
1206          {
1207             assert( pos >= 0 );
1208             selpos = pos;
1209          }
1210          else
1211          {
1212             selpos = i;
1213 
1214             /* preincrement */
1215             btriter = 1;
1216          }
1217       }
1218    }
1219 
1220    /* If fixed point is initially chosen from candidates then number of disconnections will be preincreased by one. */
1221 
1222    /* backtrackcycle */
1223    for (btriter = mincands + btriter; btriter >= 1; --btriter)
1224    {
1225       assert( selpos >= 0);
1226       assert( fixvertex >= 0);
1227 
1228       /* interchange */
1229       selvertex = workingset[selpos];
1230       workingset[selpos] = workingset[nexts];
1231       workingset[nexts] = selvertex;
1232 
1233       /* create new workingset */
1234       nextsnew = 0;
1235       for (j = 0 ; j < nexts; ++j)
1236       {
1237          if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) )
1238             workingsetnew[nextsnew++] = workingset[j];
1239       }
1240       nworkingsetnew = nextsnew;
1241       for (j = nexts + 1; j < nworkingset; ++j)
1242       {
1243          if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) )
1244             workingsetnew[nworkingsetnew++] = workingset[j];
1245       }
1246 
1247       newclique[cliquesizes[*ncliques]++] = selvertex;
1248 
1249       /* if we found a new clique */
1250       if ( nworkingsetnew == 0 )
1251       {
1252          char consname[SCIP_MAXSTRLEN];
1253          SCIP_CONSDATA* consdata;
1254          SCIP_CONS* newcons;
1255          int cliqueind;
1256 
1257          cliqueind = nsos1vars + *ncliques; /* index of clique in the vertex-clique graph */
1258 
1259          /* save new clique */
1260          assert( cliquesizes[*ncliques] >= 0 && cliquesizes[*ncliques] <= nsos1vars );
1261          assert( *ncliques < MAX(1, conshdlrdata->maxextensions) * nconss );
1262          SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(cliques[*ncliques]), cliquesizes[*ncliques]) );/*lint !e866*/
1263          for (j = 0 ; j < cliquesizes[*ncliques]; ++j)
1264          {
1265             vars[j] = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, newclique[j]);
1266             weights[j] = j+1;
1267             cliques[*ncliques][j] = newclique[j];
1268          }
1269 
1270          SCIPsortInt(cliques[*ncliques], cliquesizes[*ncliques]);
1271 
1272          /* create new constraint */
1273          (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "extsos1_%d", conshdlrdata->cntextsos1);
1274 
1275          SCIP_CALL( SCIPcreateConsSOS1(scip, &newcons, consname, cliquesizes[*ncliques], vars, weights,
1276                SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons),
1277                SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
1278                SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
1279                SCIPconsIsDynamic(cons),
1280                SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
1281 
1282          consdata = SCIPconsGetData(newcons);
1283 
1284          /* add directed edges to the vertex-clique graph */
1285          for (j = 0; j < consdata->nvars; ++j)
1286          {
1287             /* add arc from clique vertex to clique (needed in presolRoundConssSOS1() to delete redundand cliques) */
1288             SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[*ncliques][j], cliqueind, NULL) );
1289          }
1290 
1291          SCIP_CALL( SCIPaddCons(scip, newcons) );
1292          SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1293 
1294          ++(*naddconss);
1295          ++(conshdlrdata->cntextsos1);
1296          ++(*ncliques);
1297          cliquesizes[*ncliques] = cliquesizes[*ncliques-1]; /* cliquesizes[*ncliques] = size of newclique */
1298 
1299          *success = TRUE;
1300 
1301          --(*maxextensions);
1302 
1303          if ( *maxextensions <= 0 )
1304          {
1305             SCIPfreeBufferArray(scip, &workingsetnew);
1306             return SCIP_OKAY;
1307          }
1308       }
1309       else if ( nextsnew < nworkingsetnew ) /* else if the number of of candidates equals zero */
1310       {
1311          /* if backtracking is used, it is necessary to keep the memory for 'workingsetnew' */
1312          if ( usebacktrack )
1313          {
1314             SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack,
1315                   cliques, ncliques, cliquesizes, newclique, workingsetnew, nworkingsetnew, nextsnew, pos, maxextensions, naddconss, success) );
1316             if ( *maxextensions <= 0 )
1317             {
1318                SCIPfreeBufferArrayNull(scip, &workingsetnew);
1319                return SCIP_OKAY;
1320             }
1321          }
1322          else
1323          {
1324             int w;
1325 
1326             assert( nworkingset >= nworkingsetnew );
1327             for (w = 0; w < nworkingsetnew; ++w)
1328                workingset[w] = workingsetnew[w];
1329             nworkingset = nworkingsetnew;
1330 
1331             SCIPfreeBufferArrayNull(scip, &workingsetnew);
1332 
1333             SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack,
1334                   cliques, ncliques, cliquesizes, newclique, workingset, nworkingset, nextsnew, pos, maxextensions, naddconss, success) );
1335             assert( *maxextensions <= 0 );
1336             return SCIP_OKAY;
1337          }
1338       }
1339       assert( workingsetnew != NULL );
1340       assert( workingset != NULL );
1341 
1342       /* remove selvertex from clique */
1343       --cliquesizes[*ncliques];
1344 
1345       /* add selvertex to the set of vertices that already served as extension */
1346       ++nexts;
1347 
1348       if ( btriter > 1 )
1349       {
1350          /* select a candidate that is not connected to the fixed vertex */
1351          for (j = nexts; j < nworkingset; ++j)
1352          {
1353             assert( fixvertex != workingset[j] );
1354             if ( ! isConnectedSOS1(adjacencymatrix, NULL, fixvertex, workingset[j]) )
1355             {
1356                selpos = j;
1357                break;
1358             }
1359          }
1360       }
1361    }
1362 
1363    SCIPfreeBufferArrayNull(scip, &workingsetnew);
1364 
1365    return SCIP_OKAY;
1366 }
1367 
1368 
1369 /** generates conflict graph that is induced by the variables of a linear constraint */
1370 static
genConflictgraphLinearCons(SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraphlin,SCIP_DIGRAPH * conflictgraphorig,SCIP_VAR ** linvars,int nlinvars,int * posinlinvars)1371 SCIP_RETCODE genConflictgraphLinearCons(
1372    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
1373    SCIP_DIGRAPH*         conflictgraphlin,   /**< conflict graph of linear constraint (nodes: 1, ..., nlinvars) */
1374    SCIP_DIGRAPH*         conflictgraphorig,  /**< original conflict graph (nodes: 1, ..., nsos1vars) */
1375    SCIP_VAR**            linvars,            /**< linear variables in linear constraint */
1376    int                   nlinvars,           /**< number of linear variables in linear constraint */
1377    int*                  posinlinvars        /**< posinlinvars[i] = position (index) of SOS1 variable i in linear constraint,
1378                                               *   posinlinvars[i]= -1 if @p i is not a SOS1 variable or not a variable of the linear constraint */
1379    )
1380 {
1381    int indexinsosvars;
1382    int indexinlinvars;
1383    int* succ;
1384    int nsucc;
1385    int v;
1386    int s;
1387 
1388    assert( conflictgraphlin != NULL );
1389    assert( conflictgraphorig != NULL );
1390    assert( linvars != NULL );
1391    assert( posinlinvars != NULL );
1392 
1393    for (v = 1; v < nlinvars; ++v) /* we start with v = 1, since "indexinlinvars < v" (see below) is never fulfilled for v = 0 */
1394    {
1395       indexinsosvars = varGetNodeSOS1(conshdlrdata, linvars[v]);
1396 
1397       /* if linvars[v] is contained in at least one SOS1 constraint */
1398       if ( indexinsosvars >= 0 )
1399       {
1400          succ = SCIPdigraphGetSuccessors(conflictgraphorig, indexinsosvars);
1401          nsucc = SCIPdigraphGetNSuccessors(conflictgraphorig, indexinsosvars);
1402 
1403          for (s = 0; s < nsucc; ++s)
1404          {
1405             assert( succ[s] >= 0 );
1406             indexinlinvars = posinlinvars[succ[s]];
1407             assert( indexinlinvars < nlinvars );
1408 
1409             if ( indexinlinvars >= 0 && indexinlinvars < v )
1410             {
1411                SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, v, indexinlinvars, NULL) );
1412                SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, indexinlinvars, v, NULL) );
1413             }
1414          }
1415       }
1416    }
1417 
1418    return SCIP_OKAY;
1419 }
1420 
1421 
1422 /** determine the common successors of the vertices from the considered clique */
1423 static
cliqueGetCommonSuccessorsSOS1(SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,int * clique,SCIP_VAR ** vars,int nvars,int * comsucc,int * ncomsucc)1424 SCIP_RETCODE cliqueGetCommonSuccessorsSOS1(
1425    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
1426    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
1427    int*                  clique,             /**< current clique */
1428    SCIP_VAR**            vars,               /**< clique variables */
1429    int                   nvars,              /**< number of clique variables */
1430    int*                  comsucc,            /**< pointer to store common successors of clique vertices (size = nvars) */
1431    int*                  ncomsucc            /**< pointer to store number common successors of clique vertices */
1432    )
1433 {
1434    int nsucc;
1435    int* succ;
1436    int ind;
1437    int k = 0;
1438    int v;
1439    int i;
1440    int j;
1441 
1442    assert( conflictgraph != NULL );
1443    assert( clique != NULL );
1444    assert( vars != NULL );
1445    assert( comsucc != NULL );
1446    assert( ncomsucc != NULL );
1447 
1448    *ncomsucc = 0;
1449 
1450    /* determine the common successors of the vertices from the considered clique */
1451 
1452    /* determine successors of variable var[0] that are not in the clique */
1453    assert(vars[0] != NULL );
1454    ind =  varGetNodeSOS1(conshdlrdata, vars[0]);
1455 
1456    if( ind == -1 )
1457       return SCIP_INVALIDDATA;
1458 
1459    assert( ind < SCIPdigraphGetNNodes(conflictgraph) );
1460    nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind);
1461    succ = SCIPdigraphGetSuccessors(conflictgraph, ind);
1462 
1463    for (j = 0; j < nvars; ++j)
1464    {
1465       for (i = k; i < nsucc; ++i)
1466       {
1467          if ( succ[i] > clique[j] )
1468          {
1469             k = i;
1470             break;
1471          }
1472          else if ( succ[i] == clique[j] )
1473          {
1474             k = i + 1;
1475             break;
1476          }
1477          else
1478             comsucc[(*ncomsucc)++] = succ[i];
1479       }
1480    }
1481 
1482    /* for all variables except the first one */
1483    for (v = 1; v < nvars; ++v)
1484    {
1485       int ncomsuccsave = 0;
1486       k = 0;
1487 
1488       assert(vars[v] != NULL );
1489       ind =  varGetNodeSOS1(conshdlrdata, vars[v]);
1490       assert( ind >= 0 && ind < SCIPdigraphGetNNodes(conflictgraph) );
1491 
1492       if ( ind >= 0 )
1493       {
1494          nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind);
1495          succ = SCIPdigraphGetSuccessors(conflictgraph, ind);
1496 
1497          /* determine successors that are in comsucc */
1498          for (j = 0; j < *ncomsucc; ++j)
1499          {
1500             for (i = k; i < nsucc; ++i)
1501             {
1502                if ( succ[i] > comsucc[j] )
1503                {
1504                   k = i;
1505                   break;
1506                }
1507                else if ( succ[i] == comsucc[j] )
1508                {
1509                   comsucc[ncomsuccsave++] = succ[i];
1510                   k = i + 1;
1511                   break;
1512                }
1513             }
1514          }
1515          *ncomsucc = ncomsuccsave;
1516       }
1517    }
1518 
1519    return SCIP_OKAY;
1520 }
1521 
1522 
1523 /** get nodes whose corresponding SOS1 variables are nonzero if an SOS1 variable of a given node is nonzero */
1524 static
getSOS1Implications(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR ** vars,SCIP_DIGRAPH * implgraph,SCIP_HASHMAP * implhash,SCIP_Bool * implnodes,int node)1525 SCIP_RETCODE getSOS1Implications(
1526    SCIP*                 scip,               /**< SCIP pointer */
1527    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
1528    SCIP_VAR**            vars,               /**< problem and SOS1 variables */
1529    SCIP_DIGRAPH*         implgraph,          /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
1530    SCIP_HASHMAP*         implhash,           /**< hash map from variable to node in implication graph */
1531    SCIP_Bool*            implnodes,          /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
1532    int                   node                /**< node of the implication graph */
1533    )
1534 {
1535    SCIP_SUCCDATA** succdatas;
1536    int sos1node;
1537    int* succ;
1538    int nsucc;
1539    int s;
1540 
1541    assert( scip != NULL );
1542    assert( implgraph != NULL );
1543    assert( implnodes != NULL );
1544    assert( node >= 0 );
1545    assert( vars[node] != NULL );
1546    assert( SCIPhashmapGetImageInt(implhash, vars[node]) == node );
1547 
1548    /* get node of variable in the conflict graph (-1 if variable is no SOS1 variable) */
1549    sos1node = varGetNodeSOS1(conshdlrdata, vars[node]);
1550    if ( sos1node < 0 )
1551       return SCIP_OKAY;
1552 
1553    succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node);
1554    nsucc = SCIPdigraphGetNSuccessors(implgraph, node);
1555    succ = SCIPdigraphGetSuccessors(implgraph, node);
1556 
1557    for (s = 0; s < nsucc; ++s)
1558    {
1559       SCIP_SUCCDATA* data;
1560       int succnode;
1561       succnode = succ[s];
1562       data = succdatas[s];
1563       sos1node = varGetNodeSOS1(conshdlrdata, vars[succnode]);
1564 
1565       /* if node is SOS1 and the corresponding variable is implied to be nonzero */
1566       assert( succdatas[s] != NULL );
1567       if ( sos1node >= 0 && ! implnodes[sos1node] && ( SCIPisFeasPositive(scip, data->lbimpl) || SCIPisFeasNegative(scip, data->ubimpl) ) )
1568       {
1569          assert( sos1node == succnode );
1570          implnodes[sos1node] = TRUE;
1571          SCIP_CALL( getSOS1Implications(scip, conshdlrdata, vars, implgraph, implhash, implnodes, succnode) );
1572       }
1573    }
1574 
1575    return SCIP_OKAY;
1576 }
1577 
1578 
1579 /** perform one presolving round for a single SOS1 constraint
1580  *
1581  *  We perform the following presolving steps.
1582  *
1583  *  - If the bounds of some variable force it to be nonzero, we can
1584  *    fix all other variables to zero and remove the SOS1 constraints
1585  *    that contain it.
1586  *  - If a variable is fixed to zero, we can remove the variable.
1587  *  - If a variable appears twice, it can be fixed to 0.
1588  *  - We substitute appregated variables.
1589  */
1590 static
presolRoundConsSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_CONSDATA * consdata,SCIP_EVENTHDLR * eventhdlr,SCIP_Bool * substituted,SCIP_Bool * cutoff,SCIP_Bool * success,int * ndelconss,int * nupgdconss,int * nfixedvars,int * nremovedvars)1591 SCIP_RETCODE presolRoundConsSOS1(
1592    SCIP*                 scip,               /**< SCIP pointer */
1593    SCIP_CONS*            cons,               /**< constraint */
1594    SCIP_CONSDATA*        consdata,           /**< constraint data */
1595    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1596    SCIP_Bool*            substituted,        /**< whether a variable was substituted */
1597    SCIP_Bool*            cutoff,             /**< whether a cutoff happened */
1598    SCIP_Bool*            success,            /**< whether we performed a successful reduction */
1599    int*                  ndelconss,          /**< number of deleted constraints */
1600    int*                  nupgdconss,         /**< number of upgraded constraints */
1601    int*                  nfixedvars,         /**< number of fixed variables */
1602    int*                  nremovedvars        /**< number of variables removed */
1603    )
1604 {
1605    SCIP_VAR** vars;
1606    SCIP_Bool allvarsbinary;
1607    SCIP_Bool infeasible;
1608    SCIP_Bool fixed;
1609    int nfixednonzeros;
1610    int lastFixedNonzero;
1611    int j;
1612 
1613    assert( scip != NULL );
1614    assert( cons != NULL );
1615    assert( consdata != NULL );
1616    assert( eventhdlr != NULL );
1617    assert( cutoff != NULL );
1618    assert( success != NULL );
1619    assert( ndelconss != NULL );
1620    assert( nfixedvars != NULL );
1621    assert( nremovedvars != NULL );
1622 
1623    *substituted = FALSE;
1624    *cutoff = FALSE;
1625    *success = FALSE;
1626 
1627    SCIPdebugMsg(scip, "Presolving SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
1628 
1629    j = 0;
1630    nfixednonzeros = 0;
1631    lastFixedNonzero = -1;
1632    allvarsbinary = TRUE;
1633    vars = consdata->vars;
1634 
1635    /* check for variables fixed to 0 and bounds that fix a variable to be nonzero */
1636    while ( j < consdata->nvars )
1637    {
1638       int l;
1639       SCIP_VAR* var;
1640       SCIP_Real lb;
1641       SCIP_Real ub;
1642       SCIP_Real scalar;
1643       SCIP_Real constant;
1644 
1645       scalar = 1.0;
1646       constant = 0.0;
1647 
1648       /* check for aggregation: if the constant is zero the variable is zero iff the aggregated
1649        * variable is 0 */
1650       var = vars[j];
1651       SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
1652 
1653       /* if constant is zero and we get a different variable, substitute variable */
1654       if ( SCIPisZero(scip, constant) && ! SCIPisZero(scip, scalar) && var != vars[j] )
1655       {
1656          SCIPdebugMsg(scip, "substituted variable <%s> by <%s>.\n", SCIPvarGetName(vars[j]), SCIPvarGetName(var));
1657          SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/
1658          SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/
1659 
1660          /* change the rounding locks */
1661          SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[j]) );
1662          SCIP_CALL( lockVariableSOS1(scip, cons, var) );
1663 
1664          vars[j] = var;
1665          *substituted = TRUE;
1666       }
1667 
1668       /* check whether the variable appears again later */
1669       for (l = j+1; l < consdata->nvars; ++l)
1670       {
1671          /* if variable appeared before, we can fix it to 0 and remove it */
1672          if ( vars[j] == vars[l] )
1673          {
1674             SCIPdebugMsg(scip, "variable <%s> appears twice in constraint, fixing it to 0.\n", SCIPvarGetName(vars[j]));
1675             SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) );
1676 
1677             if ( infeasible )
1678             {
1679                *cutoff = TRUE;
1680                return SCIP_OKAY;
1681             }
1682             if ( fixed )
1683                ++(*nfixedvars);
1684          }
1685       }
1686 
1687       /* get bounds */
1688       lb = SCIPvarGetLbLocal(vars[j]);
1689       ub = SCIPvarGetUbLocal(vars[j]);
1690 
1691       /* if the variable if fixed to nonzero */
1692       if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) )
1693       {
1694          ++nfixednonzeros;
1695          lastFixedNonzero = j;
1696       }
1697 
1698       /* if the variable is fixed to 0 */
1699       if ( SCIPisFeasZero(scip, lb) && SCIPisFeasZero(scip, ub) )
1700       {
1701          SCIPdebugMsg(scip, "deleting variable <%s> fixed to 0.\n", SCIPvarGetName(vars[j]));
1702          SCIP_CALL( deleteVarSOS1(scip, cons, consdata, eventhdlr, j) );
1703          ++(*nremovedvars);
1704       }
1705       else
1706       {
1707          /* check whether all variables are binary */
1708          if ( ! SCIPvarIsBinary(vars[j]) )
1709             allvarsbinary = FALSE;
1710 
1711          ++j;
1712       }
1713    }
1714 
1715    /* if the number of variables is less than 2 */
1716    if ( consdata->nvars < 2 )
1717    {
1718       SCIPdebugMsg(scip, "Deleting SOS1 constraint <%s> with < 2 variables.\n", SCIPconsGetName(cons));
1719 
1720       /* delete constraint */
1721       assert( ! SCIPconsIsModifiable(cons) );
1722       SCIP_CALL( SCIPdelCons(scip, cons) );
1723       ++(*ndelconss);
1724       *success = TRUE;
1725       return SCIP_OKAY;
1726    }
1727 
1728    /* if more than one variable are fixed to be nonzero, we are infeasible */
1729    if ( nfixednonzeros > 1 )
1730    {
1731       SCIPdebugMsg(scip, "The problem is infeasible: more than one variable has bounds that keep it from being 0.\n");
1732       assert( lastFixedNonzero >= 0 );
1733       *cutoff = TRUE;
1734       return SCIP_OKAY;
1735    }
1736 
1737    /* if there is exactly one fixed nonzero variable */
1738    if ( nfixednonzeros == 1 )
1739    {
1740       assert( lastFixedNonzero >= 0 );
1741 
1742       /* fix all other variables to zero */
1743       for (j = 0; j < consdata->nvars; ++j)
1744       {
1745          if ( j != lastFixedNonzero )
1746          {
1747             SCIP_CALL( fixVariableZero(scip, vars[j], &infeasible, &fixed) );
1748             if ( infeasible )
1749             {
1750                *cutoff = TRUE;
1751                return SCIP_OKAY;
1752             }
1753             if ( fixed )
1754                ++(*nfixedvars);
1755          }
1756       }
1757 
1758       SCIPdebugMsg(scip, "Deleting redundant SOS1 constraint <%s> with one variable.\n", SCIPconsGetName(cons));
1759 
1760       /* delete original constraint */
1761       assert( ! SCIPconsIsModifiable(cons) );
1762       SCIP_CALL( SCIPdelCons(scip, cons) );
1763       ++(*ndelconss);
1764       *success = TRUE;
1765    }
1766    /* note: there is no need to update consdata->nfixednonzeros, since the constraint is deleted as soon nfixednonzeros > 0. */
1767    else
1768    {
1769       /* if all variables are binary create a set packing constraint */
1770       if ( allvarsbinary && SCIPfindConshdlr(scip, "setppc") != NULL )
1771       {
1772          SCIP_CONS* setpackcons;
1773 
1774          /* create, add, and release the logicor constraint */
1775          SCIP_CALL( SCIPcreateConsSetpack(scip, &setpackcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
1776                SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
1777                SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons),
1778                SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
1779          SCIP_CALL( SCIPaddCons(scip, setpackcons) );
1780          SCIP_CALL( SCIPreleaseCons(scip, &setpackcons) );
1781 
1782          SCIPdebugMsg(scip, "Upgrading SOS1 constraint <%s> to set packing constraint.\n", SCIPconsGetName(cons));
1783 
1784          /* remove the SOS1 constraint globally */
1785          assert( ! SCIPconsIsModifiable(cons) );
1786          SCIP_CALL( SCIPdelCons(scip, cons) );
1787          ++(*nupgdconss);
1788          *success = TRUE;
1789       }
1790    }
1791 
1792    return SCIP_OKAY;
1793 }
1794 
1795 
1796 
1797 /** perform one presolving round for all SOS1 constraints
1798  *
1799  *  We perform the following presolving steps.
1800  *
1801  *  - If the bounds of some variable force it to be nonzero, we can
1802  *    fix all other variables to zero and remove the SOS1 constraints
1803  *    that contain it.
1804  *  - If a variable is fixed to zero, we can remove the variable.
1805  *  - If a variable appears twice, it can be fixed to 0.
1806  *  - We substitute appregated variables.
1807  *  - Remove redundant SOS1 constraints
1808  *
1809  *  If the adjacency matrix of the conflict graph is present, then
1810  *  we perform the following additional presolving steps
1811  *
1812  *  - Search for larger SOS1 constraints in the conflict graph
1813  *
1814  *  @todo Use one long array for storing cliques.
1815  */
1816 static
presolRoundConssSOS1(SCIP * scip,SCIP_EVENTHDLR * eventhdlr,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_Bool ** adjacencymatrix,SCIP_CONS ** conss,int nconss,int nsos1vars,int * naddconss,int * ndelconss,int * nupgdconss,int * nfixedvars,int * nremovedvars,SCIP_RESULT * result)1817 SCIP_RETCODE presolRoundConssSOS1(
1818    SCIP*                 scip,               /**< SCIP pointer */
1819    SCIP_EVENTHDLR*       eventhdlr,          /**< event handler */
1820    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
1821    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
1822    SCIP_Bool**           adjacencymatrix,    /**< adjacency matrix of conflict graph (or NULL) */
1823    SCIP_CONS**           conss,              /**< SOS1 constraints */
1824    int                   nconss,             /**< number of SOS1 constraints */
1825    int                   nsos1vars,          /**< number of SOS1 variables */
1826    int*                  naddconss,          /**< number of added constraints */
1827    int*                  ndelconss,          /**< number of deleted constraints */
1828    int*                  nupgdconss,         /**< number of upgraded constraints */
1829    int*                  nfixedvars,         /**< number of fixed variables */
1830    int*                  nremovedvars,       /**< number of variables removed */
1831    SCIP_RESULT*          result              /**< result */
1832    )
1833 {
1834    SCIP_DIGRAPH* vertexcliquegraph;
1835    SCIP_VAR** consvars;
1836    SCIP_Real* consweights;
1837    int** cliques = NULL;
1838    int ncliques = 0;
1839    int* cliquesizes = NULL;
1840    int* newclique = NULL;
1841    int* indconss = NULL;
1842    int* lengthconss = NULL;
1843    int* comsucc = NULL;
1844    int csize;
1845    int iter;
1846    int c;
1847 
1848    assert( scip != NULL );
1849    assert( eventhdlr != NULL );
1850    assert( conshdlrdata != NULL );
1851    assert( conflictgraph != NULL );
1852    assert( conss != NULL );
1853    assert( naddconss != NULL );
1854    assert( ndelconss != NULL );
1855    assert( nupgdconss != NULL );
1856    assert( nfixedvars != NULL );
1857    assert( nremovedvars != NULL );
1858    assert( result != NULL );
1859 
1860    /* create digraph whose nodes represent variables and cliques in the conflict graph */
1861    csize = MAX(1, conshdlrdata->maxextensions) * nconss;
1862    SCIP_CALL( SCIPcreateDigraph(scip, &vertexcliquegraph, nsos1vars + csize) );
1863 
1864    /* allocate buffer arrays */
1865    SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nsos1vars) );
1866    SCIP_CALL( SCIPallocBufferArray(scip, &consweights, nsos1vars) );
1867    SCIP_CALL( SCIPallocBufferArray(scip, &newclique, nsos1vars) );
1868    SCIP_CALL( SCIPallocBufferArray(scip, &indconss, csize) );
1869    SCIP_CALL( SCIPallocBufferArray(scip, &lengthconss, csize) );
1870    SCIP_CALL( SCIPallocBufferArray(scip, &comsucc, MAX(nsos1vars, csize)) );
1871 
1872    /* Use block memory for cliques, because sizes might be quite different and allocation interfers with workingset. */
1873    SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliquesizes, csize) );
1874    SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliques, csize) );
1875 
1876    /* get constraint indices and sort them in descending order of their lengths */
1877    for (c = 0; c < nconss; ++c)
1878    {
1879       SCIP_CONSDATA* consdata;
1880 
1881       consdata = SCIPconsGetData(conss[c]);
1882       assert( consdata != NULL );
1883 
1884       indconss[c] = c;
1885       lengthconss[c] = consdata->nvars;
1886    }
1887    SCIPsortDownIntInt(lengthconss, indconss, nconss);
1888 
1889    /* check each constraint */
1890    for (iter = 0; iter < nconss; ++iter)
1891    {
1892       SCIP_CONSDATA* consdata;
1893       SCIP_CONS* cons;
1894       SCIP_Bool substituted;
1895       SCIP_Bool success;
1896       SCIP_Bool cutoff;
1897       int savennupgdconss;
1898       int savendelconss;
1899 
1900       SCIP_VAR** vars;
1901       int nvars;
1902 
1903       c = indconss[iter];
1904 
1905       assert( conss != NULL );
1906       assert( conss[c] != NULL );
1907       cons = conss[c];
1908       consdata = SCIPconsGetData(cons);
1909 
1910       assert( consdata != NULL );
1911       assert( consdata->nvars >= 0 );
1912       assert( consdata->nvars <= consdata->maxvars );
1913       assert( ! SCIPconsIsModifiable(cons) );
1914       assert( ncliques < csize );
1915 
1916       savendelconss = *ndelconss;
1917       savennupgdconss = *nupgdconss;
1918 
1919       /* perform one presolving round for SOS1 constraint */
1920       SCIP_CALL( presolRoundConsSOS1(scip, cons, consdata, eventhdlr, &substituted, &cutoff, &success, ndelconss, nupgdconss, nfixedvars, nremovedvars) );
1921 
1922       if ( cutoff )
1923       {
1924          *result = SCIP_CUTOFF;
1925          break;
1926       }
1927 
1928       if ( *ndelconss > savendelconss || *nupgdconss > savennupgdconss || substituted )
1929       {
1930          *result = SCIP_SUCCESS;
1931          continue;
1932       }
1933 
1934       if ( success )
1935          *result = SCIP_SUCCESS;
1936 
1937       /* get number of variables of constraint */
1938       nvars = consdata->nvars;
1939 
1940       /* get variables of constraint */
1941       vars = consdata->vars;
1942 
1943       if ( nvars > 1 && conshdlrdata->maxextensions != 0 )
1944       {
1945          SCIP_Bool extended = FALSE;
1946          int cliquesize = 0;
1947          int ncomsucc = 0;
1948          int varprobind;
1949          int j;
1950 
1951          /* get clique and size of clique */
1952          for (j = 0; j < nvars; ++j)
1953          {
1954             varprobind = varGetNodeSOS1(conshdlrdata, vars[j]);
1955 
1956             if ( varprobind >= 0 )
1957                newclique[cliquesize++] = varprobind;
1958          }
1959 
1960          if ( cliquesize > 1 )
1961          {
1962             cliquesizes[ncliques] = cliquesize;
1963 
1964             /* sort clique vertices */
1965             SCIPsortInt(newclique, cliquesizes[ncliques]);
1966 
1967             /* check if clique is contained in an already known clique */
1968             if ( ncliques > 0 )
1969             {
1970                int* succ;
1971                int nsucc;
1972                int v;
1973 
1974                varprobind = newclique[0];
1975                ncomsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind);
1976                succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind);
1977 
1978                /* get all (already processed) cliques that contain 'varpropind' */
1979                for (j = 0; j < ncomsucc; ++j)
1980                {
1981                   /* successors should have been sorted in a former step of the algorithm */
1982                   assert( j == 0 || succ[j] > succ[j-1] );
1983                   comsucc[j] = succ[j];
1984                }
1985 
1986                /* loop through remaining nodes of clique (case v = 0 already processed) */
1987                for (v = 1; v < cliquesize && ncomsucc > 0; ++v)
1988                {
1989                   varprobind = newclique[v];
1990 
1991                   /* get all (already processed) cliques that contain 'varpropind' */
1992                   nsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind);
1993                   succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind);
1994                   assert( succ != NULL || nsucc == 0 );
1995 
1996                   if ( nsucc < 1 )
1997                   {
1998                      ncomsucc = 0;
1999                      break;
2000                   }
2001 
2002                   /* get intersection with comsucc */
2003                   SCIP_CALL( SCIPcomputeArraysIntersection(comsucc, ncomsucc, succ, nsucc, comsucc, &ncomsucc) );
2004                }
2005             }
2006 
2007             /* if constraint is redundand then delete it */
2008             if ( ncomsucc > 0 )
2009             {
2010                assert( ! SCIPconsIsModifiable(cons) );
2011                SCIP_CALL( SCIPdelCons(scip, cons) );
2012                ++(*ndelconss);
2013                *result = SCIP_SUCCESS;
2014                continue;
2015             }
2016 
2017             if ( conshdlrdata->maxextensions != 0 && adjacencymatrix != NULL )
2018             {
2019                int maxextensions;
2020                ncomsucc = 0;
2021 
2022                /* determine the common successors of the vertices from the considered clique */
2023                SCIP_CALL( cliqueGetCommonSuccessorsSOS1(conshdlrdata, conflictgraph, newclique, vars, nvars, comsucc, &ncomsucc) );
2024 
2025                /* find extensions for the clique */
2026                maxextensions = conshdlrdata->maxextensions;
2027                extended = FALSE;
2028                SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, consvars, consweights,
2029                      TRUE, (maxextensions <= 1) ? FALSE : TRUE, cliques, &ncliques, cliquesizes, newclique, comsucc, ncomsucc, 0, -1, &maxextensions,
2030                      naddconss, &extended) );
2031             }
2032 
2033             /* if an extension was found for the current clique then free the old SOS1 constraint */
2034             if ( extended )
2035             {
2036                assert( ! SCIPconsIsModifiable(cons) );
2037                SCIP_CALL( SCIPdelCons(scip, cons) );
2038                ++(*ndelconss);
2039                *result = SCIP_SUCCESS;
2040             }
2041             else /* if we keep the constraint */
2042             {
2043                int cliqueind;
2044 
2045                cliqueind = nsos1vars + ncliques; /* index of clique in vertex-clique graph */
2046 
2047                /* add directed edges to the vertex-clique graph */
2048                assert( cliquesize >= 0 && cliquesize <= nsos1vars );
2049                assert( ncliques < csize );
2050                SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cliques[ncliques], cliquesize) );/*lint !e866*/
2051                for (j = 0; j < cliquesize; ++j)
2052                {
2053                   cliques[ncliques][j] = newclique[j];
2054                   SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[ncliques][j], cliqueind, NULL) );
2055                }
2056 
2057                /* update number of maximal cliques */
2058                ++ncliques;
2059             }
2060          }
2061       }
2062    }
2063 
2064    /* free buffer arrays */
2065    for (c = ncliques-1; c >= 0; --c)
2066       SCIPfreeBlockMemoryArray(scip, &cliques[c], cliquesizes[c]);
2067    SCIPfreeBlockMemoryArrayNull(scip, &cliques, csize);
2068    SCIPfreeBlockMemoryArrayNull(scip, &cliquesizes, csize);
2069 
2070    SCIPfreeBufferArrayNull(scip, &comsucc);
2071    SCIPfreeBufferArrayNull(scip, &lengthconss);
2072    SCIPfreeBufferArrayNull(scip, &indconss);
2073    SCIPfreeBufferArrayNull(scip, &newclique);
2074    SCIPfreeBufferArrayNull(scip, &consweights);
2075    SCIPfreeBufferArrayNull(scip, &consvars);
2076    SCIPdigraphFree(&vertexcliquegraph);
2077 
2078    return SCIP_OKAY;
2079 }
2080 
2081 
2082 /** performs implication graph analysis
2083  *
2084  *  Tentatively fixes a variable to nonzeero and extracts consequences from it:
2085  *  - adds (possibly new) complementarity constraints to the problem if variables are implied to be zero
2086  *  - returns that the subproblem is infeasible if the domain of a variable turns out to be empty
2087  */
2088 static
performImplicationGraphAnalysis(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_VAR ** totalvars,SCIP_DIGRAPH * implgraph,SCIP_HASHMAP * implhash,SCIP_Bool ** adjacencymatrix,int givennode,int nonznode,SCIP_Real * impllbs,SCIP_Real * implubs,SCIP_Bool * implnodes,int * naddconss,int * probingdepth,SCIP_Bool * infeasible)2089 SCIP_RETCODE performImplicationGraphAnalysis(
2090    SCIP*                 scip,               /**< SCIP pointer */
2091    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
2092    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
2093    SCIP_VAR**            totalvars,          /**< problem and SOS1 variables */
2094    SCIP_DIGRAPH*         implgraph,          /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
2095    SCIP_HASHMAP*         implhash,           /**< hash map from variable to node in implication graph */
2096    SCIP_Bool**           adjacencymatrix,    /**< adjacencymatrix of the conflict graph (only lower half filled) */
2097    int                   givennode,          /**< node of the conflict graph */
2098    int                   nonznode,           /**< node of the conflict graph that is implied to be nonzero if given node is nonzero */
2099    SCIP_Real*            impllbs,            /**< current lower variable bounds if given node is nonzero (update possible) */
2100    SCIP_Real*            implubs,            /**< current upper variable bounds if given node is nonzero (update possible) */
2101    SCIP_Bool*            implnodes,          /**< indicates which variables are currently implied to be nonzero if given node is nonzero (update possible) */
2102    int*                  naddconss,          /**< pointer to store number of added SOS1 constraints */
2103    int*                  probingdepth,       /**< pointer to store current probing depth */
2104    SCIP_Bool*            infeasible          /**< pointer to store whether the subproblem gets infeasible if variable to 'nonznode' is nonzero */
2105    )
2106 {
2107    SCIP_SUCCDATA** succdatas;
2108    int succnode;
2109    int* succ;
2110    int nsucc;
2111    int s;
2112 
2113    assert( nonznode >= 0 && nonznode < SCIPdigraphGetNNodes(conflictgraph) );
2114 
2115    /* check probing depth */
2116    if ( conshdlrdata->depthimplanalysis >= 0 && *probingdepth >= conshdlrdata->depthimplanalysis )
2117       return SCIP_OKAY;
2118    ++(*probingdepth);
2119 
2120    /* get successors of 'nonznode' in the conflict graph */
2121    nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nonznode);
2122    succ = SCIPdigraphGetSuccessors(conflictgraph, nonznode);
2123 
2124    /* loop through neighbors of 'nonznode' in the conflict graph; these variables are implied to be zero */
2125    for (s = 0; s < nsucc; ++s)
2126    {
2127       succnode = succ[s];
2128 
2129       /* if the current variable domain of the successor node does not contain the value zero then return that the problem is infeasible
2130        * else if 'succnode' is not already complementary to 'givennode' then add a new complementarity constraint */
2131       if ( givennode == succnode || SCIPisFeasPositive(scip, impllbs[succnode]) || SCIPisFeasNegative(scip, implubs[succnode]) )
2132       {
2133 	*infeasible = TRUE;
2134 	return SCIP_OKAY;
2135       }
2136       else if ( ! isConnectedSOS1(adjacencymatrix, NULL, givennode, succnode) )
2137       {
2138 	char namesos[SCIP_MAXSTRLEN];
2139 	SCIP_CONS* soscons = NULL;
2140 	SCIP_VAR* var1;
2141 	SCIP_VAR* var2;
2142 
2143 	/* update implied bounds of succnode */
2144 	impllbs[succnode] = 0;
2145 	implubs[succnode] = 0;
2146 
2147 	/* add arcs to the conflict graph */
2148 	SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, givennode, succnode, NULL) );
2149 	SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, succnode, givennode, NULL) );
2150 
2151 	/* resort successors */
2152 	SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, givennode), SCIPdigraphGetNSuccessors(conflictgraph, givennode));
2153 	SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, succnode), SCIPdigraphGetNSuccessors(conflictgraph, succnode));
2154 
2155 	/* update adjacencymatrix */
2156 	if ( givennode > succnode )
2157 	  adjacencymatrix[givennode][succnode] = 1;
2158 	else
2159 	  adjacencymatrix[succnode][givennode] = 1;
2160 
2161 	var1 = SCIPnodeGetVarSOS1(conflictgraph, givennode);
2162 	var2 = SCIPnodeGetVarSOS1(conflictgraph, succnode);
2163 
2164 	/* create SOS1 constraint */
2165 	assert( SCIPgetDepth(scip) == 0 );
2166 	(void) SCIPsnprintf(namesos, SCIP_MAXSTRLEN, "presolved_sos1_%s_%s", SCIPvarGetName(var1), SCIPvarGetName(var2) );
2167 	SCIP_CALL( SCIPcreateConsSOS1(scip, &soscons, namesos, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE,
2168 				      FALSE, FALSE, FALSE, FALSE) );
2169 
2170 	/* add variables to SOS1 constraint */
2171 	SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var1, 1.0) );
2172 	SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var2, 2.0) );
2173 
2174 	/* add constraint */
2175 	SCIP_CALL( SCIPaddCons(scip, soscons) );
2176 
2177 	/* release constraint */
2178 	SCIP_CALL( SCIPreleaseCons(scip, &soscons) );
2179 
2180 	++(*naddconss);
2181       }
2182    }
2183 
2184    /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */
2185    assert( nonznode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, nonznode)) );
2186    succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, nonznode);
2187    nsucc = SCIPdigraphGetNSuccessors(implgraph, nonznode);
2188    succ = SCIPdigraphGetSuccessors(implgraph, nonznode);
2189 
2190    /* go further in implication graph */
2191    for (s = 0; s < nsucc; ++s)
2192    {
2193      SCIP_SUCCDATA* data;
2194      int oldprobingdepth;
2195 
2196      succnode = succ[s];
2197      data = succdatas[s];
2198      oldprobingdepth = *probingdepth;
2199 
2200      /* if current lower bound is smaller than implied lower bound */
2201      if ( SCIPisFeasLT(scip, impllbs[succnode], data->lbimpl) )
2202      {
2203 	impllbs[succnode] = data->lbimpl;
2204 
2205 	/* if node is SOS1 and implied to be nonzero for the first time, then this recursively may imply further bound changes */
2206 	if ( varGetNodeSOS1(conshdlrdata, totalvars[succnode]) >= 0 && ! implnodes[succnode] && SCIPisFeasPositive(scip, data->lbimpl) )
2207 	{
2208 	   /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */
2209 	   assert( succnode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, succnode)) );
2210 	   implnodes[succnode] = TRUE; /* in order to avoid cycling */
2211 	   SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, givennode, succnode, impllbs, implubs, implnodes, naddconss, probingdepth, infeasible) );
2212 	   *probingdepth = oldprobingdepth;
2213 
2214 	   /* return if the subproblem is known to be infeasible */
2215 	   if ( *infeasible )
2216 	      return SCIP_OKAY;
2217 	}
2218      }
2219 
2220      /* if current upper bound is larger than implied upper bound */
2221      if ( SCIPisFeasGT(scip, implubs[succnode], data->ubimpl) )
2222      {
2223 	implubs[succnode] = data->ubimpl;
2224 
2225 	/* if node is SOS1 and implied to be nonzero for the first time, then this recursively may imply further bound changes */
2226 	if ( varGetNodeSOS1(conshdlrdata, totalvars[succnode]) >= 0 && ! implnodes[succnode] && SCIPisFeasNegative(scip, data->ubimpl) )
2227 	{
2228 	   /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */
2229 	   assert( succnode == SCIPhashmapGetImageInt(implhash, SCIPnodeGetVarSOS1(conflictgraph, succnode)) );
2230 	   implnodes[succnode] = TRUE; /* in order to avoid cycling */
2231 	   SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, givennode, succnode, impllbs, implubs, implnodes, naddconss, probingdepth, infeasible) );
2232 	   *probingdepth = oldprobingdepth;
2233 
2234 	   /* return if the subproblem is known to be infeasible */
2235 	   if ( *infeasible )
2236 	      return SCIP_OKAY;
2237 	}
2238      }
2239    }
2240 
2241    return SCIP_OKAY;
2242 }
2243 
2244 
2245 /** returns whether node is implied to be zero; this information is taken from the input array 'implnodes' */
2246 static
isImpliedZero(SCIP_DIGRAPH * conflictgraph,SCIP_Bool * implnodes,int node)2247 SCIP_Bool isImpliedZero(
2248    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
2249    SCIP_Bool*            implnodes,          /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
2250    int                   node                /**< node of the conflict graph (or -1) */
2251    )
2252 {
2253    int* succ;
2254    int nsucc;
2255    int s;
2256 
2257    if ( node < 0 )
2258       return FALSE;
2259 
2260    nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
2261    succ = SCIPdigraphGetSuccessors(conflictgraph, node);
2262 
2263    /* check whether any successor is implied to be nonzero */
2264    for (s = 0; s < nsucc; ++s)
2265    {
2266       if ( implnodes[succ[s]] )
2267          return TRUE;
2268    }
2269 
2270    return FALSE;
2271 }
2272 
2273 
2274 /** updates arc data of implication graph */
2275 static
updateArcData(SCIP * scip,SCIP_DIGRAPH * implgraph,SCIP_HASHMAP * implhash,SCIP_VAR ** totalvars,SCIP_VAR * varv,SCIP_VAR * varw,SCIP_Real lb,SCIP_Real ub,SCIP_Real newbound,SCIP_Bool lower,int * nchgbds,SCIP_Bool * update,SCIP_Bool * infeasible)2276 SCIP_RETCODE updateArcData(
2277    SCIP*                 scip,               /**< SCIP pointer */
2278    SCIP_DIGRAPH*         implgraph,          /**< implication graph */
2279    SCIP_HASHMAP*         implhash,           /**< hash map from variable to node in implication graph */
2280    SCIP_VAR**            totalvars,          /**< problem and SOS1 variables */
2281    SCIP_VAR*             varv,               /**< variable that is assumed to be nonzero */
2282    SCIP_VAR*             varw,               /**< implication variable */
2283    SCIP_Real             lb,                 /**< old lower bound of \f$x_w\f$ */
2284    SCIP_Real             ub,                 /**< old upper bound of \f$x_w\f$ */
2285    SCIP_Real             newbound,           /**< new bound of \f$x_w\f$ */
2286    SCIP_Bool             lower,              /**< whether to consider lower bound implication (otherwise upper bound) */
2287    int*                  nchgbds,            /**< pointer to store number of changed bounds */
2288    SCIP_Bool*            update,             /**< pointer to store whether implication graph has been updated */
2289    SCIP_Bool*            infeasible          /**< pointer to store whether an infeasibility has been detected */
2290    )
2291 {
2292    SCIP_SUCCDATA** succdatas;
2293    SCIP_SUCCDATA* data = NULL;
2294    int nsucc;
2295    int* succ;
2296    int indv;
2297    int indw;
2298    int s;
2299 
2300    assert( scip != NULL );
2301    assert( implgraph != NULL );
2302    assert( implhash != NULL );
2303    assert( totalvars != NULL );
2304    assert( varv != NULL );
2305    assert( varw != NULL );
2306 
2307    /* if x_v != 0 turns out to be infeasible then fix x_v = 0 */
2308    if ( ( lower && SCIPisFeasLT(scip, ub, newbound) ) || ( ! lower && SCIPisFeasGT(scip, lb, newbound) ) )
2309    {
2310       SCIP_Bool infeasible1;
2311       SCIP_Bool infeasible2;
2312       SCIP_Bool tightened1;
2313       SCIP_Bool tightened2;
2314 
2315       SCIP_CALL( SCIPtightenVarLb(scip, varv, 0.0, FALSE, &infeasible1, &tightened1) );
2316       SCIP_CALL( SCIPtightenVarUb(scip, varv, 0.0, FALSE, &infeasible2, &tightened2) );
2317 
2318       if ( infeasible1 || infeasible2 )
2319       {
2320          SCIPdebugMsg(scip, "detected infeasibility while trying to fix variable <%s> to zero\n", SCIPvarGetName(varv));
2321          *infeasible = TRUE;
2322       }
2323 
2324       if ( tightened1 || tightened2 )
2325       {
2326          SCIPdebugMsg(scip, "fixed variable %s from lb = %f and ub = %f to 0.0 \n", SCIPvarGetName(varv), lb, ub);
2327          ++(*nchgbds);
2328       }
2329    }
2330 
2331    /* get successor information */
2332    indv = SCIPhashmapGetImageInt(implhash, varv); /* get index of x_v in implication graph */
2333    assert( SCIPhashmapGetImageInt(implhash, totalvars[indv]) == indv );
2334    succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, indv);
2335    nsucc = SCIPdigraphGetNSuccessors(implgraph, indv);
2336    succ = SCIPdigraphGetSuccessors(implgraph, indv);
2337 
2338    /* search for nodew in existing successors. If this is the case then check whether the lower implication bound may be updated ... */
2339    indw = SCIPhashmapGetImageInt(implhash, varw);
2340    assert( SCIPhashmapGetImageInt(implhash, totalvars[indw]) == indw );
2341    for (s = 0; s < nsucc; ++s)
2342    {
2343       if ( succ[s] == indw )
2344       {
2345          data = succdatas[s];
2346          assert( data != NULL );
2347          if ( lower && SCIPisFeasLT(scip, data->lbimpl, newbound) )
2348          {
2349             if ( SCIPvarIsIntegral(varw) )
2350                data->lbimpl = SCIPceil(scip, newbound);
2351             else
2352                data->lbimpl = newbound;
2353 
2354             *update = TRUE;
2355             SCIPdebugMsg(scip, "updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2356          }
2357          else if ( ! lower && SCIPisFeasGT(scip, data->ubimpl, newbound) )
2358          {
2359             if ( SCIPvarIsIntegral(varw) )
2360                data->ubimpl = SCIPfloor(scip, newbound);
2361             else
2362                data->ubimpl = newbound;
2363 
2364             *update = TRUE;
2365             SCIPdebugMsg(scip, "updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2366          }
2367          break;
2368       }
2369    }
2370 
2371    /* ..., otherwise if there does not exist an arc between indv and indw already, then create one and add implication */
2372    if ( s == nsucc )
2373    {
2374       assert( data == NULL );
2375       SCIP_CALL( SCIPallocBlockMemory(scip, &data) );
2376       if ( lower )
2377       {
2378          data->lbimpl = newbound;
2379          data->ubimpl = ub;
2380          SCIPdebugMsg(scip, "add implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2381       }
2382       else
2383       {
2384          data->lbimpl = lb;
2385          data->ubimpl = newbound;
2386          SCIPdebugMsg(scip, "add implication %s != 0 -> %s <= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2387       }
2388       SCIP_CALL( SCIPdigraphAddArc(implgraph, indv, indw, (void*)data) );
2389       *update = TRUE;
2390    }
2391 
2392    return SCIP_OKAY;
2393 }
2394 
2395 
2396 /** updates implication graph
2397  *
2398  *  Assume the variable from the input is nonzero. If this implies that some other variable is also nonzero, then
2399  *  store this information in an implication graph
2400  */
2401 static
updateImplicationGraphSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_Bool ** adjacencymatrix,SCIP_DIGRAPH * implgraph,SCIP_HASHMAP * implhash,SCIP_Bool * implnodes,SCIP_VAR ** totalvars,int ** cliquecovers,int * cliquecoversizes,int * varincover,SCIP_VAR ** vars,SCIP_Real * coefs,int nvars,SCIP_Real * bounds,SCIP_VAR * var,SCIP_Real bound,SCIP_Real boundnonzero,int ninftynonzero,SCIP_Bool lower,int * nchgbds,SCIP_Bool * update,SCIP_Bool * infeasible)2402 SCIP_RETCODE updateImplicationGraphSOS1(
2403    SCIP*                 scip,               /**< SCIP pointer */
2404    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
2405    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
2406    SCIP_Bool**           adjacencymatrix,    /**< adjacency matrix of conflict graph (lower half) */
2407    SCIP_DIGRAPH*         implgraph,          /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
2408    SCIP_HASHMAP*         implhash,           /**< hash map from variable to node in implication graph */
2409    SCIP_Bool*            implnodes,          /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
2410    SCIP_VAR**            totalvars,          /**< problem and SOS1 variables */
2411    int**                 cliquecovers,       /**< clique covers of linear constraint */
2412    int*                  cliquecoversizes,   /**< size of clique covers */
2413    int*                  varincover,         /**< array with varincover[i] = cover of SOS1 index @p i */
2414    SCIP_VAR**            vars,               /**< variables to be checked */
2415    SCIP_Real*            coefs,              /**< coefficients of variables in linear constraint */
2416    int                   nvars,              /**< number of variables to be checked */
2417    SCIP_Real*            bounds,             /**< bounds of variables */
2418    SCIP_VAR*             var,                /**< variable that is assumed to be nonzero */
2419    SCIP_Real             bound,              /**< bound of variable */
2420    SCIP_Real             boundnonzero,       /**< bound of variable if it is known to be nonzero if infinity values are not summarized */
2421    int                   ninftynonzero,      /**< number of times infinity/-infinity has to be summarized to boundnonzero */
2422    SCIP_Bool             lower,              /**< TRUE if lower bounds are consideres; FALSE for upper bounds */
2423    int*                  nchgbds,            /**< pointer to store number of changed bounds */
2424    SCIP_Bool*            update,             /**< pointer to store whether implication graph has been updated */
2425    SCIP_Bool*            infeasible          /**< pointer to store whether an infeasibility has been detected */
2426    )
2427 {
2428    int nodev;
2429    int w;
2430 
2431    assert( update != NULL );
2432 
2433    /* update implication graph if possible */
2434    *update = FALSE;
2435    *infeasible = FALSE;
2436    nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
2437 
2438    /* if nodev is an index of an SOS1 variable and at least one lower bound of a variable that is not x_v is infinity */
2439    if ( nodev < 0 || SCIPisInfinity(scip, REALABS(bound)) || ninftynonzero > 1 )
2440       return SCIP_OKAY;
2441 
2442    /* for every variable x_w: compute upper bound of a_w * x_w if x_v is known to be nonzero */
2443    for (w = 0; w < nvars; ++w)
2444    {
2445       int newninftynonzero;
2446       SCIP_Bool implinfty = FALSE;
2447       int nodew;
2448 
2449       /* get node of x_w in conflict graph: nodew = -1 if it is no SOS1 variable */
2450       nodew = varGetNodeSOS1(conshdlrdata, vars[w]);
2451 
2452       newninftynonzero = ninftynonzero;
2453 
2454       /* variable should not be fixed to be already zero (note x_v is fixed to be nonzero by assumption) */
2455       if ( nodew < 0 || ( nodev != nodew && ! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodew) && ! isImpliedZero(conflictgraph, implnodes, nodew) ) )
2456       {
2457          SCIP_Real implbound;
2458          SCIP_Bool implcoverw;
2459          int nodecliq;
2460          int indcliq;
2461          int ind;
2462          int j;
2463 
2464          /* boundnonzero is the bound of x_v if x_v is nonzero we use this information to get a bound of x_w if x_v is
2465           * nonzero; therefore, we have to perform some recomputations */
2466          implbound = boundnonzero - bound;
2467          ind = varincover[w];
2468          assert( cliquecoversizes[ind] > 0 );
2469 
2470          implcoverw = FALSE;
2471          for (j = 0; j < cliquecoversizes[ind]; ++j)
2472          {
2473             indcliq = cliquecovers[ind][j];
2474             assert( 0 <= indcliq && indcliq < nvars );
2475 
2476             nodecliq = varGetNodeSOS1(conshdlrdata, vars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
2477 
2478             /* if nodecliq is not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0  */
2479             if ( nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
2480             {
2481                if ( indcliq == w )
2482                {
2483                   if ( !SCIPisInfinity(scip, REALABS(bounds[w])) && !SCIPisInfinity(scip, REALABS(implbound + bounds[w])) )
2484                      implbound += bounds[w];
2485                   else
2486                      --newninftynonzero;
2487                   implcoverw = TRUE;
2488                }
2489                else if ( implcoverw )
2490                {
2491                   if ( SCIPisInfinity(scip, REALABS(bounds[indcliq])) || SCIPisInfinity(scip, REALABS(implbound - bounds[indcliq])) )
2492                      implinfty = TRUE;
2493                   else
2494                      implbound -= bounds[indcliq];
2495                   break;
2496                }
2497                else
2498                {
2499                   if ( SCIPisInfinity(scip, REALABS(bounds[indcliq])) )
2500                      implinfty = TRUE;
2501                   break;
2502                }
2503             }
2504          }
2505 
2506          /* check whether x_v != 0 implies a bound change of x_w */
2507          if ( ! implinfty && newninftynonzero == 0 )
2508          {
2509             SCIP_Real newbound;
2510             SCIP_Real coef;
2511             SCIP_Real lb;
2512             SCIP_Real ub;
2513 
2514             lb = SCIPvarGetLbLocal(vars[w]);
2515             ub = SCIPvarGetUbLocal(vars[w]);
2516             coef = coefs[w];
2517 
2518             if ( SCIPisFeasZero(scip, coef) )
2519                continue;
2520 
2521             newbound = implbound / coef;
2522 
2523             if ( SCIPisInfinity(scip, newbound) )
2524                continue;
2525 
2526             /* check if an implication can be added/updated or assumption x_v != 0 is infeasible */
2527             if ( lower )
2528             {
2529                if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasLT(scip, lb, newbound) )
2530                {
2531                   SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update, infeasible) );
2532                }
2533                else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasGT(scip, ub, newbound) )
2534                {
2535                   SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update, infeasible) );
2536                }
2537             }
2538             else
2539             {
2540                if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasGT(scip, ub, newbound) )
2541                {
2542                   SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update, infeasible) );
2543                }
2544                else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasLT(scip, lb, newbound) )
2545                {
2546                   SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update, infeasible) );
2547                }
2548             }
2549          }
2550       }
2551    }
2552 
2553    return SCIP_OKAY;
2554 }
2555 
2556 
2557 /** search new disjoint clique that covers given node
2558  *
2559  *  For a given vertex @p v search for a clique of the conflict graph induced by the variables of a linear constraint that
2560  *  - covers @p v and
2561  *  - has an an empty intersection with already computed clique cover.
2562  */
2563 static
computeVarsCoverSOS1(SCIP * scip,SCIP_DIGRAPH * conflictgraphroot,SCIP_DIGRAPH * conflictgraphlin,SCIP_VAR ** linvars,SCIP_Bool * coveredvars,int * clique,int * cliquesize,int v,SCIP_Bool considersolvals)2564 SCIP_RETCODE computeVarsCoverSOS1(
2565    SCIP*                 scip,               /**< SCIP pointer */
2566    SCIP_DIGRAPH*         conflictgraphroot,  /**< conflict graph of the root node (nodes: 1, ..., @p nsos1vars) */
2567    SCIP_DIGRAPH*         conflictgraphlin,   /**< conflict graph of linear constraint (nodes: 1, ..., @p nlinvars) */
2568    SCIP_VAR**            linvars,            /**< variables in linear constraint */
2569    SCIP_Bool*            coveredvars,        /**< states which variables of the linear constraint are currently covered by a clique */
2570    int*                  clique,             /**< array to store new clique in cover */
2571    int*                  cliquesize,         /**< pointer to store the size of @p clique */
2572    int                   v,                  /**< position of variable in linear constraint that should be covered */
2573    SCIP_Bool             considersolvals     /**< TRUE if largest auxiliary bigM values of variables should be prefered */
2574    )
2575 {
2576    int nsucc;
2577    int s;
2578 
2579    assert( conflictgraphlin != NULL );
2580    assert( linvars != NULL );
2581    assert( coveredvars != NULL );
2582    assert( clique != NULL );
2583    assert( cliquesize != NULL );
2584 
2585    assert( ! coveredvars[v] );  /* we should produce a new clique */
2586 
2587    /* add index 'v' to the clique cover */
2588    clique[0] = v;
2589    *cliquesize = 1;
2590 
2591    nsucc = SCIPdigraphGetNSuccessors(conflictgraphlin, v);
2592    if ( nsucc > 0 )
2593    {
2594       int* extensions;
2595       int nextensions = 0;
2596       int nextensionsnew;
2597       int succnode;
2598       int* succ;
2599 
2600       /* allocate buffer array */
2601       SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) );
2602 
2603       succ = SCIPdigraphGetSuccessors(conflictgraphlin, v);
2604 
2605       /* compute possible extensions for the clique cover */
2606       for (s = 0; s < nsucc; ++s)
2607       {
2608          succnode = succ[s];
2609          if ( ! coveredvars[succnode] )
2610             extensions[nextensions++] = succ[s];
2611       }
2612 
2613       /* while there exist possible extensions for the clique cover */
2614       while ( nextensions > 0 )
2615       {
2616          int bestindex = -1;
2617 
2618          if ( considersolvals )
2619          {
2620             SCIP_Real bestbigMval;
2621             SCIP_Real bigMval;
2622 
2623             bestbigMval = -SCIPinfinity(scip);
2624 
2625             /* search for the extension with the largest absolute value of its LP relaxation solution value */
2626             for (s = 0; s < nextensions; ++s)
2627             {
2628                bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraphroot, NULL, extensions[s]);
2629                if ( SCIPisFeasLT(scip, bestbigMval, bigMval) )
2630                {
2631                   bestbigMval = bigMval;
2632                   bestindex = extensions[s];
2633                }
2634             }
2635          }
2636          else
2637             bestindex = extensions[0];
2638 
2639          assert( bestindex != -1 );
2640 
2641          /* add bestindex to the clique cover */
2642          clique[(*cliquesize)++] = bestindex;
2643 
2644          /* compute new 'extensions' array */
2645          nextensionsnew = 0;
2646          for (s = 0; s < nextensions; ++s)
2647          {
2648             if ( s != bestindex && isConnectedSOS1(NULL, conflictgraphlin, bestindex, extensions[s]) )
2649                extensions[nextensionsnew++] = extensions[s];
2650          }
2651          nextensions = nextensionsnew;
2652       }
2653 
2654       /* free buffer array */
2655       SCIPfreeBufferArray(scip, &extensions);
2656    }
2657 
2658    /* mark covered indices */
2659    for (s = 0; s < *cliquesize; ++s)
2660    {
2661       int ind;
2662 
2663       ind = clique[s];
2664       assert( 0 <= ind );
2665       assert( ! coveredvars[ind] );
2666       coveredvars[ind] = TRUE;
2667    }
2668 
2669    return SCIP_OKAY;
2670 }
2671 
2672 
2673 /** try to tighten upper and lower bounds for variables */
2674 static
tightenVarsBoundsSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_DIGRAPH * implgraph,SCIP_HASHMAP * implhash,SCIP_Bool ** adjacencymatrix,SCIP_VAR ** totalvars,int ntotalvars,int nsos1vars,int * nchgbds,SCIP_Bool * implupdate,SCIP_Bool * cutoff)2675 SCIP_RETCODE tightenVarsBoundsSOS1(
2676    SCIP*                 scip,               /**< SCIP pointer */
2677    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
2678    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
2679    SCIP_DIGRAPH*         implgraph,          /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \f$ implies a new lower/upper bound for \f$ x_j\f$) */
2680    SCIP_HASHMAP*         implhash,           /**< hash map from variable to node in implication graph */
2681    SCIP_Bool**           adjacencymatrix,    /**< adjacencymatrix of conflict graph */
2682    SCIP_VAR**            totalvars,          /**< problem and SOS1 vars */
2683    int                   ntotalvars,         /**< number of problem and SOS1 variables*/
2684    int                   nsos1vars,          /**< number of SOS1 variables */
2685    int*                  nchgbds,            /**< pointer to store number of changed bounds */
2686    SCIP_Bool*            implupdate,         /**< pointer to store whether the implication graph has been updated in this function call */
2687    SCIP_Bool*            cutoff              /**< pointer to store if current nodes LP is infeasible  */
2688    )
2689 {
2690    SCIP_CONSHDLR* conshdlrlinear;
2691    SCIP_CONS** linearconss;
2692    int nlinearconss;
2693 
2694    SCIP_Bool* implnodes = NULL;     /* implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
2695    SCIP_Bool* coveredvars = NULL;   /* coveredvars[i] = TRUE if variable with index i is covered by the clique cover */
2696    int* varindincons = NULL;        /* varindincons[i] = position of SOS1 index i in linear constraint (-1 if x_i is not involved in linear constraint) */
2697 
2698    SCIP_VAR** trafolinvars = NULL;  /* variables of transformed linear constraints without (multi)aggregated variables */
2699    int ntrafolinvars = 0;
2700    SCIP_Real* trafolinvals = NULL;
2701    SCIP_Real* trafoubs = NULL;
2702    SCIP_Real* trafolbs = NULL;
2703    SCIP_Real traforhs;
2704    SCIP_Real trafolhs;
2705 
2706    SCIP_VAR** sos1linvars = NULL;  /* variables that are not contained in linear constraint, but are in conflict with a variable from the linear constraint */
2707    int nsos1linvars;
2708    int c;
2709 
2710    assert( scip != NULL );
2711    assert( conflictgraph != NULL );
2712    assert( adjacencymatrix != NULL );
2713    assert( nchgbds != NULL );
2714    assert( cutoff != NULL );
2715 
2716    *cutoff = FALSE;
2717    *implupdate = FALSE;
2718 
2719    /* get constraint handler data of linear constraints */
2720    conshdlrlinear = SCIPfindConshdlr(scip, "linear");
2721    if ( conshdlrlinear == NULL )
2722       return SCIP_OKAY;
2723 
2724    /* get linear constraints and number of linear constraints */
2725    nlinearconss = SCIPconshdlrGetNConss(conshdlrlinear);
2726    linearconss = SCIPconshdlrGetConss(conshdlrlinear);
2727 
2728    /* allocate buffer arrays */
2729    SCIP_CALL( SCIPallocBufferArray(scip, &sos1linvars, nsos1vars) );
2730    SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
2731    SCIP_CALL( SCIPallocBufferArray(scip, &varindincons, nsos1vars) );
2732    SCIP_CALL( SCIPallocBufferArray(scip, &coveredvars, ntotalvars) );
2733    SCIP_CALL( SCIPallocBufferArray(scip, &trafoubs, ntotalvars) );
2734    SCIP_CALL( SCIPallocBufferArray(scip, &trafolbs, ntotalvars) );
2735 
2736    /* for every linear constraint and every SOS1 variable */
2737    for (c = 0; c < nlinearconss + nsos1vars && ! (*cutoff); ++c)
2738    {
2739       SCIP_DIGRAPH* conflictgraphlin;
2740       int** cliquecovers = NULL;           /* clique covers of indices of variables in linear constraint */
2741       int* cliquecoversizes = NULL;        /* size of each cover */
2742       SCIP_VAR* sosvar = NULL;
2743       SCIP_Real* cliquecovervals = NULL;
2744       SCIP_Real constant;
2745       int* varincover = NULL;              /* varincover[i] = cover of SOS1 index i */
2746       int ncliquecovers;
2747       int requiredsize;
2748 
2749       int v;
2750       int i;
2751       int j;
2752 
2753       /* get transformed linear constraints (without aggregated variables) */
2754       if ( c < nlinearconss )
2755       {
2756          SCIP_VAR** origlinvars;
2757          SCIP_Real* origlinvals;
2758 
2759          /* get data of linear constraint */
2760          ntrafolinvars = SCIPgetNVarsLinear(scip, linearconss[c]);
2761          if ( ntrafolinvars < 1 )
2762             continue;
2763 
2764          origlinvars = SCIPgetVarsLinear(scip, linearconss[c]);
2765          origlinvals = SCIPgetValsLinear(scip, linearconss[c]);
2766          assert( origlinvars != NULL );
2767          assert( origlinvals != NULL );
2768 
2769          /* copy variables and coefficients of linear constraint */
2770          SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvars, origlinvars, ntrafolinvars) );
2771          SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvals, origlinvals, ntrafolinvars) );
2772 
2773          trafolhs = SCIPgetLhsLinear(scip, linearconss[c]);
2774          traforhs = SCIPgetRhsLinear(scip, linearconss[c]);
2775       }
2776       else
2777       {
2778          sosvar = SCIPnodeGetVarSOS1(conflictgraph, c - nlinearconss);
2779 
2780          if ( SCIPvarGetStatus(sosvar) != SCIP_VARSTATUS_AGGREGATED
2781             && SCIPvarGetStatus(sosvar) != SCIP_VARSTATUS_MULTAGGR
2782             && SCIPvarGetStatus(sosvar) != SCIP_VARSTATUS_NEGATED )
2783             continue;
2784 
2785          /* store variable so it will be transformed to active variables below */
2786          ntrafolinvars = 1;
2787          SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvars, ntrafolinvars + 1) );
2788          SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvals, ntrafolinvars + 1) );
2789 
2790          trafolinvars[0] = sosvar;
2791          trafolinvals[0] = 1.0;
2792 
2793          trafolhs = 0.0;
2794          traforhs = 0.0;
2795       }
2796       assert( ntrafolinvars >= 1 );
2797 
2798       /* transform linear constraint */
2799       constant = 0.0;
2800       SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, ntrafolinvars, &constant, &requiredsize, TRUE) );
2801       if( requiredsize > ntrafolinvars )
2802       {
2803          SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvars, requiredsize + 1) );
2804          SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvals, requiredsize + 1) );
2805 
2806          SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, requiredsize, &constant, &requiredsize, TRUE) );
2807          assert( requiredsize <= ntrafolinvars );
2808       }
2809       if( !SCIPisInfinity(scip, -trafolhs) )
2810          trafolhs -= constant;
2811       if( !SCIPisInfinity(scip,  traforhs) )
2812          traforhs -= constant;
2813 
2814       if ( ntrafolinvars == 0 )
2815       {
2816          SCIPfreeBufferArray(scip, &trafolinvals);
2817          SCIPfreeBufferArray(scip, &trafolinvars);
2818          continue;
2819       }
2820 
2821       /* possibly add sos1 variable to create aggregation/multiaggregation/negation equality */
2822       if ( sosvar != NULL )
2823       {
2824          trafolinvals[ntrafolinvars] = -1.0;
2825          trafolinvars[ntrafolinvars] = sosvar;
2826          ++ntrafolinvars;
2827       }
2828 
2829       /* compute lower and upper bounds of each term a_i * x_i of transformed constraint */
2830       for (v = 0; v < ntrafolinvars; ++v)
2831       {
2832          SCIP_Real lb;
2833          SCIP_Real ub;
2834 
2835          lb = SCIPvarGetLbLocal(trafolinvars[v]);
2836          ub = SCIPvarGetUbLocal(trafolinvars[v]);
2837 
2838          if ( trafolinvals[v] < 0.0 )
2839             SCIPswapReals(&lb, &ub);
2840 
2841          assert( ! SCIPisInfinity(scip, REALABS(trafolinvals[v])) );
2842 
2843          if ( SCIPisInfinity(scip, REALABS(lb)) || SCIPisInfinity(scip, REALABS(lb * trafolinvals[v])) )
2844             trafolbs[v] = -SCIPinfinity(scip);
2845          else
2846             trafolbs[v] = lb * trafolinvals[v];
2847 
2848          if ( SCIPisInfinity(scip, REALABS(ub)) || SCIPisInfinity(scip, REALABS(ub * trafolinvals[v])) )
2849             trafoubs[v] = SCIPinfinity(scip);
2850          else
2851             trafoubs[v] = ub * trafolinvals[v];
2852       }
2853 
2854       /* initialization: mark all the SOS1 variables as 'not a member of the linear constraint' */
2855       for (v = 0; v < nsos1vars; ++v)
2856          varindincons[v] = -1;
2857 
2858       /* save position of SOS1 variables in linear constraint */
2859       for (v = 0; v < ntrafolinvars; ++v)
2860       {
2861          int node;
2862 
2863          node = varGetNodeSOS1(conshdlrdata, trafolinvars[v]);
2864 
2865          if ( node >= 0 )
2866             varindincons[node] = v;
2867       }
2868 
2869       /* create conflict graph of linear constraint */
2870       SCIP_CALL( SCIPcreateDigraph(scip, &conflictgraphlin, ntrafolinvars) );
2871       SCIP_CALL( genConflictgraphLinearCons(conshdlrdata, conflictgraphlin, conflictgraph, trafolinvars, ntrafolinvars, varindincons) );
2872 
2873       /* mark all the variables as 'not covered by some clique cover' */
2874       for (i = 0; i < ntrafolinvars; ++i)
2875          coveredvars[i] = FALSE;
2876 
2877       /* allocate buffer array */
2878       SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovervals, ntrafolinvars) );
2879       SCIP_CALL( SCIPallocBufferArray(scip, &cliquecoversizes, ntrafolinvars) );
2880       SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovers, ntrafolinvars) );
2881 
2882       /* compute distinct cliques that cover all the variables of the linear constraint */
2883       ncliquecovers = 0;
2884       for (v = 0; v < ntrafolinvars; ++v)
2885       {
2886          /* if variable is not already covered by an already known clique cover */
2887          if ( ! coveredvars[v] )
2888          {
2889             SCIP_CALL( SCIPallocBufferArray(scip, &(cliquecovers[ncliquecovers]), ntrafolinvars) ); /*lint !e866*/
2890             SCIP_CALL( computeVarsCoverSOS1(scip, conflictgraph, conflictgraphlin, trafolinvars, coveredvars, cliquecovers[ncliquecovers], &(cliquecoversizes[ncliquecovers]), v, FALSE) );
2891             ++ncliquecovers;
2892          }
2893       }
2894 
2895       /* free conflictgraph */
2896       SCIPdigraphFree(&conflictgraphlin);
2897 
2898       /* compute variables that are not contained in transformed linear constraint, but are in conflict with a variable from the transformed linear constraint */
2899       nsos1linvars = 0;
2900       for (v = 0; v < ntrafolinvars; ++v)
2901       {
2902          int nodev;
2903 
2904          nodev = varGetNodeSOS1(conshdlrdata, trafolinvars[v]);
2905 
2906          /* if variable is an SOS1 variable */
2907          if ( nodev >= 0 )
2908          {
2909             int succnode;
2910             int nsucc;
2911             int* succ;
2912             int s;
2913 
2914             succ = SCIPdigraphGetSuccessors(conflictgraph, nodev);
2915             nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nodev);
2916 
2917             for (s = 0; s < nsucc; ++s)
2918             {
2919                succnode = succ[s];
2920 
2921                /* if variable is not a member of linear constraint and not already listed in the array sos1linvars */
2922                if ( varindincons[succnode] == -1 )
2923                {
2924                   sos1linvars[nsos1linvars] = SCIPnodeGetVarSOS1(conflictgraph, succnode);
2925                   varindincons[succnode] = -2; /* mark variable as listed in array sos1linvars */
2926                   ++nsos1linvars;
2927                }
2928             }
2929          }
2930       }
2931 
2932       /* try to tighten lower bounds */
2933 
2934       /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */
2935       SCIP_CALL( SCIPallocBufferArray(scip, &varincover, ntrafolinvars) );
2936       for (i = 0; i < ncliquecovers; ++i)
2937       {
2938          for (j = 0; j < cliquecoversizes[i]; ++j)
2939          {
2940             int ind = cliquecovers[i][j];
2941 
2942             varincover[ind] = i;
2943             cliquecovervals[j] = trafoubs[ind];
2944          }
2945          SCIPsortDownRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]);
2946       }
2947 
2948       /* for every variable in transformed constraint: try lower bound tightening */
2949       for (v = 0; v < ntrafolinvars + nsos1linvars; ++v)
2950       {
2951          SCIP_Real newboundnonzero; /* new bound of a_v * x_v if we assume that x_v != 0 */
2952          SCIP_Real newboundnores;   /* new bound of a_v * x_v if we assume that x_v = 0 is possible */
2953          SCIP_Real newbound;        /* resulting new bound of x_v */
2954          SCIP_VAR* var;
2955          SCIP_Real trafoubv;
2956          SCIP_Real linval;
2957          SCIP_Real ub;
2958          SCIP_Real lb;
2959          SCIP_Bool tightened;
2960          SCIP_Bool infeasible;
2961          SCIP_Bool inftynores = FALSE;
2962          SCIP_Bool update;
2963          int ninftynonzero = 0;
2964          int nodev;
2965          int w;
2966 
2967          if ( v < ntrafolinvars )
2968          {
2969             var = trafolinvars[v];
2970             trafoubv = trafoubs[v];
2971          }
2972          else
2973          {
2974             assert( v >= ntrafolinvars );
2975             var = sos1linvars[v-ntrafolinvars];/*lint !e679*/
2976             trafoubv = 0.0;
2977          }
2978 
2979          ub = SCIPvarGetUbLocal(var);
2980          lb = SCIPvarGetLbLocal(var);
2981 
2982          if ( SCIPisInfinity(scip, -trafolhs) || SCIPisZero(scip, ub - lb) )
2983             continue;
2984 
2985          newboundnonzero = trafolhs;
2986          newboundnores = trafolhs;
2987          nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
2988          assert( nodev < nsos1vars );
2989 
2990          /* determine incidence vector of implication variables */
2991          for (w = 0; w < nsos1vars; ++w)
2992             implnodes[w] = FALSE;
2993          SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, SCIPhashmapGetImageInt(implhash, var)) );
2994 
2995          /* compute new bound */
2996          for (i = 0; i < ncliquecovers; ++i)
2997          {
2998             int indcliq;
2999             int nodecliq;
3000 
3001             assert( cliquecoversizes[i] > 0 );
3002 
3003             indcliq = cliquecovers[i][0];
3004             assert( 0 <= indcliq && indcliq < ntrafolinvars );
3005 
3006             /* determine maximum without index v (note that the array 'cliquecovers' is sorted by the values of trafoub in non-increasing order) */
3007             if ( v != indcliq )
3008             {
3009                if ( SCIPisInfinity(scip, trafoubs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnores - trafoubs[indcliq])) )
3010                   inftynores = TRUE;
3011                else
3012                   newboundnores -= trafoubs[indcliq];
3013             }
3014             else if ( cliquecoversizes[i] > 1 )
3015             {
3016                assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars );
3017                if ( SCIPisInfinity(scip, trafoubs[cliquecovers[i][1]]) || SCIPisInfinity(scip, REALABS(newboundnores - trafoubs[cliquecovers[i][1]])) )
3018                   inftynores = TRUE;
3019                else
3020                   newboundnores -= trafoubs[cliquecovers[i][1]];/*lint --e{679}*/
3021             }
3022 
3023             /* determine maximum without index v and if x_v is nonzero (note that the array 'cliquecovers' is sorted by the values of trafoub in non-increasing order) */
3024             for (j = 0; j < cliquecoversizes[i]; ++j)
3025             {
3026                indcliq = cliquecovers[i][j];
3027                assert( 0 <= indcliq && indcliq < ntrafolinvars );
3028 
3029                nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
3030                assert( nodecliq < nsos1vars );
3031 
3032                if ( v != indcliq )
3033                {
3034                   /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0  */
3035                   if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
3036                   {
3037                      if ( SCIPisInfinity(scip, trafoubs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnonzero - trafoubs[indcliq])) )
3038                         ++ninftynonzero;
3039                      else
3040                         newboundnonzero -= trafoubs[indcliq];
3041                      break; /* break since we are only interested in the maximum upper bound among the variables in the clique cover;
3042                              * the variables in the clique cover form an SOS1 constraint, thus only one of them can be nonzero */
3043                   }
3044                }
3045             }
3046          }
3047          assert( ninftynonzero == 0 || inftynores );
3048 
3049          /* if computed upper bound is not infinity and variable is contained in linear constraint */
3050          if ( ninftynonzero == 0 && v < ntrafolinvars )
3051          {
3052             linval = trafolinvals[v];
3053 
3054             if ( SCIPisFeasZero(scip, linval) )
3055                continue;
3056 
3057             /* compute new bound */
3058             if ( SCIPisFeasPositive(scip, newboundnores) && ! inftynores )
3059                newbound = newboundnonzero;
3060             else
3061                newbound = MIN(0, newboundnonzero);
3062             newbound /= linval;
3063 
3064             if ( SCIPisInfinity(scip, newbound) )
3065                continue;
3066 
3067             /* check if new bound is tighter than the old one or problem is infeasible */
3068             if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasLT(scip, lb, newbound) )
3069             {
3070                if ( SCIPisFeasLT(scip, ub, newbound) )
3071                {
3072                   *cutoff = TRUE;
3073                   break;
3074                }
3075 
3076                if ( SCIPvarIsIntegral(var) )
3077                   newbound = SCIPceil(scip, newbound);
3078 
3079                SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) );
3080                assert( ! infeasible );
3081 
3082                if ( tightened )
3083                {
3084                   SCIPdebugMsg(scip, "changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound);
3085                   ++(*nchgbds);
3086                }
3087             }
3088             else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasGT(scip, ub, newbound) )
3089             {
3090                /* if assumption a_i * x_i != 0 was not correct */
3091                if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), newbound) )
3092                {
3093                   *cutoff = TRUE;
3094                   break;
3095                }
3096 
3097                if ( SCIPvarIsIntegral(var) )
3098                   newbound = SCIPfloor(scip, newbound);
3099 
3100                SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) );
3101                assert( ! infeasible );
3102 
3103                if ( tightened )
3104                {
3105                   SCIPdebugMsg(scip, "changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound);
3106                   ++(*nchgbds);
3107                }
3108             }
3109          }
3110 
3111          /* update implication graph if possible */
3112          SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover,
3113                trafolinvars, trafolinvals, ntrafolinvars, trafoubs, var, trafoubv, newboundnonzero, ninftynonzero, TRUE, nchgbds, &update, &infeasible) );
3114          if ( infeasible )
3115             *cutoff = TRUE;
3116          else if ( update )
3117             *implupdate = TRUE;
3118       }
3119 
3120       if ( *cutoff == TRUE )
3121       {
3122          /* free memory */
3123          SCIPfreeBufferArrayNull(scip, &varincover);
3124          for (j = ncliquecovers-1; j >= 0; --j)
3125             SCIPfreeBufferArrayNull(scip, &cliquecovers[j]);
3126          SCIPfreeBufferArrayNull(scip, &cliquecovers);
3127          SCIPfreeBufferArrayNull(scip, &cliquecoversizes);
3128          SCIPfreeBufferArrayNull(scip, &cliquecovervals);
3129          SCIPfreeBufferArrayNull(scip, &trafolinvals);
3130          SCIPfreeBufferArrayNull(scip, &trafolinvars);
3131          break;
3132       }
3133 
3134       /* try to tighten upper bounds */
3135 
3136       /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */
3137       for (i = 0; i < ncliquecovers; ++i)
3138       {
3139          for (j = 0; j < cliquecoversizes[i]; ++j)
3140          {
3141             int ind = cliquecovers[i][j];
3142 
3143             varincover[ind] = i;
3144             cliquecovervals[j] = trafolbs[ind];
3145          }
3146          SCIPsortRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]);
3147       }
3148 
3149       /* for every variable that is in transformed constraint or every variable that is in conflict with some variable from trans. cons.:
3150          try upper bound tightening */
3151       for (v = 0; v < ntrafolinvars + nsos1linvars; ++v)
3152       {
3153          SCIP_Real newboundnonzero; /* new bound of a_v*x_v if we assume that x_v != 0 */
3154          SCIP_Real newboundnores;   /* new bound of a_v*x_v if there are no restrictions */
3155          SCIP_Real newbound;        /* resulting new bound of x_v */
3156          SCIP_VAR* var;
3157          SCIP_Real linval;
3158          SCIP_Real trafolbv;
3159          SCIP_Real lb;
3160          SCIP_Real ub;
3161          SCIP_Bool tightened;
3162          SCIP_Bool infeasible;
3163          SCIP_Bool inftynores = FALSE;
3164          SCIP_Bool update;
3165          int ninftynonzero = 0;
3166          int nodev;
3167          int w;
3168 
3169          if ( v < ntrafolinvars )
3170          {
3171             var = trafolinvars[v];
3172             trafolbv = trafolbs[v];
3173          }
3174          else
3175          {
3176             assert( v-ntrafolinvars >= 0 );
3177             var = sos1linvars[v-ntrafolinvars];/*lint !e679*/
3178             trafolbv = 0.0; /* since variable is not a member of linear constraint */
3179          }
3180          lb = SCIPvarGetLbLocal(var);
3181          ub = SCIPvarGetUbLocal(var);
3182          if ( SCIPisInfinity(scip, traforhs) || SCIPisEQ(scip, lb, ub) )
3183             continue;
3184 
3185          newboundnonzero = traforhs;
3186          newboundnores = traforhs;
3187          nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
3188          assert( nodev < nsos1vars );
3189 
3190          /* determine incidence vector of implication variables (i.e., which SOS1 variables are nonzero if x_v is nonzero) */
3191          for (w = 0; w < nsos1vars; ++w)
3192             implnodes[w] = FALSE;
3193          SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, SCIPhashmapGetImageInt(implhash, var)) );
3194 
3195          /* compute new bound */
3196          for (i = 0; i < ncliquecovers; ++i)
3197          {
3198             int indcliq;
3199             int nodecliq;
3200 
3201             assert( cliquecoversizes[i] > 0 );
3202 
3203             indcliq = cliquecovers[i][0];
3204             assert( 0 <= indcliq && indcliq < ntrafolinvars );
3205 
3206             /* determine minimum without index v (note that the array 'cliquecovers' is sorted by the values of trafolb in increasing order) */
3207             if ( v != indcliq )
3208             {
3209                /* if bound would be infinity */
3210                if ( SCIPisInfinity(scip, -trafolbs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnores - trafolbs[indcliq])) )
3211                   inftynores = TRUE;
3212                else
3213                   newboundnores -= trafolbs[indcliq];
3214             }
3215             else if ( cliquecoversizes[i] > 1 )
3216             {
3217                assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars );
3218                if ( SCIPisInfinity(scip, -trafolbs[cliquecovers[i][1]]) || SCIPisInfinity(scip, REALABS(newboundnores - trafolbs[cliquecovers[i][1]])) )
3219                   inftynores = TRUE;
3220                else
3221                   newboundnores -= trafolbs[cliquecovers[i][1]]; /*lint --e{679}*/
3222             }
3223 
3224             /* determine minimum without index v and if x_v is nonzero (note that the array 'cliquecovers' is sorted by the values of trafolb in increasing order) */
3225             for (j = 0; j < cliquecoversizes[i]; ++j)
3226             {
3227                indcliq = cliquecovers[i][j];
3228                assert( 0 <= indcliq && indcliq < ntrafolinvars );
3229 
3230                nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
3231                assert( nodecliq < nsos1vars );
3232 
3233                if ( v != indcliq )
3234                {
3235                   /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0  */
3236                   if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
3237                   {
3238                      /* if bound would be infinity */
3239                      if ( SCIPisInfinity(scip, -trafolbs[indcliq]) || SCIPisInfinity(scip, REALABS(newboundnonzero - trafolbs[indcliq])) )
3240                         ++ninftynonzero;
3241                      else
3242                         newboundnonzero -= trafolbs[indcliq];
3243                      break; /* break since we are only interested in the minimum lower bound among the variables in the clique cover;
3244                              * the variables in the clique cover form an SOS1 constraint, thus only one of them can be nonzero */
3245                   }
3246                }
3247             }
3248          }
3249          assert( ninftynonzero == 0 || inftynores );
3250 
3251          /* if computed bound is not infinity and variable is contained in linear constraint */
3252          if ( ninftynonzero == 0 && v < ntrafolinvars )
3253          {
3254             linval = trafolinvals[v];
3255 
3256             if ( SCIPisFeasZero(scip, linval) )
3257                continue;
3258 
3259             /* compute new bound */
3260             if ( SCIPisFeasNegative(scip, newboundnores) && ! inftynores )
3261                newbound = newboundnonzero;
3262             else
3263                newbound = MAX(0, newboundnonzero);
3264             newbound /= linval;
3265 
3266             if ( SCIPisInfinity(scip, newbound) )
3267                continue;
3268 
3269             /* check if new bound is tighter than the old one or problem is infeasible */
3270             if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasGT(scip, ub, newbound) )
3271             {
3272                /* if new upper bound is smaller than the lower bound, we are infeasible */
3273                if ( SCIPisFeasGT(scip, lb, newbound) )
3274                {
3275                   *cutoff = TRUE;
3276                   break;
3277                }
3278 
3279                if ( SCIPvarIsIntegral(var) )
3280                   newbound = SCIPfloor(scip, newbound);
3281 
3282                SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) );
3283                assert( ! infeasible );
3284 
3285                if ( tightened )
3286                {
3287                   SCIPdebugMsg(scip, "changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound);
3288                   ++(*nchgbds);
3289                }
3290             }
3291             else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasLT(scip, lb, newbound) )
3292             {
3293                /* if assumption a_i * x_i != 0 was not correct */
3294                if ( SCIPisFeasLT(scip, ub, newbound) )
3295                {
3296                   *cutoff = TRUE;
3297                   break;
3298                }
3299 
3300                if ( SCIPvarIsIntegral(var) )
3301                   newbound = SCIPceil(scip, newbound);
3302 
3303                SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) );
3304                assert( ! infeasible );
3305 
3306                if ( tightened )
3307                {
3308                   SCIPdebugMsg(scip, "changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound);
3309                   ++(*nchgbds);
3310                }
3311             }
3312          }
3313 
3314          /* update implication graph if possible */
3315          SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover,
3316                trafolinvars, trafolinvals, ntrafolinvars, trafolbs, var, trafolbv, newboundnonzero, ninftynonzero, FALSE, nchgbds, &update, &infeasible) );
3317          if ( infeasible )
3318             *cutoff = TRUE;
3319          else if ( update )
3320             *implupdate = TRUE;
3321       }
3322 
3323       /* free memory */
3324       SCIPfreeBufferArrayNull(scip, &varincover);
3325       for (j = ncliquecovers-1; j >= 0; --j)
3326          SCIPfreeBufferArrayNull(scip, &cliquecovers[j]);
3327       SCIPfreeBufferArrayNull(scip, &cliquecovers);
3328       SCIPfreeBufferArrayNull(scip, &cliquecoversizes);
3329       SCIPfreeBufferArrayNull(scip, &cliquecovervals);
3330       SCIPfreeBufferArrayNull(scip, &trafolinvals);
3331       SCIPfreeBufferArrayNull(scip, &trafolinvars);
3332 
3333       if ( *cutoff == TRUE )
3334          break;
3335    } /* end for every linear constraint */
3336 
3337    /* free buffer arrays */
3338    SCIPfreeBufferArrayNull(scip, &trafolbs);
3339    SCIPfreeBufferArrayNull(scip, &trafoubs);
3340    SCIPfreeBufferArrayNull(scip, &coveredvars);
3341    SCIPfreeBufferArrayNull(scip, &varindincons);
3342    SCIPfreeBufferArrayNull(scip, &implnodes);
3343    SCIPfreeBufferArrayNull(scip, &sos1linvars);
3344 
3345    return SCIP_OKAY;
3346 }
3347 
3348 
3349 /** perform one presolving round for variables
3350  *
3351  *  We perform the following presolving steps:
3352  *  - Tighten the bounds of the variables
3353  *  - Update conflict graph based on bound implications of the variables
3354  */
3355 static
presolRoundVarsSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_Bool ** adjacencymatrix,int nsos1vars,int * nfixedvars,int * nchgbds,int * naddconss,SCIP_RESULT * result)3356 SCIP_RETCODE presolRoundVarsSOS1(
3357    SCIP*                 scip,               /**< SCIP pointer */
3358    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
3359    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
3360    SCIP_Bool**           adjacencymatrix,    /**< adjacencymatrix of conflict graph */
3361    int                   nsos1vars,          /**< number of SOS1 variables */
3362    int*                  nfixedvars,         /**< pointer to store number of fixed variables */
3363    int*                  nchgbds,            /**< pointer to store number of changed bounds */
3364    int*                  naddconss,          /**< pointer to store number of addded constraints */
3365    SCIP_RESULT*          result              /**< result */
3366    )
3367 {
3368    SCIP_DIGRAPH* implgraph;
3369    SCIP_HASHMAP* implhash;
3370 
3371    SCIP_Bool cutoff = FALSE;
3372    SCIP_Bool updateconfl;
3373 
3374    SCIP_VAR** totalvars;
3375    SCIP_VAR** probvars;
3376    int ntotalvars = 0;
3377    int nprobvars;
3378    int i;
3379    int j;
3380 
3381    /* determine totalvars (union of SOS1 and problem variables) */
3382    probvars = SCIPgetVars(scip);
3383    nprobvars = SCIPgetNVars(scip);
3384    SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) );
3385    SCIP_CALL( SCIPallocBufferArray(scip, &totalvars, nsos1vars + nprobvars) );
3386 
3387    for (i = 0; i < nsos1vars; ++i)
3388    {
3389       SCIP_VAR* var;
3390       var = SCIPnodeGetVarSOS1(conflictgraph, i);
3391 
3392       /* insert node number to hash map */
3393       assert( ! SCIPhashmapExists(implhash, var) );
3394       SCIP_CALL( SCIPhashmapInsertInt(implhash, var, ntotalvars) );
3395       assert( ntotalvars == SCIPhashmapGetImageInt(implhash, var) );
3396       totalvars[ntotalvars++] = var;
3397    }
3398 
3399    for (i = 0; i < nprobvars; ++i)
3400    {
3401       SCIP_VAR* var;
3402       var = probvars[i];
3403 
3404       /* insert node number to hash map if not existent */
3405       if ( ! SCIPhashmapExists(implhash, var) )
3406       {
3407          SCIP_CALL( SCIPhashmapInsertInt(implhash, var, ntotalvars) );
3408          assert( ntotalvars == SCIPhashmapGetImageInt(implhash, var) );
3409          totalvars[ntotalvars++] = var;
3410       }
3411    }
3412 
3413    /* create implication graph */
3414    SCIP_CALL( SCIPcreateDigraph(scip, &implgraph, ntotalvars) );
3415 
3416    /* try to tighten the lower and upper bounds of the variables */
3417    updateconfl = FALSE;
3418    for (j = 0; (j < conshdlrdata->maxtightenbds || conshdlrdata->maxtightenbds == -1 ) && ! cutoff; ++j)
3419    {
3420       SCIP_Bool implupdate;
3421       int nchgbdssave;
3422 
3423       nchgbdssave = *nchgbds;
3424 
3425       assert( ntotalvars > 0 );
3426       SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, implgraph, implhash, adjacencymatrix, totalvars, ntotalvars, nsos1vars, nchgbds, &implupdate, &cutoff) );
3427       if ( *nchgbds > nchgbdssave )
3428       {
3429          *result = SCIP_SUCCESS;
3430          if ( implupdate )
3431             updateconfl = TRUE;
3432       }
3433       else if ( implupdate )
3434          updateconfl = TRUE;
3435       else
3436          break;
3437    }
3438 
3439    /* perform implication graph analysis */
3440    if ( updateconfl && conshdlrdata->perfimplanalysis && ! cutoff )
3441    {
3442       SCIP_Real* implubs;
3443       SCIP_Real* impllbs;
3444       SCIP_Bool* implnodes;
3445       SCIP_Bool infeasible;
3446       SCIP_Bool fixed;
3447       int naddconsssave;
3448       int probingdepth;
3449 
3450       /* allocate buffer arrays */
3451       SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
3452       SCIP_CALL( SCIPallocBufferArray(scip, &impllbs, ntotalvars) );
3453       SCIP_CALL( SCIPallocBufferArray(scip, &implubs, ntotalvars) );
3454 
3455       naddconsssave = *naddconss;
3456       for (i = 0; i < nsos1vars; ++i)
3457       {
3458 	 /* initialize data for implication graph analysis */
3459 	 infeasible = FALSE;
3460 	 probingdepth = 0;
3461          for (j = 0; j < nsos1vars; ++j)
3462             implnodes[j] = FALSE;
3463 	 for (j = 0; j < ntotalvars; ++j)
3464 	 {
3465 	    impllbs[j] = SCIPvarGetLbLocal(totalvars[j]);
3466 	    implubs[j] = SCIPvarGetUbLocal(totalvars[j]);
3467 	 }
3468 
3469 	 /* try to update the conflict graph based on the information of the implication graph */
3470 	 SCIP_CALL( performImplicationGraphAnalysis(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, adjacencymatrix, i, i, impllbs, implubs, implnodes, naddconss, &probingdepth, &infeasible) );
3471 
3472 	 /* if the subproblem turned out to be infeasible then fix variable to zero */
3473 	 if ( infeasible )
3474 	 {
3475 	    SCIP_CALL( SCIPfixVar(scip, totalvars[i], 0.0, &infeasible, &fixed) );
3476 
3477 	    if ( fixed )
3478 	    {
3479 	       SCIPdebugMsg(scip, "fixed variable %s with lower bound %f and upper bound %f to zero\n",
3480 				SCIPvarGetName(totalvars[i]), SCIPvarGetLbLocal(totalvars[i]), SCIPvarGetUbLocal(totalvars[i]));
3481 	       ++(*nfixedvars);
3482 	    }
3483 
3484 	    if ( infeasible )
3485 	       cutoff = TRUE;
3486 	 }
3487       }
3488 
3489       if ( *naddconss > naddconsssave )
3490          *result = SCIP_SUCCESS;
3491 
3492       /* free buffer arrays */
3493       SCIPfreeBufferArrayNull(scip, &implubs);
3494       SCIPfreeBufferArrayNull(scip, &impllbs);
3495       SCIPfreeBufferArrayNull(scip, &implnodes);
3496    }
3497 
3498    /* if an infeasibility has been detected */
3499    if ( cutoff )
3500    {
3501       SCIPdebugMsg(scip, "cutoff \n");
3502       *result = SCIP_CUTOFF;
3503    }
3504 
3505    /* free memory */;
3506    for (j = ntotalvars-1; j >= 0; --j)
3507    {
3508       SCIP_SUCCDATA** succdatas;
3509       int nsucc;
3510       int s;
3511 
3512       succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, j);
3513       nsucc = SCIPdigraphGetNSuccessors(implgraph, j);
3514 
3515       for (s = nsucc-1; s >= 0; --s)
3516          SCIPfreeBlockMemory(scip, &succdatas[s]);/*lint !e866*/
3517    }
3518    SCIPdigraphFree(&implgraph);
3519    SCIPfreeBufferArrayNull(scip, &totalvars);
3520    SCIPhashmapFree(&implhash);
3521 
3522    return SCIP_OKAY;
3523 }
3524 
3525 
3526 /* ----------------------------- propagation -------------------------------------*/
3527 
3528 /** propagate variables of SOS1 constraint */
3529 static
propConsSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_CONSDATA * consdata,SCIP_Bool * cutoff,int * ngen)3530 SCIP_RETCODE propConsSOS1(
3531    SCIP*                 scip,               /**< SCIP pointer */
3532    SCIP_CONS*            cons,               /**< constraint */
3533    SCIP_CONSDATA*        consdata,           /**< constraint data */
3534    SCIP_Bool*            cutoff,             /**< whether a cutoff happened */
3535    int*                  ngen                /**< number of domain changes */
3536    )
3537 {
3538    assert( scip != NULL );
3539    assert( cons != NULL );
3540    assert( consdata != NULL );
3541    assert( cutoff != NULL );
3542    assert( ngen != NULL );
3543 
3544    *cutoff = FALSE;
3545 
3546    /* if more than one variable is fixed to be nonzero */
3547    if ( consdata->nfixednonzeros > 1 )
3548    {
3549       SCIPdebugMsg(scip, "the node is infeasible, more than 1 variable is fixed to be nonzero.\n");
3550       SCIP_CALL( SCIPresetConsAge(scip, cons) );
3551       *cutoff = TRUE;
3552       return SCIP_OKAY;
3553    }
3554 
3555    /* if exactly one variable is fixed to be nonzero */
3556    if ( consdata->nfixednonzeros == 1 )
3557    {
3558       SCIP_VAR** vars;
3559       SCIP_Bool infeasible;
3560       SCIP_Bool tightened;
3561       SCIP_Bool success;
3562       SCIP_Bool allVarFixed;
3563       int firstFixedNonzero;
3564       int nvars;
3565       int j;
3566 
3567       firstFixedNonzero = -1;
3568       nvars = consdata->nvars;
3569       vars = consdata->vars;
3570       assert( vars != NULL );
3571 
3572       /* search nonzero variable - is needed for propinfo */
3573       for (j = 0; j < nvars; ++j)
3574       {
3575          if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(vars[j])) )
3576          {
3577             firstFixedNonzero = j;
3578             break;
3579          }
3580       }
3581       assert( firstFixedNonzero >= 0 );
3582 
3583       SCIPdebugMsg(scip, "variable <%s> is fixed nonzero, fixing other variables to 0.\n", SCIPvarGetName(vars[firstFixedNonzero]));
3584 
3585       /* fix variables before firstFixedNonzero to 0 */
3586       allVarFixed = TRUE;
3587       for (j = 0; j < firstFixedNonzero; ++j)
3588       {
3589          /* fix variable */
3590          SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
3591          assert( ! infeasible );
3592          allVarFixed = allVarFixed && success;
3593          if ( tightened )
3594             ++(*ngen);
3595       }
3596 
3597       /* fix variables after firstFixedNonzero to 0 */
3598       for (j = firstFixedNonzero+1; j < nvars; ++j)
3599       {
3600          /* fix variable */
3601          SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
3602          assert( ! infeasible ); /* there should be no variables after firstFixedNonzero that are fixed to be nonzero */
3603          allVarFixed = allVarFixed && success;
3604          if ( tightened )
3605             ++(*ngen);
3606       }
3607 
3608       /* reset constraint age counter */
3609       if ( *ngen > 0 )
3610       {
3611          SCIP_CALL( SCIPresetConsAge(scip, cons) );
3612       }
3613 
3614       /* delete constraint locally */
3615       if ( allVarFixed )
3616       {
3617          assert( !SCIPconsIsModifiable(cons) );
3618          SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3619       }
3620    }
3621 
3622    return SCIP_OKAY;
3623 }
3624 
3625 
3626 /** propagate a variable that is known to be nonzero */
3627 static
propVariableNonzero(SCIP * scip,SCIP_DIGRAPH * conflictgraph,SCIP_DIGRAPH * implgraph,SCIP_CONS * cons,int node,SCIP_Bool implprop,SCIP_Bool * cutoff,int * ngen)3628 SCIP_RETCODE propVariableNonzero(
3629    SCIP*                 scip,               /**< SCIP pointer */
3630    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
3631    SCIP_DIGRAPH*         implgraph,          /**< implication graph */
3632    SCIP_CONS*            cons,               /**< some arbitrary SOS1 constraint */
3633    int                   node,               /**< conflict graph node of variable that is known to be nonzero */
3634    SCIP_Bool             implprop,           /**< whether implication graph propagation shall be applied */
3635    SCIP_Bool*            cutoff,             /**< whether a cutoff happened */
3636    int*                  ngen                /**< number of domain changes */
3637    )
3638 {
3639    int inferinfo;
3640    int* succ;
3641    int nsucc;
3642    int s;
3643 
3644    assert( scip != NULL );
3645    assert( conflictgraph != NULL );
3646    assert( cutoff != NULL );
3647    assert( ngen != NULL );
3648    assert( node >= 0 );
3649 
3650    *cutoff = FALSE;
3651    inferinfo = -node - 1;
3652 
3653    /* by assumption zero is outside the domain of variable */
3654    assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(SCIPnodeGetVarSOS1(conflictgraph, node))) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(SCIPnodeGetVarSOS1(conflictgraph, node))) );
3655 
3656    /* apply conflict graph propagation (fix all neighbors in the conflict graph to zero) */
3657    succ = SCIPdigraphGetSuccessors(conflictgraph, node);
3658    nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
3659    for (s = 0; s < nsucc; ++s)
3660    {
3661       SCIP_VAR* succvar;
3662       SCIP_Real lb;
3663       SCIP_Real ub;
3664 
3665       succvar = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
3666       lb = SCIPvarGetLbLocal(succvar);
3667       ub = SCIPvarGetUbLocal(succvar);
3668 
3669       if ( ! SCIPisFeasZero(scip, lb) || ! SCIPisFeasZero(scip, ub) )
3670       {
3671          SCIP_Bool infeasible;
3672          SCIP_Bool tightened;
3673          SCIP_Bool success;
3674 
3675          /* fix variable if it is not multi-aggregated */
3676          SCIP_CALL( inferVariableZero(scip, succvar, cons, inferinfo, &infeasible, &tightened, &success) );
3677 
3678          if ( infeasible )
3679          {
3680             /* variable cannot be nonzero */
3681             *cutoff = TRUE;
3682             return SCIP_OKAY;
3683          }
3684          if ( tightened )
3685             ++(*ngen);
3686          assert( success || SCIPvarGetStatus(succvar) == SCIP_VARSTATUS_MULTAGGR );
3687       }
3688    }
3689 
3690    /* apply implication graph propagation */
3691    if ( implprop && implgraph != NULL )
3692    {
3693       SCIP_SUCCDATA** succdatas;
3694 
3695 #ifndef NDEBUG
3696       SCIP_NODEDATA* nodedbgdata;
3697       nodedbgdata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, node);
3698       assert( SCIPvarCompare(nodedbgdata->var, SCIPnodeGetVarSOS1(conflictgraph, node)) == 0 );
3699 #endif
3700 
3701       /* get successor datas */
3702       succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node);
3703 
3704       if ( succdatas != NULL )
3705       {
3706          succ = SCIPdigraphGetSuccessors(implgraph, node);
3707          nsucc = SCIPdigraphGetNSuccessors(implgraph, node);
3708          for (s = 0; s < nsucc; ++s)
3709          {
3710             SCIP_SUCCDATA* succdata;
3711             SCIP_NODEDATA* nodedata;
3712             SCIP_VAR* var;
3713 
3714             nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]);
3715             assert( nodedata != NULL );
3716             succdata = succdatas[s];
3717             assert( succdata != NULL );
3718             var = nodedata->var;
3719             assert( var != NULL );
3720 
3721             /* tighten variable if it is not multi-aggregated */
3722             if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR )
3723             {
3724                /* check for lower bound implication */
3725                if ( SCIPisFeasLT(scip, SCIPvarGetLbLocal(var), succdata->lbimpl) )
3726                {
3727                   SCIP_Bool infeasible;
3728                   SCIP_Bool tightened;
3729 
3730                   SCIP_CALL( SCIPinferVarLbCons(scip, var, succdata->lbimpl, cons, inferinfo, FALSE, &infeasible, &tightened) );
3731                   if ( infeasible )
3732                   {
3733                      *cutoff = TRUE;
3734                      return SCIP_OKAY;
3735                   }
3736                   if ( tightened )
3737                      ++(*ngen);
3738                }
3739 
3740                /* check for upper bound implication */
3741                if ( SCIPisFeasGT(scip, SCIPvarGetUbLocal(var), succdata->ubimpl) )
3742                {
3743                   SCIP_Bool infeasible;
3744                   SCIP_Bool tightened;
3745 
3746                   SCIP_CALL( SCIPinferVarUbCons(scip, var, succdata->ubimpl, cons, inferinfo, FALSE, &infeasible, &tightened) );
3747                   if ( infeasible )
3748                   {
3749                      *cutoff = TRUE;
3750                      return SCIP_OKAY;
3751                   }
3752                   if ( tightened )
3753                      ++(*ngen);
3754                }
3755             }
3756          }
3757       }
3758    }
3759 
3760    return SCIP_OKAY;
3761 }
3762 
3763 
3764 /** initialize implication graph
3765  *
3766  *  @p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$
3767  *
3768  *  @note By construction the implication graph is globally valid.
3769  */
3770 static
initImplGraphSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,int nsos1vars,int maxrounds,int * nchgbds,SCIP_Bool * cutoff,SCIP_Bool * success)3771 SCIP_RETCODE initImplGraphSOS1(
3772    SCIP*                 scip,               /**< SCIP pointer */
3773    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
3774    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
3775    int                   nsos1vars,          /**< number of SOS1 variables */
3776    int                   maxrounds,          /**< maximal number of propagation rounds for generating implications */
3777    int*                  nchgbds,            /**< pointer to store number of bound changes */
3778    SCIP_Bool*            cutoff,             /**< pointer to store  whether a cutoff occurred */
3779    SCIP_Bool*            success             /**< whether initialization was successful */
3780    )
3781 {
3782    SCIP_HASHMAP* implhash = NULL;
3783    SCIP_Bool** adjacencymatrix = NULL;
3784    SCIP_Bool* implnodes = NULL;
3785    SCIP_VAR** implvars = NULL;
3786    SCIP_VAR** probvars;
3787    int nimplnodes;
3788    int nprobvars;
3789    int i;
3790    int j;
3791 
3792    assert( scip != NULL );
3793    assert( conshdlrdata != NULL );
3794    assert( conflictgraph != NULL );
3795    assert( conshdlrdata->implgraph == NULL );
3796    assert( conshdlrdata->nimplnodes == 0 );
3797    assert( cutoff != NULL );
3798    assert( nchgbds != NULL );
3799 
3800    *nchgbds = 0;
3801    *cutoff = FALSE;
3802 
3803    /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */
3804    if ( conshdlrdata->maxsosadjacency != -1 && nsos1vars > conshdlrdata->maxsosadjacency )
3805    {
3806       *success = FALSE;
3807       SCIPdebugMsg(scip, "Implication graph was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency);
3808 
3809       return SCIP_OKAY;
3810    }
3811    *success = TRUE;
3812 
3813    /* only add globally valid implications to implication graph */
3814    assert ( SCIPgetDepth(scip) == 0 );
3815 
3816    probvars = SCIPgetVars(scip);
3817    nprobvars = SCIPgetNVars(scip);
3818    nimplnodes = 0;
3819 
3820    /* create implication graph */
3821    SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->implgraph, nsos1vars + nprobvars) );
3822 
3823    /* create hashmap */
3824    SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) );
3825 
3826    /* determine implvars (union of SOS1 and problem variables)
3827     * Note: For separation of implied bound cuts it is important that SOS1 variables are enumerated first
3828     */
3829    SCIP_CALL( SCIPallocBufferArray(scip, &implvars, nsos1vars + nprobvars) );
3830    for (i = 0; i < nsos1vars; ++i)
3831    {
3832       SCIP_VAR* var;
3833       var = SCIPnodeGetVarSOS1(conflictgraph, i);
3834 
3835       /* insert node number to hash map */
3836       assert( ! SCIPhashmapExists(implhash, var) );
3837       SCIP_CALL( SCIPhashmapInsertInt(implhash, var, nimplnodes) );
3838       assert( nimplnodes == SCIPhashmapGetImageInt(implhash, var) );
3839       implvars[nimplnodes++] = var;
3840    }
3841 
3842    for (i = 0; i < nprobvars; ++i)
3843    {
3844       SCIP_VAR* var;
3845       var = probvars[i];
3846 
3847       /* insert node number to hash map if not existent */
3848       if ( ! SCIPhashmapExists(implhash, var) )
3849       {
3850          SCIP_CALL( SCIPhashmapInsertInt(implhash, var, nimplnodes) );
3851          assert( nimplnodes == SCIPhashmapGetImageInt(implhash, var) );
3852          implvars[nimplnodes++] = var;
3853       }
3854    }
3855    conshdlrdata->nimplnodes = nimplnodes;
3856 
3857    /* add variables to nodes of implication graph */
3858    for (i = 0; i < nimplnodes; ++i)
3859    {
3860       SCIP_NODEDATA* nodedata = NULL;
3861 
3862       /* create node data */
3863       SCIP_CALL( SCIPallocBlockMemory(scip, &nodedata) );
3864       nodedata->var = implvars[i];
3865 
3866       /* set node data */
3867       SCIPdigraphSetNodeData(conshdlrdata->implgraph, (void*) nodedata, i);
3868    }
3869 
3870    /* allocate buffer arrays */
3871    SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
3872    SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) );
3873 
3874    for (i = 0; i < nsos1vars; ++i)
3875       SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) ); /*lint !e866*/
3876 
3877    /* create adjacency matrix */
3878    for (i = 0; i < nsos1vars; ++i)
3879    {
3880       for (j = 0; j < i+1; ++j)
3881          adjacencymatrix[i][j] = 0;
3882    }
3883 
3884    for (i = 0; i < nsos1vars; ++i)
3885    {
3886       int* succ;
3887       int nsucc;
3888       succ = SCIPdigraphGetSuccessors(conflictgraph, i);
3889       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
3890 
3891       for (j = 0; j < nsucc; ++j)
3892       {
3893          if ( i > succ[j] )
3894             adjacencymatrix[i][succ[j]] = 1;
3895       }
3896    }
3897 
3898    assert( SCIPgetDepth(scip) == 0 );
3899 
3900    /* compute SOS1 implications from linear constraints and tighten bounds of variables */
3901    for (j = 0; (j < maxrounds || maxrounds == -1 ); ++j)
3902    {
3903       SCIP_Bool implupdate;
3904       int nchgbdssave;
3905 
3906       nchgbdssave = *nchgbds;
3907 
3908       assert( nimplnodes > 0 );
3909       SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->implgraph, implhash, adjacencymatrix, implvars, nimplnodes, nsos1vars, nchgbds, &implupdate, cutoff) );
3910       if ( *cutoff || ( ! implupdate && ! ( *nchgbds > nchgbdssave ) ) )
3911          break;
3912    }
3913 
3914    /* free memory */
3915    for (i = nsos1vars-1; i >= 0; --i)
3916       SCIPfreeBufferArrayNull(scip, &adjacencymatrix[i]);
3917    SCIPfreeBufferArrayNull(scip, &adjacencymatrix);
3918    SCIPfreeBufferArrayNull(scip, &implnodes);
3919    SCIPfreeBufferArrayNull(scip, &implvars);
3920    SCIPhashmapFree(&implhash);
3921 
3922 #ifdef SCIP_DEBUG
3923    /* evaluate results */
3924    if ( cutoff )
3925    {
3926       SCIPdebugMsg(scip, "cutoff \n");
3927    }
3928    else if ( *nchgbds > 0 )
3929    {
3930       SCIPdebugMsg(scip, "found %d bound changes\n", *nchgbds);
3931    }
3932 #endif
3933 
3934    assert( conshdlrdata->implgraph != NULL );
3935 
3936    return SCIP_OKAY;
3937 }
3938 
3939 
3940 /** deinitialize implication graph */
3941 static
freeImplGraphSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata)3942 SCIP_RETCODE freeImplGraphSOS1(
3943    SCIP*                 scip,               /**< SCIP pointer */
3944    SCIP_CONSHDLRDATA*    conshdlrdata        /**< constraint handler data */
3945    )
3946 {
3947    int j;
3948 
3949    assert( scip != NULL );
3950    assert( conshdlrdata != NULL );
3951 
3952    /* free whole memory of implication graph */
3953    if ( conshdlrdata->implgraph == NULL )
3954    {
3955       assert( conshdlrdata->nimplnodes == 0 );
3956       return SCIP_OKAY;
3957    }
3958 
3959    /* free arc data */
3960    for (j = conshdlrdata->nimplnodes-1; j >= 0; --j)
3961    {
3962       SCIP_SUCCDATA** succdatas;
3963       int nsucc;
3964       int s;
3965 
3966       succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(conshdlrdata->implgraph, j);
3967       nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->implgraph, j);
3968 
3969       for (s = nsucc-1; s >= 0; --s)
3970       {
3971          assert( succdatas[s] != NULL );
3972          SCIPfreeBlockMemory(scip, &succdatas[s]);/*lint !e866*/
3973       }
3974    }
3975 
3976    /* free node data */
3977    for (j = conshdlrdata->nimplnodes-1; j >= 0; --j)
3978    {
3979       SCIP_NODEDATA* nodedata;
3980       nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->implgraph, j);
3981       assert( nodedata != NULL );
3982       SCIPfreeBlockMemory(scip, &nodedata);
3983       SCIPdigraphSetNodeData(conshdlrdata->implgraph, NULL, j);
3984    }
3985 
3986    /* free implication graph */
3987    SCIPdigraphFree(&conshdlrdata->implgraph);
3988    conshdlrdata->nimplnodes = 0;
3989 
3990    return SCIP_OKAY;
3991 }
3992 
3993 
3994 /* ----------------------------- branching -------------------------------------*/
3995 
3996 /** get the vertices whose neighbor set covers a subset of the neighbor set of a given other vertex.
3997  *
3998  *  This function can be used to compute sets of variables to branch on.
3999  */
4000 static
getCoverVertices(SCIP_DIGRAPH * conflictgraph,SCIP_Bool * verticesarefixed,int vertex,int * neightocover,int nneightocover,int * coververtices,int * ncoververtices)4001 SCIP_RETCODE getCoverVertices(
4002    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
4003    SCIP_Bool*            verticesarefixed,   /**< array that indicates which variables are currently fixed to zero */
4004    int                   vertex,             /**< vertex (-1 if not needed) */
4005    int*                  neightocover,       /**< neighbors of given vertex to be covered (or NULL if all neighbors shall be covered) */
4006    int                   nneightocover,      /**< number of entries of neightocover (or 0 if all neighbors shall be covered )*/
4007    int*                  coververtices,      /**< array to store the vertices whose neighbor set covers the neighbor set of the given vertex */
4008    int*                  ncoververtices      /**< pointer to store size of coververtices */
4009    )
4010 {
4011    int* succ1;
4012    int nsucc1;
4013    int s;
4014 
4015    assert( conflictgraph != NULL );
4016    assert( verticesarefixed != NULL );
4017    assert( coververtices != NULL );
4018    assert( ncoververtices != NULL );
4019 
4020    *ncoververtices = 0;
4021 
4022    /* if all the neighbors shall be covered */
4023    if ( neightocover == NULL )
4024    {
4025       assert( nneightocover == 0 );
4026       nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex);
4027       succ1 = SCIPdigraphGetSuccessors(conflictgraph, vertex);
4028    }
4029    else
4030    {
4031       nsucc1 = nneightocover;
4032       succ1 = neightocover;
4033    }
4034 
4035    /* determine all the successors of the first unfixed successor */
4036    for (s = 0; s < nsucc1; ++s)
4037    {
4038       int succvertex1 = succ1[s];
4039 
4040       if ( ! verticesarefixed[succvertex1] )
4041       {
4042          int succvertex2;
4043          int* succ2;
4044          int nsucc2;
4045          int j;
4046 
4047          nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, succvertex1);
4048          succ2 = SCIPdigraphGetSuccessors(conflictgraph, succvertex1);
4049 
4050          /* for the first unfixed vertex */
4051          if ( *ncoververtices == 0 )
4052          {
4053             for (j = 0; j < nsucc2; ++j)
4054             {
4055                succvertex2 = succ2[j];
4056                if ( ! verticesarefixed[succvertex2] )
4057                   coververtices[(*ncoververtices)++] = succvertex2;
4058             }
4059          }
4060          else
4061          {
4062             int vv = 0;
4063             int k = 0;
4064             int v;
4065 
4066             /* determine all the successors that are in the set "coververtices" */
4067             for (v = 0; v < *ncoververtices; ++v)
4068             {
4069                assert( vv <= v );
4070                for (j = k; j < nsucc2; ++j)
4071                {
4072                   succvertex2 = succ2[j];
4073                   if ( succvertex2 > coververtices[v] )
4074                   {
4075                      /* coververtices[v] does not appear in succ2 list, go to next vertex in coververtices */
4076                      k = j;
4077                      break;
4078                   }
4079                   else if ( succvertex2 == coververtices[v] )
4080                   {
4081                      /* vertices are equal, copy to free position vv */
4082                      coververtices[vv++] = succvertex2;
4083                      k = j + 1;
4084                      break;
4085                   }
4086                }
4087             }
4088             /* store new size of coververtices */
4089             *ncoververtices = vv;
4090          }
4091       }
4092    }
4093 
4094 #ifdef SCIP_DEBUG
4095    /* check sorting */
4096    for (s = 0; s < *ncoververtices; ++s)
4097    {
4098       assert( *ncoververtices <= 1 || coververtices[*ncoververtices - 1] > coververtices[*ncoververtices - 2] );
4099    }
4100 #endif
4101 
4102    return SCIP_OKAY;
4103 }
4104 
4105 
4106 /** get vertices of variables that will be fixed to zero for each node */
4107 static
getBranchingVerticesSOS1(SCIP * scip,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,SCIP_Bool * verticesarefixed,SCIP_Bool bipbranch,int branchvertex,int * fixingsnode1,int * nfixingsnode1,int * fixingsnode2,int * nfixingsnode2)4108 SCIP_RETCODE getBranchingVerticesSOS1(
4109    SCIP*                 scip,               /**< SCIP pointer */
4110    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
4111    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
4112    SCIP_Bool*            verticesarefixed,   /**< vector that indicates which variables are currently fixed to zero */
4113    SCIP_Bool             bipbranch,          /**< TRUE if bipartite branching method should be used */
4114    int                   branchvertex,       /**< branching vertex */
4115    int*                  fixingsnode1,       /**< vertices of variables that will be fixed to zero for the first node */
4116    int*                  nfixingsnode1,      /**< pointer to store number of fixed variables for the first node */
4117    int*                  fixingsnode2,       /**< vertices of variables that will be fixed to zero for the second node */
4118    int*                  nfixingsnode2       /**< pointer to store number of fixed variables for the second node */
4119    )
4120 {
4121    SCIP_Bool takeallsucc; /* whether to set fixingsnode1 = neighbors of 'branchvertex' in the conflict graph */
4122    int* succ;
4123    int nsucc;
4124    int j;
4125 
4126    assert( scip != NULL );
4127    assert( conflictgraph != NULL );
4128    assert( verticesarefixed != NULL );
4129    assert( ! verticesarefixed[branchvertex] );
4130    assert( fixingsnode1 != NULL );
4131    assert( fixingsnode2 != NULL );
4132    assert( nfixingsnode1 != NULL );
4133    assert( nfixingsnode2 != NULL );
4134 
4135    *nfixingsnode1 = 0;
4136    *nfixingsnode2 = 0;
4137    takeallsucc = TRUE;
4138 
4139    /* get successors and number of successors of branching vertex */
4140    nsucc = SCIPdigraphGetNSuccessors(conflictgraph, branchvertex);
4141    succ = SCIPdigraphGetSuccessors(conflictgraph, branchvertex);
4142 
4143    /* if bipartite branching method is turned on */
4144    if ( bipbranch )
4145    {
4146       SCIP_Real solval;
4147       int cnt = 0;
4148 
4149       /* get all the neighbors of the variable with index 'branchvertex' whose solution value is nonzero */
4150       for (j = 0; j < nsucc; ++j)
4151       {
4152          if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[j]))) )
4153          {
4154             assert( ! verticesarefixed[succ[j]] );
4155             fixingsnode1[(*nfixingsnode1)++] = succ[j];
4156          }
4157       }
4158 
4159       /* if one of the sets fixingsnode1 or fixingsnode2 contains only one variable with a nonzero LP value we perform standard neighborhood branching */
4160       if ( *nfixingsnode1 > 0 )
4161       {
4162          /* get the vertices whose neighbor set cover the selected subset of the neighbors of the given branching vertex */
4163          SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) );
4164 
4165          /* determine the intersection of the neighbors of branchvertex with the intersection of all the neighbors of fixingsnode2 */
4166          SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode2, *nfixingsnode2, fixingsnode1, nfixingsnode1) );
4167 
4168          for (j = 0; j < *nfixingsnode2; ++j)
4169          {
4170             solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]));
4171             if( ! SCIPisFeasZero(scip, solval) )
4172                ++cnt;
4173          }
4174 
4175          /* we decide whether to use all successors if one partition of complete bipartite subgraph has only one node */
4176          if ( cnt >= 2 )
4177          {
4178             cnt = 0;
4179             for (j = 0; j < *nfixingsnode1; ++j)
4180             {
4181                solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]));
4182                if( ! SCIPisFeasZero(scip, solval) )
4183                   ++cnt;
4184             }
4185 
4186             if ( cnt >= 2 )
4187                takeallsucc = FALSE;
4188          }
4189       }
4190    }
4191 
4192    if ( takeallsucc )
4193    {
4194       /* get all the unfixed neighbors of the branching vertex */
4195       *nfixingsnode1 = 0;
4196       for (j = 0; j < nsucc; ++j)
4197       {
4198          if ( ! verticesarefixed[succ[j]] )
4199             fixingsnode1[(*nfixingsnode1)++] = succ[j];
4200       }
4201 
4202       if ( bipbranch )
4203       {
4204          /* get the vertices whose neighbor set covers the neighbor set of a given branching vertex */
4205          SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) );
4206       }
4207       else
4208       {
4209          /* use neighborhood branching, i.e, for the second node only the branching vertex can be fixed */
4210          fixingsnode2[0] = branchvertex;
4211          *nfixingsnode2 = 1;
4212       }
4213    }
4214 
4215    return SCIP_OKAY;
4216 }
4217 
4218 
4219 /** gets branching priorities for SOS1 variables and applies 'most infeasible selection' rule to determine a vertex for the next branching decision */
4220 static
getBranchingPrioritiesSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,int nsos1vars,SCIP_Bool * verticesarefixed,SCIP_Bool bipbranch,int * fixingsnode1,int * fixingsnode2,SCIP_Real * branchpriors,int * vertexbestprior,SCIP_Bool * relsolfeas)4221 SCIP_RETCODE getBranchingPrioritiesSOS1(
4222    SCIP*                 scip,               /**< SCIP pointer */
4223    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
4224    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
4225    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
4226    int                   nsos1vars,          /**< number of SOS1 variables */
4227    SCIP_Bool*            verticesarefixed,   /**< vector that indicates which variables are currently fixed to zero */
4228    SCIP_Bool             bipbranch,          /**< TRUE if bipartite branching method should be used */
4229    int*                  fixingsnode1,       /**< vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */
4230    int*                  fixingsnode2,       /**< vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */
4231    SCIP_Real*            branchpriors,       /**< pointer to store branching priorities (size = nsos1vars) or NULL if not needed */
4232    int*                  vertexbestprior,    /**< pointer to store vertex with the best branching priority or NULL if not needed */
4233    SCIP_Bool*            relsolfeas          /**< pointer to store if LP relaxation solution is feasible */
4234    )
4235 {
4236    SCIP_Real bestprior;
4237    int i;
4238 
4239    assert( scip != NULL );
4240    assert( conshdlrdata != NULL );
4241    assert( conflictgraph != NULL );
4242    assert( verticesarefixed != NULL );
4243    assert( fixingsnode1 != NULL );
4244    assert( fixingsnode2 != NULL );
4245    assert( relsolfeas != NULL );
4246 
4247    bestprior = -SCIPinfinity(scip);
4248 
4249    /* make sure data is initialized */
4250    if ( vertexbestprior != NULL )
4251       *vertexbestprior = -1;
4252 
4253    for (i = 0; i < nsos1vars; ++i)
4254    {
4255       SCIP_Real prior;
4256       SCIP_Real solval;
4257       int nfixingsnode1;
4258       int nfixingsnode2;
4259       int nsucc;
4260       int j;
4261 
4262       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
4263 
4264       if ( nsucc == 0 || SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, i))) || verticesarefixed[i] )
4265          prior = -SCIPinfinity(scip);
4266       else
4267       {
4268          SCIP_Bool iszero1 = TRUE;
4269          SCIP_Bool iszero2 = TRUE;
4270          SCIP_Real sum1 = 0.0;
4271          SCIP_Real sum2 = 0.0;
4272 
4273          /* get vertices of variables that will be fixed to zero for each strong branching execution */
4274          assert( ! verticesarefixed[i] );
4275          SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, i, fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
4276 
4277          for (j = 0; j < nfixingsnode1; ++j)
4278          {
4279             solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]));
4280             if ( ! SCIPisFeasZero(scip, solval) )
4281             {
4282                sum1 += REALABS( solval );
4283                iszero1 = FALSE;
4284             }
4285          }
4286 
4287          for (j = 0; j < nfixingsnode2; ++j)
4288          {
4289             solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]));
4290             if ( ! SCIPisFeasZero(scip, solval) )
4291             {
4292                sum2 += REALABS( solval );
4293                iszero2 = FALSE;
4294             }
4295          }
4296 
4297          if ( iszero1 || iszero2 )
4298             prior = -SCIPinfinity(scip);
4299          else
4300             prior = sum1 * sum2;
4301       }
4302 
4303       if ( branchpriors != NULL )
4304          branchpriors[i] = prior;
4305       if ( bestprior < prior )
4306       {
4307          bestprior = prior;
4308 
4309          if ( vertexbestprior != NULL )
4310             *vertexbestprior = i;
4311       }
4312    }
4313 
4314    if ( SCIPisInfinity(scip, -bestprior) )
4315       *relsolfeas = TRUE;
4316    else
4317       *relsolfeas = FALSE;
4318 
4319    return SCIP_OKAY;
4320 }
4321 
4322 
4323 /** performs strong branching with given domain fixings */
4324 static
performStrongbranchSOS1(SCIP * scip,SCIP_DIGRAPH * conflictgraph,int * fixingsexec,int nfixingsexec,int * fixingsop,int nfixingsop,int inititer,SCIP_Bool fixnonzero,int * domainfixings,int * ndomainfixings,SCIP_Bool * infeasible,SCIP_Real * objval,SCIP_Bool * lperror)4325 SCIP_RETCODE performStrongbranchSOS1(
4326    SCIP*                 scip,               /**< SCIP pointer */
4327    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
4328    int*                  fixingsexec,        /**< vertices of variables to be fixed to zero for this strong branching execution */
4329    int                   nfixingsexec,       /**< number of vertices of variables to be fixed to zero for this strong branching execution */
4330    int*                  fixingsop,          /**< vertices of variables to be fixed to zero for the opposite strong branching execution */
4331    int                   nfixingsop,         /**< number of vertices of variables to be fixed to zero for the opposite strong branching execution */
4332    int                   inititer,           /**< maximal number of LP iterations to perform */
4333    SCIP_Bool             fixnonzero,         /**< shall opposite variable (if positive in sign) fixed to the feasibility tolerance
4334                                               *   (only possible if nfixingsop = 1) */
4335    int*                  domainfixings,      /**< vertices that can be used to reduce the domain (should have size equal to number of variables) */
4336    int*                  ndomainfixings,     /**< pointer to store number of vertices that can be used to reduce the domain, could be filled by earlier calls */
4337    SCIP_Bool*            infeasible,         /**< pointer to store whether branch is infeasible */
4338    SCIP_Real*            objval,             /**< pointer to store objective value of LP with fixed variables (SCIP_INVALID if reddomain = TRUE or lperror = TRUE) */
4339    SCIP_Bool*            lperror             /**< pointer to store whether an unresolved LP error or a strange solution status occurred */
4340    )
4341 {
4342    SCIP_LPSOLSTAT solstat;
4343    int i;
4344 
4345    assert( scip != NULL );
4346    assert( conflictgraph != NULL );
4347    assert( fixingsexec != NULL );
4348    assert( nfixingsop > 0 );
4349    assert( fixingsop != NULL );
4350    assert( nfixingsop > 0 );
4351    assert( inititer >= -1 );
4352    assert( domainfixings != NULL );
4353    assert( ndomainfixings != NULL );
4354    assert( *ndomainfixings >= 0 );
4355    assert( infeasible != NULL );
4356    assert( objval != NULL );
4357    assert( lperror != NULL );
4358 
4359    *objval = SCIP_INVALID; /* for debugging */
4360    *lperror = FALSE;
4361    *infeasible = FALSE;
4362 
4363    /* start probing */
4364    SCIP_CALL( SCIPstartProbing(scip) );
4365 
4366    /* perform domain fixings */
4367    if ( fixnonzero && nfixingsop == 1 )
4368    {
4369       SCIP_VAR* var;
4370       SCIP_Real lb;
4371       SCIP_Real ub;
4372 
4373       var = SCIPnodeGetVarSOS1(conflictgraph, fixingsop[0]);
4374       lb = SCIPvarGetLbLocal(var);
4375       ub = SCIPvarGetUbLocal(var);
4376 
4377       if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR )
4378       {
4379          if ( SCIPisZero(scip, lb) )
4380          {
4381             /* fix variable to some very small, but positive number or to 1.0 if variable is integral */
4382             if (SCIPvarIsIntegral(var) )
4383             {
4384                SCIP_CALL( SCIPchgVarLbProbing(scip, var, 1.0) );
4385             }
4386             else
4387             {
4388                SCIP_CALL( SCIPchgVarLbProbing(scip, var, 1.5 * SCIPfeastol(scip)) );
4389             }
4390          }
4391          else if ( SCIPisZero(scip, ub) )
4392          {
4393             /* fix variable to some negative number with small absolute value or to -1.0 if variable is integral */
4394             if (SCIPvarIsIntegral(var) )
4395             {
4396                SCIP_CALL( SCIPchgVarUbProbing(scip, var, -1.0) );
4397             }
4398             else
4399             {
4400                SCIP_CALL( SCIPchgVarUbProbing(scip, var, -1.5 * SCIPfeastol(scip)) );
4401             }
4402          }
4403       }
4404    }
4405 
4406    /* injects variable fixings into current probing node */
4407    for (i = 0; i < nfixingsexec && ! *infeasible; ++i)
4408    {
4409       SCIP_VAR* var;
4410 
4411       var = SCIPnodeGetVarSOS1(conflictgraph, fixingsexec[i]);
4412       if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), 0.0) || SCIPisFeasLT(scip, SCIPvarGetUbLocal(var), 0.0) )
4413          *infeasible = TRUE;
4414       else
4415       {
4416          SCIP_CALL( SCIPfixVarProbing(scip, var, 0.0) );
4417       }
4418    }
4419 
4420    /* apply domain propagation */
4421    if ( ! *infeasible )
4422    {
4423       SCIP_CALL( SCIPpropagateProbing(scip, 0, infeasible, NULL) );
4424    }
4425 
4426    if ( *infeasible )
4427       solstat = SCIP_LPSOLSTAT_INFEASIBLE;
4428    else
4429    {
4430       /* solve the probing LP */
4431       SCIP_CALL( SCIPsolveProbingLP(scip, inititer, lperror, NULL) );
4432       if ( *lperror )
4433       {
4434          SCIP_CALL( SCIPendProbing(scip) );
4435          return SCIP_OKAY;
4436       }
4437 
4438       /* get solution status */
4439       solstat = SCIPgetLPSolstat(scip);
4440    }
4441 
4442    /* if objective limit was reached, then the domain can be reduced */
4443    if ( solstat == SCIP_LPSOLSTAT_OBJLIMIT || solstat == SCIP_LPSOLSTAT_INFEASIBLE )
4444    {
4445       *infeasible = TRUE;
4446 
4447       for (i = 0; i < nfixingsop; ++i)
4448          domainfixings[(*ndomainfixings)++] = fixingsop[i];
4449    }
4450    else if ( solstat == SCIP_LPSOLSTAT_OPTIMAL || solstat == SCIP_LPSOLSTAT_TIMELIMIT || solstat == SCIP_LPSOLSTAT_ITERLIMIT )
4451    {
4452       /* get objective value of probing LP */
4453       *objval = SCIPgetLPObjval(scip);
4454    }
4455    else
4456       *lperror = TRUE;
4457 
4458    /* end probing */
4459    SCIP_CALL( SCIPendProbing(scip) );
4460 
4461    return SCIP_OKAY;
4462 }
4463 
4464 
4465 /** apply strong branching to determine the vertex for the next branching decision */
4466 static
getBranchingDecisionStrongbranchSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,int nsos1vars,SCIP_Real lpobjval,SCIP_Bool bipbranch,int nstrongrounds,SCIP_Bool * verticesarefixed,int * fixingsnode1,int * fixingsnode2,int * vertexbestprior,SCIP_Real * bestobjval1,SCIP_Real * bestobjval2,SCIP_RESULT * result)4467 SCIP_RETCODE getBranchingDecisionStrongbranchSOS1(
4468    SCIP*                 scip,               /**< SCIP pointer */
4469    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< SOS1 constraint handler data */
4470    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
4471    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
4472    int                   nsos1vars,          /**< number of SOS1 variables */
4473    SCIP_Real             lpobjval,           /**< current LP relaxation solution */
4474    SCIP_Bool             bipbranch,          /**< TRUE if bipartite branching method should be used */
4475    int                   nstrongrounds,      /**< number of strong branching rounds */
4476    SCIP_Bool*            verticesarefixed,   /**< vector that indicates which variables are currently fixed to zero */
4477    int*                  fixingsnode1,       /**< pointer to store vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */
4478    int*                  fixingsnode2,       /**< pointer to store vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */
4479    int*                  vertexbestprior,    /**< pointer to store vertex with the best strong branching priority */
4480    SCIP_Real*            bestobjval1,        /**< pointer to store LP objective for left child node of branching decision with best priority */
4481    SCIP_Real*            bestobjval2,        /**< pointer to store LP objective for right child node of branching decision with best priority */
4482    SCIP_RESULT*          result              /**< pointer to store result of strong branching */
4483    )
4484 {
4485    SCIP_Real* branchpriors = NULL;
4486    int* indsos1vars = NULL;
4487    int* domainfixings = NULL;
4488    int ndomainfixings;
4489    int nfixingsnode1;
4490    int nfixingsnode2;
4491 
4492    SCIP_Bool relsolfeas;
4493    SCIP_Real bestscore;
4494    int lastscorechange;
4495    int maxfailures;
4496 
4497    SCIP_Longint nlpiterations;
4498    SCIP_Longint nlps;
4499    int inititer;
4500    int j;
4501    int i;
4502 
4503    assert( scip != NULL );
4504    assert( conshdlrdata != NULL );
4505    assert( conflictgraph != NULL );
4506    assert( verticesarefixed != NULL );
4507    assert( fixingsnode1 != NULL );
4508    assert( fixingsnode2 != NULL );
4509    assert( vertexbestprior != NULL );
4510    assert( result != NULL );
4511 
4512    /* allocate buffer arrays */
4513    SCIP_CALL( SCIPallocBufferArray(scip, &branchpriors, nsos1vars) );
4514 
4515    /* get branching priorities */
4516    SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, verticesarefixed,
4517          bipbranch, fixingsnode1, fixingsnode2, branchpriors, NULL, &relsolfeas) );
4518 
4519    /* if LP relaxation solution is feasible */
4520    if ( relsolfeas )
4521    {
4522       SCIPdebugMsg(scip, "all the SOS1 constraints are feasible.\n");
4523       *vertexbestprior = -1;
4524       *result = SCIP_FEASIBLE;
4525 
4526       /* free memory */
4527       SCIPfreeBufferArrayNull(scip, &branchpriors);
4528 
4529       return SCIP_OKAY;
4530    }
4531 
4532    /* allocate buffer arrays */
4533    SCIP_CALL( SCIPallocBufferArray(scip, &indsos1vars, nsos1vars) );
4534    SCIP_CALL( SCIPallocBufferArray(scip, &domainfixings, nsos1vars) );
4535 
4536    /* sort branching priorities (descending order) */
4537    for (j = 0; j < nsos1vars; ++j)
4538       indsos1vars[j] = j;
4539    SCIPsortDownRealInt(branchpriors, indsos1vars, nsos1vars);
4540 
4541    /* determine the number of LP iterations to perform in each strong branch */
4542    nlpiterations =  SCIPgetNDualResolveLPIterations(scip);
4543    nlps = SCIPgetNDualResolveLPs(scip);
4544    if ( nlps == 0 )
4545    {
4546       nlpiterations = SCIPgetNNodeInitLPIterations(scip);
4547       nlps = SCIPgetNNodeInitLPs(scip);
4548       if ( nlps == 0 )
4549       {
4550          nlpiterations = 1000;
4551          nlps = 1;
4552       }
4553    }
4554    assert(nlps >= 1);
4555 
4556    /* compute number of LP iterations performed per strong branching iteration */
4557    if ( conshdlrdata->nstrongiter == -2 )
4558    {
4559       inititer = (int)(2*nlpiterations / nlps);
4560       inititer = (int)((SCIP_Real)inititer * (1.0 + 20.0/SCIPgetNNodes(scip)));
4561       inititer = MAX(inititer, 10);
4562       inititer = MIN(inititer, 500);
4563    }
4564    else
4565       inititer = conshdlrdata->nstrongiter;
4566 
4567    /* get current LP relaxation solution */
4568    lpobjval = SCIPgetLPObjval(scip);
4569 
4570    /* determine branching variable by strong branching or reduce domain */
4571    ndomainfixings = 0;
4572    lastscorechange = -1;
4573    assert( nsos1vars > 0 );
4574    *vertexbestprior = indsos1vars[0]; /* for the case that nstrongrounds = 0 */
4575    bestscore = -SCIPinfinity(scip);
4576    *bestobjval1 = -SCIPinfinity(scip);
4577    *bestobjval2 = -SCIPinfinity(scip);
4578    maxfailures = nstrongrounds;
4579 
4580    /* for each strong branching round */
4581    for (j = 0; j < nstrongrounds; ++j)
4582    {
4583       int testvertex;
4584 
4585       /* get branching vertex for the current strong branching iteration */
4586       testvertex = indsos1vars[j];
4587 
4588       /* if variable with index 'vertex' does not violate any complementarity in its neighborhood for the current LP relaxation solution */
4589       if ( SCIPisPositive(scip, branchpriors[j]) )
4590       {
4591          SCIP_Bool infeasible1;
4592          SCIP_Bool infeasible2;
4593          SCIP_Bool lperror;
4594          SCIP_Real objval1;
4595          SCIP_Real objval2;
4596          SCIP_Real score;
4597 
4598          /* get vertices of variables that will be fixed to zero for each strong branching execution */
4599          assert( ! verticesarefixed[testvertex] );
4600          SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, testvertex,
4601                fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
4602 
4603          /* get information for first strong branching execution */
4604          SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2,
4605                inititer, conshdlrdata->fixnonzero, domainfixings, &ndomainfixings, &infeasible1, &objval1, &lperror) );
4606          if ( lperror )
4607             continue;
4608 
4609          /* get information for second strong branching execution */
4610          SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1,
4611                inititer, FALSE, domainfixings, &ndomainfixings, &infeasible2, &objval2, &lperror) );
4612          if ( lperror )
4613             continue;
4614 
4615          /* if both subproblems are infeasible */
4616          if ( infeasible1 && infeasible2 )
4617          {
4618             SCIPdebugMsg(scip, "detected cutoff.\n");
4619 
4620             /* update result */
4621             *result = SCIP_CUTOFF;
4622 
4623             /* free memory */
4624             SCIPfreeBufferArrayNull(scip, &domainfixings);
4625             SCIPfreeBufferArrayNull(scip, &indsos1vars);
4626             SCIPfreeBufferArrayNull(scip, &branchpriors);
4627 
4628             return SCIP_OKAY;
4629          }
4630          else if ( ! infeasible1 && ! infeasible2 ) /* both subproblems are feasible */
4631          {
4632             /* if domain has not been reduced in this for-loop */
4633             if ( ndomainfixings == 0 )
4634             {
4635                score = MAX( REALABS(objval1 - lpobjval), SCIPfeastol(scip) ) * MAX( REALABS(objval2 - lpobjval), SCIPfeastol(scip) );/*lint !e666*/
4636 
4637                if ( SCIPisPositive(scip, score - bestscore) )
4638                {
4639                   bestscore = score;
4640                   *vertexbestprior = testvertex;
4641                   *bestobjval1 = objval1;
4642                   *bestobjval2 = objval2;
4643 
4644                   lastscorechange = j;
4645                }
4646                else if ( j - lastscorechange > maxfailures )
4647                   break;
4648             }
4649          }
4650       }
4651    }
4652 
4653    /* if variable fixings have been detected by probing, then reduce domain */
4654    if ( ndomainfixings > 0 )
4655    {
4656       SCIP_NODE* node = SCIPgetCurrentNode(scip);
4657       SCIP_Bool infeasible;
4658 
4659       for (i = 0; i < ndomainfixings; ++i)
4660       {
4661          SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, domainfixings[i]), node, &infeasible) );
4662          assert( ! infeasible );
4663       }
4664 
4665       SCIPdebugMsg(scip, "found %d domain fixings.\n", ndomainfixings);
4666 
4667       /* update result */
4668       *result = SCIP_REDUCEDDOM;
4669    }
4670 
4671    /* free buffer arrays */
4672    SCIPfreeBufferArrayNull(scip, &domainfixings);
4673    SCIPfreeBufferArrayNull(scip, &indsos1vars);
4674    SCIPfreeBufferArrayNull(scip, &branchpriors);
4675 
4676    return SCIP_OKAY;
4677 }
4678 
4679 
4680 /** for two given vertices @p v1 and @p v2 search for a clique in the conflict graph that contains these vertices. From
4681  *  this clique, we create a bound constraint.
4682  */
4683 static
getBoundConsFromVertices(SCIP * scip,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,int v1,int v2,SCIP_VAR * boundvar,SCIP_Bool extend,SCIP_CONS * cons,SCIP_Real * feas)4684 SCIP_RETCODE getBoundConsFromVertices(
4685    SCIP*                 scip,               /**< SCIP pointer */
4686    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
4687    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
4688    int                   v1,                 /**< first vertex that shall be contained in bound constraint */
4689    int                   v2,                 /**< second vertex that shall be contained in bound constraint */
4690    SCIP_VAR*             boundvar,           /**< bound variable of @p v1 and @p v2 (or NULL if not existent) */
4691    SCIP_Bool             extend,             /**< should @p v1 and @p v2 be greedily extended to a clique of larger size */
4692    SCIP_CONS*            cons,               /**< bound constraint */
4693    SCIP_Real*            feas                /**< feasibility value of bound constraint */
4694    )
4695 {
4696    SCIP_NODEDATA* nodedata;
4697    SCIP_Bool addv2 = TRUE;
4698    SCIP_Real solval;
4699    SCIP_VAR* var;
4700    SCIP_Real coef = 0.0;
4701    int nsucc;
4702    int s;
4703 
4704    int* extensions = NULL;
4705    int nextensions = 0;
4706    int nextensionsnew;
4707    int* succ;
4708 
4709    assert( scip != NULL );
4710    assert( conflictgraph != NULL );
4711    assert( cons != NULL );
4712    assert( feas != NULL );
4713 
4714    *feas = 0.0;
4715 
4716    /* add index 'v1' to the clique */
4717    nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, v1);
4718    var = nodedata->var;
4719    assert( boundvar == NULL || SCIPvarCompare(boundvar, nodedata->ubboundvar) == 0 );
4720    solval = SCIPgetSolVal(scip, sol, var);
4721 
4722    /* if 'v1' and 'v2' have the same bound variable then the bound cut can be strengthened */
4723    if ( boundvar == NULL )
4724    {
4725       if ( SCIPisFeasPositive(scip, solval) )
4726       {
4727          SCIP_Real ub;
4728          ub = SCIPvarGetUbLocal(var);
4729          assert( SCIPisFeasPositive(scip, ub));
4730 
4731          if ( ! SCIPisInfinity(scip, ub) )
4732             coef = 1.0/ub;
4733       }
4734       else if ( SCIPisFeasNegative(scip, solval) )
4735       {
4736          SCIP_Real lb;
4737          lb = SCIPvarGetLbLocal(var);
4738          assert( SCIPisFeasNegative(scip, lb) );
4739          if ( ! SCIPisInfinity(scip, -lb) )
4740             coef = 1.0/lb;
4741       }
4742    }
4743    else if ( boundvar == nodedata->ubboundvar )
4744    {
4745       if ( SCIPisFeasPositive(scip, solval) )
4746       {
4747          SCIP_Real ub;
4748 
4749          ub = nodedata->ubboundcoef;
4750          assert( SCIPisFeasPositive(scip, ub) );
4751          if ( ! SCIPisInfinity(scip, ub) )
4752             coef = 1.0/ub;
4753       }
4754       else if ( SCIPisFeasNegative(scip, solval) )
4755       {
4756          SCIP_Real lb;
4757 
4758          lb = nodedata->lbboundcoef;
4759          assert( SCIPisFeasPositive(scip, lb) );
4760          if ( ! SCIPisInfinity(scip, lb) )
4761             coef = 1.0/lb;
4762       }
4763    }
4764 
4765    if ( ! SCIPisZero(scip, coef) )
4766    {
4767       *feas += coef * solval;
4768       SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) );
4769    }
4770 
4771    /* if clique shall be greedily extended to a clique of larger size */
4772    if ( extend )
4773    {
4774       /* get successors */
4775       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, v1);
4776       succ = SCIPdigraphGetSuccessors(conflictgraph, v1);
4777       assert( nsucc > 0 );
4778 
4779       /* allocate buffer array */
4780       SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) );
4781 
4782       /* get possible extensions for the clique cover */
4783       for (s = 0; s < nsucc; ++s)
4784          extensions[s] = succ[s];
4785       nextensions = nsucc;
4786    }
4787    else
4788       nextensions = 1;
4789 
4790    /* while there exist possible extensions for the clique cover */
4791    while ( nextensions > 0 )
4792    {
4793       SCIP_Real bestbigMval;
4794       SCIP_Real bigMval;
4795       int bestindex = -1;
4796       int ext;
4797 
4798       bestbigMval = -SCIPinfinity(scip);
4799 
4800       /* if v2 has not been added to clique already */
4801       if ( addv2 )
4802       {
4803          bestindex = v2;
4804          addv2 = FALSE;
4805       }
4806       else /* search for the extension with the largest absolute value of its LP relaxation solution value */
4807       {
4808          assert( extensions != NULL );
4809          for (s = 0; s < nextensions; ++s)
4810          {
4811             ext = extensions[s];
4812             bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraph, sol, ext);
4813             if ( SCIPisFeasLT(scip, bestbigMval, bigMval) )
4814             {
4815                bestbigMval = bigMval;
4816                bestindex = ext;
4817             }
4818          }
4819       }
4820       assert( bestindex != -1 );
4821 
4822       /* add bestindex variable to the constraint */
4823       nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, bestindex);
4824       var = nodedata->var;
4825       solval = SCIPgetSolVal(scip, sol, var);
4826       coef = 0.0;
4827       if ( boundvar == NULL )
4828       {
4829          if ( SCIPisFeasPositive(scip, solval) )
4830          {
4831             SCIP_Real ub;
4832             ub = SCIPvarGetUbLocal(var);
4833             assert( SCIPisFeasPositive(scip, ub));
4834 
4835             if ( ! SCIPisInfinity(scip, ub) )
4836                coef = 1.0/ub;
4837          }
4838          else if ( SCIPisFeasNegative(scip, solval) )
4839          {
4840             SCIP_Real lb;
4841             lb = SCIPvarGetLbLocal(var);
4842             assert( SCIPisFeasNegative(scip, lb) );
4843             if ( ! SCIPisInfinity(scip, -lb) )
4844                coef = 1.0/lb;
4845          }
4846       }
4847       else if ( boundvar == nodedata->ubboundvar )
4848       {
4849          if ( SCIPisFeasPositive(scip, solval) )
4850          {
4851             SCIP_Real ub;
4852 
4853             ub = nodedata->ubboundcoef;
4854             assert( SCIPisFeasPositive(scip, ub) );
4855             if ( ! SCIPisInfinity(scip, ub) )
4856                coef = 1.0/ub;
4857          }
4858          else if ( SCIPisFeasNegative(scip, solval) )
4859          {
4860             SCIP_Real lb;
4861 
4862             lb = nodedata->lbboundcoef;
4863             assert( SCIPisFeasPositive(scip, lb) );
4864             if ( ! SCIPisInfinity(scip, -lb) )
4865                coef = 1.0/lb;
4866          }
4867       }
4868       if ( ! SCIPisZero(scip, coef) )
4869       {
4870          *feas += coef * solval;
4871          SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) );
4872       }
4873 
4874       if ( extend )
4875       {
4876          assert( extensions != NULL );
4877          /* compute new 'extensions' array */
4878          nextensionsnew = 0;
4879          for (s = 0; s < nextensions; ++s)
4880          {
4881             if ( s != bestindex && isConnectedSOS1(NULL, conflictgraph, bestindex, extensions[s]) )
4882                extensions[nextensionsnew++] = extensions[s];
4883          }
4884          nextensions = nextensionsnew;
4885       }
4886       else
4887          nextensions = 0;
4888    }
4889 
4890    /* free buffer array */
4891    if ( extend )
4892       SCIPfreeBufferArray(scip, &extensions);
4893 
4894    /* subtract rhs of constraint from feasibility value or add bound variable if existent */
4895    if ( boundvar == NULL )
4896       *feas -= 1.0;
4897    else
4898    {
4899       SCIP_CALL( SCIPaddCoefLinear(scip, cons, boundvar, -1.0) );
4900       *feas -= SCIPgetSolVal(scip, sol, boundvar);
4901    }
4902 
4903    return SCIP_OKAY;
4904 }
4905 
4906 
4907 /** tries to add feasible complementarity constraints to a given child branching node.
4908  *
4909  *  @note In this function the conflict graph is updated to the conflict graph of the considered child branching node.
4910  */
4911 static
addBranchingComplementaritiesSOS1(SCIP * scip,SCIP_NODE * node,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_DIGRAPH * localconflicts,SCIP_SOL * sol,int nsos1vars,SCIP_Bool * verticesarefixed,int * fixingsnode1,int nfixingsnode1,int * fixingsnode2,int nfixingsnode2,int * naddedconss,SCIP_Bool onlyviolsos1)4912 SCIP_RETCODE addBranchingComplementaritiesSOS1(
4913    SCIP*                 scip,               /**< SCIP pointer */
4914    SCIP_NODE*            node,               /**< branching node */
4915    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
4916    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph of the current node */
4917    SCIP_DIGRAPH*         localconflicts,     /**< local conflicts (updates to local conflicts of child node) */
4918    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
4919    int                   nsos1vars,          /**< number of SOS1 variables */
4920    SCIP_Bool*            verticesarefixed,   /**< vector that indicates which variables are currently fixed to zerox */
4921    int*                  fixingsnode1,       /**< vertices of variables that will be fixed to zero for the branching node in the input of this function */
4922    int                   nfixingsnode1,      /**< number of entries of array nfixingsnode1 */
4923    int*                  fixingsnode2,       /**< vertices of variables that will be fixed to zero for the other branching node */
4924    int                   nfixingsnode2,      /**< number of entries of array nfixingsnode2 */
4925    int*                  naddedconss,        /**< pointer to store the number of added SOS1 constraints */
4926    SCIP_Bool             onlyviolsos1        /**< should only SOS1 constraints be added that are violated by the LP solution */
4927    )
4928 {
4929    assert( scip != NULL );
4930    assert( node != NULL );
4931    assert( conshdlrdata != NULL );
4932    assert( conflictgraph != NULL );
4933    assert( verticesarefixed != NULL );
4934    assert( fixingsnode1 != NULL );
4935    assert( fixingsnode2 != NULL );
4936    assert( naddedconss != NULL );
4937 
4938    *naddedconss = 0;
4939 
4940    if ( nfixingsnode2 > 1 )
4941    {
4942       int* fixingsnode21; /* first partition of fixingsnode2 */
4943       int* fixingsnode22; /* second partition of fixingsnode2 */
4944       int nfixingsnode21;
4945       int nfixingsnode22;
4946 
4947       int* coverarray; /* vertices, not in fixingsnode1 that cover all the vertices in array fixingsnode22 */
4948       int ncoverarray;
4949 
4950       SCIP_Bool* mark;
4951       int* succarray;
4952       int nsuccarray;
4953       int* succ;
4954       int nsucc;
4955 
4956       int i;
4957       int s;
4958 
4959       /* allocate buffer arrays */
4960       SCIP_CALL( SCIPallocBufferArray(scip, &succarray, nsos1vars) );
4961       SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) );
4962       SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode21, nfixingsnode2) );
4963       SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode22, nfixingsnode2) );
4964 
4965       /* mark all the unfixed vertices with FALSE */
4966       for (i = 0; i < nsos1vars; ++i)
4967          mark[i] = (verticesarefixed[i]);
4968 
4969       /* mark all the vertices that are in the set fixingsnode1 */
4970       for (i = 0; i < nfixingsnode1; ++i)
4971       {
4972          assert( nfixingsnode1 <= 1 || (fixingsnode1[nfixingsnode1 - 1] > fixingsnode1[nfixingsnode1 - 2]) ); /* test: vertices are sorted */
4973          mark[fixingsnode1[i]] = TRUE;
4974       }
4975 
4976       /* mark all the vertices that are in the set fixingsnode2 */
4977       for (i = 0; i < nfixingsnode2; ++i)
4978       {
4979          assert( nfixingsnode2 <= 1 || (fixingsnode2[nfixingsnode2 - 1] > fixingsnode2[nfixingsnode2 - 2]) ); /* test: vertices are sorted */
4980          mark[fixingsnode2[i]] = TRUE;
4981       }
4982 
4983       /* compute the set of vertices that have a neighbor in the set fixingsnode2, but are not in the set fixingsnode1 or fixingsnode2 and are not already fixed */
4984       nsuccarray = 0;
4985       for (i = 0; i < nfixingsnode2; ++i)
4986       {
4987          nsucc = SCIPdigraphGetNSuccessors(conflictgraph, fixingsnode2[i]);
4988          succ = SCIPdigraphGetSuccessors(conflictgraph, fixingsnode2[i]);
4989 
4990          for (s = 0; s < nsucc; ++s)
4991          {
4992             int succnode = succ[s];
4993 
4994             if ( ! mark[succnode] )
4995             {
4996                mark[succnode] = TRUE;
4997                succarray[nsuccarray++] = succnode;
4998             }
4999          }
5000       }
5001 
5002       /* allocate buffer array */
5003       SCIP_CALL( SCIPallocBufferArray(scip, &coverarray, nsos1vars) );
5004 
5005       /* mark all the vertices with FALSE */
5006       for (i = 0; i < nsos1vars; ++i)
5007          mark[i] = FALSE;
5008 
5009       /* mark all the vertices that are in the set fixingsnode2 */
5010       for (i = 0; i < nfixingsnode2; ++i)
5011          mark[fixingsnode2[i]] = TRUE;
5012 
5013       /* for every node in succarray */
5014       for (i = 0; i < nsuccarray; ++i)
5015       {
5016          SCIP_Real solval1;
5017          SCIP_VAR* var1;
5018          int vertex1;
5019          int j;
5020 
5021          vertex1 = succarray[i];
5022          var1 = SCIPnodeGetVarSOS1(conflictgraph, vertex1);
5023          solval1 = SCIPgetSolVal(scip, sol, var1);
5024 
5025          /* we only add complementarity constraints if they are violated by the current LP solution */
5026          if ( ! onlyviolsos1 || ! SCIPisFeasZero(scip, solval1) )
5027          {
5028             /* compute first partition of fixingsnode2 that is the intersection of the neighbors of 'vertex1' with the set fixingsnode2 */
5029             nsucc = SCIPdigraphGetNSuccessors(conflictgraph, vertex1);
5030             succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1);
5031             nfixingsnode21 = 0;
5032 
5033             for (s = 0; s < nsucc; ++s)
5034             {
5035                if ( mark[succ[s]] )
5036                {
5037                   fixingsnode21[nfixingsnode21++] = succ[s];
5038                   assert( nfixingsnode21 == 1 || (fixingsnode21[nfixingsnode21 - 1] > fixingsnode21[nfixingsnode21 - 2]) ); /* test: successor vertices are sorted */
5039                }
5040             }
5041 
5042             /* if variable can be fixed to zero */
5043             if ( nfixingsnode21 == nfixingsnode2 )
5044             {
5045                SCIP_Bool infeasible;
5046 
5047                SCIP_CALL( fixVariableZeroNode(scip, var1, node, &infeasible) );
5048                assert( ! infeasible );
5049                continue;
5050             }
5051 
5052             /* compute second partition of fixingsnode2 (that is fixingsnode2 \setminus fixingsnode21 ) */
5053             SCIP_CALL( SCIPcomputeArraysSetminus(fixingsnode2, nfixingsnode2, fixingsnode21, nfixingsnode21, fixingsnode22, &nfixingsnode22) );
5054             assert ( nfixingsnode22 + nfixingsnode21 == nfixingsnode2 );
5055 
5056             /* compute cover set (that are all the vertices not in fixingsnode1 and fixingsnode21, whose neighborhood covers all the vertices of fixingsnode22) */
5057             SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, -1, fixingsnode22, nfixingsnode22, coverarray, &ncoverarray) );
5058             SCIP_CALL( SCIPcomputeArraysSetminus(coverarray, ncoverarray, fixingsnode1, nfixingsnode1, coverarray, &ncoverarray) );
5059             SCIP_CALL( SCIPcomputeArraysSetminus(coverarray, ncoverarray, fixingsnode21, nfixingsnode21, coverarray, &ncoverarray) );
5060 
5061             for (j = 0; j < ncoverarray; ++j)
5062             {
5063                int vertex2;
5064 
5065                vertex2 = coverarray[j];
5066                assert( vertex2 != vertex1 );
5067 
5068                /* prevent double enumeration */
5069                if ( vertex2 < vertex1 )
5070                {
5071                   SCIP_VAR* var2;
5072                   SCIP_Real solval2;
5073 
5074                   var2 = SCIPnodeGetVarSOS1(conflictgraph, vertex2);
5075                   solval2 = SCIPgetSolVal(scip, sol, var2);
5076 
5077                   if ( onlyviolsos1 && ( SCIPisFeasZero(scip, solval1) || SCIPisFeasZero(scip, solval2) ) )
5078                      continue;
5079 
5080                   if ( ! isConnectedSOS1(NULL, conflictgraph, vertex1, vertex2) )
5081                   {
5082                      char name[SCIP_MAXSTRLEN];
5083                      SCIP_CONS* conssos1 = NULL;
5084                      SCIP_Bool takebound = FALSE;
5085                      SCIP_Real feas;
5086 
5087                      SCIP_NODEDATA* nodedata;
5088                      SCIP_Real lbboundcoef1;
5089                      SCIP_Real lbboundcoef2;
5090                      SCIP_Real ubboundcoef1;
5091                      SCIP_Real ubboundcoef2;
5092                      SCIP_VAR* boundvar1;
5093                      SCIP_VAR* boundvar2;
5094 
5095                      /* get bound variables if available */
5096                      nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex1);
5097                      assert( nodedata != NULL );
5098                      boundvar1 = nodedata->ubboundvar;
5099                      lbboundcoef1 = nodedata->lbboundcoef;
5100                      ubboundcoef1 = nodedata->ubboundcoef;
5101                      nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex2);
5102                      assert( nodedata != NULL );
5103                      boundvar2 = nodedata->ubboundvar;
5104                      lbboundcoef2 = nodedata->lbboundcoef;
5105                      ubboundcoef2 = nodedata->ubboundcoef;
5106 
5107                      if ( boundvar1 != NULL && boundvar2 != NULL && SCIPvarCompare(boundvar1, boundvar2) == 0 )
5108                         takebound = TRUE;
5109 
5110                      /* add new arc to local conflicts in order to generate tighter bound inequalities */
5111                      if ( conshdlrdata->addextendedbds )
5112                      {
5113                         if ( localconflicts == NULL )
5114                         {
5115                            SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, nsos1vars) );
5116                            localconflicts = conshdlrdata->localconflicts;
5117                         }
5118                         SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex1, vertex2, NULL) );
5119                         SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex2, vertex1, NULL) );
5120                         SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex1, vertex2, NULL) );
5121                         SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex2, vertex1, NULL) );
5122 
5123                         /* can sort successors in place - do not use arcdata */
5124                         SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex1), SCIPdigraphGetNSuccessors(localconflicts, vertex1));
5125                         SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex2), SCIPdigraphGetNSuccessors(localconflicts, vertex2));
5126                         SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex1), SCIPdigraphGetNSuccessors(conflictgraph, vertex1));
5127                         SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex2), SCIPdigraphGetNSuccessors(conflictgraph, vertex2));
5128 
5129                         /* mark conflictgraph as not local such that the new arcs are deleted after currents node processing */
5130                         conshdlrdata->isconflocal = TRUE;
5131                      }
5132 
5133                      /* measure feasibility of complementarity between var1 and var2 */
5134                      if ( ! takebound )
5135                      {
5136                         feas = -1.0;
5137                         if ( SCIPisFeasPositive(scip, solval1) )
5138                         {
5139                            assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var1)));
5140                            if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var1)) )
5141                               feas += solval1/SCIPvarGetUbLocal(var1);
5142                         }
5143                         else if ( SCIPisFeasNegative(scip, solval1) )
5144                         {
5145                            assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var1)));
5146                            if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var1)) )
5147                               feas += solval1/SCIPvarGetLbLocal(var1);
5148                         }
5149 
5150                         if ( SCIPisFeasPositive(scip, solval2) )
5151                         {
5152                            assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var2)));
5153                            if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) )
5154                               feas += solval2/SCIPvarGetUbLocal(var2);
5155                         }
5156                         else if ( SCIPisFeasNegative(scip, solval2) )
5157                         {
5158                            assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var2)));
5159                            if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) )
5160                               feas += solval2/SCIPvarGetLbLocal(var2);
5161                         }
5162                      }
5163                      else
5164                      {
5165                         feas = -SCIPgetSolVal(scip, sol, boundvar1);
5166                         if ( SCIPisFeasPositive(scip, solval1) )
5167                         {
5168                            assert( SCIPisFeasPositive(scip, ubboundcoef1));
5169                            if ( ! SCIPisInfinity(scip, ubboundcoef1) )
5170                               feas += solval1/ubboundcoef1;
5171                         }
5172                         else if ( SCIPisFeasNegative(scip, solval1) )
5173                         {
5174                            assert( SCIPisFeasPositive(scip, lbboundcoef1));
5175                            if ( ! SCIPisInfinity(scip, -lbboundcoef1) )
5176                               feas += solval1/lbboundcoef1;
5177                         }
5178 
5179                         if ( SCIPisFeasPositive(scip, solval2) )
5180                         {
5181                            assert( SCIPisFeasPositive(scip, ubboundcoef2));
5182                            if ( ! SCIPisInfinity(scip, ubboundcoef2) )
5183                               feas += solval2/ubboundcoef2;
5184                         }
5185                         else if ( SCIPisFeasNegative(scip, solval2) )
5186                         {
5187                            assert( SCIPisFeasPositive(scip, lbboundcoef2));
5188                            if ( ! SCIPisInfinity(scip, -lbboundcoef2) )
5189                               feas += solval2/lbboundcoef2;
5190                         }
5191                         assert( ! SCIPisFeasNegative(scip, solval2) );
5192                      }
5193 
5194                      if ( SCIPisGT(scip, feas, conshdlrdata->addcompsfeas) )
5195                      {
5196                         /* create SOS1 constraint */
5197                         (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sos1_branchnode_%" SCIP_LONGINT_FORMAT "_no_%i", SCIPnodeGetNumber(node), *naddedconss);
5198                         SCIP_CALL( SCIPcreateConsSOS1(scip, &conssos1, name, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE,
5199                               TRUE, FALSE, FALSE, FALSE) );
5200 
5201                         /* add variables to SOS1 constraint */
5202                         SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var1, 1.0) );
5203                         SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var2, 2.0) );
5204 
5205                         /* add SOS1 constraint to the branching node */
5206                         SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) );
5207                         ++(*naddedconss);
5208 
5209                         /* release constraint */
5210                         SCIP_CALL( SCIPreleaseCons(scip, &conssos1) );
5211                      }
5212 
5213                      /* add bound inequality*/
5214                      if ( ! SCIPisFeasZero(scip, solval1) && ! SCIPisFeasZero(scip, solval2) )
5215                      {
5216                         /* possibly create linear constraint of the form x_i/u_i + x_j/u_j <= t if a bound variable t with x_i <= u_i * t and x_j <= u_j * t exists.
5217                          * Otherwise try to create a constraint of the form x_i/u_i + x_j/u_j <= 1. Try the same for the lower bounds. */
5218                         (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "boundcons_branchnode_%" SCIP_LONGINT_FORMAT "_no_%i", SCIPnodeGetNumber(node), *naddedconss);
5219                         if ( takebound )
5220                         {
5221                            /* create constraint with right hand side = 0.0 */
5222                            SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 0.0, TRUE, FALSE, TRUE, FALSE, FALSE,
5223                                  TRUE, FALSE, FALSE, FALSE, FALSE) );
5224 
5225                            /* add variables */
5226                            SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, sol, vertex1, vertex2, boundvar1, conshdlrdata->addextendedbds, conssos1, &feas) );
5227                         }
5228                         else
5229                         {
5230                            /* create constraint with right hand side = 1.0 */
5231                            SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 1.0, TRUE, FALSE, TRUE, FALSE, FALSE,
5232                                  TRUE, FALSE, FALSE, FALSE, FALSE) );
5233 
5234                            /* add variables */
5235                            SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, sol, vertex1, vertex2, NULL, conshdlrdata->addextendedbds, conssos1, &feas) );
5236                         }
5237 
5238                         /* add linear constraint to the branching node if usefull */
5239                         if ( SCIPisGT(scip, feas, conshdlrdata->addbdsfeas ) )
5240                         {
5241                            SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) );
5242                            ++(*naddedconss);
5243                         }
5244 
5245                         /* release constraint */
5246                         SCIP_CALL( SCIPreleaseCons(scip, &conssos1) );
5247                      }
5248 
5249                      /* break if number of added constraints exceeds a predefined value */
5250                      if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps )
5251                         break;
5252                   }
5253                }
5254             }
5255          }
5256 
5257          /* break if number of added constraints exceeds a predefined value */
5258          if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps )
5259             break;
5260       }
5261 
5262       /* free buffer array */
5263       SCIPfreeBufferArray(scip, &coverarray);
5264       SCIPfreeBufferArray(scip, &fixingsnode22);
5265       SCIPfreeBufferArray(scip, &fixingsnode21);
5266       SCIPfreeBufferArray(scip, &mark);
5267       SCIPfreeBufferArray(scip, &succarray);
5268    }
5269 
5270    return SCIP_OKAY;
5271 }
5272 
5273 
5274 /** resets local conflict graph to the conflict graph of the root node */
5275 static
resetConflictgraphSOS1(SCIP_DIGRAPH * conflictgraph,SCIP_DIGRAPH * localconflicts,int nsos1vars)5276 SCIP_RETCODE resetConflictgraphSOS1(
5277    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph of root node */
5278    SCIP_DIGRAPH*         localconflicts,     /**< local conflicts that should be removed from conflict graph */
5279    int                   nsos1vars           /**< number of SOS1 variables */
5280    )
5281 {
5282    int j;
5283 
5284    for (j = 0; j < nsos1vars; ++j)
5285    {
5286       int nsuccloc;
5287 
5288       nsuccloc = SCIPdigraphGetNSuccessors(localconflicts, j);
5289       if ( nsuccloc > 0 )
5290       {
5291          int* succloc;
5292          int* succ;
5293          int nsucc;
5294          int k = 0;
5295 
5296          succloc = SCIPdigraphGetSuccessors(localconflicts, j);
5297          succ = SCIPdigraphGetSuccessors(conflictgraph, j);
5298          nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
5299 
5300          /* reset number of successors */
5301          SCIP_CALL( SCIPcomputeArraysSetminus(succ, nsucc, succloc, nsuccloc, succ, &k) );
5302          SCIP_CALL( SCIPdigraphSetNSuccessors(conflictgraph, j, k) );
5303          SCIP_CALL( SCIPdigraphSetNSuccessors(localconflicts, j, 0) );
5304       }
5305    }
5306 
5307    return SCIP_OKAY;
5308 }
5309 
5310 
5311 /** Conflict graph enforcement method
5312  *
5313  *  The conflict graph can be enforced by different branching rules:
5314  *
5315  *  - Branch on the neighborhood of a single variable @p i, i.e., in one branch \f$x_i\f$ is fixed to zero and in the
5316  *    other its neighbors from the conflict graph.
5317  *
5318  *  - Branch on complete bipartite subgraphs of the conflict graph, i.e., in one branch fix the variables from the first
5319  *    bipartite partition and the variables from the second bipartite partition in the other.
5320  *
5321  *  - In addition to variable domain fixings, it is sometimes also possible to add new SOS1 constraints to the branching
5322  *    nodes. This results in a nonstatic conflict graph, which may change dynamically with every branching node.
5323  *
5324  *  We make use of different selection rules that define on which system of SOS1 variables to branch next:
5325  *
5326  *  - Most infeasible branching: Branch on the system of SOS1 variables with largest violation.
5327  *
5328  *  - Strong branching: Here, the LP-relaxation is partially solved for each branching decision among a candidate list.
5329  *    Then the decision with best progress is chosen.
5330  */
5331 static
enforceConflictgraph(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONSHDLR * conshdlr,int nconss,SCIP_CONS ** conss,SCIP_SOL * sol,SCIP_RESULT * result)5332 SCIP_RETCODE enforceConflictgraph(
5333    SCIP*                 scip,               /**< SCIP pointer */
5334    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
5335    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5336    int                   nconss,             /**< number of constraints */
5337    SCIP_CONS**           conss,              /**< SOS1 constraints */
5338    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
5339    SCIP_RESULT*          result              /**< result */
5340    )
5341 {
5342    SCIP_DIGRAPH* conflictgraph;
5343    int nsos1vars;
5344 
5345    SCIP_Bool* verticesarefixed = NULL;
5346    int* fixingsnode1 = NULL;
5347    int* fixingsnode2 = NULL;
5348    int nfixingsnode1;
5349    int nfixingsnode2;
5350 
5351    SCIP_Real bestobjval1 = -SCIPinfinity(scip);
5352    SCIP_Real bestobjval2 = -SCIPinfinity(scip);
5353    SCIP_Real lpobjval = -SCIPinfinity(scip);
5354 
5355    SCIP_Bool infeasible;
5356    SCIP_Bool bipbranch = FALSE;
5357    int nstrongrounds;
5358 
5359    int branchvertex;
5360    SCIP_NODE* node1;
5361    SCIP_NODE* node2;
5362    SCIP_Real nodeselest;
5363    SCIP_Real objest;
5364 
5365    int i;
5366    int j;
5367    int c;
5368 
5369    assert( scip != NULL );
5370    assert( conshdlrdata != NULL );
5371    assert( conshdlr != NULL );
5372    assert( conss != NULL );
5373    assert( result != NULL );
5374 
5375    SCIPdebugMsg(scip, "Enforcing SOS1 conflict graph <%s>.\n", SCIPconshdlrGetName(conshdlr) );
5376    *result = SCIP_DIDNOTRUN;
5377 
5378    /* get number of SOS1 variables */
5379    nsos1vars = conshdlrdata->nsos1vars;
5380 
5381    /* exit for trivial cases */
5382    if ( nsos1vars == 0 || nconss == 0 )
5383    {
5384       *result = SCIP_FEASIBLE;
5385       return SCIP_OKAY;
5386    }
5387 
5388    /* get conflict graph */
5389    conflictgraph = conshdlrdata->conflictgraph;
5390    assert( ! conshdlrdata->isconflocal ); /* conflictgraph should be the one of the root node */
5391 
5392    /* check each constraint and update conflict graph if necessary */
5393    for (c = 0; c < nconss; ++c)
5394    {
5395       SCIP_CONSDATA* consdata;
5396       SCIP_CONS* cons;
5397       SCIP_Bool cutoff;
5398       int ngen = 0;
5399 
5400       cons = conss[c];
5401       assert( cons != NULL );
5402       consdata = SCIPconsGetData(cons);
5403       assert( consdata != NULL );
5404 
5405       /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
5406       if ( consdata->nvars < 2 )
5407          continue;
5408 
5409       /* first perform propagation (it might happen that standard propagation is turned off) */
5410       SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
5411       SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen);
5412       if ( cutoff )
5413       {
5414          *result = SCIP_CUTOFF;
5415 	 break;
5416       }
5417       if ( ngen > 0 )
5418       {
5419          *result = SCIP_REDUCEDDOM;
5420 	 break;
5421       }
5422       assert( ngen == 0 );
5423 
5424       /* add local conflicts to conflict graph and save them in 'localconflicts' */
5425       if ( consdata->local )
5426       {
5427          SCIP_VAR** vars;
5428          int nvars;
5429          int indi;
5430          int indj;
5431 
5432          if ( conshdlrdata->localconflicts == NULL )
5433          {
5434             SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, nsos1vars) );
5435          }
5436 
5437          vars = consdata->vars;
5438          nvars = consdata->nvars;
5439          for (i = 0; i < nvars-1; ++i)
5440          {
5441             SCIP_VAR* var;
5442 
5443             var = vars[i];
5444             indi = varGetNodeSOS1(conshdlrdata, var);
5445 
5446             if( indi == -1 )
5447                return SCIP_INVALIDDATA;
5448 
5449             if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) )
5450             {
5451                for (j = i+1; j < nvars; ++j)
5452                {
5453                   var = vars[j];
5454                   indj = varGetNodeSOS1(conshdlrdata, var);
5455 
5456                   if( indj == -1 )
5457                      return SCIP_INVALIDDATA;
5458 
5459                   if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) )
5460                   {
5461                      if ( ! isConnectedSOS1(NULL, conflictgraph, indi, indj) )
5462                      {
5463                         SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indi, indj, NULL) );
5464                         SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indj, indi, NULL) );
5465 
5466                         SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indi, indj, NULL) );
5467                         SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indj, indi, NULL) );
5468 
5469                         conshdlrdata->isconflocal = TRUE;
5470                      }
5471                   }
5472                }
5473             }
5474          }
5475       }
5476    }
5477 
5478    /* sort successor list of conflict graph if necessary */
5479    if ( conshdlrdata->isconflocal )
5480    {
5481       for (j = 0; j < nsos1vars; ++j)
5482       {
5483          int nsuccloc;
5484 
5485          nsuccloc = SCIPdigraphGetNSuccessors(conshdlrdata->localconflicts, j);
5486          if ( nsuccloc > 0 )
5487          {
5488             SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, j), SCIPdigraphGetNSuccessors(conflictgraph, j));
5489             SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->localconflicts, j), nsuccloc);
5490          }
5491       }
5492    }
5493 
5494    if ( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM )
5495    {
5496       /* remove local conflicts from conflict graph */
5497       if ( conshdlrdata->isconflocal )
5498       {
5499 	 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5500 	 conshdlrdata->isconflocal = FALSE;
5501       }
5502       return SCIP_OKAY;
5503    }
5504 
5505    /* detect fixed variables */
5506    SCIP_CALL( SCIPallocBufferArray(scip, &verticesarefixed, nsos1vars) );
5507    for (j = 0; j < nsos1vars; ++j)
5508    {
5509       SCIP_VAR* var;
5510       SCIP_Real ub;
5511       SCIP_Real lb;
5512 
5513       var = SCIPnodeGetVarSOS1(conflictgraph, j);
5514       ub = SCIPvarGetUbLocal(var);
5515       lb = SCIPvarGetLbLocal(var);
5516       if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) )
5517          verticesarefixed[j] = TRUE;
5518       else
5519          verticesarefixed[j] = FALSE;
5520    }
5521 
5522    /* should bipartite branching be used? */
5523    if ( conshdlrdata->branchingrule == 'b' )
5524       bipbranch = TRUE;
5525 
5526    /* determine number of strong branching iterations */
5527    if ( conshdlrdata->nstrongrounds >= 0 )
5528       nstrongrounds = MIN(conshdlrdata->nstrongrounds, nsos1vars);
5529    else
5530    {
5531       /* determine number depending on depth, based on heuristical considerations */
5532       if ( SCIPgetDepth(scip) <= 10 )
5533          nstrongrounds = MAX(10, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 1.0)));/*lint !e666*/
5534       else if ( SCIPgetDepth(scip) <= 20 )
5535          nstrongrounds = MAX(5, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 0.7)));/*lint !e666*/
5536       else
5537          nstrongrounds = 0;
5538       nstrongrounds = MIN(nsos1vars, nstrongrounds);
5539    }
5540 
5541    /* allocate buffer arrays */
5542    SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode1, nsos1vars) );
5543    if ( bipbranch )
5544       SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, nsos1vars) );
5545    else
5546       SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, 1) );
5547 
5548    /* if strongbranching is turned off: use most infeasible branching */
5549    if ( nstrongrounds == 0 )
5550    {
5551       SCIP_Bool relsolfeas;
5552 
5553       /* get branching vertex using most infeasible branching */
5554       SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, verticesarefixed,
5555             bipbranch, fixingsnode1, fixingsnode2, NULL, &branchvertex, &relsolfeas) );
5556 
5557       /* if LP relaxation solution is feasible */
5558       if ( relsolfeas )
5559       {
5560          SCIPdebugMsg(scip, "all the SOS1 constraints are feasible.\n");
5561 
5562          /* update result */
5563          *result = SCIP_FEASIBLE;
5564 
5565          /* remove local conflicts from conflict graph */
5566          if ( conshdlrdata->isconflocal )
5567          {
5568             SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5569             conshdlrdata->isconflocal = FALSE;
5570          }
5571 
5572          /* free memory */
5573          SCIPfreeBufferArrayNull(scip, &fixingsnode2);
5574          SCIPfreeBufferArrayNull(scip, &fixingsnode1);
5575          SCIPfreeBufferArrayNull(scip, &verticesarefixed);
5576 
5577          return SCIP_OKAY;
5578       }
5579    }
5580    else
5581    {
5582       /* get branching vertex using strong branching */
5583       SCIP_CALL( getBranchingDecisionStrongbranchSOS1(scip, conshdlrdata, conflictgraph, sol, nsos1vars, lpobjval,
5584             bipbranch, nstrongrounds, verticesarefixed, fixingsnode1, fixingsnode2, &branchvertex, &bestobjval1,
5585             &bestobjval2, result) );
5586 
5587       if ( *result == SCIP_CUTOFF || *result == SCIP_FEASIBLE || *result == SCIP_REDUCEDDOM )
5588       {
5589          /* remove local conflicts from conflict graph */
5590          if ( conshdlrdata->isconflocal )
5591          {
5592             SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5593             conshdlrdata->isconflocal = FALSE;
5594          }
5595 
5596          /* free memory */
5597          SCIPfreeBufferArrayNull(scip, &fixingsnode2);
5598          SCIPfreeBufferArrayNull(scip, &fixingsnode1);
5599          SCIPfreeBufferArrayNull(scip, &verticesarefixed);
5600 
5601          return SCIP_OKAY;
5602       }
5603    }
5604 
5605    /* if we should leave branching decision to branching rules */
5606    if ( ! conshdlrdata->branchsos )
5607    {
5608       /* remove local conflicts from conflict graph */
5609       if ( conshdlrdata->isconflocal )
5610       {
5611 	 SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5612 	 conshdlrdata->isconflocal = FALSE;
5613       }
5614 
5615       /* free memory */
5616       SCIPfreeBufferArrayNull(scip, &fixingsnode2);
5617       SCIPfreeBufferArrayNull(scip, &fixingsnode1);
5618       SCIPfreeBufferArrayNull(scip, &verticesarefixed);
5619 
5620       assert( branchvertex >= 0 && branchvertex < nsos1vars );
5621       if ( SCIPvarIsBinary(SCIPnodeGetVarSOS1(conflictgraph, branchvertex)) )
5622       {
5623          *result = SCIP_INFEASIBLE;
5624          return SCIP_OKAY;
5625       }
5626       else
5627       {
5628          SCIPerrorMessage("Incompatible parameter setting: branchsos can only be set to false if all SOS1 variables are binary.\n");
5629          return SCIP_PARAMETERWRONGVAL;
5630       }
5631    }
5632 
5633    /* create branching nodes */
5634 
5635    /* get vertices of variables that will be fixed to zero for each node */
5636    assert( branchvertex >= 0 && branchvertex < nsos1vars );
5637    assert( ! verticesarefixed[branchvertex] );
5638    SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, sol, verticesarefixed, bipbranch, branchvertex,
5639          fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
5640 
5641    /* calculate node selection and objective estimate for node 1 */
5642    nodeselest = 0.0;
5643    objest = SCIPgetLocalTransEstimate(scip);
5644    for (j = 0; j < nfixingsnode1; ++j)
5645    {
5646       SCIP_VAR* var;
5647 
5648       var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]);
5649       objest += SCIPcalcChildEstimateIncrease(scip, var, SCIPgetSolVal(scip, sol, var), 0.0);
5650       nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0);
5651    }
5652    assert( objest >= SCIPgetLocalTransEstimate(scip) );
5653 
5654    /* create node 1 */
5655    SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
5656 
5657    /* fix variables for the first node */
5658    if ( conshdlrdata->fixnonzero && nfixingsnode2 == 1 )
5659    {
5660       SCIP_VAR* var;
5661       SCIP_Real lb;
5662       SCIP_Real ub;
5663 
5664       var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[0]);
5665       lb = SCIPvarGetLbLocal(var);
5666       ub = SCIPvarGetUbLocal(var);
5667 
5668       if ( SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR )
5669       {
5670          if ( SCIPisZero(scip, lb) )
5671          {
5672             /* fix variable to some very small, but positive number or to 1.0 if variable is integral */
5673             if (SCIPvarIsIntegral(var) )
5674             {
5675                SCIP_CALL( SCIPchgVarLbNode(scip, node1, var, 1.0) );
5676             }
5677             else
5678             {
5679                SCIP_CALL( SCIPchgVarLbNode(scip, node1, var, 1.5 * SCIPfeastol(scip)) );
5680             }
5681          }
5682          else if ( SCIPisZero(scip, ub) )
5683          {
5684             if (SCIPvarIsIntegral(var) )
5685             {
5686                /* fix variable to some negative number with small absolute value to -1.0 if variable is integral */
5687                SCIP_CALL( SCIPchgVarUbNode(scip, node1, var, -1.0) );
5688             }
5689             else
5690             {
5691                /* fix variable to some negative number with small absolute value to -1.0 if variable is integral */
5692                SCIP_CALL( SCIPchgVarUbNode(scip, node1, var, -1.5 * SCIPfeastol(scip)) );
5693             }
5694          }
5695       }
5696    }
5697 
5698    for (j = 0; j < nfixingsnode1; ++j)
5699    {
5700       /* fix variable to zero */
5701       SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]), node1, &infeasible) );
5702       assert( ! infeasible );
5703    }
5704 
5705    /* calculate node selection and objective estimate for node 2 */
5706    nodeselest = 0.0;
5707    objest = SCIPgetLocalTransEstimate(scip);
5708    for (j = 0; j < nfixingsnode2; ++j)
5709    {
5710       SCIP_VAR* var;
5711 
5712       var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]);
5713       objest += SCIPcalcChildEstimateIncrease(scip, var, SCIPgetSolVal(scip, sol, var), 0.0);
5714       nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0);
5715    }
5716    assert( objest >= SCIPgetLocalTransEstimate(scip) );
5717 
5718    /* create node 2 */
5719    SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
5720 
5721    /* fix variables to zero */
5722    for (j = 0; j < nfixingsnode2; ++j)
5723    {
5724       SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]), node2, &infeasible) );
5725       assert( ! infeasible );
5726    }
5727 
5728    /* add complementarity constraints to the branching nodes */
5729    if ( conshdlrdata->addcomps && ( conshdlrdata->addcompsdepth == -1 || conshdlrdata->addcompsdepth >= SCIPgetDepth(scip) ) )
5730    {
5731       int naddedconss;
5732 
5733       assert( ! conshdlrdata->fixnonzero );
5734 
5735       /* add complementarity constraints to the left branching node */
5736       SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node1, conshdlrdata, conflictgraph, conshdlrdata->localconflicts, sol,
5737                nsos1vars, verticesarefixed, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2, &naddedconss, TRUE) );
5738 
5739       if ( naddedconss == 0 )
5740       {
5741          /* add complementarity constraints to the right branching node */
5742          SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node2, conshdlrdata, conflictgraph, conshdlrdata->localconflicts, sol,
5743                nsos1vars, verticesarefixed, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1, &naddedconss, TRUE) );
5744       }
5745    }
5746 
5747    /* sets node's lower bound to the best known value */
5748    if ( nstrongrounds > 0 )
5749    {
5750       SCIP_CALL( SCIPupdateNodeLowerbound(scip, node1, MAX(lpobjval, bestobjval1) ) );
5751       SCIP_CALL( SCIPupdateNodeLowerbound(scip, node2, MAX(lpobjval, bestobjval2) ) );
5752    }
5753 
5754    /* remove local conflicts from conflict graph */
5755    if ( conshdlrdata->isconflocal )
5756    {
5757       SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5758       conshdlrdata->isconflocal = FALSE;
5759    }
5760 
5761    /* free buffer arrays */
5762    SCIPfreeBufferArrayNull(scip, &fixingsnode2);
5763    SCIPfreeBufferArrayNull(scip, &fixingsnode1);
5764    SCIPfreeBufferArrayNull(scip, &verticesarefixed );
5765    *result = SCIP_BRANCHED;
5766 
5767    return SCIP_OKAY;
5768 }
5769 
5770 
5771 /** SOS1 branching enforcement method
5772  *
5773  *  We check whether the current solution is feasible, i.e., contains at most one nonzero
5774  *  variable. If not, we branch along the lines indicated by Beale and Tomlin:
5775  *
5776  *  We first compute \f$W = \sum_{j=1}^n |x_i|\f$ and \f$w = \sum_{j=1}^n j\, |x_i|\f$. Then we
5777  *  search for the index \f$k\f$ that satisfies
5778  *  \f[
5779  *        k \leq \frac{w}{W} < k+1.
5780  *  \f]
5781  *  The branches are then
5782  *  \f[
5783  *        x_1 = 0, \ldots, x_k = 0 \qquad \mbox{and}\qquad x_{k+1} = 0, \ldots, x_n = 0.
5784  *  \f]
5785  *
5786  *  If the constraint contains two variables, the branching of course simplifies.
5787  *
5788  *  Depending on the parameters (@c branchnonzeros, @c branchweight) there are three ways to choose
5789  *  the branching constraint.
5790  *
5791  *  <TABLE>
5792  *  <TR><TD>@c branchnonzeros</TD><TD>@c branchweight</TD><TD>constraint chosen</TD></TR>
5793  *  <TR><TD>@c true          </TD><TD> ?             </TD><TD>most number of nonzeros</TD></TR>
5794  *  <TR><TD>@c false         </TD><TD> @c true       </TD><TD>maximal weight corresponding to nonzero variable</TD></TR>
5795  *  <TR><TD>@c false         </TD><TD> @c true       </TD><TD>largest sum of variable values</TD></TR>
5796  *  </TABLE>
5797  *
5798  *  @c branchnonzeros = @c false, @c branchweight = @c true allows the user to specify an order for
5799  *  the branching importance of the constraints (setting the weights accordingly).
5800  *
5801  *  Constraint branching can also be turned off using parameter @c branchsos.
5802  */
5803 static
enforceConssSOS1(SCIP * scip,SCIP_CONSHDLR * conshdlr,int nconss,SCIP_CONS ** conss,SCIP_SOL * sol,SCIP_RESULT * result)5804 SCIP_RETCODE enforceConssSOS1(
5805    SCIP*                 scip,               /**< SCIP pointer */
5806    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
5807    int                   nconss,             /**< number of constraints */
5808    SCIP_CONS**           conss,              /**< indicator constraints */
5809    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
5810    SCIP_RESULT*          result              /**< result */
5811    )
5812 {
5813    SCIP_CONSHDLRDATA* conshdlrdata;
5814    SCIP_CONSDATA* consdata;
5815    SCIP_NODE* node1;
5816    SCIP_NODE* node2;
5817    SCIP_CONS* branchCons;
5818    SCIP_Real maxWeight;
5819    SCIP_VAR** vars;
5820    int nvars;
5821    int c;
5822 
5823    assert( scip != NULL );
5824    assert( conshdlr != NULL );
5825    assert( conss != NULL );
5826    assert( result != NULL );
5827 
5828    maxWeight = -SCIP_REAL_MAX;
5829    branchCons = NULL;
5830 
5831    SCIPdebugMsg(scip, "Enforcing SOS1 constraints <%s>.\n", SCIPconshdlrGetName(conshdlr) );
5832    *result = SCIP_FEASIBLE;
5833 
5834    /* get constraint handler data */
5835    conshdlrdata = SCIPconshdlrGetData(conshdlr);
5836    assert( conshdlrdata != NULL );
5837 
5838    /* check each constraint */
5839    for (c = 0; c < nconss; ++c)
5840    {
5841       SCIP_CONS* cons;
5842       SCIP_Bool cutoff;
5843       SCIP_Real weight;
5844       int ngen;
5845       int cnt;
5846       int j;
5847 
5848       cons = conss[c];
5849       assert( cons != NULL );
5850       consdata = SCIPconsGetData(cons);
5851       assert( consdata != NULL );
5852 
5853       ngen = 0;
5854       cnt = 0;
5855       nvars = consdata->nvars;
5856       vars = consdata->vars;
5857 
5858       /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
5859       if ( nvars < 2 )
5860          continue;
5861 
5862       /* first perform propagation (it might happen that standard propagation is turned off) */
5863       SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
5864       SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen);
5865       if ( cutoff )
5866       {
5867          *result = SCIP_CUTOFF;
5868          return SCIP_OKAY;
5869       }
5870       if ( ngen > 0 )
5871       {
5872          *result = SCIP_REDUCEDDOM;
5873          return SCIP_OKAY;
5874       }
5875       assert( ngen == 0 );
5876 
5877       /* check constraint */
5878       weight = 0.0;
5879       for (j = 0; j < nvars; ++j)
5880       {
5881          SCIP_Real val = REALABS(SCIPgetSolVal(scip, sol, vars[j]));
5882 
5883          if ( ! SCIPisFeasZero(scip, val) )
5884          {
5885             if ( conshdlrdata->branchnonzeros )
5886                weight += 1.0;
5887             else
5888             {
5889                if ( conshdlrdata->branchweight && consdata->weights != NULL )
5890                {
5891                   /* choose maximum nonzero-variable weight */
5892                   if ( consdata->weights[j] > weight )
5893                      weight = consdata->weights[j];
5894                }
5895                else
5896                   weight += val;
5897             }
5898             ++cnt;
5899          }
5900       }
5901       /* if constraint is violated */
5902       if ( cnt > 1 && weight > maxWeight )
5903       {
5904          maxWeight = weight;
5905          branchCons = cons;
5906       }
5907    }
5908 
5909    /* if all constraints are feasible */
5910    if ( branchCons == NULL )
5911    {
5912       SCIPdebugMsg(scip, "All SOS1 constraints are feasible.\n");
5913       return SCIP_OKAY;
5914    }
5915 
5916    /* if we should leave branching decision to branching rules */
5917    if ( ! conshdlrdata->branchsos )
5918    {
5919       int j;
5920 
5921       consdata = SCIPconsGetData(branchCons);
5922       for (j = 0; j < consdata->nvars; ++j)
5923       {
5924          if ( ! SCIPvarIsBinary(consdata->vars[j]) )
5925             break;
5926       }
5927 
5928       if ( j == consdata->nvars )
5929       {
5930          *result = SCIP_INFEASIBLE;
5931          return SCIP_OKAY;
5932       }
5933       else
5934       {
5935          SCIPerrorMessage("Incompatible parameter setting: branchsos can only be set to false if all SOS1 variables are binary.\n");
5936          return SCIP_PARAMETERWRONGVAL;
5937       }
5938    }
5939 
5940    /* otherwise create branches */
5941    SCIPdebugMsg(scip, "Branching on constraint <%s> (weight: %f).\n", SCIPconsGetName(branchCons), maxWeight);
5942    consdata = SCIPconsGetData(branchCons);
5943    assert( consdata != NULL );
5944    nvars = consdata->nvars;
5945    vars = consdata->vars;
5946 
5947    if ( nvars == 2 )
5948    {
5949       SCIP_Bool infeasible;
5950 
5951       /* constraint is infeasible: */
5952       assert( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[0])) && ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[1])) );
5953 
5954       /* create branches */
5955       SCIPdebugMsg(scip, "Creating two branches.\n");
5956 
5957       SCIP_CALL( SCIPcreateChild(scip, &node1, SCIPcalcNodeselPriority(scip, vars[0], SCIP_BRANCHDIR_DOWNWARDS, 0.0), SCIPcalcChildEstimate(scip, vars[0], 0.0) ) );
5958       SCIP_CALL( fixVariableZeroNode(scip, vars[0], node1, &infeasible) );
5959       assert( ! infeasible );
5960 
5961       SCIP_CALL( SCIPcreateChild(scip, &node2, SCIPcalcNodeselPriority(scip, vars[1], SCIP_BRANCHDIR_DOWNWARDS, 0.0), SCIPcalcChildEstimate(scip, vars[1], 0.0) ) );
5962       SCIP_CALL( fixVariableZeroNode(scip, vars[1], node2, &infeasible) );
5963       assert( ! infeasible );
5964    }
5965    else
5966    {
5967       SCIP_Bool infeasible;
5968       SCIP_Real weight1;
5969       SCIP_Real weight2;
5970       SCIP_Real nodeselest;
5971       SCIP_Real objest;
5972       SCIP_Real w;
5973       int j;
5974       int ind;
5975       int cnt;
5976 
5977       cnt = 0;
5978 
5979       weight1 = 0.0;
5980       weight2 = 0.0;
5981 
5982       /* compute weight */
5983       for (j = 0; j < nvars; ++j)
5984       {
5985          SCIP_Real val = REALABS(SCIPgetSolVal(scip, sol, vars[j]));
5986          weight1 += val * (SCIP_Real) j;
5987          weight2 += val;
5988 
5989          if ( ! SCIPisFeasZero(scip, val) )
5990             ++cnt;
5991       }
5992 
5993       assert( cnt >= 2 );
5994       assert( !SCIPisFeasZero(scip, weight2) );
5995       w = weight1/weight2;  /*lint !e795*/
5996 
5997       ind = (int) SCIPfloor(scip, w);
5998       assert( 0 <= ind && ind < nvars-1 );
5999 
6000       /* branch on variable ind: either all variables up to ind or all variables after ind are zero */
6001       SCIPdebugMsg(scip, "Branching on variable <%s>.\n", SCIPvarGetName(vars[ind]));
6002 
6003       /* calculate node selection and objective estimate for node 1 */
6004       nodeselest = 0.0;
6005       objest = SCIPgetLocalTransEstimate(scip);
6006       for (j = 0; j <= ind; ++j)
6007       {
6008          objest += SCIPcalcChildEstimateIncrease(scip, vars[j], SCIPgetSolVal(scip, sol, vars[j]), 0.0);
6009          nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
6010       }
6011       assert( objest >= SCIPgetLocalTransEstimate(scip) );
6012 
6013       /* create node 1 */
6014       SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
6015       for (j = 0; j <= ind; ++j)
6016       {
6017          SCIP_CALL( fixVariableZeroNode(scip, vars[j], node1, &infeasible) );
6018          assert( ! infeasible );
6019       }
6020 
6021       /* calculate node selection and objective estimate for node 1 */
6022       nodeselest = 0.0;
6023       objest = SCIPgetLocalTransEstimate(scip);
6024       for (j = ind+1; j < nvars; ++j)
6025       {
6026          objest += SCIPcalcChildEstimateIncrease(scip, vars[j], SCIPgetSolVal(scip, sol, vars[j]), 0.0);
6027          nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
6028       }
6029       assert( objest >= SCIPgetLocalTransEstimate(scip) );
6030 
6031       /* create node 2 */
6032       SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
6033       for (j = ind+1; j < nvars; ++j)
6034       {
6035          SCIP_CALL( fixVariableZeroNode(scip, vars[j], node2, &infeasible) );
6036          assert( ! infeasible );
6037       }
6038    }
6039    SCIP_CALL( SCIPresetConsAge(scip, branchCons) );
6040    *result = SCIP_BRANCHED;
6041 
6042    return SCIP_OKAY;
6043 }
6044 
6045 
6046 /** constraint enforcing method of constraint handler */
6047 static
enforceSOS1(SCIP * scip,SCIP_CONSHDLR * conshdlr,int nconss,SCIP_CONS ** conss,SCIP_SOL * sol,SCIP_RESULT * result)6048 SCIP_RETCODE enforceSOS1(
6049    SCIP*                 scip,               /**< SCIP pointer */
6050    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6051    int                   nconss,             /**< number of constraints */
6052    SCIP_CONS**           conss,              /**< indicator constraints */
6053    SCIP_SOL*             sol,                /**< solution to be enforced (NULL for LP solution) */
6054    SCIP_RESULT*          result              /**< result */
6055    )
6056 {
6057    SCIP_CONSHDLRDATA* conshdlrdata;
6058 
6059    assert( scip != NULL );
6060    assert( conshdlr != NULL );
6061    assert( conss != NULL );
6062    assert( result != NULL );
6063 
6064    /* get constraint handler data */
6065    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6066    assert( conshdlrdata != NULL );
6067 
6068    if ( conshdlrdata->addcomps && conshdlrdata->fixnonzero )
6069    {
6070       SCIPerrorMessage("Incompatible parameter setting: addcomps = TRUE and fixnonzero = TRUE.\n");
6071       return SCIP_PARAMETERWRONGVAL;
6072    }
6073 
6074    if ( conshdlrdata->fixnonzero && ( conshdlrdata->branchingrule == 'b' || conshdlrdata->branchingrule == 's' ) )
6075    {
6076       SCIPerrorMessage("Incompatible parameter setting: nonzero fixing is not compatible with bipartite or sos1 branching.\n");
6077       return SCIP_PARAMETERWRONGVAL;
6078    }
6079 
6080    if ( conshdlrdata->branchingrule == 's' && conshdlrdata->nstrongrounds != 0 )
6081    {
6082       SCIPerrorMessage("Strong branching is not available for SOS1 branching.\n");
6083       return SCIP_PARAMETERWRONGVAL;
6084    }
6085 
6086    if ( conshdlrdata->branchingrule == 's' || conshdlrdata->switchsos1branch )
6087    {
6088       /* enforce SOS1 constraints */
6089       SCIP_CALL( enforceConssSOS1(scip, conshdlr, nconss, conss, sol, result) );
6090    }
6091    else
6092    {
6093       if ( conshdlrdata->branchingrule != 'n' && conshdlrdata->branchingrule != 'b' )
6094       {
6095          SCIPerrorMessage("branching rule %c unknown\n", conshdlrdata->branchingrule);
6096          return SCIP_PARAMETERWRONGVAL;
6097       }
6098 
6099       /* enforce conflict graph */
6100       SCIP_CALL( enforceConflictgraph(scip, conshdlrdata, conshdlr, nconss, conss, sol, result) );
6101    }
6102 
6103    return SCIP_OKAY;
6104 }
6105 
6106 
6107 /* ----------------------------- separation ------------------------------------*/
6108 
6109 /** initialitze tclique graph and create clique data */
6110 static
initTCliquegraph(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,int nsos1vars)6111 SCIP_RETCODE initTCliquegraph(
6112    SCIP*                 scip,               /**< SCIP pointer */
6113    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6114    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
6115    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
6116    int                   nsos1vars           /**< number of SOS1 variables */
6117    )
6118 {
6119    TCLIQUE_DATA* tcliquedata;
6120    int j;
6121 
6122    /* try to generate bound cuts */
6123    if ( ! tcliqueCreate(&conshdlrdata->tcliquegraph) )
6124       return SCIP_NOMEMORY;
6125 
6126    /* add nodes */
6127    for (j = 0; j < nsos1vars; ++j)
6128    {
6129       if ( ! tcliqueAddNode(conshdlrdata->tcliquegraph, j, 0 ) )
6130          return SCIP_NOMEMORY;
6131    }
6132 
6133    /* add edges */
6134    for (j = 0; j < nsos1vars; ++j)
6135    {
6136       int* succ;
6137       int nsucc;
6138       int succnode;
6139       int i;
6140 
6141       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
6142       succ = SCIPdigraphGetSuccessors(conflictgraph, j);
6143 
6144       for (i = 0; i < nsucc; ++i)
6145       {
6146          succnode = succ[i];
6147 
6148          if ( succnode > j && SCIPvarIsActive(SCIPnodeGetVarSOS1(conflictgraph, succnode)) )
6149          {
6150             if ( ! tcliqueAddEdge(conshdlrdata->tcliquegraph, j, succnode) )
6151                return SCIP_NOMEMORY;
6152          }
6153       }
6154    }
6155 
6156    if ( ! tcliqueFlush(conshdlrdata->tcliquegraph) )
6157       return SCIP_NOMEMORY;
6158 
6159    /* allocate clique data */
6160    SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata->tcliquedata) );
6161    tcliquedata = conshdlrdata->tcliquedata;
6162 
6163    /* initialize clique data */
6164    tcliquedata->scip = scip;
6165    tcliquedata->sol = NULL;
6166    tcliquedata->conshdlr = conshdlr;
6167    tcliquedata->conflictgraph = conflictgraph;
6168    tcliquedata->scaleval = 1000.0;
6169    tcliquedata->ncuts = 0;
6170    tcliquedata->nboundcuts = conshdlrdata->nboundcuts;
6171    tcliquedata->strthenboundcuts = conshdlrdata->strthenboundcuts;
6172    tcliquedata->maxboundcuts = conshdlrdata->maxboundcutsroot;
6173 
6174    return SCIP_OKAY;
6175 }
6176 
6177 
6178 /** update weights of tclique graph */
6179 static
updateWeightsTCliquegraph(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,TCLIQUE_DATA * tcliquedata,SCIP_DIGRAPH * conflictgraph,SCIP_SOL * sol,int nsos1vars)6180 SCIP_RETCODE updateWeightsTCliquegraph(
6181    SCIP*                 scip,               /**< SCIP pointer */
6182    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
6183    TCLIQUE_DATA*         tcliquedata,        /**< tclique data */
6184    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
6185    SCIP_SOL*             sol,                /**< LP solution to be separated (or NULL) */
6186    int                   nsos1vars           /**< number of SOS1 variables */
6187    )
6188 {
6189    SCIP_Real scaleval;
6190    int j;
6191 
6192    scaleval = tcliquedata->scaleval;
6193 
6194    for (j = 0; j < nsos1vars; ++j)
6195    {
6196       SCIP_Real solval;
6197       SCIP_Real bound;
6198       SCIP_VAR* var;
6199 
6200       var = SCIPnodeGetVarSOS1(conflictgraph, j);
6201       solval = SCIPgetSolVal(scip, sol, var);
6202 
6203       if ( SCIPisFeasPositive(scip, solval) )
6204       {
6205          if ( conshdlrdata->strthenboundcuts )
6206             bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, j) );
6207          else
6208             bound = REALABS( SCIPvarGetUbLocal(var) );
6209       }
6210       else if ( SCIPisFeasNegative(scip, solval) )
6211       {
6212          if ( conshdlrdata->strthenboundcuts )
6213             bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, j) );
6214          else
6215             bound = REALABS( SCIPvarGetLbLocal(var) );
6216       }
6217       else
6218          bound = 0.0;
6219 
6220       solval = REALABS( solval );
6221 
6222       if ( ! SCIPisFeasZero(scip, bound) && ! SCIPisInfinity(scip, bound) )
6223       {
6224          SCIP_Real nodeweight;
6225          nodeweight = REALABS( solval/bound ) * scaleval;/*lint !e414*/
6226          tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, (int)nodeweight);
6227       }
6228       else
6229       {
6230          tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, 0);
6231       }
6232    }
6233 
6234    return SCIP_OKAY;
6235 }
6236 
6237 
6238 /** adds bound cut(s) to separation storage */
6239 static
addBoundCutSepa(SCIP * scip,TCLIQUE_DATA * tcliquedata,SCIP_ROW * rowlb,SCIP_ROW * rowub,SCIP_Bool * success,SCIP_Bool * cutoff)6240 SCIP_RETCODE addBoundCutSepa(
6241    SCIP*                 scip,               /**< SCIP pointer */
6242    TCLIQUE_DATA*         tcliquedata,        /**< clique data */
6243    SCIP_ROW*             rowlb,              /**< row for lower bounds (or NULL) */
6244    SCIP_ROW*             rowub,              /**< row for upper bounds (or NULL) */
6245    SCIP_Bool*            success,            /**< pointer to store if bound cut was added */
6246    SCIP_Bool*            cutoff              /**< pointer to store if a cutoff occurred */
6247    )
6248 {
6249    assert( scip != NULL );
6250    assert( tcliquedata != NULL );
6251    assert( success != NULL);
6252    assert( cutoff != NULL );
6253 
6254    *success = FALSE;
6255    *cutoff = FALSE;
6256 
6257    /* add cut for lower bounds */
6258    if ( rowlb != NULL )
6259    {
6260       if ( ! SCIProwIsInLP(rowlb) && SCIPisCutEfficacious(scip, NULL, rowlb) )
6261       {
6262          SCIP_Bool infeasible;
6263 
6264          SCIP_CALL( SCIPaddRow(scip, rowlb, FALSE, &infeasible) );
6265          if ( infeasible )
6266             *cutoff = TRUE;
6267          SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) );
6268          ++tcliquedata->nboundcuts;
6269          ++tcliquedata->ncuts;
6270          *success = TRUE;
6271       }
6272    }
6273 
6274    /* add cut for upper bounds */
6275    if ( rowub != NULL )
6276    {
6277       if ( ! SCIProwIsInLP(rowub) && SCIPisCutEfficacious(scip, NULL, rowub) )
6278       {
6279          SCIP_Bool infeasible;
6280 
6281          SCIP_CALL( SCIPaddRow(scip, rowub, FALSE, &infeasible) );
6282          if ( infeasible )
6283             *cutoff = TRUE;
6284          SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) );
6285          ++tcliquedata->nboundcuts;
6286          ++tcliquedata->ncuts;
6287          *success = TRUE;
6288       }
6289    }
6290 
6291    return SCIP_OKAY;
6292 }
6293 
6294 
6295 /** Generate bound constraint
6296  *
6297  *  We generate the row corresponding to the following simple valid inequalities:
6298  *  \f[
6299  *         \frac{x_1}{u_1} + \ldots + \frac{x_n}{u_n} \leq 1\qquad\mbox{and}\qquad
6300  *         \frac{x_1}{\ell_1} + \ldots + \frac{x_n}{\ell_1} \leq 1,
6301  *  \f]
6302  *  where \f$\ell_1, \ldots, \ell_n\f$ and \f$u_1, \ldots, u_n\f$ are the nonzero and finite lower and upper bounds of
6303  *  the variables \f$x_1, \ldots, x_n\f$. If an upper bound < 0 or a lower bound > 0, the constraint itself is
6304  *  redundant, so the cut is not applied (lower bounds > 0 and upper bounds < 0 are usually detected in presolving or
6305  *  propagation). Infinite bounds and zero are skipped. Thus \f$\ell_1, \ldots, \ell_n\f$ are all negative, which
6306  *  results in the \f$\leq\f$ inequality. In case of the presence of variable upper bounds, the bound inequality can
6307  *  be further strengthened.
6308  *
6309  *  Note that in fact, any mixture of nonzero finite lower and upper bounds would lead to a valid inequality as
6310  *  above. However, usually either the lower or upper bound is nonzero. Thus, the above inequalities are the most
6311  *  interesting.
6312  */
6313 static
generateBoundInequalityFromSOS1Nodes(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_DIGRAPH * conflictgraph,int * nodes,int nnodes,SCIP_Real rhs,SCIP_Bool local,SCIP_Bool global,SCIP_Bool strengthen,SCIP_Bool removable,const char * nameext,SCIP_ROW ** rowlb,SCIP_ROW ** rowub)6314 SCIP_RETCODE generateBoundInequalityFromSOS1Nodes(
6315    SCIP*                 scip,               /**< SCIP pointer */
6316    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6317    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
6318    int*                  nodes,              /**< conflict graph nodes for bound constraint */
6319    int                   nnodes,             /**< number of conflict graph nodes for bound constraint */
6320    SCIP_Real             rhs,                /**< right hand side of bound constraint */
6321    SCIP_Bool             local,              /**< in any case produce a local cut (even if local bounds of variables are valid globally) */
6322    SCIP_Bool             global,             /**< in any case produce a global cut */
6323    SCIP_Bool             strengthen,         /**< whether trying to strengthen bound constraint */
6324    SCIP_Bool             removable,          /**< should the inequality be removed from the LP due to aging or cleanup? */
6325    const char*           nameext,            /**< part of name of bound constraints */
6326    SCIP_ROW**            rowlb,              /**< output: row for lower bounds (or NULL if not needed) */
6327    SCIP_ROW**            rowub               /**< output: row for upper bounds (or NULL if not needed) */
6328    )
6329 {
6330    char name[SCIP_MAXSTRLEN];
6331    SCIP_VAR* lbboundvar = NULL;
6332    SCIP_VAR* ubboundvar = NULL;
6333    SCIP_Bool locallbs;
6334    SCIP_Bool localubs;
6335    SCIP_VAR** vars;
6336    SCIP_Real* vals;
6337 
6338    assert( scip != NULL );
6339    assert( conshdlr != NULL );
6340    assert( conflictgraph != NULL );
6341    assert( ! local || ! global );
6342    assert( nodes != NULL );
6343 
6344    /* allocate buffer array */
6345    SCIP_CALL( SCIPallocBufferArray(scip, &vars, nnodes+1) );
6346    SCIP_CALL( SCIPallocBufferArray(scip, &vals, nnodes+1) );
6347 
6348    /* take care of upper bounds */
6349    if ( rowub != NULL )
6350    {
6351       SCIP_Bool useboundvar;
6352       int cnt = 0;
6353       int j;
6354 
6355       /* Loop through all variables. We check whether all bound variables (if existent) are equal; if this is the
6356        * case then the bound constraint can be strengthened */
6357       localubs = local;
6358       useboundvar = strengthen;
6359       for (j = 0; j < nnodes; ++j)
6360       {
6361          SCIP_NODEDATA* nodedata;
6362          SCIP_VAR* var;
6363          SCIP_Real val;
6364 
6365          nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]);
6366          assert( nodedata != NULL );
6367          var = nodedata->var;
6368          assert( var != NULL );
6369 
6370          /* if variable is not involved in a variable bound constraint */
6371          if ( ! useboundvar || nodedata->ubboundvar == NULL )
6372          {
6373             useboundvar = FALSE;
6374             if ( localubs )
6375             {
6376                assert( ! global );
6377                val = SCIPvarGetUbLocal(var);
6378             }
6379             else
6380             {
6381                val = SCIPvarGetUbGlobal(var);
6382                if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetUbLocal(var)) )
6383                {
6384                   localubs = TRUE;
6385                   val = SCIPvarGetUbLocal(var);
6386                }
6387             }
6388          }
6389          else
6390          {
6391             /* in this case the cut is always valid globally */
6392 
6393             /* if we have a bound variable for the first time */
6394             if ( ubboundvar == NULL )
6395             {
6396                ubboundvar = nodedata->ubboundvar;
6397                val = nodedata->ubboundcoef;
6398             }
6399             /* else if the bound variable equals the stored bound variable */
6400             else if ( ubboundvar == nodedata->ubboundvar )
6401                val = nodedata->ubboundcoef;
6402             else /* else use bounds on the variables */
6403             {
6404                useboundvar = FALSE;
6405 
6406                /* restart 'for'-loop */
6407                j = -1;  /*lint !e850*/
6408                cnt = 0;
6409                continue;
6410             }
6411          }
6412 
6413          /* should not apply the cut if a variable is fixed to be negative -> constraint is redundant */
6414          if ( SCIPisNegative(scip, val) )
6415             break;
6416 
6417          /* store variable if relevant for bound inequality */
6418          if ( ! SCIPisInfinity(scip, val) && ! SCIPisZero(scip, val) )
6419          {
6420             vars[cnt] = var;
6421 
6422             /* if only two nodes then we scale the cut differently */
6423             if ( nnodes == 2 )
6424                vals[cnt++] = val;
6425             else
6426                vals[cnt++] = 1.0/val;
6427          }
6428       }
6429 
6430       /* if cut is meaningful */
6431       if ( j == nnodes && cnt >= 2 )/*lint !e850*/
6432       {
6433          /* if only two nodes then we scale the cut differently */
6434          if ( nnodes == 2 )
6435          {
6436             SCIP_Real save;
6437 
6438             save = vals[0];
6439             vals[0] = vals[1];
6440             vals[1] = save;
6441             rhs = rhs * vals[0] * vals[1];
6442             assert( (! useboundvar && cnt == 2 ) || (useboundvar && cnt == 3 ) );
6443          }
6444 
6445          if ( useboundvar )
6446          {
6447             /* add bound variable to array */
6448             vars[cnt] = ubboundvar;
6449             vals[cnt++] = -rhs;
6450             assert(ubboundvar != NULL );
6451 
6452             /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6453             (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext);
6454             SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowub, conshdlr, name, -SCIPinfinity(scip), 0.0, localubs, FALSE, removable) );
6455             SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) );
6456             SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) );
6457          }
6458          else
6459          {
6460             /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6461             (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext);
6462             SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowub, conshdlr, name, -SCIPinfinity(scip), rhs, localubs, FALSE, removable) );
6463             SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) );
6464             SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) );
6465          }
6466       }
6467    }
6468 
6469    /* take care of lower bounds */
6470    if ( rowlb != NULL )
6471    {
6472       SCIP_Bool useboundvar;
6473       int cnt = 0;
6474       int j;
6475 
6476       /* loop through all variables. We check whether all bound variables (if existent) are equal; if this is the
6477        * case then the bound constraint can be strengthened */
6478       locallbs = local;
6479       useboundvar = strengthen;
6480       for (j = 0; j < nnodes; ++j)
6481       {
6482          SCIP_NODEDATA* nodedata;
6483          SCIP_VAR* var;
6484          SCIP_Real val;
6485 
6486          nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]);
6487          assert( nodedata != NULL );
6488          var = nodedata->var;
6489          assert( var != NULL );
6490 
6491          /* if variable is not involved in a variable bound constraint */
6492          if ( ! useboundvar || nodedata->lbboundvar == NULL )
6493          {
6494             useboundvar = FALSE;
6495             if ( locallbs )
6496             {
6497                assert( ! global );
6498                val = SCIPvarGetLbLocal(var);
6499             }
6500             else
6501             {
6502                val = SCIPvarGetLbGlobal(var);
6503                if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetLbLocal(var)) )
6504                {
6505                   locallbs = TRUE;
6506                   val = SCIPvarGetLbLocal(var);
6507                }
6508             }
6509          }
6510          else
6511          {
6512             /* in this case the cut is always valid globally */
6513 
6514             /* if we have a bound variable for the first time */
6515             if ( lbboundvar == NULL )
6516             {
6517                lbboundvar = nodedata->lbboundvar;
6518                val = nodedata->lbboundcoef;
6519             }
6520             /* else if the bound variable equals the stored bound variable */
6521             else if ( SCIPvarCompare(lbboundvar, nodedata->lbboundvar) == 0 )
6522             {
6523                val = nodedata->lbboundcoef;
6524             }
6525             else /* else use bounds on the variables */
6526             {
6527                useboundvar = FALSE;
6528 
6529                /* restart 'for'-loop */
6530                j = -1;  /*lint !e850*/
6531                cnt = 0;
6532                continue;
6533             }
6534          }
6535 
6536          /* should not apply the cut if a variable is fixed to be positive -> constraint is redundant */
6537          if ( SCIPisPositive(scip, val) )
6538             break;
6539 
6540          /* store variable if relevant for bound inequality */
6541          if ( ! SCIPisInfinity(scip, -val) && ! SCIPisZero(scip, val) )
6542          {
6543             vars[cnt] = var;
6544 
6545             /* if only two nodes then we scale the cut differently */
6546             if ( nnodes == 2 )
6547                vals[cnt++] = val;
6548             else
6549                vals[cnt++] = 1.0/val;
6550          }
6551       }
6552 
6553       /* if cut is meaningful */
6554       if ( j == nnodes && cnt >= 2 )/*lint !e850*/
6555       {
6556          /* if only two nodes then we scale the cut differently */
6557          if ( nnodes == 2 )
6558          {
6559             SCIP_Real save;
6560 
6561             save = vals[0];
6562             vals[0] = vals[1];
6563             vals[1] = save;
6564             rhs = rhs * vals[0] * vals[1];
6565             assert( (! useboundvar && cnt == 2 ) || (useboundvar && cnt == 3 ) );
6566          }
6567 
6568          if ( useboundvar )
6569          {
6570             /* add bound variable to array */
6571             vars[cnt] = lbboundvar;
6572             vals[cnt++] = -rhs;
6573             assert(lbboundvar != NULL );
6574 
6575             /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6576             (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext);
6577             SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), 0.0, locallbs, FALSE, TRUE) );
6578             SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) );
6579             SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) );
6580          }
6581          else
6582          {
6583             /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6584             (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext);
6585             SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), rhs, locallbs, FALSE, TRUE) );
6586             SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) );
6587             SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) );
6588          }
6589       }
6590    }
6591 
6592    /* free buffer array */
6593    SCIPfreeBufferArray(scip, &vals);
6594    SCIPfreeBufferArray(scip, &vars);
6595 
6596    return SCIP_OKAY;
6597 }
6598 
6599 
6600 /** generates bound cuts using a clique found by algorithm for maximum weight clique
6601  *  and decides whether to stop generating cliques with the algorithm for maximum weight clique
6602  */
6603 static
TCLIQUE_NEWSOL(tcliqueNewsolClique)6604 TCLIQUE_NEWSOL(tcliqueNewsolClique)
6605 {
6606    TCLIQUE_WEIGHT minweightinc;
6607 
6608    assert( acceptsol != NULL );
6609    assert( stopsolving != NULL );
6610    assert( tcliquedata != NULL );
6611 
6612    /* we don't accept the solution as new incumbent, because we want to find many violated clique inequalities */
6613    *acceptsol = FALSE;
6614    *stopsolving = FALSE;
6615 
6616    /* slightly increase the minimal weight for additional cliques */
6617    minweightinc = (cliqueweight - *minweight)/10;
6618    minweightinc = MAX(minweightinc, 1);
6619    *minweight += minweightinc;
6620 
6621    /* adds cut if weight of the clique is greater than 1 */
6622    if( cliqueweight > tcliquedata->scaleval )
6623    {
6624       SCIP* scip;
6625       SCIP_SOL* sol;
6626       SCIP_Real unscaledweight;
6627       SCIP_Real solval;
6628       SCIP_Real bound;
6629       SCIP_VAR* var;
6630       int node;
6631       int i;
6632 
6633       scip = tcliquedata->scip;
6634       sol = tcliquedata->sol;
6635       assert( scip != NULL );
6636 
6637       /* calculate the weight of the clique in unscaled fractional variable space */
6638       unscaledweight = 0.0;
6639       for( i = 0; i < ncliquenodes; i++ )
6640       {
6641          node = cliquenodes[i];
6642          var = SCIPnodeGetVarSOS1(tcliquedata->conflictgraph, node);
6643          solval = SCIPgetSolVal(scip, sol, var);
6644 
6645          if ( SCIPisFeasPositive(scip, solval) )
6646          {
6647             if ( tcliquedata->strthenboundcuts )
6648                bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, tcliquedata->conflictgraph, sol, node) );
6649             else
6650                bound = REALABS( SCIPvarGetUbLocal(var) );
6651          }
6652          else if ( SCIPisFeasNegative(scip, solval) )
6653          {
6654             if ( tcliquedata->strthenboundcuts )
6655                bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, tcliquedata->conflictgraph, sol, node) );
6656             else
6657                bound = REALABS( SCIPvarGetLbLocal(var) );
6658          }
6659          else
6660             bound = 0.0;
6661 
6662          solval = REALABS( solval );
6663 
6664          if ( ! SCIPisFeasZero(scip, bound) && ! SCIPisInfinity(scip, bound) )
6665             unscaledweight += REALABS( solval/bound );/*lint !e414*/
6666       }
6667 
6668       if ( SCIPisEfficacious(scip, unscaledweight - 1.0) )
6669       {
6670          char nameext[SCIP_MAXSTRLEN];
6671          SCIP_ROW* rowlb = NULL;
6672          SCIP_ROW* rowub = NULL;
6673          SCIP_Bool success;
6674          SCIP_Bool cutoff;
6675 
6676          /* generate bound inequalities for lower and upper bound case
6677           * NOTE: tests have shown that non-removable rows give the best results */
6678          (void) SCIPsnprintf(nameext, SCIP_MAXSTRLEN, "%d", tcliquedata->nboundcuts);
6679          if ( generateBoundInequalityFromSOS1Nodes(scip, tcliquedata->conshdlr, tcliquedata->conflictgraph,
6680                cliquenodes, ncliquenodes, 1.0, FALSE, FALSE, tcliquedata->strthenboundcuts, FALSE, nameext, &rowlb, &rowub) != SCIP_OKAY )
6681          {
6682             SCIPerrorMessage("Unexpected error in bound cut creation.\n");
6683             SCIPABORT();
6684             return;   /*lint !e527*/
6685          }
6686 
6687          /* add bound cut(s) to separation storage if existent */
6688          if ( addBoundCutSepa(scip, tcliquedata, rowlb, rowub, &success, &cutoff) != SCIP_OKAY )
6689          {
6690             SCIPerrorMessage("Unexpected error in bound cut creation.\n");
6691             SCIPABORT();
6692             return;   /*lint !e527*/
6693          }
6694 
6695          if ( rowlb != NULL )
6696          {
6697             if ( SCIPreleaseRow(scip, &rowlb) != SCIP_OKAY )
6698             {
6699                SCIPerrorMessage("Cannot release row,\n");
6700                SCIPABORT();
6701                return;   /*lint !e527*/
6702             }
6703          }
6704          if ( rowub != NULL )
6705          {
6706             if ( SCIPreleaseRow(scip, &rowub) != SCIP_OKAY )
6707             {
6708                SCIPerrorMessage("Cannot release row,\n");
6709                SCIPABORT();
6710                return;   /*lint !e527*/
6711             }
6712          }
6713 
6714          /* if at least one cut has been added */
6715          if ( success )
6716          {
6717             SCIPdebugMsg(scip, " -> found bound cut corresponding to clique (act=%g)\n", unscaledweight);
6718 
6719             /* if we found more than half the cuts we are allowed to generate, we accept the clique as new incumbent,
6720              * such that only more violated cuts are generated afterwards
6721              */
6722             if( tcliquedata->maxboundcuts >= 0 )
6723             {
6724                if ( tcliquedata->ncuts > tcliquedata->maxboundcuts/2 )
6725                   *acceptsol = TRUE;
6726                if ( tcliquedata->ncuts >= tcliquedata->maxboundcuts )
6727                   *stopsolving = TRUE;
6728             }
6729          }
6730          else
6731             *stopsolving = TRUE;
6732       } /*lint !e438*/
6733    }
6734 }
6735 
6736 
6737 /** separate bound inequalities from conflict graph */
6738 static
sepaBoundInequalitiesFromGraph(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_SOL * sol,int maxboundcuts,int * ngen,SCIP_Bool * cutoff)6739 SCIP_RETCODE sepaBoundInequalitiesFromGraph(
6740    SCIP*                 scip,               /**< SCIP pointer */
6741    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6742    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
6743    SCIP_SOL*             sol,                /**< LP solution to be separated (or NULL) */
6744    int                   maxboundcuts,       /**< maximal number of bound cuts separated per separation round (-1: no limit) */
6745    int*                  ngen,               /**< pointer to store number of cuts generated */
6746    SCIP_Bool*            cutoff              /**< pointer whether a cutoff occurred */
6747    )
6748 {
6749    SCIP_DIGRAPH* conflictgraph;
6750    TCLIQUE_DATA* tcliquedata;
6751    TCLIQUE_WEIGHT cliqueweight;
6752    TCLIQUE_STATUS tcliquestatus;
6753    int nsos1vars;
6754 
6755    SCIP_Real scaleval = 1000.0;                  /* factor for scaling weights */
6756    int maxtreenodes = 10000;                     /* maximal number of nodes of b&b tree */
6757    int maxzeroextensions = 1000;                 /* maximal number of zero-valued variables extending the clique (-1: no limit) */
6758    int backtrackfreq = 1000;                     /* frequency for premature backtracking up to tree level 1 (0: no backtracking) */
6759    int ntreenodes;
6760    int* cliquenodes;
6761    int ncliquenodes;
6762 
6763    assert( scip != NULL );
6764    assert( conshdlr != NULL );
6765    assert( conshdlrdata != NULL );
6766    assert( ngen != NULL );
6767 
6768    /* get conflict graph */
6769    conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
6770    assert( conflictgraph != NULL );
6771 
6772    /* get number of SOS1 variables */
6773    nsos1vars = SCIPgetNSOS1Vars(conshdlr);
6774 
6775    /* initialize data of tclique graph*/
6776    tcliquedata = conshdlrdata->tcliquedata;
6777    tcliquedata->scaleval = scaleval;
6778    tcliquedata->maxboundcuts = maxboundcuts;
6779    tcliquedata->sol = sol;
6780    tcliquedata->ncuts = 0;
6781    tcliquedata->cutoff = FALSE;
6782 
6783    /* update the weights of the tclique graph */
6784    SCIP_CALL( updateWeightsTCliquegraph(scip, conshdlrdata, tcliquedata, conflictgraph, sol, nsos1vars) );
6785 
6786    /* allocate buffer array */
6787    SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nsos1vars) );
6788 
6789    /* start algorithm to find maximum weight cliques and use them to generate bound cuts */
6790    tcliqueMaxClique(tcliqueGetNNodes, tcliqueGetWeights, tcliqueIsEdge, tcliqueSelectAdjnodes,
6791       conshdlrdata->tcliquegraph, tcliqueNewsolClique, tcliquedata,
6792       cliquenodes, &ncliquenodes, &cliqueweight, (int)scaleval-1, (int)scaleval+1,
6793       maxtreenodes, backtrackfreq, maxzeroextensions, -1, &ntreenodes, &tcliquestatus);
6794 
6795    /* free buffer array */
6796    SCIPfreeBufferArray(scip, &cliquenodes);
6797 
6798    /* get number of cuts of current separation round */
6799    *ngen = tcliquedata->ncuts;
6800 
6801    /* store whether a cutoff occurred */
6802    *cutoff = tcliquedata->cutoff;
6803 
6804    /* update number of bound cuts in separator data */
6805    conshdlrdata->nboundcuts = tcliquedata->nboundcuts;
6806 
6807    return SCIP_OKAY;
6808 }
6809 
6810 
6811 /** Generate a bound constraint from the variables of an SOS1 constraint (see generateBoundInequalityFromSOS1Nodes() for more information) */
6812 static
generateBoundInequalityFromSOS1Cons(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS * cons,SCIP_Bool local,SCIP_Bool global,SCIP_Bool strengthen,SCIP_Bool removable,SCIP_ROW ** rowlb,SCIP_ROW ** rowub)6813 SCIP_RETCODE generateBoundInequalityFromSOS1Cons(
6814    SCIP*                 scip,               /**< SCIP pointer */
6815    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6816    SCIP_CONS*            cons,               /**< SOS1 constraint */
6817    SCIP_Bool             local,              /**< in any case produce a local cut (even if local bounds of variables are valid globally) */
6818    SCIP_Bool             global,             /**< in any case produce a global cut */
6819    SCIP_Bool             strengthen,         /**< whether trying to strengthen bound constraint */
6820    SCIP_Bool             removable,          /**< should the inequality be removed from the LP due to aging or cleanup? */
6821    SCIP_ROW**            rowlb,              /**< output: row for lower bounds (or NULL if not needed) */
6822    SCIP_ROW**            rowub               /**< output: row for upper bounds (or NULL if not needed) */
6823    )
6824 {
6825    SCIP_CONSHDLRDATA* conshdlrdata;
6826    SCIP_CONSDATA* consdata;
6827    int* nodes;
6828    int nvars;
6829    int cnt = 0;
6830    int j;
6831 
6832    assert( scip != NULL );
6833    assert( conshdlr != NULL );
6834    assert( cons != NULL );
6835 
6836    /* get constraint data */
6837    consdata = SCIPconsGetData(cons);
6838    assert( consdata != NULL );
6839    assert( consdata->vars != NULL );
6840    nvars = consdata->nvars;
6841 
6842    /* get constraint handler data */
6843    conshdlrdata = SCIPconshdlrGetData(conshdlr);
6844    assert( conshdlrdata != NULL );
6845    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6846 
6847    /* allocate buffer array */
6848    SCIP_CALL( SCIPallocBufferArray(scip, &nodes, nvars) );
6849 
6850    /* get nodes in the conflict graph */
6851    for (j = 0; j < nvars; ++j)
6852    {
6853       if ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(consdata->vars[j])) )
6854       {
6855          assert( varGetNodeSOS1(conshdlrdata, consdata->vars[j]) >= 0 );
6856          nodes[cnt++] = varGetNodeSOS1(conshdlrdata, consdata->vars[j]);
6857       }
6858    }
6859 
6860    /* generate bound constraint from conflict graph nodes */
6861    if ( cnt > 0 )
6862    {
6863       SCIP_CALL( generateBoundInequalityFromSOS1Nodes(scip, conshdlr, conshdlrdata->conflictgraph, nodes, cnt, 1.0, local, global,
6864             strengthen, removable, SCIPconsGetName(cons), rowlb, rowub) );
6865    }
6866 
6867    /* free buffer array */
6868    SCIPfreeBufferArray(scip, &nodes);
6869 
6870    return SCIP_OKAY;
6871 }
6872 
6873 
6874 /** initialize or separate bound inequalities from SOS1 constraints */
6875 static
initsepaBoundInequalityFromSOS1Cons(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONS ** conss,int nconss,SCIP_SOL * sol,SCIP_Bool solvedinitlp,int maxboundcuts,int * ngen,SCIP_Bool * cutoff)6876 SCIP_RETCODE initsepaBoundInequalityFromSOS1Cons(
6877    SCIP*                 scip,               /**< SCIP pointer */
6878    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6879    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
6880    SCIP_CONS**           conss,              /**< SOS1 constraints */
6881    int                   nconss,             /**< number of SOS1 constraints */
6882    SCIP_SOL*             sol,                /**< LP solution to be separated (or NULL) */
6883    SCIP_Bool             solvedinitlp,       /**< TRUE if initial LP relaxation at a node is solved */
6884    int                   maxboundcuts,       /**< maximal number of bound cuts separated per separation round (-1: no limit) */
6885    int*                  ngen,               /**< pointer to store number of cuts generated (or NULL) */
6886    SCIP_Bool*            cutoff              /**< pointer to store whether a cutoff occurred */
6887    )
6888 {
6889    int cnt = 0;
6890    int c;
6891 
6892    assert( scip != NULL );
6893    assert( conshdlrdata != NULL );
6894    assert( conss != NULL );
6895 
6896    *cutoff = FALSE;
6897 
6898    for (c = 0; c < nconss; ++c)
6899    {
6900       SCIP_CONSDATA* consdata;
6901       SCIP_ROW* rowub = NULL;
6902       SCIP_ROW* rowlb = NULL;
6903       SCIP_Bool release = FALSE;
6904 
6905       assert( conss != NULL );
6906       assert( conss[c] != NULL );
6907       consdata = SCIPconsGetData(conss[c]);
6908       assert( consdata != NULL );
6909 
6910       if ( solvedinitlp )
6911       {
6912          SCIPdebugMsg(scip, "Separating inequalities for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
6913       }
6914       else
6915       {
6916          SCIPdebugMsg(scip, "Checking for initial rows for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
6917       }
6918 
6919       /* in case that the SOS1 constraint is local, we always generate new rows - the former rows might be invalid;
6920        * otherwise if the SOS1 constraint is global, we only generate rows if not yet done */
6921       if ( consdata->local )
6922       {
6923          SCIP_CALL( generateBoundInequalityFromSOS1Cons(scip, conshdlr, conss[c], TRUE, FALSE, TRUE, FALSE, &rowlb, &rowub) );
6924          release = TRUE;
6925       }
6926       else
6927       {
6928          if ( consdata->rowub == NULL || consdata->rowlb == NULL )
6929          {
6930             SCIP_CALL( generateBoundInequalityFromSOS1Cons(scip, conshdlr, conss[c], FALSE, TRUE, TRUE, FALSE,
6931                   (consdata->rowlb == NULL) ? &consdata->rowlb : NULL,
6932                   (consdata->rowub == NULL) ? &consdata->rowub : NULL) ); /*lint !e826*/
6933          }
6934          rowub = consdata->rowub;
6935          rowlb = consdata->rowlb;
6936       }
6937 
6938       /* put corresponding rows into LP */
6939       if ( rowub != NULL && ! SCIProwIsInLP(rowub) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowub) ) )
6940       {
6941          SCIP_CALL( SCIPaddRow(scip, rowub, FALSE, cutoff) );
6942          SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) );
6943 
6944          if ( solvedinitlp )
6945          {
6946             SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
6947          }
6948          ++cnt;
6949       }
6950 
6951       if ( ! (*cutoff) && rowlb != NULL && ! SCIProwIsInLP(rowlb) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowlb) ) )
6952       {
6953          SCIP_CALL( SCIPaddRow(scip, rowlb, FALSE, cutoff) );
6954          SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) );
6955 
6956          if ( solvedinitlp )
6957          {
6958             SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
6959          }
6960          ++cnt;
6961       }
6962 
6963       /* release rows if they are local */
6964       if ( release )
6965       {
6966          if ( rowlb != NULL )
6967          {
6968             SCIP_CALL( SCIPreleaseRow(scip, &rowlb) );
6969          }
6970          if ( rowub != NULL )
6971          {
6972             SCIP_CALL( SCIPreleaseRow(scip, &rowub) );
6973          }
6974       }
6975 
6976       if ( *cutoff || ( maxboundcuts >= 0 && cnt >= maxboundcuts ) )
6977          break;
6978    }
6979 
6980    /* store number of generated cuts */
6981    if ( ngen != NULL )
6982       *ngen = cnt;
6983 
6984    return SCIP_OKAY;
6985 }
6986 
6987 
6988 /** separate implied bound cuts */
6989 static
sepaImplBoundCutsSOS1(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_SOL * sol,int maxcuts,int * ngen,SCIP_Bool * cutoff)6990 SCIP_RETCODE sepaImplBoundCutsSOS1(
6991    SCIP*                 scip,               /**< SCIP pointer */
6992    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
6993    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
6994    SCIP_SOL*             sol,                /**< LP solution to be separated (or NULL) */
6995    int                   maxcuts,            /**< maximal number of implied bound cuts separated per separation round (-1: no limit) */
6996    int*                  ngen,               /**< pointer to store number of cuts generated */
6997    SCIP_Bool*            cutoff              /**< pointer whether a cutoff occurred */
6998    )
6999 {
7000    SCIP_DIGRAPH* implgraph;
7001    SCIP_Bool genbreak;
7002    int nimplnodes;
7003    int i;
7004 
7005    assert( scip != NULL);
7006    assert( conshdlrdata != NULL);
7007    assert( conshdlr != NULL);
7008    assert( ngen != NULL);
7009    assert( cutoff != NULL);
7010 
7011    *cutoff = FALSE;
7012    *ngen = 0;
7013 
7014    /* return if conflict graph is not available */
7015    if ( conshdlrdata->conflictgraph == NULL )
7016       return SCIP_OKAY;
7017 
7018    /* get implication graph  */
7019    implgraph = conshdlrdata->implgraph;
7020 
7021    /* create implication graph if not done already */
7022    if ( implgraph == NULL )
7023    {
7024       int nchbds;
7025 
7026       if ( SCIPgetDepth(scip) == 0 )
7027       {
7028          SCIP_Bool success;
7029          SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, cutoff, &success) );
7030          if ( *cutoff || ! success )
7031             return SCIP_OKAY;
7032          implgraph = conshdlrdata->implgraph;
7033       }
7034       else
7035       {
7036          return SCIP_OKAY;
7037       }
7038    }
7039    nimplnodes = conshdlrdata->nimplnodes;
7040    assert( implgraph != NULL );
7041    assert( nimplnodes > 0);
7042 
7043    /* exit if implication graph has no arcs between its nodes */
7044    if ( SCIPdigraphGetNArcs(implgraph) < 1 )
7045       return SCIP_OKAY;
7046 
7047    /* loop through all nodes of the implication graph */
7048    genbreak = FALSE;
7049    for (i = 0; i < nimplnodes && ! genbreak; ++i)
7050    {
7051       SCIP_SUCCDATA** succdatas;
7052       SCIP_NODEDATA* nodedata;
7053       SCIP_Real solval;
7054       SCIP_VAR* var;
7055       int* succ;
7056       int nsucc;
7057       int s;
7058 
7059       succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, i);
7060       nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, i);
7061       assert( nodedata != NULL );
7062       var = nodedata->var;
7063       assert( var != NULL );
7064       solval = SCIPgetSolVal(scip, sol, var);
7065 
7066       if ( succdatas != NULL && ! SCIPisFeasZero(scip, solval) )
7067       {
7068          succ = SCIPdigraphGetSuccessors(implgraph, i);
7069          nsucc = SCIPdigraphGetNSuccessors(implgraph, i);
7070 
7071          for (s = 0; s < nsucc && ! genbreak; ++s)
7072          {
7073             SCIP_SUCCDATA* succdata;
7074             SCIP_VAR* succvar;
7075             SCIP_ROW* cut = NULL;
7076             SCIP_Bool bound1lower;
7077             SCIP_Bool bound2lower;
7078             SCIP_Real solvalsucc;
7079             SCIP_Real bound1;
7080             SCIP_Real bound2;
7081             SCIP_Real lhsrhs;
7082             SCIP_Real impl;
7083             int k;
7084 
7085             nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]);
7086             succdata = succdatas[s];
7087             assert( nodedata != NULL && succdata != NULL && nodedata->var != NULL );
7088             succvar = nodedata->var;
7089             solvalsucc = SCIPgetSolVal(scip, sol, succvar);
7090 
7091             /* determine coefficients for bound inequality */
7092             assert( ! SCIPisFeasZero(scip, solval) );
7093             if ( SCIPisFeasNegative(scip, solval) )
7094             {
7095                bound1lower = TRUE;
7096                bound1 = SCIPvarGetLbGlobal(var);
7097             }
7098             else
7099             {
7100                bound1lower = FALSE;
7101                bound1 = SCIPvarGetUbGlobal(var);
7102             }
7103 
7104             /* handle lower bound upper bound implications */
7105             for (k = 0; k < 2; ++k)
7106             {
7107                if ( k == 0 )
7108                {
7109                   SCIP_Real lbsucc;
7110                   lbsucc = SCIPvarGetLbGlobal(succvar);
7111                   if ( SCIPisFeasLT(scip, lbsucc, succdata->lbimpl) )
7112                   {
7113                      impl = succdata->lbimpl;
7114                      bound2 = lbsucc;
7115                   }
7116                   else
7117                      continue;
7118                }
7119                else
7120                {
7121                   SCIP_Real ubsucc;
7122                   ubsucc = SCIPvarGetUbGlobal(succvar);
7123                   if ( SCIPisFeasGT(scip, ubsucc, succdata->ubimpl) )
7124                   {
7125                      impl = succdata->ubimpl;
7126                      bound2 = ubsucc;
7127                   }
7128                   else
7129                      continue;
7130                }
7131 
7132                if ( SCIPisInfinity(scip, REALABS(bound1)) || SCIPisInfinity(scip, REALABS(bound2)) )
7133                   continue;
7134                assert( ! SCIPisInfinity(scip, REALABS(impl)) );
7135 
7136                if ( SCIPisFeasNegative(scip, bound2-impl) )
7137                   bound2lower = TRUE;
7138                else
7139                   bound2lower = FALSE;
7140 
7141                /* determine left/right hand side of bound inequality */
7142                lhsrhs = bound1 * bound2;
7143 
7144                /* create cut */
7145                if ( bound1lower == bound2lower )
7146                {
7147                   if ( SCIPisFeasGT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) )
7148                   {
7149                      SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &cut, conshdlr, "", -SCIPinfinity(scip), lhsrhs, FALSE, FALSE, TRUE) );
7150                   }
7151                   else
7152                      continue;
7153                }
7154                else
7155                {
7156                   if ( SCIPisFeasLT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) )
7157                   {
7158                      SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &cut, conshdlr, "", lhsrhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
7159                   }
7160                   else
7161                      continue;
7162                }
7163 
7164                /* add coefficients of variables */
7165                SCIP_CALL( SCIPcacheRowExtensions(scip, cut) );
7166                SCIP_CALL( SCIPaddVarToRow(scip, cut, var, bound2-impl) );
7167                SCIP_CALL( SCIPaddVarToRow(scip, cut, succvar, bound1) );
7168                SCIP_CALL( SCIPflushRowExtensions(scip, cut) );
7169 
7170                /* add cut if useful */
7171                if ( ! SCIProwIsInLP(cut) && SCIPisCutEfficacious(scip, NULL, cut) )
7172                {
7173                   SCIP_Bool infeasible;
7174                   SCIP_CALL( SCIPaddRow(scip, cut, FALSE, &infeasible) );
7175                   if ( infeasible )
7176                   {
7177                      genbreak = TRUE;
7178                      *cutoff = TRUE;
7179                      break;
7180                   }
7181                   SCIPdebug( SCIP_CALL( SCIPprintRow(scip, cut, NULL) ) );
7182 #ifdef SCIP_DEBUG
7183                   if ( k == 0 )
7184                   {
7185                      SCIPdebugMsg(scip, "added cut for implication %s != 0 -> %s >= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->lbimpl);
7186                   }
7187                   else
7188                   {
7189                      SCIPdebugMsg(scip, "added cut for implication %s != 0 -> %s <= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->ubimpl);
7190                   }
7191 #endif
7192 
7193                   ++(*ngen);
7194                }
7195 
7196                if ( maxcuts >= 0 && *ngen > maxcuts )
7197                {
7198                   genbreak = TRUE;
7199                   break;
7200                }
7201             }
7202 
7203             if ( cut != NULL )
7204                SCIP_CALL( SCIPreleaseRow(scip, &cut) );
7205          }
7206       }
7207    }
7208 
7209    return SCIP_OKAY;
7210 }
7211 
7212 
7213 /** separates SOS1 constraints for arbitrary solutions */
7214 static
separateSOS1(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_SOL * sol,int nconss,SCIP_CONS ** conss,SCIP_RESULT * result)7215 SCIP_RETCODE separateSOS1(
7216    SCIP*                 scip,               /**< SCIP pointer */
7217    SCIP_CONSHDLR*        conshdlr,           /**< constraint handler */
7218    SCIP_SOL*             sol,                /**< solution to be separated (or NULL) */
7219    int                   nconss,             /**< number of constraints */
7220    SCIP_CONS**           conss,              /**< SOS1 constraints */
7221    SCIP_RESULT*          result              /**< result */
7222    )
7223 {
7224    SCIP_CONSHDLRDATA* conshdlrdata;
7225    int depth;
7226 
7227    assert( scip != NULL );
7228    assert( conshdlr != NULL );
7229    assert( conss != NULL );
7230    assert( result != NULL );
7231 
7232    *result = SCIP_DIDNOTRUN;
7233 
7234    if ( nconss == 0 )
7235       return SCIP_OKAY;
7236 
7237    /* only separate cuts if we are not close to terminating */
7238    if( SCIPisStopped(scip) )
7239       return SCIP_OKAY;
7240 
7241    *result = SCIP_DIDNOTFIND;
7242 
7243    /* get constraint handler data */
7244    conshdlrdata = SCIPconshdlrGetData(conshdlr);
7245    assert( conshdlrdata != NULL );
7246 
7247    /* get node depth */
7248    depth = SCIPgetDepth(scip);
7249 
7250    /* separate bound (clique) inequalities */
7251    if ( conshdlrdata->boundcutsfreq >= 0 &&
7252       ( (conshdlrdata->boundcutsfreq == 0 && depth == 0) || (conshdlrdata->boundcutsfreq > 0 && depth % conshdlrdata->boundcutsfreq == 0)) )
7253    {
7254       int maxboundcuts;
7255       int ngen = 0;
7256 
7257       /* determine maximal number of cuts*/
7258       if ( depth == 0 )
7259          maxboundcuts = conshdlrdata->maxboundcutsroot;
7260       else
7261          maxboundcuts = conshdlrdata->maxboundcuts;
7262 
7263       if ( maxboundcuts >= 1 )
7264       {
7265          /* separate bound inequalities from SOS1 constraints */
7266          if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 )
7267          {
7268             SCIP_Bool cutoff;
7269 
7270             SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, sol, TRUE, maxboundcuts, &ngen, &cutoff) );
7271             if ( cutoff )
7272             {
7273                *result = SCIP_CUTOFF;
7274                return SCIP_OKAY;
7275             }
7276          }
7277 
7278          /* separate bound inequalities from the conflict graph */
7279          if( conshdlrdata->boundcutsfromgraph && ! conshdlrdata->switchcutsfromsos1 )
7280          {
7281             SCIP_Bool cutoff;
7282             SCIP_CALL( sepaBoundInequalitiesFromGraph(scip, conshdlr, conshdlrdata, sol, maxboundcuts, &ngen, &cutoff) );
7283             if ( cutoff )
7284             {
7285                *result = SCIP_CUTOFF;
7286                return SCIP_OKAY;
7287             }
7288          }
7289       }
7290 
7291       /* evaluate results */
7292       if ( ngen > 0 )
7293          *result = SCIP_SEPARATED;
7294       SCIPdebugMsg(scip, "Separated %d bound (clique) inequalities.\n", ngen);
7295    }
7296 
7297    /* separate implied bound inequalities */
7298    if ( conshdlrdata->implcutsfreq >= 0 &&
7299       ( (conshdlrdata->implcutsfreq == 0 && depth == 0) || (conshdlrdata->implcutsfreq > 0 && depth % conshdlrdata->implcutsfreq == 0)) )
7300    {
7301       int maximplcuts;
7302       int ngen = 0;
7303 
7304       /* determine maximal number of cuts*/
7305       if ( depth == 0 )
7306          maximplcuts = conshdlrdata->maximplcutsroot;
7307       else
7308          maximplcuts = conshdlrdata->maximplcuts;
7309 
7310       /* call separator for implied bound cuts */
7311       if ( maximplcuts >= 1 )
7312       {
7313          SCIP_Bool cutoff;
7314          SCIP_CALL( sepaImplBoundCutsSOS1(scip, conshdlr, conshdlrdata, sol, maximplcuts, &ngen, &cutoff) );
7315          if ( cutoff )
7316          {
7317             *result = SCIP_CUTOFF;
7318             return SCIP_OKAY;
7319          }
7320       }
7321 
7322       /* evaluate results */
7323       if ( ngen > 0 )
7324          *result = SCIP_SEPARATED;
7325       SCIPdebugMsg(scip, "Separated %d implied bound inequalities.\n", ngen);
7326    }
7327 
7328    return SCIP_OKAY;
7329 }
7330 
7331 
7332 /* -------------------------- heuristic methods --------------------------------*/
7333 
7334 /** gets weights determining an order of the variables in a heuristic for the maximum weighted independent set problem */
7335 static
getVectorOfWeights(SCIP * scip,SCIP_SOL * sol,SCIP_DIGRAPH * conflictgraph,int nsos1vars,SCIP_Bool * indicatorzero,SCIP_Real * weights)7336 SCIP_RETCODE getVectorOfWeights(
7337    SCIP*                 scip,               /**< SCIP pointer */
7338    SCIP_SOL*             sol,                /**< primal solution or NULL for current LP solution */
7339    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
7340    int                   nsos1vars,          /**< number of SOS1 variables */
7341    SCIP_Bool*            indicatorzero,      /**< vector that indicates which variables are currently fixed to zero */
7342    SCIP_Real*            weights             /**< pointer to store weights determining the order of the variables (length = nsos1vars) */
7343    )
7344 {
7345    SCIP_VAR* var;
7346    SCIP_Real val;
7347    SCIP_Real sum;
7348    int nviols;
7349    int* succ;
7350    int nsucc;
7351    int i;
7352    int j;
7353 
7354    assert( scip != NULL );
7355    assert( conflictgraph != NULL );
7356    assert( indicatorzero != NULL );
7357    assert( weights != NULL );
7358 
7359    for (i = 0; i < nsos1vars; ++i)
7360    {
7361       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
7362 
7363       if( nsucc == 0 || indicatorzero[i] )
7364          weights[i] = 0.0;
7365       else
7366       {
7367          var = SCIPnodeGetVarSOS1(conflictgraph, i);
7368          val = REALABS( SCIPgetSolVal(scip, sol, var) );
7369          if ( SCIPisFeasZero(scip, val) )
7370             weights[i] = 0.0;
7371          else
7372          {
7373             succ = SCIPdigraphGetSuccessors(conflictgraph, i);
7374 
7375             nviols = 0;
7376             sum = 0.0;
7377             for (j = 0; j < nsucc; ++j)
7378             {
7379                SCIP_Real valsucc;
7380 
7381                valsucc = REALABS( SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[j])) );
7382                if( ! SCIPisFeasZero(scip, valsucc) )
7383                {
7384                   sum += MIN(10E05, valsucc);
7385                   ++nviols;
7386                }
7387             }
7388 
7389             if ( nviols == 0 )
7390                weights[i] = 0.0;
7391             else
7392             {
7393                assert( SCIPisFeasPositive(scip, sum * (SCIP_Real)nviols));
7394                val = MIN(1e6, val);
7395                weights[i] = ( val + SCIPsumepsilon(scip) ) / ( sum * (SCIP_Real)nviols + SCIPsumepsilon(scip) );
7396             }
7397          }
7398       }
7399    }
7400 
7401    return SCIP_OKAY;
7402 }
7403 
7404 
7405 /* marks neighbors of a given node as not a member of the maximal independent set */
7406 static
markNeighborsMWISHeuristic(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_DIGRAPH * conflictgraph,int node,SCIP_Bool * mark,SCIP_Bool * indset,int * cnt,SCIP_Bool * cutoff)7407 SCIP_RETCODE markNeighborsMWISHeuristic(
7408    SCIP*                 scip,               /**< SCIP pointer */
7409    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
7410    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
7411    int                   node,               /**< node of the conflict graph */
7412    SCIP_Bool*            mark,               /**< indicator vector of processed nodes */
7413    SCIP_Bool*            indset,             /**< indicator vector of current independent */
7414    int*                  cnt,                /**< pointer to store number of marked nodes */
7415    SCIP_Bool*            cutoff              /**< pointer to store whether operation is infeasible */
7416    )
7417 {
7418    int nsucc;
7419    int* succ;
7420    int j;
7421 
7422    assert( scip != NULL );
7423    assert( conflictgraph != NULL );
7424    assert( mark != NULL );
7425    assert( indset != NULL );
7426    assert( cutoff != NULL );
7427    assert( cnt != NULL );
7428 
7429    *cutoff = FALSE;
7430 
7431    nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
7432    succ = SCIPdigraphGetSuccessors(conflictgraph, node);
7433 
7434    /* for all successors */
7435    for (j = 0; j < nsucc && !(*cutoff); ++j)
7436    {
7437       int succj;
7438 
7439       succj = succ[j];
7440       assert( indset[succj] == 0 );
7441       if( ! mark[succj] )
7442       {
7443          SCIP_VARSTATUS varstatus;
7444          SCIP_VAR* var;
7445 
7446          /* mark node as processed */
7447          mark[succj] = TRUE;
7448          ++(*cnt);
7449 
7450          /* get variable and variable status corresponding to successor node */
7451          var = SCIPnodeGetVarSOS1(conflictgraph, succj);
7452          varstatus = SCIPvarGetStatus(var);
7453 
7454          /* if variable is aggregated */
7455          if ( varstatus == SCIP_VARSTATUS_AGGREGATED )
7456          {
7457             int aggrnode;
7458 
7459             aggrnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetAggrVar(var));
7460 
7461             /* if aggregated variable is an SOS1 variable */
7462             if ( aggrnode >= 0 )
7463             {
7464                /* if aggregated variable is implied to be zero */
7465                if ( SCIPisFeasZero(scip, SCIPvarGetAggrConstant(var)) )
7466                {
7467                   if ( ! mark[aggrnode] )
7468                   {
7469                      mark[aggrnode] = TRUE;
7470                      ++(*cnt);
7471                   }
7472                   else if ( indset[aggrnode] == 1 )
7473                   {
7474                      *cutoff = TRUE;
7475                      return SCIP_OKAY;
7476                   }
7477                }
7478                else
7479                {
7480                   /* if aggregated variable is not already a member of the maximal independent set */
7481                   if ( indset[aggrnode] == 0 )
7482                   {
7483                      /* if variable is already marked */
7484                      if ( mark[aggrnode] )
7485                      {
7486                         *cutoff = TRUE;
7487                         return SCIP_OKAY;
7488                      }
7489                      else
7490                      {
7491                         indset[aggrnode] = 1;
7492                         mark[aggrnode] = TRUE;
7493                         ++(*cnt);
7494                      }
7495 
7496                      /* mark neighbors of aggregated variable */
7497                      SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, aggrnode, mark, indset, cnt, cutoff) );
7498                   }
7499                }
7500             }
7501          }
7502          else if ( varstatus == SCIP_VARSTATUS_NEGATED )
7503          {
7504             int negnode;
7505 
7506             negnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetNegationVar(var));
7507 
7508             /* if negated variable is an SOS1 variable */
7509             if ( negnode >= 0 )
7510             {
7511                if ( SCIPisFeasZero(scip, SCIPvarGetNegationConstant(var) ) )
7512                {
7513                   if ( indset[negnode] == 1 )
7514                   {
7515                      *cutoff = TRUE;
7516                      return SCIP_OKAY;
7517                   }
7518                   else if ( ! mark[negnode] )
7519                   {
7520                      mark[negnode] = TRUE;
7521                      ++(*cnt);
7522                   }
7523                }
7524             }
7525          }
7526       }
7527    }
7528 
7529    return SCIP_OKAY;
7530 }
7531 
7532 
7533 /** calls greedy algorithm for the maximum weighted independent set problem (MWIS)
7534  *
7535  * We compute a feasible solution to
7536  * \f[
7537  *  \begin{array}{ll}
7538  *  \min\limits_{z} & {x^*}^T z \\
7539  *                  & z_i + z_j \leq 1, \qquad (i,j)\in E \\
7540  *                  &       z_i \in  \{0,1\}, \qquad\quad  i\in V
7541  * \end{array}
7542  * \f]
7543  * by the algorithm GGWMIN of Shuichi Sakai, Mitsunori Togasaki and Koichi Yamazaki in "A note on greedy algorithms for the
7544  * maximum weighted independent set problem", Discrete Applied Mathematics. Here \f$x^*\f$ denotes the current LP
7545  * relaxation solution. Note that the solution of the MWIS is the indicator vector of an independent set.
7546  */
7547 static
maxWeightIndSetHeuristic(SCIP * scip,SCIP_SOL * sol,SCIP_CONSHDLR * conshdlr,SCIP_DIGRAPH * conflictgraph,int nsos1vars,SCIP_Bool * indicatorzero,SCIP_Bool * indset)7548 SCIP_RETCODE maxWeightIndSetHeuristic(
7549    SCIP*                 scip,               /**< SCIP pointer */
7550    SCIP_SOL*             sol,                /**< primal solution or NULL for current LP solution */
7551    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
7552    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
7553    int                   nsos1vars,          /**< number of SOS1 variables */
7554    SCIP_Bool*            indicatorzero,      /**< vector that indicates which variables are currently fixed to zero */
7555    SCIP_Bool*            indset              /**< pointer to store indicator vector of an independent set */
7556    )
7557 {
7558    SCIP_Bool* mark = NULL;
7559    SCIP_Real* weights = NULL;
7560    int* indscipvars = NULL;
7561    int ind;
7562    int nsucc;
7563    int i;
7564    int k;
7565 
7566    assert( scip != NULL );
7567    assert( conflictgraph != NULL );
7568    assert( indicatorzero != NULL );
7569    assert( indset != NULL );
7570 
7571    /* allocate buffer arrays */
7572    SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) );
7573    SCIP_CALL( SCIPallocBufferArray(scip, &weights, nsos1vars) );
7574    SCIP_CALL( SCIPallocBufferArray(scip, &indscipvars, nsos1vars) );
7575 
7576    /* sort SOS1 variables in nonincreasing order of weights */
7577    for (i = 0; i < nsos1vars; ++i)
7578       indscipvars[i] = i;
7579 
7580    SCIP_CALL( getVectorOfWeights(scip, sol, conflictgraph, nsos1vars, indicatorzero, weights) );
7581    SCIPsortDownRealInt(weights, indscipvars, nsos1vars);
7582 
7583    /* mark fixed variables and variables without any neighbors in the conflict graph */
7584    k = 0;
7585    for (i = 0; i < nsos1vars; ++i)
7586    {
7587       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
7588 
7589       if ( indset[i] == 0 )
7590       {
7591          if( indicatorzero[i] )
7592          {
7593             mark[i] = TRUE;
7594             ++k;
7595          }
7596          else if ( nsucc == 0 )
7597          {
7598             indset[i] = 1;
7599             mark[i] = TRUE;
7600             ++k;
7601          }
7602          else
7603             mark[i] = FALSE;
7604       }
7605       else
7606       {
7607          SCIP_Bool cutoff;
7608 
7609          ++k;
7610          mark[i] = TRUE;
7611 
7612          SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, i, mark, indset, &k, &cutoff) );
7613          assert( ! cutoff );
7614       }
7615    }
7616 
7617    /* mark vertices in the order of their largest weight */
7618    for (i = 0; k < nsos1vars; ++i) /*lint !e440*/
7619    {
7620       assert( i < nsos1vars );
7621 
7622       ind = indscipvars[i];
7623 
7624       if ( ! mark[ind] )
7625       {
7626          SCIP_Bool cutoff;
7627 
7628          /* mark ind */
7629          indset[ind] = 1;
7630          mark[ind] = TRUE;
7631          ++k;
7632 
7633          SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, ind, mark, indset, &k, &cutoff) );
7634          if ( cutoff )
7635             indset[ind] = 0;
7636       }
7637    }
7638    assert( k == nsos1vars );
7639 
7640    /* free buffer arrays */
7641    SCIPfreeBufferArrayNull(scip, &indscipvars);
7642    SCIPfreeBufferArrayNull(scip, &weights);
7643    SCIPfreeBufferArrayNull(scip, &mark);
7644 
7645    return SCIP_OKAY;
7646 }
7647 
7648 
7649 /** based on solution values of the variables, fixes variables of the conflict graph to zero to turn all SOS1 constraints feasible
7650  *
7651  *  if the SOS1 constraints do not overlap, the method makeSOS1constraintsFeasible() may be faster
7652  */
7653 static
makeSOS1conflictgraphFeasible(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_SOL * sol,SCIP_Bool * changed,SCIP_Bool * allroundable)7654 SCIP_RETCODE makeSOS1conflictgraphFeasible(
7655    SCIP*                 scip,               /**< SCIP pointer */
7656    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
7657    SCIP_SOL*             sol,                /**< solution */
7658    SCIP_Bool*            changed,            /**< pointer to store whether the solution has been changed */
7659    SCIP_Bool*            allroundable        /**< pointer to store whether all variables are roundable */
7660    )
7661 {
7662    SCIP_DIGRAPH* conflictgraph;  /* conflict graph for SOS1 constraints */
7663    SCIP_Bool* indicatorzero;     /* indicates which solution values are zero */
7664    SCIP_Bool* indset;            /* indicator vector of feasible solution; i.e., an independent set */
7665    int nsos1vars;
7666    int j;
7667 
7668    assert( scip != NULL );
7669    assert( conshdlr != NULL );
7670    assert( sol != NULL );
7671    assert( changed != NULL );
7672    assert( allroundable != NULL );
7673 
7674    *allroundable = TRUE;
7675    *changed = FALSE;
7676 
7677    /* get number of SOS1 variables */
7678    nsos1vars = SCIPgetNSOS1Vars(conshdlr);
7679    assert( nsos1vars >= 0 );
7680 
7681    /* get conflict graph */
7682    conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
7683    assert( conflictgraph != NULL );
7684 
7685    /* allocate buffer arrays */
7686    SCIP_CALL( SCIPallocBufferArray(scip, &indset, nsos1vars) );
7687    SCIP_CALL( SCIPallocBufferArray(scip, &indicatorzero, nsos1vars) );
7688 
7689    /* determine if variables with nonzero solution value are roundable */
7690    for (j = 0; j < nsos1vars; ++j)
7691    {
7692       SCIP_VAR* var;
7693       SCIP_Real lb;
7694       SCIP_Real ub;
7695 
7696       var = SCIPnodeGetVarSOS1(conflictgraph, j);
7697       lb = SCIPvarGetLbLocal(var);
7698       ub = SCIPvarGetUbLocal(var);
7699       indset[j] = 0;
7700 
7701       /* if solution value of variable is zero */
7702       if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) )
7703          indicatorzero[j] = TRUE;
7704       else
7705       {
7706          indicatorzero[j] = FALSE;
7707 
7708          /* if variable is not roundable */
7709          if ( ! SCIPvarMayRoundDown(var) && ! SCIPvarMayRoundUp(var) )
7710          {
7711             *allroundable = FALSE;
7712             break;
7713          }
7714 
7715          /* if bounds of variable are fixed to zero */
7716          if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) )
7717             indicatorzero[j] = TRUE;
7718          else if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) ) /* if variable is fixed to be nonzero */
7719             indset[j] = 1;
7720       }
7721    }
7722 
7723    /* return if at least one SOS1 variable is not roundable */
7724    if ( ! (*allroundable) )
7725    {
7726       SCIPfreeBufferArray(scip, &indicatorzero);
7727       SCIPfreeBufferArray(scip, &indset);
7728       return SCIP_OKAY;
7729    }
7730 
7731    /* call greedy algorithm for the maximum weighted independent set problem */
7732    SCIP_CALL( maxWeightIndSetHeuristic(scip, sol, conshdlr, conflictgraph, nsos1vars, indicatorzero, indset) );
7733 
7734    /* make solution feasible */
7735    for (j = 0; j < nsos1vars; ++j)
7736    {
7737       if ( indset[j] == 0 )
7738       {
7739          SCIP_CALL( SCIPsetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, j), 0.0) );
7740          *changed = TRUE;
7741       }
7742    }
7743 
7744    /* free buffer arrays */
7745    SCIPfreeBufferArray(scip, &indicatorzero);
7746    SCIPfreeBufferArray(scip, &indset);
7747 
7748 #ifdef SCIP_NDEBUG
7749    {
7750       SCIP_CONSDATA* consdata;
7751       SCIP_CONS** conss;
7752       int nconss;
7753       int c;
7754 
7755       conss = SCIPconshdlrGetConss(conshdlr);
7756       nconss = SCIPconshdlrGetNConss(conshdlr);
7757       for (c = 0; c < nconss; ++c)
7758       {
7759          int cnt = 0;
7760          consdata = SCIPconsGetData(conss[c]);
7761          assert( consdata != NULL );
7762 
7763          for (j = 0; j < consdata->nvars; ++j)
7764          {
7765             if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
7766             {
7767                ++cnt;
7768             }
7769          }
7770          assert( cnt < 2 );
7771       }
7772    }
7773 #endif
7774 
7775    return SCIP_OKAY;
7776 }
7777 
7778 
7779 /** based on solution values of the variables, fixes variables of the SOS1 constraints to zero to turn these constraints feasible
7780  *
7781  *  if the SOS1 constraints overlap, the method makeSOS1constraintsFeasible() may result in better primal solutions
7782  */
7783 static
makeSOS1constraintsFeasible(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_SOL * sol,SCIP_Bool * changed,SCIP_Bool * allroundable)7784 SCIP_RETCODE makeSOS1constraintsFeasible(
7785    SCIP*                 scip,               /**< SCIP pointer */
7786    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
7787    SCIP_SOL*             sol,                /**< solution */
7788    SCIP_Bool*            changed,            /**< pointer to store whether the solution has been changed */
7789    SCIP_Bool*            allroundable        /**< pointer to store whether all variables are roundable */
7790    )
7791 {
7792    SCIP_CONSDATA* consdata;
7793    SCIP_CONS** conss;
7794    int nconss;
7795    int c;
7796 
7797    assert( scip != NULL );
7798    assert( conshdlr != NULL );
7799    assert( sol != NULL );
7800    assert( changed != NULL );
7801    assert( allroundable != NULL );
7802 
7803    *allroundable = TRUE;
7804    *changed = FALSE;
7805 
7806    /* get SOS1 constraints and number of SOS1 constraints */
7807    conss = SCIPconshdlrGetConss(conshdlr);
7808    nconss = SCIPconshdlrGetNConss(conshdlr);
7809    assert( nconss > 0 );
7810 
7811    /* loop through all SOS1 constraints */
7812    for (c = 0; c < nconss && *allroundable; ++c)
7813    {
7814       SCIP_CONS* cons;
7815       SCIP_VAR** vars;
7816       SCIP_Bool varisfixed = FALSE;
7817       SCIP_Real maxval = 0.0;
7818       int pos = -1;
7819       int nvars;
7820       int j;
7821 
7822       cons = conss[c];
7823       assert( cons != NULL );
7824       consdata = SCIPconsGetData(cons);
7825       assert( consdata != NULL );
7826 
7827       nvars = consdata->nvars;
7828       vars = consdata->vars;
7829 
7830       /* search for maximum solution value */
7831       for (j = 0; j < nvars; ++j)
7832       {
7833          SCIP_VAR* var;
7834 
7835          var = vars[j];
7836 
7837          if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) )
7838          {
7839             SCIP_Real lb;
7840             SCIP_Real ub;
7841 
7842             lb = SCIPvarGetLbLocal(var);
7843             ub = SCIPvarGetUbLocal(var);
7844 
7845             /* if variable is not roundable */
7846             if ( ! SCIPvarMayRoundDown(var) && ! SCIPvarMayRoundUp(var) )
7847             {
7848                *allroundable = FALSE;
7849                break;
7850             }
7851 
7852             /* it is possible that the bounds were proagated to zero although the current solution value is nonzero
7853              * in this case fix the solution value to zero */
7854             if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) )
7855             {
7856                SCIP_CALL( SCIPsetSolVal(scip, sol, var, 0.0) );
7857                *changed = TRUE;
7858             }
7859             else if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) ) /* if variable is fixed to be nonzero */
7860             {
7861                assert( ! varisfixed );
7862                varisfixed = TRUE;
7863                maxval = SCIPgetSolVal(scip, sol, var);
7864                pos = j;
7865             }
7866             else if ( ! varisfixed && SCIPisFeasGT(scip, REALABS(SCIPgetSolVal(scip, sol, var)), REALABS(maxval)) ) /* search for variable with maximum solution value */
7867             {
7868                maxval = SCIPgetSolVal(scip, sol, var);
7869                pos = j;
7870             }
7871 
7872             /* fix variable to zero; the solution value of the variable with maximum solution value
7873              * will be restored in a later step */
7874             SCIP_CALL( SCIPsetSolVal(scip, sol, var, 0.0) );
7875             *changed = TRUE;
7876          }
7877       }
7878 
7879       if ( ! (*allroundable) )
7880          break;
7881       else if ( pos >= 0 ) /* restore solution of variable with maximum solution value */
7882       {
7883          SCIP_CALL( SCIPsetSolVal(scip, sol, vars[pos], maxval) );
7884       }
7885    }
7886 
7887 #ifdef SCIP_NDEBUG
7888    if ( *allroundable )
7889    {
7890       for (c = 0; c < nconss; ++c)
7891       {
7892          int cnt = 0;
7893          int j;
7894 
7895          consdata = SCIPconsGetData(conss[c]);
7896          assert( consdata != NULL );
7897 
7898          for (j = 0; j < consdata->nvars; ++j)
7899          {
7900             if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
7901             {
7902                ++cnt;
7903             }
7904          }
7905          assert( cnt < 2 );
7906       }
7907    }
7908 #endif
7909 
7910    return SCIP_OKAY;
7911 }
7912 
7913 
7914 /** determine a diving variables and boundchanges of diving variables by analyzing the conflict graph
7915  *
7916  *  if the SOS1 constraints do not overlap, the method getDiveBdChgsSOS1constraints() may be faster
7917  */
7918 static
getDiveBdChgsSOS1conflictgraph(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_DIVESET * diveset,SCIP_SOL * sol,SCIP_Bool * success)7919 SCIP_RETCODE getDiveBdChgsSOS1conflictgraph(
7920    SCIP*                 scip,               /**< SCIP pointer */
7921    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
7922    SCIP_DIVESET*         diveset,            /**< diving settings */
7923    SCIP_SOL*             sol,                /**< solution */
7924    SCIP_Bool*            success             /**< pointer to store */
7925    )
7926 {
7927    SCIP_DIGRAPH* conflictgraph;
7928    SCIP_VAR* bestvar = NULL;
7929    SCIP_Bool bestvarfixneigh = FALSE;
7930    SCIP_Real bestscore = SCIP_REAL_MIN;
7931    int bestnode = -1;
7932    int nsos1vars;
7933    int v;
7934 
7935    assert( scip != NULL );
7936    assert( conshdlr != NULL );
7937    assert( diveset != NULL );
7938    assert( success != NULL );
7939 
7940    *success = FALSE;
7941 
7942    /* get number of SOS1 variables */
7943    nsos1vars = SCIPgetNSOS1Vars(conshdlr);
7944 
7945    /* get conflict graph of SOS1 constraints */
7946    conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
7947 
7948    /* loop over SOS1 variables  */
7949    for (v = 0; v < nsos1vars; ++v)
7950    {
7951       /* check whether the variable violates an SOS1 constraint together with at least one other variable */
7952       if ( isViolatedSOS1(scip, conflictgraph, v, sol) )
7953       {
7954          SCIP_VAR* var;
7955          SCIP_Real solval;
7956          SCIP_Real score;
7957          SCIP_Real bound;
7958          SCIP_Real fracval;
7959          SCIP_Bool fixneigh;
7960 
7961          var = SCIPnodeGetVarSOS1(conflictgraph, v);
7962          solval = SCIPgetSolVal(scip, sol, var);
7963 
7964          /* compute (variable) bound of candidate */
7965          if ( SCIPisFeasNegative(scip, solval) )
7966             bound = nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, v);
7967          else
7968             bound = nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, v);
7969 
7970          /* ensure finiteness */
7971          bound = MIN(DIVINGCUTOFFVALUE, REALABS(bound)); /*lint !e666*/
7972          fracval = MIN(DIVINGCUTOFFVALUE, REALABS(solval)); /*lint !e666*/
7973          assert( ! SCIPisInfinity(scip, bound) );
7974          assert( ! SCIPisInfinity(scip, fracval) );
7975          assert( SCIPisPositive(scip, bound) );
7976 
7977          /* bound may have changed in propagation; ensure that fracval <= 1 */
7978          if ( SCIPisFeasLT(scip, bound, fracval) )
7979             bound = fracval;
7980 
7981          /* get fractionality of candidate */
7982          fracval /= (bound + SCIPsumepsilon(scip));
7983 
7984          /* should SOS1 variables be scored by the diving heuristics specific score function;
7985           *  otherwise use the score function of the SOS1 constraint handler */
7986          if ( SCIPdivesetSupportsType(diveset, SCIP_DIVETYPE_SOS1VARIABLE) )
7987          {
7988             SCIP_Bool roundup;
7989 
7990             SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_SOS1VARIABLE, var, solval, fracval,
7991                   &score, &roundup) );
7992 
7993             fixneigh = roundup;
7994             if ( SCIPisFeasNegative(scip, solval) )
7995                fixneigh = !fixneigh;
7996          }
7997          else
7998          {
7999             /* we always fix the candidates neighbors in the conflict graph to zero */
8000             fixneigh = TRUE;
8001 
8002             /* score fractionality of candidate */
8003             score = fracval;
8004          }
8005 
8006          /* best candidate maximizes the score */
8007          if ( score > bestscore )
8008          {
8009             bestscore = score;
8010 
8011             *success = TRUE;
8012             bestvar = var;
8013             bestnode = v;
8014             bestvarfixneigh = fixneigh;
8015          }
8016       }
8017    }
8018    assert( !(*success) || bestvar != NULL );
8019 
8020    if ( *success )
8021    {
8022       int* succ;
8023       int nsucc;
8024       int s;
8025 
8026       assert( bestnode >= 0 && bestnode < nsos1vars );
8027 
8028       nsucc = SCIPdigraphGetNSuccessors(conflictgraph, bestnode);
8029       succ = SCIPdigraphGetSuccessors(conflictgraph, bestnode);
8030 
8031       /* if the diving score voted for fixing the best variable to 0.0, we add this as the preferred bound change;
8032        * otherwise, fixing the neighbors in the conflict graph to 0.0 is the preferred bound change.
8033        */
8034       assert( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(bestvar)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(bestvar)) );
8035       SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_FIXED, 0.0, !bestvarfixneigh) );
8036       for (s = 0; s < nsucc; ++s)
8037       {
8038          SCIP_VAR* var;
8039 
8040          var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
8041 
8042          /* if variable is not already fixed */
8043          if ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var)) )
8044          {
8045             SCIP_CALL( SCIPaddDiveBoundChange(scip, var, SCIP_BRANCHDIR_FIXED, 0.0, bestvarfixneigh) );
8046          }
8047       }
8048    }
8049 
8050    return SCIP_OKAY;
8051 }
8052 
8053 
8054 /** determine a diving variables and boundchanges of diving variables by analyzing the SOS1 constraints
8055  *
8056  *  if the SOS1 constraints overlap, the method getDiveBdChgsSOS1conflictgraph() may produce better results (e.g., due to more
8057  *  diving candidates)
8058  */
8059 static
getDiveBdChgsSOS1constraints(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_DIVESET * diveset,SCIP_SOL * sol,SCIP_Bool * success)8060 SCIP_RETCODE getDiveBdChgsSOS1constraints(
8061    SCIP*                 scip,               /**< SCIP pointer */
8062    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
8063    SCIP_DIVESET*         diveset,            /**< diving settings */
8064    SCIP_SOL*             sol,                /**< solution */
8065    SCIP_Bool*            success             /**< pointer to store */
8066    )
8067 {
8068    SCIP_VAR* bestvar = NULL;
8069    SCIP_Bool bestvarfixcomp = FALSE;
8070    SCIP_Real bestscore = SCIP_REAL_MIN;
8071    SCIP_CONSDATA* consdata;
8072    SCIP_CONS** conss;
8073    int nconss;
8074    int bestcons = -1;
8075    int c;
8076 
8077    assert( scip != NULL );
8078    assert( conshdlr != NULL );
8079    assert( diveset != NULL );
8080    assert( success != NULL );
8081 
8082    *success = FALSE;
8083 
8084    /* get SOS1 constraints and number of SOS1 constraints */
8085    conss = SCIPconshdlrGetConss(conshdlr);
8086    nconss = SCIPconshdlrGetNConss(conshdlr);
8087 
8088    /* loop through all SOS1 constraints */
8089    for (c = 0; c < nconss; ++c)
8090    {
8091       SCIP_VAR** vars;
8092       int nvars;
8093       int cnt = 0;
8094       int j;
8095 
8096       consdata = SCIPconsGetData(conss[c]);
8097       assert( consdata != NULL );
8098 
8099       nvars = consdata->nvars;
8100       vars = consdata->vars;
8101 
8102       /* check whether SOS1 constraint is violated */
8103       for (j = 0; j < nvars && cnt < 2; ++j)
8104       {
8105          SCIP_VAR* var;
8106 
8107          var = vars[j];
8108 
8109          /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */
8110          if ( !SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var))
8111                && (!SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || !SCIPisFeasZero(scip, SCIPvarGetUbLocal(var))) )
8112             ++cnt;
8113       }
8114 
8115       /* if SOS1 constraint is not violated then continue with the next SOS1 constraint */
8116       if ( cnt < 2 )
8117          continue;
8118 
8119       /* get diving score of every variable in constraint */
8120       for (j = 0; j < nvars; ++j)
8121       {
8122          SCIP_VAR* var;
8123          SCIP_Real solval;
8124          SCIP_Real score;
8125          SCIP_Real bound;
8126          SCIP_Real fracval;
8127          SCIP_Real lb;
8128          SCIP_Real ub;
8129          SCIP_Bool fixcomp;  /* whether to fix the complementary variables of the candidate in the SOS1 constraint to zero */
8130 
8131          var = vars[j];
8132          solval = SCIPgetSolVal(scip, sol, var);
8133          lb = SCIPvarGetLbLocal(var);
8134          ub = SCIPvarGetUbLocal(var);
8135 
8136          /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */
8137          if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, lb) || ! SCIPisFeasZero(scip, ub) ) )
8138          {
8139             /* compute (variable) bound of candidate */
8140             if ( SCIPisFeasNegative(scip, solval) )
8141                bound = lb;
8142             else
8143                bound = ub;
8144 
8145             /* bound may have changed in propagation; ensure that fracval <= 1 */
8146             if ( SCIPisFeasLT(scip, REALABS(bound), REALABS(solval)) )
8147                bound = solval;
8148 
8149             /* ensure finiteness */
8150             bound = MIN(DIVINGCUTOFFVALUE, REALABS(bound)); /*lint !e666*/
8151             fracval = MIN(DIVINGCUTOFFVALUE, REALABS(solval)); /*lint !e666*/
8152             assert( ! SCIPisInfinity(scip, bound) );
8153             assert( ! SCIPisInfinity(scip, fracval) );
8154             assert( SCIPisPositive(scip, bound) );
8155 
8156             /* get fractionality of candidate */
8157             fracval /= (bound + SCIPsumepsilon(scip));
8158 
8159             /* should SOS1 variables be scored by the diving heuristics specific score function;
8160              *  otherwise use the score function of the SOS1 constraint handler
8161              */
8162             if ( SCIPdivesetSupportsType(diveset, SCIP_DIVETYPE_SOS1VARIABLE) )
8163             {
8164                SCIP_Bool roundup;
8165 
8166                SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_SOS1VARIABLE, var, solval, fracval,
8167                 &score, &roundup) );
8168 
8169                fixcomp = roundup;
8170                if ( SCIPisFeasNegative(scip, solval) )
8171                   fixcomp = !fixcomp;
8172             }
8173             else
8174             {
8175                /* we always fix the complementary variables of the candidate in the SOS1 constraint to zero */
8176                fixcomp = TRUE;
8177 
8178                /* score fractionality of candidate */
8179                score = fracval;
8180             }
8181 
8182             /* best candidate maximizes the score */
8183             if ( score > bestscore )
8184             {
8185                bestscore = score;
8186 
8187                *success = TRUE;
8188                bestvar = var;
8189                bestcons = c;
8190                bestvarfixcomp = fixcomp;
8191             }
8192          }
8193       }
8194    }
8195    assert( !(*success) || bestvar != NULL );
8196 
8197    if ( *success )
8198    {
8199       SCIP_VAR** vars;
8200       int nvars;
8201       int j;
8202 
8203       consdata = SCIPconsGetData(conss[bestcons]);
8204       assert( consdata != NULL );
8205 
8206       nvars = consdata->nvars;
8207       vars = consdata->vars;
8208 
8209       assert( bestcons >= 0 && bestcons < nconss );
8210 
8211       /* if the diving score voted for fixing the best variable to 0.0, we add this as the preferred bound change;
8212        * otherwise, fixing the complementary variables of the candidate in the SOS1 constraint to 0.0 is the preferred bound change.
8213        */
8214       assert( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(bestvar)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(bestvar)) );
8215 
8216       SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_FIXED, 0.0, !bestvarfixcomp) );
8217       for (j = 0; j < nvars; ++j)
8218       {
8219          SCIP_VAR* var;
8220 
8221          var = vars[j];
8222 
8223          /* if variable is not already fixed and is not the candidate variable */
8224          if ( var != bestvar && ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var)) ) )
8225          {
8226             SCIP_CALL( SCIPaddDiveBoundChange(scip, var, SCIP_BRANCHDIR_FIXED, 0.0, bestvarfixcomp) );
8227          }
8228       }
8229    }
8230 
8231    return SCIP_OKAY;
8232 }
8233 
8234 
8235 /* --------------------initialization/deinitialization ------------------------*/
8236 
8237 /** check whether \f$x_1\f$ is a bound variable of \f$x_0\f$; i.e., \f$x_0 \leq c\cdot x_1\f$ or \f$x_0 \geq d\cdot x_1\f$
8238  *  for positive values \f$c, d\f$. If true, then add this information to the node data of the conflict graph.
8239  */
8240 static
detectVarboundSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var0,SCIP_VAR * var1,SCIP_Real val0,SCIP_Real val1)8241 SCIP_RETCODE detectVarboundSOS1(
8242    SCIP*                 scip,               /**< SCIP pointer */
8243    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< SOS1 constraint handler data */
8244    SCIP_VAR*             var0,               /**< first variable */
8245    SCIP_VAR*             var1,               /**< second variable */
8246    SCIP_Real             val0,               /**< first coefficient */
8247    SCIP_Real             val1                /**< second coefficient */
8248    )
8249 {
8250    int node0;
8251 
8252    assert( scip != NULL );
8253    assert( conshdlrdata != NULL );
8254    assert( var0 != NULL && var1 != NULL );
8255 
8256    /* get nodes of variable in the conflict graph (node = -1 if no SOS1 variable) */
8257    node0 = varGetNodeSOS1(conshdlrdata, var0);
8258 
8259    /* if var0 is an SOS1 variable */
8260    if ( node0 >= 0 )
8261    {
8262       SCIP_Real val;
8263 
8264       assert( ! SCIPisFeasZero(scip, val0) );
8265       val = -val1/val0;
8266 
8267       /* check variable bound relation of variables */
8268 
8269       /* handle lower bound case */
8270       if ( SCIPisFeasNegative(scip, val0) && SCIPisFeasNegative(scip, val) )
8271       {
8272          SCIP_NODEDATA* nodedata;
8273 
8274          /* get node data of the conflict graph */
8275          nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0);
8276 
8277          /* @todo: maybe save multiple variable bounds for each SOS1 variable */
8278          if ( nodedata->lbboundvar == NULL )
8279          {
8280             /* add variable bound information to node data */
8281             nodedata->lbboundvar = var1;
8282             nodedata->lbboundcoef = val;
8283 
8284             SCIPdebugMsg(scip, "detected variable bound constraint %s >= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1));
8285          }
8286       }
8287       /* handle upper bound case */
8288       else if ( SCIPisFeasPositive(scip, val0) && SCIPisFeasPositive(scip, val) )
8289       {
8290          SCIP_NODEDATA* nodedata;
8291          assert( SCIPisFeasPositive(scip, val0) );
8292 
8293          /* get node data of the conflict graph */
8294          nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0);
8295 
8296          if ( nodedata->ubboundvar == NULL )
8297          {
8298             /* add variable bound information to node data */
8299             nodedata->ubboundvar = var1;
8300             nodedata->ubboundcoef = val;
8301 
8302             SCIPdebugMsg(scip, "detected variable bound constraint %s <= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1));
8303          }
8304       }
8305    }
8306 
8307    return SCIP_OKAY;
8308 }
8309 
8310 
8311 /** pass connected component \f$C\f$ of the conflict graph and check whether all the variables correspond to a unique variable upper bound variable \f$z\f$,
8312  *  i.e., \f$x_i \leq u_i z\f$ for every \f$i\in C\f$.
8313  *
8314  *  @note if the bound variable is unique, then bound inequalities can be strengthened.
8315  */
8316 static
passConComponentVarbound(SCIP * scip,SCIP_DIGRAPH * conflictgraph,int node,SCIP_VAR * boundvar,SCIP_Bool checklb,SCIP_Bool * processed,int * concomp,int * nconcomp,SCIP_Bool * unique)8317 SCIP_RETCODE passConComponentVarbound(
8318    SCIP*                 scip,               /**< SCIP pointer */
8319    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
8320    int                   node,               /**< current node of connected component */
8321    SCIP_VAR*             boundvar,           /**< bound variable of connected component */
8322    SCIP_Bool             checklb,            /**< whether to check lower bound variable (else upper bound variable) */
8323    SCIP_Bool*            processed,          /**< states for each variable whether it has been processed */
8324    int*                  concomp,            /**< current connected component */
8325    int*                  nconcomp,           /**< pointer to store number of elements of connected component */
8326    SCIP_Bool*            unique              /**< pointer to store whether bound variable is unique */
8327    )
8328 {
8329    int* succ;
8330    int nsucc;
8331    int s;
8332 
8333    assert( scip != NULL );
8334    assert( conflictgraph != NULL );
8335    assert( processed != NULL );
8336    assert( concomp != NULL );
8337    assert( nconcomp != NULL );
8338    assert( unique != NULL );
8339 
8340    processed[node] = TRUE;/*lint !e737*/
8341    concomp[(*nconcomp)++] = node;
8342 
8343    /* if bound variable of connected component without new node is unique */
8344    if ( *unique )
8345    {
8346       SCIP_NODEDATA* nodedata;
8347       SCIP_VAR* comparevar;
8348       nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
8349       assert( nodedata != NULL );
8350 
8351       if ( checklb )
8352          comparevar = nodedata->lbboundvar;
8353       else
8354          comparevar = nodedata->ubboundvar;
8355 
8356       /* check whether bound variable is unique for connected component without new node */
8357       if ( boundvar == NULL )
8358       {
8359          if ( comparevar != NULL )
8360             *unique = FALSE;
8361       }
8362       else
8363       {
8364          if ( comparevar == NULL )
8365             *unique = FALSE;
8366          else if ( SCIPvarCompare(boundvar, comparevar) != 0 )
8367             *unique = FALSE;
8368       }
8369    }
8370 
8371    /* pass through successor variables */
8372    nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
8373    succ = SCIPdigraphGetSuccessors(conflictgraph, node);
8374    for (s = 0; s < nsucc; ++s)
8375    {
8376       if ( ! processed[succ[s]] )
8377          SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, nconcomp, unique) );
8378    }
8379 
8380    return SCIP_OKAY;
8381 }
8382 
8383 
8384 /** for each connected component \f$C\f$ of the conflict graph check whether all the variables correspond to a unique variable upper bound variable \f$z\f$
8385  *  (e.g., for the upper bound case this means that \f$x_i \leq u_i z\f$ for every \f$i\in C\f$).
8386  *
8387  *  @note if the bound variable is unique, then bound inequalities can be strengthened.
8388  */
8389 static
checkConComponentsVarbound(SCIP * scip,SCIP_DIGRAPH * conflictgraph,int nsos1vars,SCIP_Bool checklb)8390 SCIP_RETCODE checkConComponentsVarbound(
8391    SCIP*                 scip,               /**< SCIP pointer */
8392    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
8393    int                   nsos1vars,          /**< number of SOS1 variables */
8394    SCIP_Bool             checklb             /**< whether to check lower bound variable (else check upper bound variable) */
8395    )
8396 {
8397    SCIP_Bool* processed;  /* states for each variable whether it has been processed */
8398    int* concomp;          /* current connected component */
8399    int nconcomp;
8400    int j;
8401 
8402    assert( scip != NULL );
8403    assert( conflictgraph != NULL );
8404 
8405    /* allocate buffer arrays and initialize 'processed' array */
8406    SCIP_CALL( SCIPallocBufferArray(scip, &processed, nsos1vars) );
8407    SCIP_CALL( SCIPallocBufferArray(scip, &concomp, nsos1vars) );
8408    for (j = 0; j < nsos1vars; ++j)
8409       processed[j] = FALSE;
8410 
8411    /* run through all SOS1 variables */
8412    for (j = 0; j < nsos1vars; ++j)
8413    {
8414       /* if variable belongs to a connected component that has not been processed so far */
8415       if ( ! processed[j] )
8416       {
8417          SCIP_NODEDATA* nodedata;
8418          SCIP_VAR* boundvar;
8419          SCIP_Bool unique;
8420          int* succ;
8421          int nsucc;
8422          int s;
8423 
8424          nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, j);
8425          assert( nodedata != NULL );
8426 
8427          if ( checklb )
8428             boundvar = nodedata->lbboundvar;
8429          else
8430             boundvar = nodedata->ubboundvar;
8431          unique = TRUE;
8432 
8433          processed[j] = TRUE;
8434          concomp[0] = j;
8435          nconcomp = 1;
8436 
8437          /* pass through successor variables */
8438          nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
8439          succ = SCIPdigraphGetSuccessors(conflictgraph, j);
8440          for (s = 0; s < nsucc; ++s)
8441          {
8442             if ( ! processed[succ[s]] )
8443             {
8444                SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, &nconcomp, &unique) );
8445             }
8446          }
8447 
8448          /* if the connected component has a unique bound variable */
8449          if ( unique && boundvar != NULL )
8450          {
8451             for (s = 0; s < nconcomp; ++s)
8452             {
8453                nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, concomp[s]);
8454                assert( processed[concomp[s]] == TRUE );
8455                assert( nodedata != NULL );
8456 
8457                if ( checklb )
8458                   nodedata->lbboundcomp = TRUE;
8459                else
8460                   nodedata->ubboundcomp = TRUE;
8461             }
8462             SCIPdebugMsg(scip, "Found a connected component of size <%i> with unique bound variable.\n", nconcomp);
8463          }
8464       }
8465    }
8466 
8467    /* free buffer arrays */
8468    SCIPfreeBufferArray(scip, &concomp);
8469    SCIPfreeBufferArray(scip, &processed);
8470 
8471    return SCIP_OKAY;
8472 }
8473 
8474 
8475 /** check all linear constraints for variable bound constraints of the form \f$c\cdot z \leq x \leq d\cdot z\f$, where @p x is some SOS1
8476  *  variable and @p z is some arbitrary variable (not necessarily binary)
8477  */
8478 static
checkLinearConssVarboundSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONS ** linconss,int nlinconss)8479 SCIP_RETCODE checkLinearConssVarboundSOS1(
8480    SCIP*                 scip,               /**< SCIP pointer */
8481    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< SOS1 constraint handler data */
8482    SCIP_CONS**           linconss,           /**< linear constraints */
8483    int                   nlinconss           /**< number of linear constraints */
8484    )
8485 {
8486    int c;
8487 
8488    /* loop through linear constraints */
8489    for (c = 0; c < nlinconss; ++c)
8490    {
8491       SCIP_CONS* lincons;
8492       int nvars;
8493 
8494       lincons = linconss[c];
8495 
8496       /* variable bound constraints only contain two variables */
8497       nvars = SCIPgetNVarsLinear(scip, lincons);
8498       if ( nvars == 2 )
8499       {
8500          SCIP_VAR** vars;
8501          SCIP_Real* vals;
8502          SCIP_VAR* var0;
8503          SCIP_VAR* var1;
8504          SCIP_Real lhs;
8505          SCIP_Real rhs;
8506 
8507          /* get constraint data */
8508          vars = SCIPgetVarsLinear(scip, lincons);
8509          vals = SCIPgetValsLinear(scip, lincons);
8510          lhs = SCIPgetLhsLinear(scip, lincons);
8511          rhs = SCIPgetRhsLinear(scip, lincons);
8512 
8513          var0 = vars[0];
8514          var1 = vars[1];
8515          assert( var0 != NULL && var1 != NULL );
8516 
8517          /* at least one variable should be an SOS1 variable */
8518          if ( varIsSOS1(conshdlrdata, var0) || varIsSOS1(conshdlrdata, var1) )
8519          {
8520             SCIP_Real val0;
8521             SCIP_Real val1;
8522 
8523             /* check whether right hand side or left hand side of constraint is zero */
8524             if ( SCIPisFeasZero(scip, lhs) )
8525             {
8526                val0 = -vals[0];
8527                val1 = -vals[1];
8528 
8529                /* check whether the two variables are in a variable bound relation */
8530                SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) );
8531                SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) );
8532             }
8533             else if( SCIPisFeasZero(scip, rhs) )
8534             {
8535                val0 = vals[0];
8536                val1 = vals[1];
8537 
8538                /* check whether the two variables are in a variable bound relation */
8539                SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) );
8540                SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) );
8541             }
8542          }
8543       }
8544    }
8545 
8546    return SCIP_OKAY;
8547 }
8548 
8549 
8550 /** switch to SOS1 branching and separating bound iniqualities from SOS1 constraints if the SOS1 constraints do not overlap */
8551 static
checkSwitchNonoverlappingSOS1Methods(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DIGRAPH * conflictgraph,SCIP_CONS ** conss,int nconss)8552 SCIP_RETCODE checkSwitchNonoverlappingSOS1Methods(
8553    SCIP*                 scip,               /**< SCIP pointer */
8554    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< SOS1 constraint handler data */
8555    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
8556    SCIP_CONS**           conss,              /**< SOS1 constraints */
8557    int                   nconss              /**< number of SOS1 constraints */
8558    )
8559 {
8560    SCIP_Bool nonoverlap = TRUE;
8561    int c;
8562 
8563    /* loop through all SOS1 constraints */
8564    if ( conshdlrdata->nsos1vars > 0 )
8565    {
8566       for (c = 0; c < nconss && nonoverlap; ++c)
8567       {
8568          SCIP_CONSDATA* consdata;
8569          SCIP_VAR** vars;
8570          int notfixed = 0;
8571          int nvars;
8572          int i;
8573 
8574          assert( conss[c] != NULL );
8575 
8576          /* get constraint data field of the constraint */
8577          consdata = SCIPconsGetData(conss[c]);
8578          assert( consdata != NULL );
8579 
8580          /* get variables and number of variables of constraint */
8581          nvars = consdata->nvars;
8582          vars = consdata->vars;
8583 
8584          /* get number of variables of SOS1 constraint that are not fixed to zero */
8585          for (i = 0; i < nvars; ++i)
8586          {
8587             if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i])) )
8588                ++notfixed;
8589          }
8590 
8591          /* check variables of SOS1 constraint */
8592          for (i = 0; i < nvars; ++i)
8593          {
8594             int node;
8595 
8596             assert( vars[i] != NULL );
8597 
8598             node = varGetNodeSOS1(conshdlrdata, vars[i]);
8599             assert( node >= 0 || ( SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) && SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i]))) );
8600             assert( node < conshdlrdata->nsos1vars );
8601             assert( node < 0 || SCIPdigraphGetNSuccessors(conflictgraph, node) >= notfixed-1 );
8602             if ( node >= 0 && SCIPdigraphGetNSuccessors(conflictgraph, node) > notfixed-1 )
8603             {
8604                nonoverlap = FALSE;
8605                break;
8606             }
8607          }
8608       }
8609    }
8610 
8611    /* if the SOS1 constraints do not overlap */
8612    if ( nonoverlap )
8613    {
8614       if ( conshdlrdata->autosos1branch )
8615       {
8616          conshdlrdata->switchsos1branch = TRUE;
8617          SCIPdebugMsg(scip, "Switched to SOS1 branching, since the SOS1 constraints do not overlap\n");
8618       }
8619 
8620       if ( conshdlrdata->autocutsfromsos1 )
8621       {
8622          conshdlrdata->switchcutsfromsos1 = TRUE;
8623          SCIPdebugMsg(scip, "Switched to separating bound cuts from SOS1 constraints (and not from the conflict graph), since the SOS1 constraints do not overlap\n");
8624       }
8625    }
8626 
8627    return SCIP_OKAY;
8628 }
8629 
8630 
8631 /** sets node data of conflict graph nodes */
8632 static
computeNodeDataSOS1(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,int nsos1vars)8633 SCIP_RETCODE computeNodeDataSOS1(
8634    SCIP*                 scip,               /**< SCIP pointer */
8635    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< SOS1 constraint handler data */
8636    int                   nsos1vars           /**< number of SOS1 variables */
8637    )
8638 {
8639    SCIP_CONSHDLR* linconshdlr;
8640    SCIP_CONS** linconss;
8641    int nlinconss;
8642 
8643    /* if no SOS1 variables exist -> exit */
8644    if ( nsos1vars == 0 )
8645       return SCIP_OKAY;
8646 
8647    /* get constraint handler data of linear constraints */
8648    linconshdlr = SCIPfindConshdlr(scip, "linear");
8649    if ( linconshdlr == NULL )
8650       return SCIP_OKAY;
8651 
8652    /* get linear constraints and number of linear constraints */
8653    nlinconss = SCIPconshdlrGetNConss(linconshdlr);
8654    linconss = SCIPconshdlrGetConss(linconshdlr);
8655 
8656    /* check linear constraints for variable bound constraints */
8657    SCIP_CALL( checkLinearConssVarboundSOS1(scip, conshdlrdata, linconss, nlinconss) );
8658 
8659    /* for each connected component of the conflict graph check whether all the variables correspond to a unique variable
8660     * upper bound variable */
8661    SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, TRUE) );
8662    SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, FALSE) );
8663 
8664    return SCIP_OKAY;
8665 }
8666 
8667 
8668 /** initialize conflictgraph and create hashmap for SOS1 variables */
8669 static
initConflictgraph(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONS ** conss,int nconss)8670 SCIP_RETCODE initConflictgraph(
8671    SCIP*                 scip,               /**< SCIP pointer */
8672    SCIP_CONSHDLRDATA*    conshdlrdata,       /**< constraint handler data */
8673    SCIP_CONS**           conss,              /**< SOS1 constraints */
8674    int                   nconss              /**< number of SOS1 constraints */
8675    )
8676 {
8677    SCIP_Bool* nodecreated; /* nodecreated[i] = TRUE if a node in the conflict graph is already created for index i
8678                             * (with i index of the original variables) */
8679    int* nodeorig;          /* nodeorig[i] = node of original variable x_i in the conflict graph */
8680    int ntotalvars;
8681    int cntsos;
8682    int i;
8683    int j;
8684    int c;
8685 
8686    assert( conshdlrdata != NULL );
8687    assert( nconss == 0 || conss != NULL );
8688 
8689    /* get the number of original problem variables */
8690    ntotalvars = SCIPgetNTotalVars(scip);
8691 
8692    /* initialize vector 'nodecreated' */
8693    SCIP_CALL( SCIPallocBufferArray(scip, &nodeorig, ntotalvars) );
8694    SCIP_CALL( SCIPallocBufferArray(scip, &nodecreated, ntotalvars) );
8695    for (i = 0; i < ntotalvars; ++i)
8696       nodecreated[i] = FALSE;
8697 
8698    /* compute number of SOS1 variables */
8699    cntsos = 0;
8700    for (c = 0; c < nconss; ++c)
8701    {
8702       SCIP_CONSDATA* consdata;
8703       SCIP_VAR** vars;
8704       int nvars;
8705 
8706       assert( conss[c] != NULL );
8707 
8708       /* get constraint data field of the constraint */
8709       consdata = SCIPconsGetData(conss[c]);
8710       assert( consdata != NULL );
8711 
8712       /* get variables and number of variables of constraint */
8713       nvars = consdata->nvars;
8714       vars = consdata->vars;
8715 
8716       /* update number of SOS1 variables */
8717       for (i = 0; i < nvars; ++i)
8718       {
8719          SCIP_VAR* var;
8720 
8721          var = vars[i];
8722 
8723          /* if the variable is not fixed to zero */
8724          if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
8725          {
8726             int ind;
8727 
8728             ind = SCIPvarGetIndex(var);
8729             assert( ind >= 0 && ind < ntotalvars );
8730             if ( ! nodecreated[ind] )
8731             {
8732                nodecreated[ind] = TRUE; /* mark node as counted */
8733                nodeorig[ind] = cntsos;
8734                ++cntsos;
8735             }
8736          }
8737       }
8738    }
8739    if ( cntsos <= 0 )
8740    {
8741       /* free buffer arrays */
8742       SCIPfreeBufferArray(scip, &nodecreated);
8743       SCIPfreeBufferArray(scip, &nodeorig);
8744       conshdlrdata->nsos1vars = 0;
8745       return SCIP_OKAY;
8746    }
8747 
8748    /* reinitialize vector 'nodecreated' */
8749    for (i = 0; i < ntotalvars; ++i)
8750       nodecreated[i] = FALSE;
8751 
8752    /* create conflict graph */
8753    SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->conflictgraph, cntsos) );
8754 
8755    /* set up hash map */
8756    SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), cntsos) );
8757 
8758    /* for every SOS1 constraint */
8759    cntsos = 0;
8760    for (c = 0; c < nconss; ++c)
8761    {
8762       SCIP_CONSDATA* consdata;
8763       SCIP_VAR** vars;
8764       int nvars;
8765 
8766       assert( conss[c] != NULL );
8767 
8768       /* get constraint data field of the constraint */
8769       consdata = SCIPconsGetData(conss[c]);
8770       assert( consdata != NULL );
8771 
8772       /* get variables and number of variables of constraint */
8773       nvars = consdata->nvars;
8774       vars = consdata->vars;
8775 
8776       /* add edges to the conflict graph and create node data for each of its nodes */
8777       for (i = 0; i < nvars; ++i)
8778       {
8779          SCIP_VAR* var;
8780 
8781          var = vars[i];
8782 
8783          /* if the variable is not fixed to zero */
8784          if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
8785          {
8786             int indi;
8787 
8788             indi = SCIPvarGetIndex(var);
8789 
8790             if ( ! nodecreated[indi] )
8791             {
8792                SCIP_NODEDATA* nodedata = NULL;
8793 
8794                /* insert node number to hash map */
8795                assert( ! SCIPhashmapExists(conshdlrdata->varhash, var) );
8796                SCIP_CALL( SCIPhashmapInsertInt(conshdlrdata->varhash, var, cntsos) );
8797                assert( cntsos == SCIPhashmapGetImageInt(conshdlrdata->varhash, var) );
8798                assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
8799 
8800                /* create node data */
8801                SCIP_CALL( SCIPallocBlockMemory(scip, &nodedata) );
8802                nodedata->var = var;
8803                nodedata->lbboundvar = NULL;
8804                nodedata->ubboundvar = NULL;
8805                nodedata->lbboundcoef = 0.0;
8806                nodedata->ubboundcoef = 0.0;
8807                nodedata->lbboundcomp = FALSE;
8808                nodedata->ubboundcomp = FALSE;
8809 
8810                /* set node data */
8811                SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, (void*)nodedata, cntsos);
8812 
8813                /* mark node and var data of node as created and update SOS1 counter */
8814                nodecreated[indi] = TRUE;
8815                ++cntsos;
8816             }
8817 
8818             /* add edges to the conflict graph */
8819             for (j = i+1; j < nvars; ++j)
8820             {
8821                var = vars[j];
8822 
8823                /* if the variable is not fixed to zero */
8824                if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
8825                {
8826                   int indj;
8827 
8828                   indj = SCIPvarGetIndex(var);
8829 
8830                   /* in case indi = indj the variable will be deleted in the presolving step */
8831                   if ( indi != indj )
8832                   {
8833                      /* arcs have to be added 'safe' */
8834                      SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indi], nodeorig[indj], NULL) );
8835                      SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indj], nodeorig[indi], NULL) );
8836                   }
8837                }
8838             }
8839          }
8840       }
8841    }
8842 
8843    /* set number of problem variables that are contained in at least one SOS1 constraint */
8844    conshdlrdata->nsos1vars = cntsos;
8845 
8846    /* free buffer arrays */
8847    SCIPfreeBufferArray(scip, &nodecreated);
8848    SCIPfreeBufferArray(scip, &nodeorig);
8849 
8850    /* sort successors in ascending order */
8851    for (j = 0; j < conshdlrdata->nsos1vars; ++j)
8852    {
8853       int nsucc;
8854 
8855       nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->conflictgraph, j);
8856       SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->conflictgraph, j), nsucc);
8857    }
8858 
8859    return SCIP_OKAY;
8860 }
8861 
8862 
8863 /** free conflict graph, nodedata and hashmap */
8864 static
freeConflictgraph(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata)8865 SCIP_RETCODE freeConflictgraph(
8866    SCIP*                 scip,               /**< SCIP pointer */
8867    SCIP_CONSHDLRDATA*    conshdlrdata        /**< constraint handler data */
8868    )
8869 {
8870    int j;
8871 
8872    if ( conshdlrdata->conflictgraph == NULL )
8873    {
8874       assert( conshdlrdata->nsos1vars == 0 );
8875       return SCIP_OKAY;
8876    }
8877 
8878    /* for every SOS1 variable */
8879    assert( conshdlrdata->nsos1vars > 0 );
8880    for (j = 0; j < conshdlrdata->nsos1vars; ++j)
8881    {
8882       SCIP_NODEDATA* nodedata;
8883 
8884       /* get node data */
8885       assert( conshdlrdata->conflictgraph != NULL );
8886       nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, j);
8887       assert( nodedata != NULL );
8888 
8889       /* free node data */
8890       SCIPfreeBlockMemory(scip, &nodedata);
8891       SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, NULL, j);
8892    }
8893 
8894    /* free conflict graph and hash map */
8895    assert( conshdlrdata->varhash != NULL );
8896    SCIPhashmapFree(&conshdlrdata->varhash);
8897    SCIPdigraphFree(&conshdlrdata->conflictgraph);
8898    conshdlrdata->nsos1vars = 0;
8899 
8900    assert( conshdlrdata->varhash == NULL );
8901    assert( conshdlrdata->conflictgraph == NULL );
8902 
8903    return SCIP_OKAY;
8904 }
8905 
8906 
8907 /* ---------------------------- constraint handler callback methods ----------------------*/
8908 
8909 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
8910 static
SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1)8911 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1)
8912 {  /*lint --e{715}*/
8913    assert( scip != NULL );
8914    assert( conshdlr != NULL );
8915    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8916 
8917    /* call inclusion method of constraint handler */
8918    SCIP_CALL( SCIPincludeConshdlrSOS1(scip) );
8919 
8920    *valid = TRUE;
8921 
8922    return SCIP_OKAY;
8923 }
8924 
8925 
8926 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
8927 static
SCIP_DECL_CONSFREE(consFreeSOS1)8928 SCIP_DECL_CONSFREE(consFreeSOS1)
8929 {
8930    SCIP_CONSHDLRDATA* conshdlrdata;
8931 
8932    assert( scip != NULL );
8933    assert( conshdlr != NULL );
8934    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8935 
8936    conshdlrdata = SCIPconshdlrGetData(conshdlr);
8937    assert(conshdlrdata != NULL);
8938 
8939    /* free stack of variables fixed to nonzero (usually already freed in consExitsolSOS1 unless instance was solved during presolving) */
8940    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars); /*lint !e737*/
8941 
8942    SCIPfreeBlockMemory(scip, &conshdlrdata);
8943 
8944    return SCIP_OKAY;
8945 }
8946 
8947 
8948 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
8949 static
SCIP_DECL_CONSINITSOL(consInitsolSOS1)8950 SCIP_DECL_CONSINITSOL(consInitsolSOS1)
8951 {  /*lint --e{715}*/
8952     SCIP_CONSHDLRDATA* conshdlrdata;
8953 
8954     assert( scip != NULL );
8955     assert( conshdlr != NULL );
8956     assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8957 
8958     conshdlrdata = SCIPconshdlrGetData(conshdlr);
8959     assert( conshdlrdata != NULL );
8960 
8961     conshdlrdata->nsos1vars = 0;
8962     conshdlrdata->varhash = NULL;
8963 
8964     if ( nconss > 0 )
8965     {
8966        /* initialize conflict graph and hashmap for SOS1 variables */
8967        SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss) );
8968 
8969        /* add data to conflict graph nodes */
8970        SCIP_CALL( computeNodeDataSOS1(scip, conshdlrdata, conshdlrdata->nsos1vars) );
8971 
8972        if ( ( conshdlrdata->autosos1branch || conshdlrdata->autocutsfromsos1 )
8973           && ( ! conshdlrdata->switchsos1branch || ! conshdlrdata->switchcutsfromsos1 )
8974           )
8975        {
8976           /* switch to nonoverlapping methods if the SOS1 constraints do not overlap */
8977           SCIP_CALL( checkSwitchNonoverlappingSOS1Methods(scip, conshdlrdata, conshdlrdata->conflictgraph, conss, nconss) );
8978        }
8979 
8980        /* initialize tclique graph */
8981        SCIP_CALL( initTCliquegraph(scip, conshdlr, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars) );
8982 
8983        /* create local conflict graph if needed */
8984        if ( conshdlrdata->addcomps )
8985        {
8986           SCIP_CALL( SCIPcreateDigraph(scip, &conshdlrdata->localconflicts, conshdlrdata->nsos1vars) );
8987        }
8988 
8989        /* initialize stack of variables fixed to nonzero (memory may be already allocated in consTransSOS1()) */
8990        if ( conshdlrdata->fixnonzerovars == NULL )
8991        {
8992           conshdlrdata->maxnfixnonzerovars = conshdlrdata->nsos1vars;
8993           SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) );
8994        }
8995     }
8996 
8997     return SCIP_OKAY;
8998 }
8999 
9000 
9001 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9002 static
SCIP_DECL_CONSEXITSOL(consExitsolSOS1)9003 SCIP_DECL_CONSEXITSOL(consExitsolSOS1)
9004 {  /*lint --e{715}*/
9005    SCIP_CONSHDLRDATA* conshdlrdata;
9006    int c;
9007 
9008    assert( scip != NULL );
9009    assert( conshdlr != NULL );
9010    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9011    conshdlrdata = SCIPconshdlrGetData(conshdlr);
9012    assert( conshdlrdata != NULL );
9013 
9014    /* check each constraint */
9015    for (c = 0; c < nconss; ++c)
9016    {
9017       SCIP_CONSDATA* consdata;
9018 
9019       assert( conss != NULL );
9020       assert( conss[c] != NULL );
9021       consdata = SCIPconsGetData(conss[c]);
9022       assert( consdata != NULL );
9023 
9024       SCIPdebugMsg(scip, "Exiting SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
9025 
9026       /* free rows */
9027       if ( consdata->rowub != NULL )
9028       {
9029          SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowub) );
9030       }
9031 
9032       if ( consdata->rowlb != NULL )
9033       {
9034          SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowlb) );
9035       }
9036    }
9037 
9038    /* free implication graph */
9039    if ( conshdlrdata->implgraph != NULL )
9040    {
9041       SCIP_CALL( freeImplGraphSOS1(scip, conshdlrdata) );
9042    }
9043    assert( conshdlrdata->implgraph == NULL );
9044 
9045    /* free tclique graph and tclique data */
9046    if ( conshdlrdata->tcliquegraph != NULL )
9047    {
9048       assert( conshdlrdata->tcliquedata != NULL );
9049       SCIPfreeBlockMemory(scip, &conshdlrdata->tcliquedata);
9050       tcliqueFree(&conshdlrdata->tcliquegraph);
9051    }
9052    assert(conshdlrdata->tcliquegraph == NULL);
9053    assert(conshdlrdata->tcliquedata == NULL);
9054 
9055    /* free stack of variables fixed to nonzero */
9056    SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars); /*lint !e737*/
9057    conshdlrdata->nfixnonzerovars = 0;
9058    conshdlrdata->maxnfixnonzerovars = 0;
9059 
9060    /* free graph for storing local conflicts */
9061    if ( conshdlrdata->localconflicts != NULL )
9062       SCIPdigraphFree(&conshdlrdata->localconflicts);
9063    assert( conshdlrdata->localconflicts == NULL );
9064 
9065    /* free conflict graph  */
9066    SCIP_CALL( freeConflictgraph(scip, conshdlrdata) );
9067    assert( conshdlrdata->conflictgraph == NULL );
9068 
9069    return SCIP_OKAY;
9070 }
9071 
9072 
9073 /** frees specific constraint data */
9074 static
SCIP_DECL_CONSDELETE(consDeleteSOS1)9075 SCIP_DECL_CONSDELETE(consDeleteSOS1)
9076 {
9077    assert( scip != NULL );
9078    assert( conshdlr != NULL );
9079    assert( cons != NULL );
9080    assert( consdata != NULL );
9081    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9082 
9083    SCIPdebugMsg(scip, "Deleting SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
9084 
9085    /* drop events on transformed variables */
9086    if ( SCIPconsIsTransformed(cons) )
9087    {
9088       SCIP_CONSHDLRDATA* conshdlrdata;
9089       int j;
9090 
9091       /* get constraint handler data */
9092       conshdlrdata = SCIPconshdlrGetData(conshdlr);
9093       assert( conshdlrdata != NULL );
9094       assert( conshdlrdata->eventhdlr != NULL );
9095 
9096       for (j = 0; j < (*consdata)->nvars; ++j)
9097       {
9098          SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
9099                (SCIP_EVENTDATA*)cons, -1) ); /*lint !e737 !e740*/
9100       }
9101    }
9102 
9103    SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->maxvars);
9104    if ( (*consdata)->weights != NULL )
9105    {
9106       SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->maxvars);
9107    }
9108 
9109    /* free rows */
9110    if ( (*consdata)->rowub != NULL )
9111    {
9112       SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowub) );
9113    }
9114    if ( (*consdata)->rowlb != NULL )
9115    {
9116       SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowlb) );
9117    }
9118    assert( (*consdata)->rowub == NULL );
9119    assert( (*consdata)->rowlb == NULL );
9120 
9121    SCIPfreeBlockMemory(scip, consdata);
9122 
9123    return SCIP_OKAY;
9124 }
9125 
9126 
9127 /** transforms constraint data into data belonging to the transformed problem */
9128 static
SCIP_DECL_CONSTRANS(consTransSOS1)9129 SCIP_DECL_CONSTRANS(consTransSOS1)
9130 {
9131    SCIP_CONSDATA* consdata;
9132    SCIP_CONSHDLRDATA* conshdlrdata;
9133    SCIP_CONSDATA* sourcedata;
9134    char s[SCIP_MAXSTRLEN];
9135    int j;
9136 
9137    assert( scip != NULL );
9138    assert( conshdlr != NULL );
9139    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9140    assert( sourcecons != NULL );
9141    assert( targetcons != NULL );
9142 
9143    /* get constraint handler data */
9144    conshdlrdata = SCIPconshdlrGetData(conshdlr);
9145    assert( conshdlrdata != NULL );
9146    assert( conshdlrdata->eventhdlr != NULL );
9147 
9148    SCIPdebugMsg(scip, "Transforming SOS1 constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
9149 
9150    /* get data of original constraint */
9151    sourcedata = SCIPconsGetData(sourcecons);
9152    assert( sourcedata != NULL );
9153    assert( sourcedata->nvars > 0 );
9154    assert( sourcedata->nvars <= sourcedata->maxvars );
9155 
9156    /* initialize stack of variables fixed to nonzero */
9157    if ( conshdlrdata->fixnonzerovars == NULL )
9158    {
9159       conshdlrdata->maxnfixnonzerovars = SCIPgetNTotalVars(scip);
9160       SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) );
9161    }
9162 
9163    /* create constraint data */
9164    SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
9165 
9166    consdata->nvars = sourcedata->nvars;
9167    consdata->maxvars = sourcedata->nvars;
9168    consdata->rowub = NULL;
9169    consdata->rowlb = NULL;
9170    consdata->nfixednonzeros = 0;
9171    consdata->local = sourcedata->local;
9172 
9173    SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) );
9174 
9175    /* if weights were used */
9176    if ( sourcedata->weights != NULL )
9177    {
9178       SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, sourcedata->weights, consdata->nvars) );
9179    }
9180    else
9181       consdata->weights = NULL;
9182 
9183    for (j = 0; j < sourcedata->nvars; ++j)
9184    {
9185       assert( sourcedata->vars[j] != 0 );
9186       SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->vars[j], &(consdata->vars[j])) );
9187 
9188       /* if variable is fixed to be nonzero */
9189       if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(consdata->vars[j])) )
9190          ++(consdata->nfixednonzeros);
9191    }
9192 
9193    /* create transformed constraint with the same flags */
9194    (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
9195    SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
9196          SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
9197          SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
9198          SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
9199          SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
9200          SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
9201 
9202    /* catch bound change events on variable */
9203    for (j = 0; j < consdata->nvars; ++j)
9204    {
9205       SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
9206             (SCIP_EVENTDATA*)*targetcons, NULL) ); /*lint !e740*/
9207    }
9208 
9209 #ifdef SCIP_DEBUG
9210    if ( consdata->nfixednonzeros > 0 )
9211    {
9212       SCIPdebugMsg(scip, "constraint <%s> has %d variables fixed to be nonzero.\n", SCIPconsGetName(*targetcons),
9213          consdata->nfixednonzeros );
9214    }
9215 #endif
9216 
9217    return SCIP_OKAY;
9218 }
9219 
9220 
9221 /** presolving method of constraint handler */
9222 static
SCIP_DECL_CONSPRESOL(consPresolSOS1)9223 SCIP_DECL_CONSPRESOL(consPresolSOS1)
9224 {  /*lint --e{715}*/
9225    SCIP_CONSHDLRDATA* conshdlrdata;
9226    SCIPdebug( int oldnfixedvars = *nfixedvars; )
9227    SCIPdebug( int oldnchgbds = *nchgbds; )
9228    SCIPdebug( int oldndelconss = *ndelconss; )
9229    SCIPdebug( int oldnupgdconss = *nupgdconss; )
9230    int nremovedvars;
9231 
9232    assert( scip != NULL );
9233    assert( conshdlr != NULL );
9234    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9235    assert( result != NULL );
9236 
9237    conshdlrdata = SCIPconshdlrGetData(conshdlr);
9238    assert( conshdlrdata != NULL );
9239 
9240    SCIPdebugMsg(scip, "Presolving SOS1 constraints.\n");
9241 
9242    *result = SCIP_DIDNOTRUN;
9243 
9244    nremovedvars = 0;
9245 
9246    /* only run if success if possible */
9247    if( nconss > 0 && ( nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 ) )
9248    {
9249       SCIP_Bool** adjacencymatrix = NULL;
9250       SCIP_DIGRAPH* conflictgraph;
9251       SCIP_EVENTHDLR* eventhdlr;
9252       int nsos1vars;
9253       int i;
9254       int j;
9255 
9256       *result = SCIP_DIDNOTFIND;
9257 
9258       /* get constraint handler data */
9259       assert( SCIPconshdlrGetData(conshdlr) != NULL );
9260       eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr;
9261       assert( eventhdlr != NULL );
9262 
9263       /* initialize conflict graph */
9264       SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss));
9265 
9266       /* get conflict graph and number of SOS1 variables */
9267       conflictgraph = conshdlrdata->conflictgraph;
9268       nsos1vars = conshdlrdata->nsos1vars;
9269       if ( nsos1vars < 2 )
9270       {
9271          SCIP_CALL( freeConflictgraph(scip, conshdlrdata));
9272          return SCIP_OKAY;
9273       }
9274 
9275       /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */
9276       if ( conshdlrdata->maxsosadjacency == -1 || nsos1vars <= conshdlrdata->maxsosadjacency )
9277       {
9278          /* allocate buffer arrays for adjacency matrix  */
9279          SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) );
9280          for (i = 0; i < nsos1vars; ++i)
9281          {
9282             SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) );/*lint !e866*/
9283          }
9284 
9285          /* create adjacency matrix */
9286          for (i = 0; i < nsos1vars; ++i)
9287          {
9288             for (j = 0; j < i+1; ++j)
9289                adjacencymatrix[i][j] = 0;
9290          }
9291          for (i = 0; i < nsos1vars; ++i)
9292          {
9293             int* succ;
9294             int nsucc;
9295 
9296             succ = SCIPdigraphGetSuccessors(conflictgraph, i);
9297             nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
9298 
9299             for (j = 0; j < nsucc; ++j)
9300             {
9301                if ( i > succ[j] )
9302                   adjacencymatrix[i][succ[j]] = 1;
9303             }
9304          }
9305       }
9306       else
9307       {
9308          SCIPdebugMsg(scip, "Adjacency matrix was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency);
9309       }
9310 
9311       /* perform one presolving round for SOS1 constraints */
9312       SCIP_CALL( presolRoundConssSOS1(scip, eventhdlr, conshdlrdata, conflictgraph, adjacencymatrix, conss, nconss, nsos1vars, naddconss, ndelconss, nupgdconss, nfixedvars, &nremovedvars, result) );
9313 
9314       if ( adjacencymatrix != NULL )
9315       {
9316          /* perform one presolving round for SOS1 variables */
9317          if ( conshdlrdata->maxtightenbds != 0 && *result != SCIP_CUTOFF )
9318          {
9319             SCIP_CALL( presolRoundVarsSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, nsos1vars, nfixedvars, nchgbds, naddconss, result) );
9320          }
9321 
9322          /* free adjacency matrix */
9323          for (j = nsos1vars-1; j >= 0; --j)
9324             SCIPfreeBufferArrayNull(scip, &adjacencymatrix[j]);
9325          SCIPfreeBufferArrayNull(scip, &adjacencymatrix);
9326       }
9327 
9328       /* free memory allocated in function initConflictgraph() */
9329       SCIP_CALL( freeConflictgraph(scip, conshdlrdata));
9330    }
9331    (*nchgcoefs) += nremovedvars;
9332 
9333    SCIPdebug( SCIPdebugMsg(scip, "presolving fixed %d variables, changed %d bounds, removed %d variables, deleted %d constraints, and upgraded %d constraints.\n",
9334                 *nfixedvars - oldnfixedvars, *nchgbds - oldnchgbds, nremovedvars, *ndelconss - oldndelconss, *nupgdconss - oldnupgdconss); )
9335 
9336    return SCIP_OKAY;
9337 }
9338 
9339 
9340 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9341 static
SCIP_DECL_CONSINITLP(consInitlpSOS1)9342 SCIP_DECL_CONSINITLP(consInitlpSOS1)
9343 {
9344    SCIP_CONSHDLRDATA* conshdlrdata;
9345 
9346    assert( scip != NULL );
9347    assert( conshdlr != NULL );
9348    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9349 
9350    conshdlrdata = SCIPconshdlrGetData(conshdlr);
9351    assert( conshdlrdata != NULL );
9352 
9353    *infeasible = FALSE;
9354 
9355    /* checking for initial rows for SOS1 constraints */
9356    if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 )
9357    {
9358       SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, NULL, FALSE, -1, NULL, infeasible) );
9359    }
9360 
9361    return SCIP_OKAY;
9362 }
9363 
9364 
9365 /** separation method of constraint handler for LP solutions */
9366 static
SCIP_DECL_CONSSEPALP(consSepalpSOS1)9367 SCIP_DECL_CONSSEPALP(consSepalpSOS1)
9368 {  /*lint --e{715}*/
9369    assert( scip != NULL );
9370    assert( conshdlr != NULL );
9371    assert( conss != NULL );
9372    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9373    assert( result != NULL );
9374 
9375    SCIP_CALL( separateSOS1(scip, conshdlr, NULL, nconss, conss, result) );
9376 
9377    return SCIP_OKAY;
9378 }
9379 
9380 
9381 /** separation method of constraint handler for arbitrary primal solutions */
9382 static
SCIP_DECL_CONSSEPASOL(consSepasolSOS1)9383 SCIP_DECL_CONSSEPASOL(consSepasolSOS1)
9384 {  /*lint --e{715}*/
9385    assert( scip != NULL );
9386    assert( conshdlr != NULL );
9387    assert( conss != NULL );
9388    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9389    assert( result != NULL );
9390 
9391    SCIP_CALL( separateSOS1(scip, conshdlr, sol, nconss, conss, result) );
9392 
9393    return SCIP_OKAY;
9394 }
9395 
9396 
9397 /** constraint enforcing method of constraint handler for LP solutions */
9398 static
SCIP_DECL_CONSENFOLP(consEnfolpSOS1)9399 SCIP_DECL_CONSENFOLP(consEnfolpSOS1)
9400 {  /*lint --e{715}*/
9401    assert( scip != NULL );
9402    assert( conshdlr != NULL );
9403    assert( conss != NULL );
9404    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9405    assert( result != NULL );
9406 
9407    SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, NULL, result) );
9408 
9409    return SCIP_OKAY;
9410 }
9411 
9412 
9413 /** constraint enforcing method of constraint handler for relaxation solutions */
9414 static
SCIP_DECL_CONSENFORELAX(consEnforelaxSOS1)9415 SCIP_DECL_CONSENFORELAX(consEnforelaxSOS1)
9416 {  /*lint --e{715}*/
9417    assert( scip != NULL );
9418    assert( conshdlr != NULL );
9419    assert( conss != NULL );
9420    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9421    assert( result != NULL );
9422 
9423    SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, sol, result) );
9424 
9425    return SCIP_OKAY;
9426 }
9427 
9428 
9429 /** constraint enforcing method of constraint handler for pseudo solutions */
9430 static
SCIP_DECL_CONSENFOPS(consEnfopsSOS1)9431 SCIP_DECL_CONSENFOPS(consEnfopsSOS1)
9432 {  /*lint --e{715}*/
9433    assert( scip != NULL );
9434    assert( conshdlr != NULL );
9435    assert( conss != NULL );
9436    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9437    assert( result != NULL );
9438 
9439    SCIP_CALL( enforceSOS1(scip, conshdlr, nconss, conss, NULL, result) );
9440 
9441    return SCIP_OKAY;
9442 }
9443 
9444 
9445 /** feasibility check method of constraint handler for integral solutions
9446  *
9447  *  We simply check whether at most one variable is nonzero in the given solution.
9448  */
9449 static
SCIP_DECL_CONSCHECK(consCheckSOS1)9450 SCIP_DECL_CONSCHECK(consCheckSOS1)
9451 {  /*lint --e{715}*/
9452    int c;
9453 
9454    assert( scip != NULL );
9455    assert( conshdlr != NULL );
9456    assert( conss != NULL );
9457    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9458    assert( result != NULL );
9459 
9460    *result = SCIP_FEASIBLE;
9461 
9462    /* check each constraint */
9463    for (c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c)
9464    {
9465       SCIP_CONSDATA* consdata;
9466       int j;
9467       int cnt;
9468 
9469       cnt = 0;
9470       assert( conss[c] != NULL );
9471       consdata = SCIPconsGetData(conss[c]);
9472       assert( consdata != NULL );
9473       SCIPdebugMsg(scip, "Checking SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]));
9474 
9475       /* check all variables */
9476       for (j = 0; j < consdata->nvars; ++j)
9477       {
9478          /* if variable is nonzero */
9479          if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
9480          {
9481             ++cnt;
9482 
9483             /* if more than one variable is nonzero */
9484             if ( cnt > 1 )
9485             {
9486                SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
9487                *result = SCIP_INFEASIBLE;
9488 
9489                /* update constraint violation in solution */
9490                if ( sol != NULL )
9491                   SCIPupdateSolConsViolation(scip, sol, 1.0, 1.0);
9492 
9493                if ( printreason )
9494                {
9495                   int l;
9496 
9497                   SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
9498                   SCIPinfoMessage(scip, NULL, ";\nviolation: ");
9499 
9500                   for (l = 0; l < consdata->nvars; ++l)
9501                   {
9502                      /* if variable is nonzero */
9503                      if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[l])) )
9504                      {
9505                         SCIPinfoMessage(scip, NULL, "<%s> = %.15g ",
9506                            SCIPvarGetName(consdata->vars[l]), SCIPgetSolVal(scip, sol, consdata->vars[l]));
9507                      }
9508                   }
9509                   SCIPinfoMessage(scip, NULL, "\n");
9510                }
9511             }
9512          }
9513       }
9514    }
9515 
9516    return SCIP_OKAY;
9517 }
9518 
9519 
9520 /** domain propagation method of constraint handler */
9521 static
SCIP_DECL_CONSPROP(consPropSOS1)9522 SCIP_DECL_CONSPROP(consPropSOS1)
9523 {  /*lint --e{715}*/
9524    SCIP_CONSHDLRDATA* conshdlrdata;
9525    SCIP_DIGRAPH* conflictgraph;
9526    SCIP_DIGRAPH* implgraph;
9527    int ngen = 0;
9528 
9529    assert( scip != NULL );
9530    assert( conshdlr != NULL );
9531    assert( conss != NULL );
9532    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9533    assert( result != NULL );
9534    assert( SCIPisTransformed(scip) );
9535 
9536    /* return if number of SOS1 constraints is zero */
9537    if ( nconss < 1 )
9538    {
9539       *result = SCIP_DIDNOTRUN;
9540       return SCIP_OKAY;
9541    }
9542    *result = SCIP_DIDNOTFIND;
9543 
9544    /* get constraint handler data */
9545    conshdlrdata = SCIPconshdlrGetData(conshdlr);
9546    assert( conshdlrdata != NULL );
9547 
9548    /* get conflict graph */
9549    conflictgraph = conshdlrdata->conflictgraph;
9550 
9551    /* get/initialize implication graph */
9552    implgraph = conshdlrdata->implgraph;
9553    if ( implgraph == NULL && conshdlrdata->implprop && conflictgraph != NULL )
9554    {
9555       if ( SCIPgetDepth(scip) == 0 )
9556       {
9557          SCIP_Bool success;
9558          SCIP_Bool cutoff;
9559          int nchbds;
9560 
9561          SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, &cutoff, &success) );
9562          if ( ! success )
9563             conshdlrdata->implprop = FALSE;
9564 
9565          if ( cutoff )
9566          {
9567             *result = SCIP_CUTOFF;
9568             return SCIP_OKAY;
9569          }
9570          else if ( nchbds > 0 )
9571             *result = SCIP_REDUCEDDOM;
9572          implgraph = conshdlrdata->implgraph;
9573       }
9574       else
9575          conshdlrdata->implprop = FALSE;
9576    }
9577 
9578    /* if conflict graph propagation shall be used */
9579    if ( conshdlrdata->conflictprop && conflictgraph != NULL )
9580    {
9581       SCIP_VAR** fixnonzerovars;
9582       int nfixnonzerovars;
9583       int j;
9584 
9585       assert( nconss > 0 );
9586 
9587       /* stack of variables fixed to nonzero */
9588       nfixnonzerovars = conshdlrdata->nfixnonzerovars;
9589       fixnonzerovars = conshdlrdata->fixnonzerovars;
9590       assert( fixnonzerovars != NULL );
9591 
9592       /* check each variable from stack */
9593       for (j = 0; j < nfixnonzerovars; ++j)
9594       {
9595          SCIP_VAR* var;
9596 
9597          var = fixnonzerovars[j];
9598          if ( var != NULL )
9599          {
9600             int node;
9601             node = varGetNodeSOS1(conshdlrdata, var);
9602 
9603             /* if variable is involved in an SOS1 constraint */
9604             if ( node >= 0 )
9605             {
9606                assert( varGetNodeSOS1(conshdlrdata, var) < conshdlrdata->nsos1vars );
9607                SCIPdebugMsg(scip, "Propagating SOS1 variable <%s>.\n", SCIPvarGetName(var) );
9608 
9609                /* if zero is outside the domain of variable */
9610                if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var)) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(var)) )
9611                {
9612                   SCIP_Bool cutoff;
9613 
9614                   SCIP_CALL( propVariableNonzero(scip, conflictgraph, implgraph, conss[0], node, conshdlrdata->implprop, &cutoff, &ngen) );
9615                   if ( cutoff )
9616                   {
9617                      *result = SCIP_CUTOFF;
9618                      return SCIP_OKAY;
9619                   }
9620                }
9621             }
9622          }
9623       }
9624    }
9625    conshdlrdata->nfixnonzerovars = 0;
9626 
9627    /* if SOS1 constraint propagation shall be used */
9628    if ( conshdlrdata->sosconsprop || conflictgraph == NULL )
9629    {
9630       int c;
9631 
9632       /* check each constraint */
9633       for (c = 0; c < nconss; ++c)
9634       {
9635          SCIP_CONS* cons;
9636          SCIP_CONSDATA* consdata;
9637          SCIP_Bool cutoff;
9638 
9639          assert( conss[c] != NULL );
9640          cons = conss[c];
9641          consdata = SCIPconsGetData(cons);
9642          assert( consdata != NULL );
9643          SCIPdebugMsg(scip, "Propagating SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
9644 
9645          SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
9646          if ( cutoff )
9647          {
9648             *result = SCIP_CUTOFF;
9649             return SCIP_OKAY;
9650          }
9651       }
9652    }
9653 
9654    SCIPdebugMsg(scip, "Propagated %d domains.\n", ngen);
9655    if ( ngen > 0 )
9656       *result = SCIP_REDUCEDDOM;
9657 
9658    return SCIP_OKAY;
9659 }
9660 
9661 
9662 /** propagation conflict resolving method of constraint handler
9663  *
9664  *  We check which bound changes were the reason for infeasibility. We
9665  *  use that @a inferinfo stores the index of the variable that has
9666  *  bounds that fix it to be nonzero (these bounds are the reason). */
9667 static
SCIP_DECL_CONSRESPROP(consRespropSOS1)9668 SCIP_DECL_CONSRESPROP(consRespropSOS1)
9669 {  /*lint --e{715}*/
9670    SCIP_VAR* var;
9671 
9672    assert( scip != NULL );
9673    assert( cons != NULL );
9674    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9675    assert( infervar != NULL );
9676    assert( bdchgidx != NULL );
9677    assert( result != NULL );
9678 
9679    *result = SCIP_DIDNOTFIND;
9680    SCIPdebugMsg(scip, "Propagation resolution method of SOS1 constraint <%s>.\n", SCIPconsGetName(cons));
9681 
9682    /* check whether conflict was detected in variable propagation or constraint propagation */
9683    if ( inferinfo < 0 )
9684    {
9685       SCIP_CONSHDLRDATA* conshdlrdata;
9686 
9687       assert( conshdlr != NULL );
9688 
9689       /* get constraint handler data */
9690       conshdlrdata = SCIPconshdlrGetData(conshdlr);
9691       assert( conshdlrdata != NULL );
9692       assert( conshdlrdata->conflictgraph != NULL );
9693       assert( inferinfo >= -conshdlrdata->maxnfixnonzerovars );
9694       assert( inferinfo >= -conshdlrdata->nsos1vars );
9695       assert( inferinfo <= -1 );
9696 
9697       var = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, -inferinfo - 1);  /*lint !e2704*/
9698    }
9699    else
9700    {
9701       SCIP_CONSDATA* consdata;
9702 
9703       /* get constraint data */
9704       consdata = SCIPconsGetData(cons);
9705       assert( consdata != NULL );
9706       assert( inferinfo < consdata->nvars );
9707 
9708       var = consdata->vars[inferinfo];
9709    }
9710    assert( var != NULL );
9711    assert( var != infervar );
9712 
9713    /* check if lower bound of var was the reason */
9714    if ( SCIPisFeasPositive(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) )
9715    {
9716       SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
9717       *result = SCIP_SUCCESS;
9718    }
9719 
9720    /* check if upper bound of var was the reason */
9721    if ( SCIPisFeasNegative(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) )
9722    {
9723       SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
9724       *result = SCIP_SUCCESS;
9725    }
9726 
9727    return SCIP_OKAY;
9728 }
9729 
9730 
9731 /** variable rounding lock method of constraint handler
9732  *
9733  *  Let lb and ub be the lower and upper bounds of a
9734  *  variable. Preprocessing usually makes sure that lb <= 0 <= ub.
9735  *
9736  *  - If lb < 0 then rounding down may violate the constraint.
9737  *  - If ub > 0 then rounding up may violated the constraint.
9738  *  - If lb > 0 or ub < 0 then the constraint is infeasible and we do
9739  *    not have to deal with it here.
9740  *  - If lb == 0 then rounding down does not violate the constraint.
9741  *  - If ub == 0 then rounding up does not violate the constraint.
9742  */
9743 static
SCIP_DECL_CONSLOCK(consLockSOS1)9744 SCIP_DECL_CONSLOCK(consLockSOS1)
9745 {
9746    SCIP_CONSDATA* consdata;
9747    SCIP_VAR** vars;
9748    int nvars;
9749    int j;
9750 
9751    assert( scip != NULL );
9752    assert( conshdlr != NULL );
9753    assert( cons != NULL );
9754    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9755    assert(locktype == SCIP_LOCKTYPE_MODEL);
9756 
9757    consdata = SCIPconsGetData(cons);
9758    assert( consdata != NULL );
9759 
9760    SCIPdebugMsg(scip, "Locking constraint <%s>.\n", SCIPconsGetName(cons));
9761 
9762    vars = consdata->vars;
9763    nvars = consdata->nvars;
9764    assert( vars != NULL );
9765 
9766    for (j = 0; j < nvars; ++j)
9767    {
9768       SCIP_VAR* var;
9769       var = vars[j];
9770 
9771       /* if lower bound is negative, rounding down may violate constraint */
9772       if ( SCIPisFeasNegative(scip, SCIPvarGetLbGlobal(var)) )
9773       {
9774          SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlockspos, nlocksneg) );
9775       }
9776 
9777       /* additionally: if upper bound is positive, rounding up may violate constraint */
9778       if ( SCIPisFeasPositive(scip, SCIPvarGetUbGlobal(var)) )
9779       {
9780          SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlocksneg, nlockspos) );
9781       }
9782    }
9783 
9784    return SCIP_OKAY;
9785 }
9786 
9787 
9788 /** constraint display method of constraint handler */
9789 static
SCIP_DECL_CONSPRINT(consPrintSOS1)9790 SCIP_DECL_CONSPRINT(consPrintSOS1)
9791 {  /*lint --e{715}*/
9792    SCIP_CONSDATA* consdata;
9793    int j;
9794 
9795    assert( scip != NULL );
9796    assert( conshdlr != NULL );
9797    assert( cons != NULL );
9798    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9799 
9800    consdata = SCIPconsGetData(cons);
9801    assert( consdata != NULL );
9802 
9803    for (j = 0; j < consdata->nvars; ++j)
9804    {
9805       if ( j > 0 )
9806          SCIPinfoMessage(scip, file, ", ");
9807       SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[j], FALSE) );
9808       if ( consdata->weights == NULL )
9809          SCIPinfoMessage(scip, file, " (%d)", j+1);
9810       else
9811          SCIPinfoMessage(scip, file, " (%3.2f)", consdata->weights[j]);
9812    }
9813 
9814    return SCIP_OKAY;
9815 }
9816 
9817 
9818 /** constraint copying method of constraint handler */
9819 static
SCIP_DECL_CONSCOPY(consCopySOS1)9820 SCIP_DECL_CONSCOPY(consCopySOS1)
9821 {  /*lint --e{715}*/
9822    SCIP_CONSDATA* sourceconsdata;
9823    SCIP_VAR** sourcevars;
9824    SCIP_VAR** targetvars;
9825    SCIP_Real* targetweights = NULL;
9826    const char* consname;
9827    int nvars;
9828    int v;
9829 
9830    assert( scip != NULL );
9831    assert( sourcescip != NULL );
9832    assert( sourcecons != NULL );
9833    assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
9834    assert( valid != NULL );
9835 
9836    *valid = TRUE;
9837 
9838    if ( name != NULL )
9839       consname = name;
9840    else
9841       consname = SCIPconsGetName(sourcecons);
9842 
9843    SCIPdebugMsg(scip, "Copying SOS1 constraint <%s> ...\n", consname);
9844 
9845    sourceconsdata = SCIPconsGetData(sourcecons);
9846    assert( sourceconsdata != NULL );
9847 
9848    /* get variables and weights of the source constraint */
9849    nvars = sourceconsdata->nvars;
9850    assert( nvars >= 0 );
9851 
9852    /* duplicate weights array */
9853    if ( sourceconsdata->weights != NULL )
9854    {
9855       SCIP_CALL( SCIPduplicateBufferArray(sourcescip, &targetweights, sourceconsdata->weights, nvars) );
9856    }
9857 
9858    /* get copied variables in target SCIP */
9859    sourcevars = sourceconsdata->vars;
9860    SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetvars, nvars) );
9861    for (v = 0; v < nvars && *valid; ++v)
9862    {
9863       assert( sourcevars != NULL );
9864       SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &(targetvars[v]), varmap, consmap, global, valid) );
9865    }
9866 
9867    /* only create the target constraint, if all variables were be copied */
9868    if ( *valid )
9869    {
9870       SCIP_CALL( SCIPcreateConsSOS1(scip, cons, consname, nvars, targetvars, targetweights,
9871             initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
9872    }
9873 
9874    /* free buffer array */
9875    SCIPfreeBufferArray(sourcescip, &targetvars);
9876    SCIPfreeBufferArrayNull(sourcescip, &targetweights);
9877 
9878    return SCIP_OKAY;
9879 }
9880 
9881 
9882 /** constraint parsing method of constraint handler */
9883 static
SCIP_DECL_CONSPARSE(consParseSOS1)9884 SCIP_DECL_CONSPARSE(consParseSOS1)
9885 {  /*lint --e{715}*/
9886    SCIP_VAR* var;
9887    SCIP_Real weight;
9888    const char* s;
9889    char* t;
9890 
9891    assert(scip != NULL);
9892    assert(conshdlr != NULL);
9893    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9894    assert(cons != NULL);
9895    assert(success != NULL);
9896 
9897    *success = TRUE;
9898    s = str;
9899 
9900    /* create empty SOS1 constraint */
9901    SCIP_CALL( SCIPcreateConsSOS1(scip, cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
9902 
9903    /* loop through string */
9904    do
9905    {
9906       /* parse variable name */
9907       SCIP_CALL( SCIPparseVarName(scip, s, &var, &t) );
9908       s = t;
9909 
9910       /* skip until beginning of weight */
9911       while ( *s != '\0' && *s != '(' )
9912          ++s;
9913 
9914       if ( *s == '\0' )
9915       {
9916          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected weight at input: %s\n", s);
9917          *success = FALSE;
9918          return SCIP_OKAY;
9919       }
9920       /* skip '(' */
9921       ++s;
9922 
9923       /* find weight */
9924       weight = strtod(s, &t);
9925       if ( t == NULL )
9926       {
9927          SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error during parsing of the weight: %s\n", s);
9928          *success = FALSE;
9929          return SCIP_OKAY;
9930       }
9931       s = t;
9932 
9933       /* skip white space, ',', and ')' */
9934       while ( *s != '\0' && ( isspace((unsigned char)*s) ||  *s == ',' || *s == ')' ) )
9935          ++s;
9936 
9937       /* add variable */
9938       SCIP_CALL( SCIPaddVarSOS1(scip, *cons, var, weight) );
9939    }
9940    while ( *s != '\0' );
9941 
9942    return SCIP_OKAY;
9943 }
9944 
9945 
9946 /** constraint method of constraint handler which returns the variables (if possible) */
9947 static
SCIP_DECL_CONSGETVARS(consGetVarsSOS1)9948 SCIP_DECL_CONSGETVARS(consGetVarsSOS1)
9949 {  /*lint --e{715}*/
9950    SCIP_CONSDATA* consdata;
9951 
9952    consdata = SCIPconsGetData(cons);
9953    assert(consdata != NULL);
9954 
9955    if( varssize < consdata->nvars )
9956       (*success) = FALSE;
9957    else
9958    {
9959       assert(vars != NULL);
9960 
9961       BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
9962       (*success) = TRUE;
9963    }
9964 
9965    return SCIP_OKAY;
9966 }
9967 
9968 
9969 /** constraint method of constraint handler which returns the number of variables (if possible) */
9970 static
SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)9971 SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)
9972 {  /*lint --e{715}*/
9973    SCIP_CONSDATA* consdata;
9974 
9975    consdata = SCIPconsGetData(cons);
9976    assert(consdata != NULL);
9977 
9978    (*nvars) = consdata->nvars;
9979    (*success) = TRUE;
9980 
9981    return SCIP_OKAY;
9982 }
9983 
9984 
9985 /* ---------------- Callback methods of event handler ---------------- */
9986 
9987 /** exec the event handler
9988  *
9989  *  We update the number of variables fixed to be nonzero
9990  */
9991 static
SCIP_DECL_EVENTEXEC(eventExecSOS1)9992 SCIP_DECL_EVENTEXEC(eventExecSOS1)
9993 {
9994    SCIP_CONSHDLRDATA* conshdlrdata;
9995    SCIP_EVENTTYPE eventtype;
9996    SCIP_CONSHDLR* conshdlr;
9997    SCIP_CONSDATA* consdata;
9998    SCIP_CONS* cons;
9999    SCIP_VAR* var;
10000    SCIP_Real oldbound;
10001    SCIP_Real newbound;
10002 
10003    assert( eventhdlr != NULL );
10004    assert( eventdata != NULL );
10005    assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0 );
10006    assert( event != NULL );
10007 
10008    cons = (SCIP_CONS*)eventdata;
10009    assert( cons != NULL );
10010    consdata = SCIPconsGetData(cons);
10011    assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
10012 
10013    oldbound = SCIPeventGetOldbound(event);
10014    newbound = SCIPeventGetNewbound(event);
10015 
10016    eventtype = SCIPeventGetType(event);
10017    switch ( eventtype )
10018    {
10019    case SCIP_EVENTTYPE_LBTIGHTENED:
10020       /* if variable is now fixed to be nonzero */
10021       if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
10022       {
10023          conshdlr = SCIPconsGetHdlr(cons);
10024          assert( conshdlr != NULL );
10025          conshdlrdata = SCIPconshdlrGetData(conshdlr);
10026          assert( conshdlrdata != NULL );
10027 
10028          /* store variable fixed to be nonzero on stack */
10029          assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) );
10030          if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars )
10031          {
10032             assert( conshdlrdata->fixnonzerovars != NULL );
10033             assert( SCIPeventGetVar(event) != NULL );
10034             conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event);
10035          }
10036 
10037          ++(consdata->nfixednonzeros);
10038       }
10039       break;
10040 
10041    case SCIP_EVENTTYPE_UBTIGHTENED:
10042       /* if variable is now fixed to be nonzero */
10043       if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
10044       {
10045          conshdlr = SCIPconsGetHdlr(cons);
10046          assert( conshdlr != NULL );
10047          conshdlrdata = SCIPconshdlrGetData(conshdlr);
10048          assert( conshdlrdata != NULL );
10049 
10050          /* store variable fixed to be nonzero on stack */
10051          assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) );
10052          if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars )
10053          {
10054             assert( conshdlrdata->fixnonzerovars != NULL );
10055             assert( SCIPeventGetVar(event) != NULL );
10056             conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event);
10057          }
10058 
10059          ++(consdata->nfixednonzeros);
10060       }
10061       break;
10062 
10063    case SCIP_EVENTTYPE_LBRELAXED:
10064       /* if variable is not fixed to be nonzero anymore */
10065       if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
10066          --(consdata->nfixednonzeros);
10067       break;
10068 
10069    case SCIP_EVENTTYPE_UBRELAXED:
10070       /* if variable is not fixed to be nonzero anymore */
10071       if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
10072          --(consdata->nfixednonzeros);
10073       break;
10074 
10075    case SCIP_EVENTTYPE_GLBCHANGED:
10076       var = SCIPeventGetVar(event);
10077       assert(var != NULL);
10078 
10079       /* global lower bound is not negative anymore -> remove down lock */
10080       if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
10081          SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10082       /* global lower bound turned negative -> add down lock */
10083       else if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
10084          SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, FALSE) );
10085       break;
10086 
10087    case SCIP_EVENTTYPE_GUBCHANGED:
10088       var = SCIPeventGetVar(event);
10089       assert(var != NULL);
10090 
10091       /* global upper bound is not positive anymore -> remove up lock */
10092       if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
10093          SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10094       /* global upper bound turned positive -> add up lock */
10095       else if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
10096          SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
10097       break;
10098 
10099    default:
10100       SCIPerrorMessage("invalid event type.\n");
10101       return SCIP_INVALIDDATA;
10102    }
10103    assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
10104 
10105    SCIPdebugMsg(scip, "changed bound of variable <%s> from %f to %f (nfixednonzeros: %d).\n", SCIPvarGetName(SCIPeventGetVar(event)),
10106                     oldbound, newbound, consdata->nfixednonzeros);
10107 
10108    return SCIP_OKAY;
10109 }
10110 
10111 
10112 /** constraint handler method to determine a diving variable by assigning a variable and two values for diving */
10113 static
SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1)10114 SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1)
10115 {
10116    SCIP_CONSHDLRDATA* conshdlrdata;
10117 
10118    assert( scip != NULL );
10119    assert( conshdlr != NULL );
10120    assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
10121    assert( diveset != NULL );
10122    assert( success != NULL );
10123    assert( infeasible != NULL );
10124 
10125    *infeasible = FALSE;
10126    *success = FALSE;
10127 
10128    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10129    {
10130       SCIPerrorMessage("not an SOS1 constraint handler.\n");
10131       return SCIP_INVALIDDATA;
10132    }
10133    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10134    assert( conshdlrdata != NULL );
10135 
10136    /* if the SOS1 constraints do not overlap, we apply a faster method getDiveBdChgsSOS1constraints() that does not make use of the conflict graph;
10137     * for overlapping SOS1 constraints we apply the method getDiveBdChgsSOS1conflictgraph(), which then may produce better results (e.g. due to more
10138     * diving candidates) */
10139    if ( conshdlrdata->switchsos1branch )
10140    {
10141       SCIP_CALL( getDiveBdChgsSOS1constraints(scip, conshdlr, diveset, sol, success) );
10142    }
10143    else
10144    {
10145       SCIP_CALL( getDiveBdChgsSOS1conflictgraph(scip, conshdlr, diveset, sol, success) );
10146    }
10147 
10148    return SCIP_OKAY;
10149 }
10150 
10151 
10152 /* ---------------- Constraint specific interface methods ---------------- */
10153 
10154 /** creates the handler for SOS1 constraints and includes it in SCIP */
SCIPincludeConshdlrSOS1(SCIP * scip)10155 SCIP_RETCODE SCIPincludeConshdlrSOS1(
10156    SCIP*                 scip                /**< SCIP data structure */
10157    )
10158 {
10159    SCIP_CONSHDLRDATA* conshdlrdata;
10160    SCIP_CONSHDLR* conshdlr;
10161 
10162    /* create constraint handler data */
10163    SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
10164    conshdlrdata->branchsos = TRUE;
10165    conshdlrdata->switchsos1branch = FALSE;
10166    conshdlrdata->switchcutsfromsos1 = FALSE;
10167    conshdlrdata->eventhdlr = NULL;
10168    conshdlrdata->fixnonzerovars = NULL;
10169    conshdlrdata->maxnfixnonzerovars = 0;
10170    conshdlrdata->nfixnonzerovars = 0;
10171    conshdlrdata->conflictgraph = NULL;
10172    conshdlrdata->localconflicts = NULL;
10173    conshdlrdata->isconflocal = FALSE;
10174    conshdlrdata->implgraph = NULL;
10175    conshdlrdata->nimplnodes = 0;
10176    conshdlrdata->nboundcuts = 0;
10177    conshdlrdata->tcliquegraph = NULL;
10178    conshdlrdata->tcliquedata = NULL;
10179    conshdlrdata->cntextsos1 = -1;
10180    conshdlrdata->varhash = NULL;
10181 
10182    /* create event handler for bound change events */
10183    SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecSOS1, NULL) );
10184    if ( conshdlrdata->eventhdlr == NULL )
10185    {
10186       SCIPerrorMessage("event handler for SOS1 constraints not found.\n");
10187       return SCIP_PLUGINNOTFOUND;
10188    }
10189 
10190    /* include constraint handler */
10191    SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
10192          CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
10193          consEnfolpSOS1, consEnfopsSOS1, consCheckSOS1, consLockSOS1, conshdlrdata) );
10194    assert(conshdlr != NULL);
10195 
10196    /* set non-fundamental callbacks via specific setter functions */
10197    SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySOS1, consCopySOS1) );
10198    SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSOS1) );
10199    SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsSOS1) );
10200    SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSOS1) );
10201    SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSOS1) );
10202    SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSOS1) );
10203    SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSOS1) );
10204    SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSOS1) );
10205    SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSOS1) );
10206    SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSOS1) );
10207    SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSOS1, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
10208    SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSOS1) );
10209    SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSOS1, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP, CONSHDLR_PROP_TIMING) );
10210    SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSOS1) );
10211    SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSOS1, consSepasolSOS1, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
10212    SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSOS1) );
10213    SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSOS1) );
10214 
10215    /* add SOS1 constraint handler parameters */
10216 
10217    /* adjacency matrix parameters */
10218    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxsosadjacency",
10219          "do not create an adjacency matrix if number of SOS1 variables is larger than predefined value (-1: no limit)",
10220          &conshdlrdata->maxsosadjacency, TRUE, DEFAULT_MAXSOSADJACENCY, -1, INT_MAX, NULL, NULL) );
10221 
10222    /* presolving parameters */
10223    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxextensions",
10224          "maximal number of extensions that will be computed for each SOS1 constraint  (-1: no limit)",
10225          &conshdlrdata->maxextensions, TRUE, DEFAULT_MAXEXTENSIONS, -1, INT_MAX, NULL, NULL) );
10226 
10227    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxtightenbds",
10228          "maximal number of bound tightening rounds per presolving round (-1: no limit)",
10229          &conshdlrdata->maxtightenbds, TRUE, DEFAULT_MAXTIGHTENBDS, -1, INT_MAX, NULL, NULL) );
10230 
10231    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/perfimplanalysis",
10232          "if TRUE then perform implication graph analysis (might add additional SOS1 constraints)",
10233          &conshdlrdata->perfimplanalysis, TRUE, DEFAULT_PERFIMPLANALYSIS, NULL, NULL) );
10234 
10235    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/depthimplanalysis",
10236          "number of recursive calls of implication graph analysis (-1: no limit)",
10237          &conshdlrdata->depthimplanalysis, TRUE, DEFAULT_DEPTHIMPLANALYSIS, -1, INT_MAX, NULL, NULL) );
10238 
10239    /* propagation parameters */
10240    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/conflictprop",
10241          "whether to use conflict graph propagation",
10242          &conshdlrdata->conflictprop, TRUE, DEFAULT_CONFLICTPROP, NULL, NULL) );
10243 
10244    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/implprop",
10245          "whether to use implication graph propagation",
10246          &conshdlrdata->implprop, TRUE, DEFAULT_IMPLPROP, NULL, NULL) );
10247 
10248    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/sosconsprop",
10249          "whether to use SOS1 constraint propagation",
10250          &conshdlrdata->sosconsprop, TRUE, DEFAULT_SOSCONSPROP, NULL, NULL) );
10251 
10252    /* branching parameters */
10253    SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchingrule",
10254          "which branching rule should be applied ? ('n': neighborhood, 'b': bipartite, 's': SOS1/clique) (note: in some cases an automatic switching to SOS1 branching is possible)",
10255          &conshdlrdata->branchingrule, TRUE, DEFAULT_BRANCHINGRULE, DEFAULT_BRANCHSTRATEGIES, NULL, NULL) );
10256 
10257    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autosos1branch",
10258          "if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap",
10259          &conshdlrdata->autosos1branch, TRUE, DEFAULT_AUTOSOS1BRANCH, NULL, NULL) );
10260 
10261    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/fixnonzero",
10262          "if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the feasibility tolerance",
10263          &conshdlrdata->fixnonzero, TRUE, DEFAULT_FIXNONZERO, NULL, NULL) );
10264 
10265    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addcomps",
10266          "if TRUE then add complementarity constraints to the branching nodes (can be used in combination with neighborhood or bipartite branching)",
10267          &conshdlrdata->addcomps, TRUE, DEFAULT_ADDCOMPS, NULL, NULL) );
10268 
10269    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxaddcomps",
10270          "maximal number of complementarity constraints added per branching node (-1: no limit)",
10271          &conshdlrdata->maxaddcomps, TRUE, DEFAULT_MAXADDCOMPS, -1, INT_MAX, NULL, NULL) );
10272 
10273    SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addcompsfeas",
10274          "minimal feasibility value for complementarity constraints in order to be added to the branching node",
10275          &conshdlrdata->addcompsfeas, TRUE, DEFAULT_ADDCOMPSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) );
10276 
10277    SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addbdsfeas",
10278          "minimal feasibility value for bound inequalities in order to be added to the branching node",
10279          &conshdlrdata->addbdsfeas, TRUE, DEFAULT_ADDBDSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) );
10280 
10281    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addextendedbds",
10282          "should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities",
10283          &conshdlrdata->addextendedbds, TRUE, DEFAULT_ADDEXTENDEDBDS, NULL, NULL) );
10284 
10285    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchsos",
10286          "Use SOS1 branching in enforcing (otherwise leave decision to branching rules)? This value can only be set to false if all SOS1 variables are binary",
10287          &conshdlrdata->branchsos, FALSE, TRUE, NULL, NULL) );
10288 
10289    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchnonzeros",
10290          "Branch on SOS constraint with most number of nonzeros?",
10291          &conshdlrdata->branchnonzeros, FALSE, FALSE, NULL, NULL) );
10292 
10293    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchweight",
10294          "Branch on SOS cons. with highest nonzero-variable weight for branching (needs branchnonzeros = false)?",
10295          &conshdlrdata->branchweight, FALSE, FALSE, NULL, NULL) );
10296 
10297    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/addcompsdepth",
10298          "only add complementarity constraints to branching nodes for predefined depth (-1: no limit)",
10299          &conshdlrdata->addcompsdepth, TRUE, DEFAULT_ADDCOMPSDEPTH, -1, INT_MAX, NULL, NULL) );
10300 
10301    /* selection rule parameters */
10302    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongrounds",
10303          "maximal number of strong branching rounds to perform for each node (-1: auto); only available for neighborhood and bipartite branching",
10304          &conshdlrdata->nstrongrounds, TRUE, DEFAULT_NSTRONGROUNDS, -1, INT_MAX, NULL, NULL) );
10305 
10306    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongiter",
10307          "maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit)",
10308          &conshdlrdata->nstrongiter, TRUE, DEFAULT_NSTRONGITER, -2, INT_MAX, NULL, NULL) );
10309 
10310    /* separation parameters */
10311    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromsos1",
10312          "if TRUE separate bound inequalities from initial SOS1 constraints",
10313          &conshdlrdata->boundcutsfromsos1, TRUE, DEFAULT_BOUNDCUTSFROMSOS1, NULL, NULL) );
10314 
10315    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromgraph",
10316          "if TRUE separate bound inequalities from the conflict graph",
10317          &conshdlrdata->boundcutsfromgraph, TRUE, DEFAULT_BOUNDCUTSFROMGRAPH, NULL, NULL) );
10318 
10319    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autocutsfromsos1",
10320          "if TRUE then automatically switch to separating initial SOS1 constraints if the SOS1 constraints do not overlap",
10321          &conshdlrdata->autocutsfromsos1, TRUE, DEFAULT_AUTOCUTSFROMSOS1, NULL, NULL) );
10322 
10323    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfreq",
10324          "frequency for separating bound cuts; zero means to separate only in the root node",
10325          &conshdlrdata->boundcutsfreq, TRUE, DEFAULT_BOUNDCUTSFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
10326 
10327    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsdepth",
10328          "node depth of separating bound cuts (-1: no limit)",
10329          &conshdlrdata->boundcutsdepth, TRUE, DEFAULT_BOUNDCUTSDEPTH, -1, INT_MAX, NULL, NULL) );
10330 
10331    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcuts",
10332          "maximal number of bound cuts separated per branching node",
10333          &conshdlrdata->maxboundcuts, TRUE, DEFAULT_MAXBOUNDCUTS, 0, INT_MAX, NULL, NULL) );
10334 
10335    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcutsroot",
10336          "maximal number of bound cuts separated per iteration in the root node",
10337          &conshdlrdata->maxboundcutsroot, TRUE, DEFAULT_MAXBOUNDCUTSROOT, 0, INT_MAX, NULL, NULL) );
10338 
10339    SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strthenboundcuts",
10340          "if TRUE then bound cuts are strengthened in case bound variables are available",
10341          &conshdlrdata->strthenboundcuts, TRUE, DEFAULT_STRTHENBOUNDCUTS, NULL, NULL) );
10342 
10343    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsfreq",
10344          "frequency for separating implied bound cuts; zero means to separate only in the root node",
10345          &conshdlrdata->implcutsfreq, TRUE, DEFAULT_IMPLCUTSFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
10346 
10347    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsdepth",
10348          "node depth of separating implied bound cuts (-1: no limit)",
10349          &conshdlrdata->implcutsdepth, TRUE, DEFAULT_IMPLCUTSDEPTH, -1, INT_MAX, NULL, NULL) );
10350 
10351    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcuts",
10352          "maximal number of implied bound cuts separated per branching node",
10353          &conshdlrdata->maximplcuts, TRUE, DEFAULT_MAXIMPLCUTS, 0, INT_MAX, NULL, NULL) );
10354 
10355    SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcutsroot",
10356          "maximal number of implied bound cuts separated per iteration in the root node",
10357          &conshdlrdata->maximplcutsroot, TRUE, DEFAULT_MAXIMPLCUTSROOT, 0, INT_MAX, NULL, NULL) );
10358 
10359    return SCIP_OKAY;
10360 }
10361 
10362 
10363 /** creates and captures a SOS1 constraint
10364  *
10365  *  We set the constraint to not be modifable. If the weights are non NULL, the variables are ordered according to these
10366  *  weights (in ascending order).
10367  *
10368  *  @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
10369  */
SCIPcreateConsSOS1(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Real * weights,SCIP_Bool initial,SCIP_Bool separate,SCIP_Bool enforce,SCIP_Bool check,SCIP_Bool propagate,SCIP_Bool local,SCIP_Bool dynamic,SCIP_Bool removable,SCIP_Bool stickingatnode)10370 SCIP_RETCODE SCIPcreateConsSOS1(
10371    SCIP*                 scip,               /**< SCIP data structure */
10372    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
10373    const char*           name,               /**< name of constraint */
10374    int                   nvars,              /**< number of variables in the constraint */
10375    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
10376    SCIP_Real*            weights,            /**< weights determining the variable order, or NULL if natural order should be used */
10377    SCIP_Bool             initial,            /**< should the LP relaxation of constraint be in the initial LP?
10378                                               *   Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
10379    SCIP_Bool             separate,           /**< should the constraint be separated during LP processing?
10380                                               *   Usually set to TRUE. */
10381    SCIP_Bool             enforce,            /**< should the constraint be enforced during node processing?
10382                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
10383    SCIP_Bool             check,              /**< should the constraint be checked for feasibility?
10384                                               *   TRUE for model constraints, FALSE for additional, redundant constraints. */
10385    SCIP_Bool             propagate,          /**< should the constraint be propagated during node processing?
10386                                               *   Usually set to TRUE. */
10387    SCIP_Bool             local,              /**< is constraint only valid locally?
10388                                               *   Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
10389    SCIP_Bool             dynamic,            /**< is constraint subject to aging?
10390                                               *   Usually set to FALSE. Set to TRUE for own cuts which
10391                                               *   are separated as constraints. */
10392    SCIP_Bool             removable,          /**< should the relaxation be removed from the LP due to aging or cleanup?
10393                                               *   Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
10394    SCIP_Bool             stickingatnode      /**< should the constraint always be kept at the node where it was added, even
10395                                               *   if it may be moved to a more global node?
10396                                               *   Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
10397    )
10398 {
10399    SCIP_CONSHDLR* conshdlr;
10400    SCIP_CONSDATA* consdata;
10401    SCIP_Bool modifiable;
10402    SCIP_Bool transformed;
10403    int v;
10404 
10405    modifiable = FALSE;
10406 
10407    /* find the SOS1 constraint handler */
10408    conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10409    if ( conshdlr == NULL )
10410    {
10411       SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
10412       return SCIP_PLUGINNOTFOUND;
10413    }
10414 
10415    /* are we in the transformed problem? */
10416    transformed = SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED;
10417 
10418    /* create constraint data */
10419    SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
10420    consdata->vars = NULL;
10421    consdata->nvars = nvars;
10422    consdata->maxvars = nvars;
10423    consdata->rowub = NULL;
10424    consdata->rowlb = NULL;
10425    consdata->nfixednonzeros = transformed ? 0 : -1;
10426    consdata->weights = NULL;
10427    consdata->local = local;
10428 
10429    if ( nvars > 0 )
10430    {
10431       SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) );
10432 
10433       /* check weights */
10434       if ( weights != NULL )
10435       {
10436          /* store weights */
10437          SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, weights, nvars) );
10438 
10439          /* sort variables - ascending order */
10440          SCIPsortRealPtr(consdata->weights, (void**)consdata->vars, nvars);
10441       }
10442    }
10443    else
10444    {
10445       assert( weights == NULL );
10446    }
10447 
10448    /* branching on multiaggregated variables does not seem to work well, so avoid it */
10449    for (v = 0; v < nvars; ++v)
10450    {
10451       SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->vars[v]) );
10452    }
10453 
10454    /* create constraint */
10455    SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
10456          local, modifiable, dynamic, removable, stickingatnode) );
10457    assert( transformed == SCIPconsIsTransformed(*cons) );
10458 
10459    /* replace original variables by transformed variables in transformed constraint, add locks, and catch events */
10460    for (v = nvars - 1; v >= 0; --v)
10461    {
10462       SCIP_CONSHDLRDATA* conshdlrdata;
10463 
10464       /* always use transformed variables in transformed constraints */
10465       if ( transformed )
10466       {
10467          SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[v], &(consdata->vars[v])) );
10468       }
10469       assert( consdata->vars[v] != NULL );
10470       assert( transformed == SCIPvarIsTransformed(consdata->vars[v]) );
10471 
10472       /* get constraint handler data */
10473       conshdlrdata = SCIPconshdlrGetData(conshdlr);
10474       assert( conshdlrdata != NULL );
10475 
10476       /* handle the new variable */
10477       SCIP_CALL( handleNewVariableSOS1(scip, *cons, consdata, conshdlrdata, consdata->vars[v], transformed) );
10478    }
10479 
10480    return SCIP_OKAY;
10481 }
10482 
10483 
10484 /** creates and captures a SOS1 constraint with all constraint flags set to their default values.
10485  *
10486  *  @warning Do NOT set the constraint to be modifiable manually, because this might lead
10487  *  to wrong results as the variable array will not be resorted
10488  *
10489  *  @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
10490  */
SCIPcreateConsBasicSOS1(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Real * weights)10491 SCIP_RETCODE SCIPcreateConsBasicSOS1(
10492    SCIP*                 scip,               /**< SCIP data structure */
10493    SCIP_CONS**           cons,               /**< pointer to hold the created constraint */
10494    const char*           name,               /**< name of constraint */
10495    int                   nvars,              /**< number of variables in the constraint */
10496    SCIP_VAR**            vars,               /**< array with variables of constraint entries */
10497    SCIP_Real*            weights             /**< weights determining the variable order, or NULL if natural order should be used */
10498    )
10499 {
10500    SCIP_CALL( SCIPcreateConsSOS1( scip, cons, name, nvars, vars, weights, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
10501 
10502    return SCIP_OKAY;
10503 }
10504 
10505 
10506 /** adds variable to SOS1 constraint, the position is determined by the given weight */
SCIPaddVarSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Real weight)10507 SCIP_RETCODE SCIPaddVarSOS1(
10508    SCIP*                 scip,               /**< SCIP data structure */
10509    SCIP_CONS*            cons,               /**< constraint */
10510    SCIP_VAR*             var,                /**< variable to add to the constraint */
10511    SCIP_Real             weight              /**< weight determining position of variable */
10512    )
10513 {
10514    SCIP_CONSHDLRDATA* conshdlrdata;
10515    SCIP_CONSHDLR* conshdlr;
10516 
10517    assert( scip != NULL );
10518    assert( var != NULL );
10519    assert( cons != NULL );
10520 
10521    SCIPdebugMsg(scip, "adding variable <%s> to constraint <%s> with weight %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), weight);
10522 
10523    conshdlr = SCIPconsGetHdlr(cons);
10524    assert( conshdlr != NULL );
10525    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10526    {
10527       SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
10528       return SCIP_INVALIDDATA;
10529    }
10530 
10531    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10532    assert( conshdlrdata != NULL );
10533 
10534    SCIP_CALL( addVarSOS1(scip, cons, conshdlrdata, var, weight) );
10535 
10536    return SCIP_OKAY;
10537 }
10538 
10539 
10540 /** appends variable to SOS1 constraint */
SCIPappendVarSOS1(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)10541 SCIP_RETCODE SCIPappendVarSOS1(
10542    SCIP*                 scip,               /**< SCIP data structure */
10543    SCIP_CONS*            cons,               /**< constraint */
10544    SCIP_VAR*             var                 /**< variable to add to the constraint */
10545    )
10546 {
10547    SCIP_CONSHDLRDATA* conshdlrdata;
10548    SCIP_CONSHDLR* conshdlr;
10549 
10550    assert( scip != NULL );
10551    assert( var != NULL );
10552    assert( cons != NULL );
10553 
10554    SCIPdebugMsg(scip, "appending variable <%s> to constraint <%s>\n", SCIPvarGetName(var), SCIPconsGetName(cons));
10555 
10556    conshdlr = SCIPconsGetHdlr(cons);
10557    assert( conshdlr != NULL );
10558    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10559    {
10560       SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
10561       return SCIP_INVALIDDATA;
10562    }
10563 
10564    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10565    assert( conshdlrdata != NULL );
10566 
10567    SCIP_CALL( appendVarSOS1(scip, cons, conshdlrdata, var) );
10568 
10569    return SCIP_OKAY;
10570 }
10571 
10572 
10573 /** gets number of variables in SOS1 constraint */
SCIPgetNVarsSOS1(SCIP * scip,SCIP_CONS * cons)10574 int SCIPgetNVarsSOS1(
10575    SCIP*                 scip,               /**< SCIP data structure */
10576    SCIP_CONS*            cons                /**< constraint */
10577    )
10578 {
10579    SCIP_CONSDATA* consdata;
10580 
10581    assert( scip != NULL );
10582    assert( cons != NULL );
10583 
10584    if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
10585    {
10586       SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
10587       SCIPABORT();
10588       return -1;  /*lint !e527*/
10589    }
10590 
10591    consdata = SCIPconsGetData(cons);
10592    assert( consdata != NULL );
10593 
10594    return consdata->nvars;
10595 }
10596 
10597 
10598 /** gets array of variables in SOS1 constraint */
SCIPgetVarsSOS1(SCIP * scip,SCIP_CONS * cons)10599 SCIP_VAR** SCIPgetVarsSOS1(
10600    SCIP*                 scip,               /**< SCIP data structure */
10601    SCIP_CONS*            cons                /**< constraint data */
10602    )
10603 {
10604    SCIP_CONSDATA* consdata;
10605 
10606    assert( scip != NULL );
10607    assert( cons != NULL );
10608 
10609    if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
10610    {
10611       SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
10612       SCIPABORT();
10613       return NULL;  /*lint !e527*/
10614    }
10615 
10616    consdata = SCIPconsGetData(cons);
10617    assert( consdata != NULL );
10618 
10619    return consdata->vars;
10620 }
10621 
10622 
10623 /** gets array of weights in SOS1 constraint (or NULL if not existent) */
SCIPgetWeightsSOS1(SCIP * scip,SCIP_CONS * cons)10624 SCIP_Real* SCIPgetWeightsSOS1(
10625    SCIP*                 scip,               /**< SCIP data structure */
10626    SCIP_CONS*            cons                /**< constraint data */
10627    )
10628 {
10629    SCIP_CONSDATA* consdata;
10630 
10631    assert( scip != NULL );
10632    assert( cons != NULL );
10633 
10634    if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
10635    {
10636       SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
10637       SCIPABORT();
10638       return NULL;  /*lint !e527*/
10639    }
10640 
10641    consdata = SCIPconsGetData(cons);
10642    assert( consdata != NULL );
10643 
10644    return consdata->weights;
10645 }
10646 
10647 
10648 /** gets conflict graph of SOS1 constraints (or NULL if not existent)
10649  *
10650  *  @note The conflict graph is globally valid; local changes are not taken into account.
10651  */
SCIPgetConflictgraphSOS1(SCIP_CONSHDLR * conshdlr)10652 SCIP_DIGRAPH* SCIPgetConflictgraphSOS1(
10653    SCIP_CONSHDLR*        conshdlr            /**< SOS1 constraint handler */
10654    )
10655 {
10656    SCIP_CONSHDLRDATA* conshdlrdata;
10657 
10658    assert( conshdlr != NULL );
10659 
10660    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10661    {
10662       SCIPerrorMessage("not an SOS1 constraint handler.\n");
10663       SCIPABORT();
10664       return NULL;  /*lint !e527*/
10665    }
10666    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10667    assert( conshdlrdata != NULL );
10668 
10669    return conshdlrdata->conflictgraph;
10670 }
10671 
10672 
10673 /** gets number of problem variables that are part of the SOS1 conflict graph */
SCIPgetNSOS1Vars(SCIP_CONSHDLR * conshdlr)10674 int SCIPgetNSOS1Vars(
10675    SCIP_CONSHDLR*        conshdlr            /**< SOS1 constraint handler */
10676    )
10677 {
10678    SCIP_CONSHDLRDATA* conshdlrdata;
10679 
10680    assert( conshdlr != NULL );
10681 
10682    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10683    {
10684       SCIPerrorMessage("not an SOS1 constraint handler.\n");
10685       SCIPABORT();
10686       return -1; /*lint !e527*/
10687    }
10688    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10689    assert( conshdlrdata != NULL );
10690 
10691    return conshdlrdata->nsos1vars;
10692 }
10693 
10694 
10695 /** returns whether variable is part of the SOS1 conflict graph */
SCIPvarIsSOS1(SCIP_CONSHDLR * conshdlr,SCIP_VAR * var)10696 SCIP_Bool SCIPvarIsSOS1(
10697    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
10698    SCIP_VAR*             var                 /**< variable */
10699    )
10700 {
10701    SCIP_CONSHDLRDATA* conshdlrdata;
10702 
10703    assert( var != NULL );
10704    assert( conshdlr != NULL );
10705 
10706    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10707    {
10708       SCIPerrorMessage("not an SOS1 constraint handler.\n");
10709       SCIPABORT();
10710       return FALSE; /*lint !e527*/
10711    }
10712    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10713    assert( conshdlrdata != NULL );
10714 
10715    return varIsSOS1(conshdlrdata, var);
10716 }
10717 
10718 
10719 /** returns SOS1 index of variable or -1 if variable is not part of the SOS1 conflict graph */
SCIPvarGetNodeSOS1(SCIP_CONSHDLR * conshdlr,SCIP_VAR * var)10720 int SCIPvarGetNodeSOS1(
10721    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
10722    SCIP_VAR*             var                 /**< variable */
10723    )
10724 {
10725    SCIP_CONSHDLRDATA* conshdlrdata;
10726 
10727    assert( conshdlr != NULL );
10728    assert( var != NULL );
10729 
10730    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10731    {
10732       SCIPerrorMessage("Not an SOS1 constraint handler.\n");
10733       SCIPABORT();
10734       return -1;  /*lint !e527*/
10735    }
10736    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10737    assert( conshdlrdata != NULL );
10738 
10739    if ( conshdlrdata->varhash == NULL )
10740    {
10741       SCIPerrorMessage("Hashmap not yet initialized.\n");
10742       SCIPABORT();
10743       return -1;  /*lint !e527*/
10744    }
10745 
10746    return varGetNodeSOS1(conshdlrdata, var);
10747 }
10748 
10749 
10750 /** returns variable that belongs to a given node from the conflict graph */
SCIPnodeGetVarSOS1(SCIP_DIGRAPH * conflictgraph,int node)10751 SCIP_VAR* SCIPnodeGetVarSOS1(
10752    SCIP_DIGRAPH*         conflictgraph,      /**< conflict graph */
10753    int                   node                /**< node from the conflict graph */
10754    )
10755 {
10756    SCIP_NODEDATA* nodedata;
10757 
10758    assert( conflictgraph != NULL );
10759    assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
10760 
10761    /* get node data */
10762    nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
10763 
10764    if ( nodedata == NULL )
10765    {
10766       SCIPerrorMessage("variable is not assigned to an index.\n");
10767       SCIPABORT();
10768       return NULL;  /*lint !e527*/
10769    }
10770 
10771    return nodedata->var;
10772 }
10773 
10774 
10775 /** based on solution values of the variables, fixes variables to zero to turn all SOS1 constraints feasible */
SCIPmakeSOS1sFeasible(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_SOL * sol,SCIP_Bool * changed,SCIP_Bool * success)10776 SCIP_RETCODE SCIPmakeSOS1sFeasible(
10777    SCIP*                 scip,               /**< SCIP pointer */
10778    SCIP_CONSHDLR*        conshdlr,           /**< SOS1 constraint handler */
10779    SCIP_SOL*             sol,                /**< solution */
10780    SCIP_Bool*            changed,            /**< pointer to store whether the solution has been changed */
10781    SCIP_Bool*            success             /**< pointer to store whether SOS1 constraints have been turned feasible and
10782                                               *   solution was good enough */
10783    )
10784 {
10785    SCIP_CONSHDLRDATA* conshdlrdata;
10786    SCIP_Real roundobjval;
10787    SCIP_Bool allroundable;
10788 
10789    assert( scip != NULL );
10790    assert( conshdlr != NULL );
10791    assert( sol != NULL );
10792    assert( changed != NULL );
10793    assert( success != NULL );
10794 
10795    if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
10796    {
10797       SCIPerrorMessage("Not an SOS1 constraint handler.\n");
10798       return SCIP_PARAMETERWRONGVAL;
10799    }
10800    conshdlrdata = SCIPconshdlrGetData(conshdlr);
10801    assert( conshdlrdata != NULL );
10802 
10803    *changed = FALSE;
10804    *success = FALSE;
10805    allroundable = FALSE;
10806 
10807    /* check number of SOS1 constraints */
10808    if ( SCIPconshdlrGetNConss(conshdlr) < 1 )
10809    {
10810       *success = TRUE;
10811       return SCIP_OKAY;
10812    }
10813 
10814    /* if the SOS1 constraints do not overlap, we apply a faster method makeSOS1constraintsFeasible() that does not make use of the conflict graph;
10815     * for overlapping SOS1 constraints we apply the method makeSOS1conflictgraphFeasible(), which then may produce better feasible solutions */
10816    if ( conshdlrdata->switchsos1branch )
10817    {
10818       SCIP_CALL( makeSOS1constraintsFeasible(scip, conshdlr, sol, changed, &allroundable) );
10819    }
10820    else
10821    {
10822       SCIP_CALL( makeSOS1conflictgraphFeasible(scip, conshdlr, sol, changed, &allroundable) );
10823    }
10824 
10825    if ( ! allroundable ) /*lint !e774*/
10826       return SCIP_OKAY;
10827 
10828    /* check whether objective value of rounded solution is good enough */
10829    roundobjval = SCIPgetSolOrigObj(scip, sol);
10830    if ( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE )
10831       roundobjval *= -1;
10832 
10833    if ( SCIPisLT(scip, roundobjval, SCIPgetUpperbound(scip) ) )
10834       *success = TRUE;
10835 
10836    return SCIP_OKAY;
10837 }
10838