SCIP Doxygen Documentation
Loading...
Searching...
No Matches
sepa_oddcycle.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file sepa_oddcycle.c
26 * @ingroup DEFPLUGINS_SEPA
27 * @brief oddcycle separator
28 * @author Robert Waniek
29 * @author Marc Pfetsch
30 *
31 * We separate odd cycle inequalities in the implication graph. Implemented are the classic method
32 * by Groetschel, Lovasz, and Schrijver (GLS) and the levelgraph method by Hoffman and Padberg (HP)
33 *
34 * Odd cycle inequalities are lifted by a heuristic method based on an idea from Alvarez-Valdes,
35 * Parreno, and Tamarit.
36 *
37 * Some part of this code is based on the odd cycle separator of the program colorbitopt by Marc
38 * Pfetsch.
39 */
40
41/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42
44#include "dijkstra/dijkstra.h"
45#include "scip/pub_implics.h"
46#include "scip/pub_lp.h"
47#include "scip/pub_message.h"
48#include "scip/pub_misc.h"
49#include "scip/pub_misc_sort.h"
50#include "scip/pub_sepa.h"
51#include "scip/pub_tree.h"
52#include "scip/pub_var.h"
53#include "scip/scip_branch.h"
54#include "scip/scip_cut.h"
55#include "scip/scip_general.h"
56#include "scip/scip_lp.h"
57#include "scip/scip_mem.h"
58#include "scip/scip_message.h"
59#include "scip/scip_numerics.h"
60#include "scip/scip_param.h"
61#include "scip/scip_prob.h"
62#include "scip/scip_sepa.h"
63#include "scip/scip_sol.h"
65#include "scip/scip_tree.h"
66#include "scip/scip_var.h"
67#include "scip/sepa_oddcycle.h"
68
69
70#define SEPA_NAME "oddcycle"
71#define SEPA_DESC "odd cycle separator"
72#define SEPA_PRIORITY -15000
73#define SEPA_FREQ -1
74#define SEPA_MAXBOUNDDIST 1.0
75#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
76#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
77
78
79/* default values for separator settings */
80#define DEFAULT_SCALEFACTOR 1000 /**< factor for scaling of the arc-weights in the Dijkstra algorithm */
81#define DEFAULT_USEGLS TRUE /**< use GLS method, otherwise HP method */
82#define DEFAULT_LIFTODDCYCLES FALSE /**< lift odd cycle cuts */
83#define DEFAULT_REPAIRCYCLES TRUE /**< try to repair violated cycles in which a variable and its negated appear */
84#define DEFAULT_ADDSELFARCS TRUE /**< add links between a variable and its negated */
85#define DEFAULT_INCLUDETRIANGLES TRUE /**< separate triangles (3-cliques) found as 3-cycles or repaired larger cycles */
86#define DEFAULT_MULTIPLECUTS FALSE /**< still try variable as start, even if it is already covered by a cut */
87#define DEFAULT_ALLOWMULTIPLECUTS TRUE /**< allow another inequality to use variable, even if it is already covered */
88#define DEFAULT_LPLIFTCOEF FALSE /**< TRUE: choose lifting candidate with highest value of coefficient*lpvalue
89 * FALSE: choose lifting candidate with highest coefficient */
90#define DEFAULT_RECALCLIFTCOEF TRUE /**< whether lifting coefficients should be recomputed */
91#define DEFAULT_MAXSEPACUTS 5000 /**< maximal number of oddcycle cuts separated per separation round */
92#define DEFAULT_MAXSEPACUTSROOT 5000 /**< maximal number of oddcycle cuts separated per separation round in root node */
93#define DEFAULT_PERCENTTESTVARS 0 /**< percent of variables to try the chosen method on [0-100] */
94#define DEFAULT_OFFSETTESTVARS 100 /**< offset of variables to try the chosen method on */
95#define DEFAULT_MAXCUTSROOT 1 /**< maximal number of oddcycle cuts generated per root of the levelgraph */
96#define DEFAULT_SORTSWITCH 3 /**< unsorted (0), maxlp (1), minlp (2), maxfrac (3), minfrac (4) */
97#define DEFAULT_MAXREFERENCE 0 /**< minimal weight on an edge (in level graph or Dijkstra graph) */
98#define DEFAULT_MAXROUNDS 10 /**< maximal number of rounds pre node */
99#define DEFAULT_MAXROUNDSROOT 10 /**< maximal number of rounds in the root node */
100#define DEFAULT_MAXNLEVELS 20 /**< maximal number of levels in level graph */
101#define DEFAULT_MAXPERNODESLEVEL 100 /**< maximal percentage of nodes allowed in one level of the levelgraph [0-100] */
102#define DEFAULT_OFFSETNODESLEVEL 10 /**< additional offset of nodes allowed in one level of the levelgraph */
103#define DEFAULT_SORTROOTNEIGHBORS TRUE /**< sort neighbors of the root in the level graph */
104#define DEFAULT_MAXCUTSLEVEL 50 /**< maximal number of cuts produced per level */
105#define DEFAULT_MAXUNSUCESSFULL 3 /**< maximal number of unsuccessful calls at each node */
106#define DEFAULT_CUTTHRESHOLD -1 /**< maximal number of other cuts s.t. separation is applied (-1 for direct call) */
107
108
109/*
110 * Data structures
111 */
112
113/** Graph structure for level graph
114 *
115 * This graph is tailored to the heuristic search for odd holes, @see separateHeur().
116 *
117 * This undirected graph is represented by a directed graph with forward and backward arcs. Arcs are
118 * forward if they lead from a level l to level l+1, i.e., away from the root; backward arcs
119 * lead from a level l+1 to level l. This distinction enables a fast construction and search
120 * process. In the latter only forward or backward arcs have to be searched.
121 *
122 * Target nodes and weights of the arcs incident to each node (adjacency lists) are stored
123 * consecutively in the arrays targetForward, targetBackward, weightForward, and weightBackward.
124 * The end of each list is marked by a -1 in targetForward and targetBackward.
125 */
126struct levelGraph
127{
128 unsigned int nnodes; /**< number of nodes */
129 unsigned int narcs; /**< number of arcs */
130 unsigned int maxnodes; /**< maximal number of nodes of the level graph */
131 unsigned int maxarcs; /**< maximal number of arcs of the level graph */
132 unsigned int nlevels; /**< number of levels completely inserted so far */
133 unsigned int* level; /**< level number for each node */
134 unsigned int lastF; /**< last storage element index in targetForward, weightForward - forward direction */
135 unsigned int lastB; /**< last storage element index in targetBackward, weightBackward - backward direction */
136 int* beginForward; /**< forward adjacency list index in targetForward, weightForward for each node */
137 int* beginBackward; /**< backward adjacency list index in targetBackward, weightBackward for each node */
138 int* targetForward; /**< target nodes of forward arcs */
139 int* targetBackward; /**< target nodes of backward arcs */
140 unsigned int* weightForward; /**< weights of forward arcs */
141 unsigned int* weightBackward; /**< weights of backwards arcs */
142 unsigned int sizeForward; /**< size of targetForward and weightForward */
143 unsigned int sizeBackward; /**< size of targetBackward and weightBackward */
144 int* beginAdj; /**< index of list of arcs inside a level (in sourceAdj) for each node
145 * (the index points at the first arc starting from this node) */
146 unsigned int* sourceAdj; /**< source nodes of arcs inside a level */
147 unsigned int* targetAdj; /**< target nodes of arcs inside a level */
148 unsigned int* weightAdj; /**< weights of arcs inside a level */
149 unsigned int* levelAdj; /**< index of the first arc inside a given level */
150 unsigned int sizeAdj; /**< size of sourceAdj, targetAdj and weightAdj */
151};
152
153typedef struct levelGraph LEVELGRAPH;
154
155
156/** sorting type for starting node or root node iteration order
157 *
158 * If the array should be sorted (1-4), the variable array is sorted every round by the chosen
159 * sorttype and the search method tries the nodes in order of the array. If the array is used
160 * unsorted (0), the search methods tries the nodes in order of the array and stores the last
161 * processed start node or root node and continues from this position in the next separation round.
162 */
164{
165 UNSORTED = 0, /**< variable array is unsorted */
166 MAXIMAL_LPVALUE = 1, /**< variable array is sorted by maximal lp-value */
167 MINIMAL_LPVALUE = 2, /**< variable array is sorted by minimal fractionality */
168 MAXIMAL_FRACTIONALITY = 3, /**< variable array is sorted by maximal lp-value */
169 MINIMAL_FRACTIONALITY = 4 /**< variable array is sorted by minimal fractionality */
170};
171typedef enum sorttype SORTTYPE;
172
173/** auxiliary data structure for passing graphs */
175{
176 SCIP_Bool usegls; /**< Use GLS algorithm? If true, dijstragraph != NULL should hold, otherwise levelgraph != NULL */
177 LEVELGRAPH* levelgraph; /**< level graph when using HP method, NULL otherwise */
178 DIJKSTRA_GRAPH* dijkstragraph; /**< Dijkstra graph if using method by GLS, NULL otherwise */
179};
180typedef struct GraphData GRAPHDATA;
181
182/** separator data */
183struct SCIP_SepaData
184{
185 int scale; /**< factor for scaling of the arc-weights */
186 unsigned int ncuts; /**< number of cuts, added by the separator so far (in current and past calls) */
187 unsigned int oldncuts; /**< number of cuts at the start the current separation round */
188 int nliftedcuts; /**< number of lifted cuts, added by the separator so far (in current and past calls) */
189 SCIP_Bool usegls; /**< use GLS method, otherwise HP method */
190 SCIP_Bool multiplecuts; /**< an odd cycle cut of length L can be generated L times; forbidding multiple cuts
191 * per node might be faster but might miss some cuts in the current round */
192 SCIP_Bool allowmultiplecuts; /**< allow multiple cuts covering one node */
193 SCIP_Bool liftoddcycles; /**< TRUE, iff we try to lift odd cycle inequalities */
194 SCIP_Bool addselfarcs; /**< add arcs between the nodes of a variable and its negated; since not all implications
195 * are in the graph, this often finds more cycles */
196 SCIP_Bool repaircycles; /**< if a variable and its negated appear in a cycle, we can repair the cycle
197 * by removing both and reconnecting the remaining nodes of the cycle */
198 SCIP_Bool includetriangles; /**< handle triangles found as 3-cycles or repaired larger cycles */
199 unsigned int* mapping; /**< mapping for getting the index of a variable in the sorted variable array */
200 SCIP_Bool lpliftcoef; /**< TRUE: choose lifting candidate with highest value of coefficient*lpvalue
201 * FALSE: choose lifting candidate with highest coefficient */
202 SCIP_Bool recalcliftcoef; /**< whether lifting coefficients should be recomputed */
203 int maxsepacuts; /**< max. number of oddcycle cuts separated per separation round */
204 int maxsepacutsroot; /**< max. number of oddcycle cuts separated per separation round in the root node */
205 int maxsepacutsround; /**< max. number of oddcycle cuts separated per separation round in the current node */
206 SORTTYPE sortswitch; /**< sorted type: unsorted (0), maxlp (1), minlp (2), maxfrac (3), minfrac (4) */
207 int lastroot; /**< save root of last GLS-method run */
208 SCIP_Bool sortrootneighbors; /**< sort neighbors of the root in the level graph */
209 int percenttestvars; /**< percentage of variables to try the chosen method on [0-100] */
210 int offsettestvars; /**< offset of variables to try the chosen method on */
211 int maxpernodeslevel; /**< percentage of nodes allowed in the same level of the level graph [0-100] */
212 int offsetnodeslevel; /**< additional offset of nodes allowed in one level of the levelgraph */
213 unsigned int maxlevelsize; /**< maximal number of nodes allowed in the same level of the level graph */
214 int maxcutsroot; /**< maximal number of oddcycle cuts generated per root of the levelgraph */
215 int maxcutslevel; /**< maximal number of oddcycle cuts generated per level of the level graph */
216 int maxrounds; /**< maximal number of oddcycle separation rounds per node (-1: unlimited) */
217 int maxroundsroot; /**< maximal number of oddcycle separation rounds in the root node (-1: unlimited) */
218 int maxreference; /**< minimal weight on an edge (in level graph or Dijkstra graph) */
219 int maxnlevels; /**< maximal number of levels in level graph */
220 int maxunsucessfull; /**< maximal number of unsuccessful calls at each node */
221 int nunsucessfull; /**< number of unsuccessful calls at current node */
222 int cutthreshold; /**< maximal number of other cuts s.t. separation is applied (-1 for direct call) */
223 SCIP_Longint lastnode; /**< number of last node */
224};
225
226
227/*
228 * debugging methods
229 */
230
231#ifdef SCIP_OUTPUT
232
233/** displays cycle of pred data structure w.r.t. variable names of the original problem (including
234 * status: original or negated node in graph)
235 */
236static
237void printCycle(
238 SCIP_VAR** vars, /**< problem variables */
239 unsigned int* pred, /**< cycle stored as predecessor list */
240 unsigned int nbinvars, /**< number of binary problem variables */
241 unsigned int startnode /**< a node of the cycle */
242 )
243{
244 unsigned int varsindex;
245 unsigned int counter;
246
247 assert(vars != NULL);
248 assert(pred != NULL);
249 assert(nbinvars > 0);
250 assert(startnode < 4*nbinvars);
251
252 counter = 0;
253 varsindex = startnode;
254
255 /* print start/end node */
256 if( varsindex < nbinvars || ( varsindex >= 2*nbinvars && varsindex < 3*nbinvars ) )
257 {
258 SCIPdebugMsg(scip, "+ %s\n",SCIPvarGetName(vars[varsindex%nbinvars]));
259 }
260 else
261 {
262 SCIPdebugMsg(scip, "- %s\n",SCIPvarGetName(vars[varsindex%nbinvars]));
263 }
264
265 /* print inner nodes */
266 for( varsindex = pred[startnode]; varsindex != startnode; varsindex = pred[varsindex] )
267 {
268 if( varsindex < nbinvars || ( varsindex >= 2*nbinvars && varsindex < 3*nbinvars ) )
269 {
270 SCIPdebugMsg(scip, "+ %s\n",SCIPvarGetName(vars[varsindex%nbinvars]));
271 }
272 else
273 {
274 SCIPdebugMsg(scip, "- %s\n",SCIPvarGetName(vars[varsindex%nbinvars]));
275 }
276 ++counter;
277 }
278
279 /* print start/end node */
280 if( varsindex < nbinvars || ( varsindex >= 2*nbinvars && varsindex < 3*nbinvars ) )
281 {
282 SCIPdebugMsg(scip, "+ %s\n",SCIPvarGetName(vars[varsindex%nbinvars]));
283 }
284 else
285 {
286 SCIPdebugMsg(scip, "- %s\n",SCIPvarGetName(vars[varsindex%nbinvars]));
287 }
288
289 ++counter;
290 SCIPdebugMsg(scip, "original cycle has %u variables.\n", counter);
291}
292#endif
293
294
295/*
296 * lifting methods
297 */
298
299/** using the level graph (if possible) or Dijkstra graph data structure (depending on the used
300 * method) we determine whether two nodes are adjacent
301 */
302static
304 SCIP_VAR** vars, /**< problem variables */
305 unsigned int nbinvars, /**< number of binary problem variables */
306 GRAPHDATA* graphdata, /**< graph */
307 unsigned int a, /**< node index of first variable */
308 unsigned int b /**< node index of second variable */
309 )
310{
311 unsigned int i;
312
313 assert(vars != NULL);
314 assert(nbinvars > 2);
315 assert(graphdata != NULL);
316 assert(graphdata->levelgraph != NULL || graphdata->usegls);
317 assert(graphdata->dijkstragraph != NULL || ! graphdata->usegls);
318 assert(a < 2*nbinvars);
319 assert(b < 2*nbinvars);
320 assert(a != b);
321
322 /* determine adjacency using the Dijkstra graph */
323 if( graphdata->usegls )
324 {
325 DIJKSTRA_GRAPH* dijkstragraph = graphdata->dijkstragraph;
326 if( dijkstragraph->outcnt[a] == 0 || dijkstragraph->outcnt[b] == 0 )
327 return FALSE;
328
329 /* @todo later: if helpful: sort head and weight list once */
330 for( i = dijkstragraph->outbeg[a]; i < dijkstragraph->outbeg[a] + dijkstragraph->outcnt[a]; ++i )
331 {
332 if( dijkstragraph->head[i] == b + 2*nbinvars )
333 return TRUE;
334 }
335 }
336 else /* determine adjacency using the level graph */
337 {
338 LEVELGRAPH* levelgraph = graphdata->levelgraph;
339
340 /* if a and b are contained in the level graph (with their arcs), we can check inside the level graph structure */
341 if( (levelgraph->beginForward[a] != -1 || levelgraph->beginBackward[a] != -1)
342 && (levelgraph->beginForward[b] != -1 || levelgraph->beginBackward[b] != -1) )
343 {
344 assert(levelgraph->level[a] <= levelgraph->nlevels);
345 assert(levelgraph->level[b] <= levelgraph->nlevels);
346
347 /* if a and b are not in neighbored levels or the same level, they cannot be adjacent */
348 if( levelgraph->level[a] > levelgraph->level[b] + 1
349 || levelgraph->level[b] > levelgraph->level[a] + 1 )
350 return FALSE;
351
352 assert(levelgraph->level[a] == levelgraph->level[b]
353 || levelgraph->level[a]+1 == levelgraph->level[b]
354 || levelgraph->level[a] == levelgraph->level[b]+1);
355
356 /* first case of adjacent level */
357 if( levelgraph->level[a] == levelgraph->level[b]+1 )
358 {
359 if( levelgraph->beginBackward[a] >= 0 )
360 {
361 i = (unsigned int) levelgraph->beginBackward[a];
362 while( levelgraph->targetBackward[i] != -1 )
363 {
364 if( levelgraph->targetBackward[i] == (int)b )
365 return TRUE;
366 ++i;
367 }
368 }
369 }
370 else if( levelgraph->level[a] == levelgraph->level[b]-1 ) /* second case of adjacent level */
371 {
372 if( levelgraph->beginForward[a] >= 0 )
373 {
374 i = (unsigned int) levelgraph->beginForward[a];
375 while( levelgraph->targetForward[i] != -1 )
376 {
377 if( levelgraph->targetForward[i] == (int)b )
378 return TRUE;
379 ++i;
380 }
381 }
382 }
383 else /* same level (note that an edge between a and b is stored for a if a < b, otherwise it is stored for b) */
384 {
385 assert(levelgraph->level[a] == levelgraph->level[b]);
386 assert(levelgraph->level[a] > 0); /* root has no neighbor in the same level */
387
388 if( a < b && levelgraph->beginAdj[a] >= 0 )
389 {
390 i = (unsigned int) levelgraph->beginAdj[a];
391 assert(i >= levelgraph->levelAdj[levelgraph->level[a]]);
392
393 while( i < levelgraph->levelAdj[levelgraph->level[a]+1] && levelgraph->sourceAdj[i] == a )
394 {
395 if( levelgraph->targetAdj[i] == b )
396 return TRUE;
397
398 /* if adjacency list ends we are done and a and b are not adjacent */
399 if( levelgraph->sourceAdj[i] == 0 && levelgraph->targetAdj[i] == 0 )
400 return FALSE;
401
402 assert(levelgraph->sourceAdj[i] < levelgraph->targetAdj[i]);
403 ++i;
404 }
405 }
406 if( b < a && levelgraph->beginAdj[b] >= 0 )
407 {
408 i = (unsigned int) levelgraph->beginAdj[b];
409 assert(i >= levelgraph->levelAdj[levelgraph->level[b]]);
410
411 while( i < levelgraph->levelAdj[levelgraph->level[b]+1] && levelgraph->sourceAdj[i] == b )
412 {
413 if( levelgraph->targetAdj[i] == a )
414 return TRUE;
415
416 /* if adjacency list ends we are done and a and b are not adjacent */
417 if( levelgraph->sourceAdj[i] == 0 && levelgraph->targetAdj[i] == 0 )
418 return FALSE;
419
420 assert(levelgraph->sourceAdj[i] < levelgraph->targetAdj[i]);
421 ++i;
422 }
423 }
424 }
425 }
426 /* if a or b is not in the levels already completely inserted in the levelgraph, we check
427 * their adjacency by the SCIP data structures
428 */
429 else
430 {
431 SCIP_CLIQUE** cliques;
432 SCIP_VAR** cliquevars;
433 SCIP_Bool* cliquevals;
434 SCIP_Bool originala;
435 SCIP_Bool originalb;
436 unsigned int ncliques;
437 unsigned int ncliquevars;
438 unsigned int j;
439
440 /* get original variables */
441 originala = TRUE;
442 if( a >= nbinvars )
443 {
444 a = a - nbinvars;
445 originala = FALSE;
446 }
447 assert(a < nbinvars);
448
449 originalb = TRUE;
450 if( b >= nbinvars )
451 {
452 b = b - nbinvars;
453 originalb = FALSE;
454 }
455 assert(b < nbinvars);
456
457 /* nodes cannot be connected by trivial observations */
458 if( SCIPvarGetNCliques(vars[a], originala) == 0 || SCIPvarGetNCliques(vars[b], originalb) == 0 )
459 return FALSE;
460
461 /* @todo later: possible improvement: do this test for implications and cliques separately if this here is time consuming */
462 /* one of the nodes seems to have more arcs than the other, we swap them (since adjacency is symmetric) */
463 if( SCIPvarGetNCliques(vars[a], originala) > SCIPvarGetNCliques(vars[b], originalb) )
464 {
465 unsigned int temp;
466 SCIP_Bool varfixingtemp;
467
468 temp = b;
469 varfixingtemp = originalb;
470 b = a;
471 originalb = originala;
472 a = temp;
473 originala = varfixingtemp;
474 }
475
476 /* check whether a and b are contained in a clique */
477 ncliques = (unsigned int) SCIPvarGetNCliques(vars[a], originala);
478 cliques = SCIPvarGetCliques(vars[a], originala);
479
480 assert(cliques != NULL || ncliques == 0);
481
482 for( i = 0; i < ncliques; ++i )
483 {
484 assert( cliques != NULL ); /* for lint */
485 ncliquevars = (unsigned int) SCIPcliqueGetNVars(cliques[i]);
486 cliquevars = SCIPcliqueGetVars(cliques[i]);
487 cliquevals = SCIPcliqueGetValues(cliques[i]);
488
489 assert(cliquevars != NULL || ncliquevars == 0);
490 assert(cliquevals != NULL || ncliquevars == 0);
491
492 for( j = 0; j < ncliquevars; ++j )
493 {
494 assert( cliquevals != NULL && cliquevars != NULL ); /* for lint */
495 if( SCIPvarGetProbindex(vars[b]) == SCIPvarGetProbindex(cliquevars[j]) )
496 {
497 if( (cliquevals[j] == FALSE && originalb == TRUE) || ( cliquevals[j] == TRUE && originalb == FALSE ) )
498 return TRUE;
499 }
500 }
501 }
502 }
503 }
504
505 return FALSE;
506}
507
508/** inside the lifting heuristic we determine the lifting coefficient by counting the length of
509 * chains adjacent to the lifting candidate.
510 *
511 * since we have to exclude all chains adjacent to an already lifted node which is not adjacent to
512 * the current lifting candidate we check all chains of the cycle of length three and block them if
513 * they are adjacent.
514 */
515static
517 unsigned int a, /**< first node of the checked cycle chain of length 3 */
518 unsigned int b, /**< second node of the checked cycle chain of length 3 */
519 unsigned int c, /**< third node of the checked cycle chain of length 3 */
520 unsigned int i, /**< current lifting candidate */
521 unsigned int* cycle, /**< list of cycle nodes in order of the cycle */
522 unsigned int ncyclevars, /**< number of variables in the odd cycle */
523 SCIP_VAR** vars, /**< problem variables */
524 unsigned int nbinvars, /**< number of binary problem variables */
525 unsigned int* lifted, /**< list of lifted nodes */
526 unsigned int* nlifted, /**< number of lifted nodes */
527 GRAPHDATA* graphdata, /**< graph */
528 SCIP_Bool* myi /**< flag array, if cycle node is inner point of a counted chain */
529 )
530{
531 unsigned int k;
532
533 assert(a < ncyclevars);
534 assert(b < ncyclevars);
535 assert(c < ncyclevars);
536 assert(cycle != NULL);
537 assert(ncyclevars % 2 == 1);
538 assert(ncyclevars > 2);
539 assert(ncyclevars <= nbinvars);
540 assert(vars != NULL);
541 assert(nbinvars > 2);
542 assert(lifted != NULL);
543 assert(nlifted != NULL);
544 assert(myi != NULL);
545
546 k = 0;
547 while( (myi[a] || myi[b] || myi[c]) && k < *nlifted )
548 {
549 /* if all three nodes are adjacent to a node which is already lifted and not adjacent with the
550 * current lifting candidate, they cannot be regarded */
551 if( !isNeighbor(vars, nbinvars, graphdata, i, lifted[k])
552 && isNeighbor(vars, nbinvars, graphdata, cycle[a], lifted[k])
553 && isNeighbor(vars, nbinvars, graphdata, cycle[b], lifted[k])
554 && isNeighbor(vars, nbinvars, graphdata, cycle[c], lifted[k]) )
555 {
556 myi[a] = FALSE;
557 myi[b] = FALSE;
558 myi[c] = FALSE;
559 }
560 ++k;
561 }
562}
563
564/** determine the heuristic lifting coefficient by counting the length of the adjacent chains of the
565 * candidate (we have to exclude all chains that are adjacent to an already lifted node which is
566 * not adjacent to the current candidate)
567 */
568static
569unsigned int getCoef(
570 SCIP* scip, /**< SCIP data structure */
571 unsigned int i, /**< current lifting candidate */
572 unsigned int* cycle, /**< list of cycle nodes in order of the cycle */
573 unsigned int ncyclevars, /**< number of variables in the odd cycle */
574 SCIP_VAR** vars, /**< problem variables */
575 unsigned int nbinvars, /**< number of binary problem variables */
576 unsigned int* lifted, /**< list of lifted nodes */
577 unsigned int* nlifted, /**< number of lifted nodes */
578 GRAPHDATA* graphdata, /**< graph data structure */
579 SCIP_Bool* myi /**< flag array, if cycle node is inner point of a counted chain */
580 )
581{
582 int j;
583 unsigned int k;
584 unsigned int coef; /* coefficient of lifting candidate of the current step */
585 unsigned int end;
586
587 assert(scip != NULL);
588 assert(i < 2*nbinvars);
589 assert(cycle != NULL);
590 assert(ncyclevars % 2 == 1);
591 assert(ncyclevars > 2);
592 assert(ncyclevars <= 2*nbinvars);
593 assert(vars != NULL);
594 assert(nbinvars > 2);
595 assert(nlifted != NULL);
596 assert(lifted != NULL);
597
598 coef = 0;
599
600 /* get inner nodes of adjacent chains in cycle */
601 for( j = 1; j < (int)ncyclevars-1; ++j )
602 {
603 myi[j] = isNeighbor(vars, nbinvars, graphdata, i, cycle[j-1]) && isNeighbor(vars, nbinvars, graphdata, i, cycle[j])
604 && isNeighbor(vars, nbinvars, graphdata, i, cycle[j+1]);
605 }
606
607 /* the first and last node of the cycle are treated separately */
608 myi[0] = isNeighbor(vars, nbinvars, graphdata, i, cycle[ncyclevars-1])
609 && isNeighbor(vars, nbinvars, graphdata, i, cycle[0])
610 && isNeighbor(vars, nbinvars, graphdata, i, cycle[1]);
611 myi[ncyclevars-1] = isNeighbor(vars, nbinvars, graphdata, i, cycle[ncyclevars-2])
612 && isNeighbor(vars, nbinvars, graphdata, i, cycle[ncyclevars-1])
613 && isNeighbor(vars, nbinvars, graphdata, i, cycle[0]);
614
615 /* consider already lifted nodes that are not adjacent to current lifting candidate and
616 * remove all inner cycle nodes that are adjacent to them
617 */
618 for( j = 1; j < (int)ncyclevars-1; ++j )
619 {
620 checkBlocking((unsigned int) (j-1), (unsigned int) j, (unsigned int) (j+1), i, cycle, ncyclevars, vars, nbinvars, lifted, nlifted, graphdata, myi);
621 }
622 checkBlocking(ncyclevars-2, ncyclevars-1, 0, i, cycle, ncyclevars, vars, nbinvars, lifted, nlifted, graphdata, myi);
623 checkBlocking(ncyclevars-1, 0, 1, i, cycle, ncyclevars, vars, nbinvars, lifted, nlifted, graphdata, myi);
624
625 /* calculate lifting coefficient */
626 k = 0;
627
628 /* first, handle the special case, that the first node of the cycle list is part of a chain */
629 if( myi[0] )
630 {
631 ++k;
632 end = ncyclevars-1;
633 while( myi[end] && end > 0 )
634 {
635 ++k;
636 --end;
637 }
638 assert(k == ncyclevars || end > 0);
639
640 /* all cycle nodes build a relevant chain (maximal chain s.t. all inner nodes are in myi) */
641 if( end == 0 )
642 {
643 assert(ncyclevars % 2 == 1);
644 coef = (ncyclevars-1)/2;
645 return coef;
646 }
647 assert(!myi[end]);
648
649 /* current nonempty relevant chain cannot be extended */
650 if( !myi[1] )
651 {
652 coef = (unsigned int) SCIPfloor(scip,(k+1.0)/2.0);
653 assert(coef <= (ncyclevars-1)/2);
654 k = 0;
655 }
656 }
657 else
658 end = ncyclevars;
659
660 /* find remaining relevant chains */
661 j = 1;
662 while( j < (int)end )
663 {
664 /* skip all nodes that are not inner node */
665 while( j<(int)end && ! myi[j] )
666 ++j;
667
668 /* collect all inner nodes (chain is extended) */
669 while( j<(int)end && myi[j] )
670 {
671 ++k;
672 ++j;
673 }
674
675 if( k > 0 )
676 {
677 assert(myi[j-1]);
678 coef += (unsigned int) SCIPfloor(scip,(k+1.0)/2.0);
679 assert(coef <= (ncyclevars-1)/2);
680 k = 0;
681 }
682 }
683
684 return coef;
685}
686
687/** Lifting Heuristic based on an idea by Alvarez-Valdes, Parreno, Tamarit
688 *
689 * This method is based on the observation, that a non-cycle node can be lifted into the inequality
690 * with coefficient \f$1\f$ if the node is adjacent to the nodes of a 3-chain on the cycle.
691 *
692 * The coefficient can be calculated as
693 * \f$\left\lfloor{\frac{|C|-1}{2}}\right\rfloor\f$
694 * where \f$C\f$ is the chain on the cycle.
695 *
696 * If the node is connected to several chains, the coefficients of the chains can be summed up, resulting
697 * in a feasible lifting coefficient.
698 *
699 * Additionally further variables can be lifted by considering chains connected to the additional lifting node
700 * which are not connected to already lifted nodes.
701 *
702 * This method is a feasible heuristic which gives a valid lifted inequality.
703 * (Furthermore the first lifting coefficient is always smaller or equal to the largest possible lifting coefficient.)
704 */
705static
707 SCIP* scip, /**< SCIP data structure */
708 unsigned int* nlifted, /**< number of lifted variables */
709 unsigned int* lifted, /**< indices of the lifted variables */
710 unsigned int* liftcoef, /**< lifting coefficients */
711 SCIP_SEPADATA* sepadata, /**< separator data structure */
712 GRAPHDATA* graphdata, /**< graph */
713 SCIP_VAR** vars, /**< problem variables */
714 unsigned int nbinvars, /**< number of binary problem variables */
715 unsigned int startnode, /**< a node of the cycle */
716 unsigned int* pred, /**< predecessor of each node (original and negated) in odd cycle */
717 unsigned int ncyclevars, /**< number of variables in the odd cycle */
718 SCIP_Real* vals, /**< values of the variables in the given solution */
719 SCIP_RESULT* result /**< pointer to store the result of the separation call */
720 )
721{
722 unsigned int* cycle; /* storage for cycle and lifted nodes (and their coefficients) */
723 unsigned int* coef;
724 SCIP_Bool* candList; /* lifting candidate list */
725 unsigned int i;
726 unsigned int j;
727 unsigned int negated;
728 int bestcand;
729 unsigned int liftround;
730 SCIP_Bool* myi;
731
732 assert(scip != NULL);
733 assert(graphdata != NULL);
734 assert(graphdata->levelgraph != NULL || graphdata->usegls);
735 assert(graphdata->dijkstragraph != NULL || ! graphdata->usegls);
736 assert(vars != NULL);
737 assert(nbinvars > 2);
738 assert(startnode < 2*nbinvars);
739 assert(pred != NULL);
740 assert(ncyclevars % 2 == 1);
741 assert(ncyclevars > 2);
742 assert(ncyclevars <= nbinvars);
743 assert(result != NULL);
744 assert(nlifted != NULL);
745 assert(lifted != NULL);
746 assert(liftcoef != NULL);
747
748 /* allocate memory for cycle list */
749 SCIP_CALL( SCIPallocBufferArray(scip, &cycle, (int) ncyclevars) );
750
751 /* transform cycle from predecessor list to array in order of appearance in cycle */
752 cycle[0] = startnode;
753 j = 1;
754 i = pred[startnode];
755 while( i != startnode )
756 {
757 cycle[j] = i;
758 i = pred[i];
759 ++j;
760 }
761 assert(j == ncyclevars);
762
763 /* allocate memory for coefficients of the lifting candidates (used in every step) */
764 SCIP_CALL( SCIPallocBufferArray(scip, &coef, (int) (2*nbinvars)) );
765
766 /* allocate memory candidate list and list of lifted nodes */
767 SCIP_CALL( SCIPallocBufferArray(scip, &candList, (int) (2*nbinvars)) );
768
769 /* allocate memory for counting of chains in getCoef() */
770 SCIP_CALL( SCIPallocBufferArray(scip, &myi, (int) ncyclevars) );
771
772 if( SCIPisStopped(scip) )
773 goto TERMINATE;
774
775 /* initialize candidate list */
776 for( i = 0; i < 2*nbinvars; ++i )
777 candList[i] = TRUE;
778
779 /* remove cycle variables and their negated from candidate list */
780 for( i = 0; i < ncyclevars; ++i )
781 {
782 candList[cycle[i]] = FALSE;
783 if( cycle[i] >= nbinvars )
784 negated = cycle[i] - nbinvars;
785 else
786 negated = cycle[i] + nbinvars;
787 assert(negated < 2*nbinvars);
788 candList[negated] = FALSE;
789 }
790
791 /* no candidates lifted so far */
792 *nlifted = 0;
793 bestcand = 0;
794 liftround = 0;
795
796 /* try lifting as long as we have lifting candidates */
797 while( bestcand >= 0 )
798 {
799 /* in case we use a lifting rule, which does not require the first lifting coefficient of all variables: REMOVE this */
800 if( sepadata->recalcliftcoef || liftround == 0 )
801 {
802 for( i = 0; i < 2*nbinvars; ++i )
803 {
804 if( candList[i] )
805 {
806 coef[i] = getCoef(scip, i, cycle, ncyclevars, vars, nbinvars, lifted, nlifted, graphdata, myi);
807 assert(coef[i] <= (ncyclevars-1)/2);
808 if( coef[i] < 1 )
809 candList[i] = FALSE;
810 }
811 }
812 }
813 ++liftround;
814 bestcand = -1;
815 for( i = 0; i < 2*nbinvars; ++i )
816 {
817 if( candList[i] )
818 {
819 /* we want to weight our choice of the lifting node by the value of the current lp solution */
820 if( sepadata->lpliftcoef )
821 {
822 if( bestcand < 0 || coef[i]*vals[i] > coef[bestcand]*vals[bestcand] )
823 bestcand = (int) i;
824 }
825 /* we only regard the coefficient */
826 else
827 {
828 if( bestcand < 0 || coef[i] > coef[bestcand] )
829 bestcand = (int) i;
830 }
831 }
832 }
833
834 /* there is at least one lifting variable */
835 if( bestcand >= 0 )
836 {
837 if( !(sepadata->recalcliftcoef) )
838 coef[i] = getCoef(scip, (unsigned int) bestcand, cycle, ncyclevars, vars, nbinvars, lifted, nlifted, graphdata, myi);
839 assert(coef[bestcand] <= (ncyclevars-1)/2);
840 candList[bestcand] = FALSE;
841 if( coef[bestcand] > 0 )
842 {
843 if( bestcand >= (int)nbinvars )
844 negated = (unsigned int) bestcand - nbinvars;
845 else
846 negated = (unsigned int) bestcand + nbinvars;
847 assert(negated < 2*nbinvars);
848
849 candList[negated] = FALSE;
850
851 assert(*nlifted < nbinvars-ncyclevars);
852 lifted[*nlifted] = (unsigned int) bestcand;
853 liftcoef[*nlifted] = coef[bestcand];
854 ++(*nlifted);
855 }
856 }
857 }
858
859 TERMINATE:
860 /* free temporary memory */
862 SCIPfreeBufferArray(scip, &candList);
864 SCIPfreeBufferArray(scip, &cycle);
865
866 return SCIP_OKAY;
867}
868
869
870/*
871 * methods for both techniques
872 */
873
874/** add the inequality corresponding to the given odd cycle to the LP (if violated)
875 * after lifting it (if requested by user flag)
876 */
877static
879 SCIP* scip, /**< SCIP data structure */
880 SCIP_SEPA* sepa, /**< separator */
881 SCIP_SOL* sol, /**< given primal solution */
882 SCIP_VAR** vars, /**< problem variables */
883 unsigned int nbinvars, /**< number of binary problem variables */
884 unsigned int startnode, /**< a node of the cycle */
885 unsigned int* pred, /**< predecessor of each node (original and negated) in odd cycle */
886 unsigned int ncyclevars, /**< number of variables in the odd cycle */
887 unsigned int* incut, /**< TRUE iff node is covered already by a cut */
888 SCIP_Real* vals, /**< values of the variables in the given solution */
889 SCIP_SEPADATA* sepadata, /**< separator data structure */
890 GRAPHDATA* graphdata, /**< graph data structure */
891 SCIP_RESULT* result /**< pointer to store the result of the separation call */
892 )
893{
894 unsigned int i;
895 unsigned int negatedcount;
896 unsigned int negated;
897
898 /* memory for lifting */
899 unsigned int nlifted; /* number of lifted variables */
900 unsigned int* lifted; /* index of the lifted variables */
901 unsigned int* liftcoef; /* lifting coefficient */
902
903 /* memory for cut generation */
904 SCIP_ROW* cut;
905 char cutname[SCIP_MAXSTRLEN];
906
907 assert(scip != NULL);
908 assert(vars != NULL);
909 assert(startnode < 2*nbinvars);
910 assert(pred != NULL);
911 assert(ncyclevars % 2 == 1);
912 assert(ncyclevars <= nbinvars);
913 assert(incut != NULL);
914 assert(graphdata != NULL);
915 assert(graphdata->levelgraph != NULL || graphdata->usegls);
916 assert(graphdata->dijkstragraph != NULL || ! graphdata->usegls);
917 assert(result != NULL);
918
919#ifdef SCIP_OUTPUT
920 /* debug method that prints out all found cycles */
921 printCycle(vars, pred, nbinvars, startnode);
922#endif
923
924 /* cycle contains only one node */
925 if( ncyclevars < 3 )
926 {
927 SCIPdebugMsg(scip, "fixing variable\n");
928 /* strengthening variable bounds due to single-variable-cycle */
929 if( startnode < nbinvars )
930 {
931 SCIP_CALL( SCIPchgVarUb(scip, vars[startnode], 0.0) );
932 }
933 else
934 {
935 negated = startnode - nbinvars;
936 assert(negated < nbinvars);
937 SCIP_CALL( SCIPchgVarLb(scip, vars[negated], 1.0) );
938 }
940 return SCIP_OKAY;
941 }
942
943 /* cycle is a triangle (can be excluded by user) */
944 if( ncyclevars < 5 && ! sepadata->includetriangles )
945 return SCIP_OKAY;
946
947 if( SCIPisStopped(scip) )
948 return SCIP_OKAY;
949
950 /* lift the cycle inequality */
951 nlifted = 0;
952 lifted = NULL;
953 liftcoef = NULL;
954 if( sepadata->liftoddcycles )
955 {
956 SCIP_CALL( SCIPallocBufferArray(scip, &lifted, (int) (nbinvars - ncyclevars)) );
957 SCIP_CALL( SCIPallocBufferArray(scip, &liftcoef, (int) (nbinvars - ncyclevars)) );
958 SCIP_CALL( liftOddCycleCut(scip, &nlifted, lifted, liftcoef, sepadata, graphdata, vars, nbinvars, startnode, pred, ncyclevars, vals, result) );
959 }
960 /* if we don't try to lift, we generate and add the cut as is */
961
962 /* create cut */
963 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "oddcycle_%d", sepadata->ncuts);
964 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), (ncyclevars-1)/2.0, FALSE, FALSE, TRUE) );
966 negatedcount = 0;
967
968 /* add variables of odd cycle to cut inequality */
969 i = pred[startnode];
970 while( i != startnode )
971 {
972 assert(i < 2*nbinvars);
973 if( i < nbinvars )
974 {
975 /* inserting original variable */
976 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[i], 1.0) );
977 incut[i] = TRUE;
978 }
979 else
980 {
981 negated = i - nbinvars;
982 assert(negated < nbinvars);
983
984 /* inserting negated variable */
985 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[negated], -1.0) );
986 ++negatedcount;
987 incut[negated] = TRUE;
988 }
989 i = pred[i];
990 }
991 assert(startnode == i);
992
993 /* insert startnode */
994 if( startnode < nbinvars )
995 {
996 /* inserting original variable */
997 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[startnode], 1.0) );
998 incut[startnode] = TRUE;
999 }
1000 else
1001 {
1002 negated = startnode - nbinvars;
1003 assert(negated < nbinvars);
1004
1005 /* inserting negated variable */
1006 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[negated], -1.0) );
1007 ++negatedcount;
1008 incut[negated] = TRUE;
1009 }
1010
1011 /* add lifted variables to cut inequality (if existing) */
1012 for( i = 0; i < nlifted; ++i)
1013 {
1014 assert(lifted != NULL);
1015 assert(liftcoef != NULL);
1016 if( lifted[i] < nbinvars )
1017 {
1018 assert(vars[lifted[i]] != NULL);
1019 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[lifted[i]], (SCIP_Real) liftcoef[i]) );
1020 }
1021 else
1022 {
1023 negated = lifted[i] - nbinvars;
1024 assert(negated < nbinvars);
1025 assert(vars[negated] != NULL);
1026 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[negated], -1.0*liftcoef[i]) );
1027 negatedcount += liftcoef[i];
1028 }
1029 }
1030
1031 /* modify right hand side corresponding to number of added negated variables */
1032 SCIP_CALL( SCIPchgRowRhs(scip, cut, SCIProwGetRhs(cut) - negatedcount) );
1034
1035 /* set cut rank: for oddcycle cuts we always set to 1 */
1036 SCIProwChgRank(cut, 1);
1037
1038 /* not every odd cycle has to be violated due to incompleteness of the implication graph */
1039 if( SCIPisCutEfficacious(scip, sol, cut) )
1040 {
1041 SCIP_Bool infeasible;
1042
1043 SCIP_CALL( SCIPaddRow(scip, cut, FALSE, &infeasible) );
1044 ++sepadata->ncuts;
1045 if ( nlifted > 0 )
1046 ++sepadata->nliftedcuts;
1047 if ( infeasible )
1049 else
1050 {
1051 SCIP_CALL( SCIPaddPoolCut(scip, cut) );
1052
1053 if( *result == SCIP_DIDNOTFIND )
1055 }
1056
1057#ifdef SCIP_OUTPUT
1058 SCIP_CALL( SCIPprintRow(scip, cut, NULL) );
1059#endif
1060
1062 }
1063
1064 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
1065
1066 if( sepadata->liftoddcycles )
1067 {
1068 SCIPfreeBufferArray(scip, &liftcoef);
1069 SCIPfreeBufferArray(scip, &lifted);
1070 }
1071 return SCIP_OKAY;
1072}
1073
1074/** check whether the given object is really a cycle without sub-cycles (sub-cycles may be
1075 * calculated by the GLS algorithm in case there is no violated odd cycle inequality) and removes
1076 * pairs of original and negated variables from the cycle
1077 */
1078static
1080 SCIP* scip, /**< SCIP data structure */
1081 unsigned int* pred, /**< predecessor list of current cycle segment */
1082 SCIP_Bool* incycle, /**< flag array iff node is in cycle segment */
1083 unsigned int* incut, /**< flag array iff node is already covered by a cut */
1084 unsigned int x, /**< index of current variable */
1085 unsigned int startnode, /**< index of first variable of cycle segment */
1086 unsigned int nbinvars, /**< number of binary problem variables */
1087 unsigned int* ncyclevars, /**< number of nodes in current cycle segment */
1088 SCIP_Bool repaircycles, /**< user flag if we should try to repair damaged cycles */
1089 SCIP_Bool allowmultiplecuts, /**< user flag if we allow multiple cuts per node */
1090 SCIP_Bool* success /**< FALSE iff an irreparable cycle appears */
1091 )
1092{
1093 unsigned int negx;
1094
1095 assert(scip != NULL);
1096 assert(pred != NULL);
1097 assert(incycle != NULL);
1098 assert(incut != NULL);
1099 assert(ncyclevars != NULL);
1100 assert(*ncyclevars <= nbinvars);
1101 assert(success != NULL);
1102 assert(*success);
1103
1104 assert(x < 2*nbinvars);
1105
1106 /* skip variable if it is already covered by a cut and we do not allow multiple cuts per node */
1107 if( incut[x] && !allowmultiplecuts )
1108 {
1109 *success = FALSE;
1110 return SCIP_OKAY;
1111 }
1112
1113 /* get index of negated variable of current variable */
1114 if( x < nbinvars )
1115 negx = x + nbinvars;
1116 else
1117 negx = x - nbinvars;
1118 assert(negx < 2*nbinvars);
1119
1120 /* given object is not an odd cycle (contains sub-cycle) or contains original and negated
1121 * variable pair but we should not repair this
1122 */
1123 if( incycle[x] || (incycle[negx] && !repaircycles) )
1124 {
1125 *success = FALSE;
1126 return SCIP_OKAY;
1127 }
1128
1129 /* cycle does not contain original and negated variable pair */
1130 if( !incycle[negx] )
1131 {
1132 assert(!incycle[x]);
1133 incycle[x] = TRUE;
1134 ++(*ncyclevars);
1135 return SCIP_OKAY;
1136 }
1137
1138 /* delete original and negated variable and cross-link their neighbors the following way, if possible:
1139 * suppose the cycle contains segments:
1140 * startnode - ... - a - neg(x) - c1 - c2 - ... - cn-1 - cn - x - z=pred(x)
1141 *
1142 * because of the chain a - neg(x) - x - cn it holds that
1143 * a=1 => x=0 => neg(x)=1 => cn=0 and
1144 * cn=1 => x=0 => neg(x)=1 => a=0
1145 * because of the chain z - x - neg(x) - b it holds that
1146 * z=1 => x=0 => neg(x)=1 => c1=0 and
1147 * c1=1 => x=0 => neg(x)=1 => z=0
1148 *
1149 * in addition to that, in our linked list structure we need to relink the chain c1-...-cn in reverse order.
1150 * so we gain the order: a - cn - cn-1 - ... - c2 - c1 - z
1151 */
1152
1153 /* if negated variable is first node in cycle,
1154 * cross-linking not possible because there is no successor z of neg(x) contained in cycle yet
1155 */
1156 if( negx == startnode )
1157 {
1158 *success = FALSE;
1159 return SCIP_OKAY;
1160 }
1161
1162 /* if original and negated variable are neighbors, cross linking is not possible,
1163 * but x and neg(x) can simply be removed
1164 * a - neg(x)=pred[a] - x=pred[neg(x)] - z=pred[x] --> a - z=pred[x]=:pred[a]
1165 */
1166 if( pred[negx] == x )
1167 {
1168 unsigned int a;
1169
1170 /* find a */
1171 a = startnode;
1172 while( pred[a] != negx )
1173 a = pred[a];
1174
1175 /* link a and z */
1176 pred[a] = pred[x];
1177 }
1178 /* cross linking as mentioned above */
1179 else
1180 {
1181 unsigned int a;
1182 unsigned int z;
1183
1184 /* memory for chain reverse */
1185 unsigned int* chain;
1186 unsigned int nchain;
1187
1188 unsigned int i;
1189
1190 /* allocate temporary memory */
1191 SCIP_CALL( SCIPallocBufferArray(scip, &chain, (int) *ncyclevars) );
1192
1193 /* find and store a */
1194 a = startnode;
1195 while( pred[a] != negx )
1196 a = pred[a];
1197
1198 /* store chain */
1199 i = pred[negx];
1200 nchain = 0;
1201 while( i != x )
1202 {
1203 chain[nchain] = i;
1204 ++nchain;
1205 i = pred[i];
1206 }
1207 assert(nchain > 0);
1208
1209 /* store z */
1210 z = pred[x];
1211
1212 /* link a and c1 */
1213 pred[a] = chain[nchain-1];
1214
1215 /* link cn and z */
1216 pred[chain[0]] = z;
1217
1218 /* reverse the chain */
1219 for( i = nchain-1; i > 0; --i )
1220 pred[chain[i]] = chain[i-1];
1221
1222 /* free temporary memory */
1223 SCIPfreeBufferArray(scip, &chain);
1224 }
1225
1226 /* remove negated variable from cycle */
1227 assert(!incycle[x] && incycle[negx]);
1228 incycle[negx] = FALSE;
1229 --(*ncyclevars);
1230
1231 return SCIP_OKAY;
1232}
1233
1234
1235/*
1236 * methods for separateHeur()
1237 */
1238
1239/** memory reallocation method (the graph is normally very dense, so we dynamically allocate only the memory we need)
1240 *
1241 * Since the array sizes differ the method can be called for each of the three data structure types:
1242 * - Forward: sizeForward, targetForward, weightForward
1243 * - Backward: sizeBackward, targetBackward, weightBackward
1244 * - Adj (inner level edges): sizeAdj, sourceAdj, targetAdj, weightAdj
1245 */
1246static
1248 SCIP* scip, /**< SCIP data structure */
1249 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
1250 unsigned int* size, /**< given size */
1251 int** targetArray, /**< given target array (or NULL if sourceAdjArray and targetAdjArray given) */
1252 unsigned int** weightArray, /**< given weight array */
1253 unsigned int** sourceAdjArray, /**< given sourceAdj array (or NULL if targetArray given) */
1254 unsigned int** targetAdjArray, /**< given targetAdj array (or NULL if targetArray given) */
1255 SCIP_Bool* success /**< FALSE, iff memory reallocation fails */
1256 )
1257{
1258 SCIP_Real memorylimit;
1259 unsigned int additional;
1260 SCIP_Bool avoidmemout;
1261
1262 assert(scip != NULL);
1263 assert(graph != NULL);
1264 assert(size != NULL);
1265 assert(targetArray != NULL || (sourceAdjArray != NULL && targetAdjArray != NULL));
1266 assert(weightArray != NULL);
1267 assert(success != NULL);
1268
1269 SCIPdebugMsg(scip, "reallocating...\n");
1270
1271 additional = MIN(graph->maxarcs + graph->maxnodes - *size, *size) * ((int) sizeof(**weightArray));
1272 if( targetArray != NULL )
1273 {
1274 additional += MIN(graph->maxarcs + graph->maxnodes - *size, *size) * ((int) sizeof(**targetArray));
1275 }
1276 else
1277 {
1278 additional += MIN(graph->maxarcs + graph->maxnodes - *size, *size) * ((int) sizeof(**sourceAdjArray));
1279 additional += MIN(graph->maxarcs + graph->maxnodes - *size, *size) * ((int) sizeof(**targetAdjArray));
1280 }
1281
1282 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
1283 if( !SCIPisInfinity(scip, memorylimit) )
1284 {
1285 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
1286 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
1287 }
1288
1289 SCIP_CALL( SCIPgetBoolParam(scip, "misc/avoidmemout", &avoidmemout) );
1290 /* if memorylimit would be exceeded or any other limit is reached free all data and exit */
1291 if( (avoidmemout && memorylimit <= additional/1048576.0) || SCIPisStopped(scip) )
1292 {
1293 *success = FALSE;
1294 SCIPdebugMsg(scip, "...memory limit exceeded\n");
1295 return SCIP_OKAY;
1296 }
1297
1298 *size = 2 * (*size);
1299
1300 SCIP_CALL( SCIPreallocBufferArray(scip, weightArray, (int) MIN(graph->maxarcs + graph->maxnodes, *size)) );
1301 if( targetArray != NULL )
1302 {
1303 SCIP_CALL( SCIPreallocBufferArray(scip, targetArray, (int) MIN(graph->maxarcs + graph->maxnodes, *size)) );
1304 }
1305 else
1306 {
1307 assert(sourceAdjArray != NULL);
1308 assert(targetAdjArray != NULL);
1309 SCIP_CALL( SCIPreallocBufferArray(scip, sourceAdjArray, (int) MIN(graph->maxarcs, *size)) );
1310 SCIP_CALL( SCIPreallocBufferArray(scip, targetAdjArray, (int) MIN(graph->maxarcs, *size)) );
1311 }
1312
1313 /* if memorylimit is exceeded free all data and exit */
1314 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
1315 if( !SCIPisInfinity(scip, memorylimit) )
1316 {
1317 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
1318 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
1319 }
1320
1321 if( avoidmemout && memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 )
1322 {
1323 *success = FALSE;
1324 SCIPdebugMsg(scip, "...memory limit exceeded\n");
1325 return SCIP_OKAY;
1326 }
1327
1328 SCIPdebugMsg(scip, "...with success\n");
1329
1330 return SCIP_OKAY;
1331}
1332
1333/** Add arc to level graph */
1334static
1336 SCIP* scip, /**< SCIP data structure */
1337 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
1338 unsigned int u, /**< source node */
1339 unsigned int v, /**< target node */
1340 unsigned int level, /**< number of current level */
1341 unsigned int weight, /**< weight of the arc */
1342 unsigned int* nAdj, /**< array of numbers of arcs inside levels */
1343 SCIP_Bool* success /**< FALSE, iff memory reallocation fails */
1344 )
1345{
1346 /* arc is a forward arc */
1347 if( graph->level[v] == level+1 )
1348 {
1349 graph->targetForward[graph->lastF] = (int) v;
1350 graph->weightForward[graph->lastF] = weight;
1351 ++(graph->lastF);
1352 ++(graph->narcs);
1353 if( graph->lastF == graph->sizeForward )
1354 {
1355 SCIP_CALL( checkArraySizesHeur(scip, graph, &(graph->sizeForward), &(graph->targetForward),
1356 &(graph->weightForward), NULL, NULL, success) );
1357 if( !(*success) )
1358 return SCIP_OKAY;
1359 }
1360 }
1361 else
1362 {
1363 assert(graph->level[v] == level || graph->level[v] == level-1);
1364
1365 /* arc is a backward arc */
1366 if( graph->level[v] == level-1 )
1367 {
1368 graph->targetBackward[graph->lastB] = (int) v;
1369 graph->weightBackward[graph->lastB] = weight;
1370 ++(graph->lastB);
1371 ++(graph->narcs);
1372
1373 if( graph->lastB == graph->sizeBackward )
1374 {
1375 SCIP_CALL( checkArraySizesHeur(scip, graph, &(graph->sizeBackward), &(graph->targetBackward),
1376 &(graph->weightBackward), NULL, NULL, success) );
1377 if( !(*success) )
1378 return SCIP_OKAY;
1379 }
1380 }
1381 else /* arc is in the same level */
1382 {
1383 assert(graph->level[v] == level);
1384
1385 /* add arc only once, i.e., if u < v */
1386 if( u < v )
1387 {
1388 graph->sourceAdj[graph->levelAdj[level+1]+*nAdj] = u;
1389 graph->targetAdj[graph->levelAdj[level+1]+*nAdj] = v;
1390 graph->weightAdj[graph->levelAdj[level+1]+*nAdj] = weight;
1391 ++(*nAdj);
1392 ++(graph->narcs);
1393
1394 if( graph->levelAdj[level+1]+*nAdj == graph->sizeAdj )
1395 {
1396 SCIP_CALL( checkArraySizesHeur(scip, graph, &(graph->sizeAdj), NULL, &(graph->weightAdj),
1397 &(graph->sourceAdj), &(graph->targetAdj), success) );
1398 if( !(*success) )
1399 return SCIP_OKAY;
1400 }
1401 }
1402 }
1403 }
1404 return SCIP_OKAY;
1405}
1406
1407/** add implications from cliques of the given node u
1408 *
1409 * @see createNextLevel()
1410 */
1411static
1413 SCIP* scip, /**< SCIP data structure */
1414 SCIP_SEPADATA* sepadata, /**< separator data structure */
1415 SCIP_VAR** vars, /**< problem variables */
1416 SCIP_Real* vals, /**< values of the binary variables in the current LP relaxation */
1417 unsigned int u, /**< current node */
1418 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
1419 unsigned int level, /**< number of current level */
1420 SCIP_Bool* inlevelgraph, /**< flag array if node is already inserted in level graph */
1421 unsigned int* newlevel, /**< array of nodes of the next level */
1422 unsigned int* nnewlevel, /**< number of nodes of the next level */
1423 unsigned int* nAdj, /**< array of numbers of arcs inside levels */
1424 SCIP_Bool* success /**< FALSE, iff memory reallocation fails */
1425 )
1426{
1427 SCIP_Bool varfixing;
1428 unsigned int ncliques;
1429 unsigned int nbinvars;
1430 unsigned int varsidx;
1431 SCIP_CLIQUE** cliques;
1432 unsigned int ncliquevars;
1433 SCIP_VAR** cliquevars;
1434 SCIP_Bool* cliquevals;
1435 unsigned int j;
1436 unsigned int k;
1437
1438 assert(scip != NULL);
1439 assert(vars != NULL);
1440 assert(vals != NULL);
1441 assert(graph != NULL);
1442 assert(graph->targetForward != NULL);
1443 assert(graph->weightForward != NULL);
1444 assert(graph->targetBackward != NULL);
1445 assert(graph->weightBackward != NULL);
1446 assert(graph->sourceAdj != NULL);
1447 assert(graph->targetAdj != NULL);
1448 assert(graph->weightAdj != NULL);
1449 assert(inlevelgraph != NULL);
1450 assert(newlevel != NULL);
1451 assert(nnewlevel != NULL);
1452 assert(nAdj != NULL);
1453 assert(success != NULL);
1454
1455 assert(u < graph->maxnodes);
1456
1457 nbinvars = (graph->maxnodes)/2;
1458
1459 /* current node signifies a problem variable */
1460 if( u < nbinvars )
1461 {
1462 varfixing = TRUE;
1463 varsidx = u;
1464 }
1465 /* current node signifies a negated variable */
1466 else
1467 {
1468 varfixing = FALSE;
1469 varsidx = u - nbinvars;
1470 }
1471 assert(varsidx < nbinvars);
1472 assert(!SCIPisFeasIntegral(scip, vals[varsidx]));
1473
1474 /* get cliques of the current variable */
1475 ncliques = (unsigned int) SCIPvarGetNCliques(vars[varsidx], varfixing);
1476 if( ncliques == 0 )
1477 return SCIP_OKAY;
1478
1479 cliques = SCIPvarGetCliques(vars[varsidx], varfixing);
1480 assert(cliques != NULL);
1481
1482 for( j = 0; j < ncliques; ++j )
1483 {
1484 ncliquevars = (unsigned int) SCIPcliqueGetNVars(cliques[j]);
1485 cliquevars = SCIPcliqueGetVars(cliques[j]);
1486 cliquevals = SCIPcliqueGetValues(cliques[j]);
1487
1488 assert(cliquevars != NULL || ncliquevars == 0);
1489 assert(cliquevals != NULL || ncliquevars == 0);
1490
1491 for( k = 0; k < ncliquevars; ++k )
1492 {
1493 unsigned int l;
1494 unsigned int v;
1495 unsigned int weight;
1496
1497 assert( cliquevars != NULL && cliquevals != NULL ); /* for lint */
1498
1499 l = sepadata->mapping[SCIPvarGetProbindex(cliquevars[k])];
1500 assert(l < nbinvars);
1501
1502 /* skip integral neighbors */
1503 if( SCIPisFeasIntegral(scip, vals[l]) )
1504 continue;
1505
1506 /* consider clique with negated variable (x = 1 -> y >= 1 <=> x = 1 -> neg(y) <= 0) */
1507 if( cliquevals[k] == FALSE )
1508 v = l + nbinvars;
1509 /* x = 1 -> y <= 0 */
1510 else
1511 v = l;
1512 assert(v < graph->maxnodes);
1513
1514 /* if variable is a new node, it will be assigned to the next level,
1515 * but if the level contains more nodes than allowed
1516 * (defined by percent per level plus offset),
1517 * we skip the rest of the nodes
1518 */
1519 if( !inlevelgraph[v] && (*nnewlevel) <= sepadata->maxlevelsize )
1520 {
1521 ++(graph->nnodes);
1522 graph->level[v] = level+1;
1523 inlevelgraph[v] = TRUE;
1524 newlevel[*nnewlevel] = v;
1525 ++(*nnewlevel);
1526 }
1527 assert(*nnewlevel > sepadata->maxlevelsize || inlevelgraph[v]);
1528
1529 /* calculate arc weight and add arc, if the neighbor node is on the same or a neighbor level */
1530 if( inlevelgraph[v] && (graph->level[v] == level+1 || graph->level[v] == level || graph->level[v] == level-1))
1531 {
1532 int tmp;
1533
1534 /* the computation of 1.0 - vals[v] if v is negated is ensured by the fact that v > nbinvars in this case */
1535 /* set weight of arc (x,y) to 1 - x* -y* */
1536 if( varfixing )
1537 {
1538 /* x = 1 -> y <= 0 or y >= 1 */
1539 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1 - vals[varsidx] - vals[v]));
1540 weight = (unsigned int) MAX(tmp, sepadata->maxreference);
1541 }
1542 else
1543 {
1544 /* x = 0 <-> neg(x) = 1 -> y <= 0 or y >= 1 */
1545 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1.0 - (1.0 - vals[varsidx]) - vals[v]));
1546 weight = (unsigned int) MAX(tmp, sepadata->maxreference);
1547 }
1548
1549 /* add arc from current to neighbor node */
1550 SCIP_CALL( addArc(scip, graph, u, v, level, weight, nAdj, success) );
1551 if( !(*success) )
1552 return SCIP_OKAY;
1553 }
1554 }
1555 }
1556 return SCIP_OKAY;
1557}
1558
1559
1560/** sort level of root neighbors
1561 *
1562 * If we limit the size of nodes of a level, we want to add the best neighbors to the next level.
1563 * Since sorting every level is too expensive, we sort the neighbors of the root (if requested).
1564 *
1565 * Create the first level as follows:
1566 * - create flag array for binary variables and their negated and set their values FALSE
1567 * - iterate over the implication and clique neighbors of the root and set their flag array values to TRUE
1568 * - create variable array and insert all variables with flag value TRUE
1569 * - sort variable array by maximal fractionality
1570 * - add variables from sorted array to levelgraph until first level is full (or all variables are inserted)
1571 *
1572 * Even inserting all variables might help for the following creation of further levels since the neighbors
1573 * of nodes with high fractionality often have high fractionalities themselves and would be inserted first
1574 * when further levels would have been sorted (which actually is not the case).
1575 */
1576static
1578 SCIP* scip, /**< SCIP data structure */
1579 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
1580 unsigned int nbinvars, /**< number of binary problem variables */
1581 unsigned int ncurlevel, /**< number of nodes of the current level */
1582 unsigned int u, /**< source node */
1583 SCIP_Real* vals, /**< values of the binary variables in the current LP relaxation */
1584 SCIP_VAR** vars, /**< problem variables */
1585 SCIP_SEPADATA* sepadata, /**< separator data structure */
1586 unsigned int* nnewlevel, /**< number of nodes of the next level */
1587 SCIP_Bool* inlevelgraph, /**< nodes in new graph corr. to old graph (-1 if unassigned) */
1588 unsigned int level, /**< number of current level */
1589 unsigned int* newlevel, /**< array of nodes of the next level */
1590 SCIP_Bool* success /**< FALSE, iff memory reallocation fails */
1591 )
1592{
1593 /* storage for the neighbors of the root */
1594 unsigned int root;
1595 unsigned int nneighbors;
1596 SCIP_Bool* isneighbor;
1597 int* neighbors;
1598 SCIP_Real* sortvals;
1599
1600 SCIP_Bool varfixing;
1601 unsigned int varsidx;
1602
1603 /* storage for cliques to the neighbors of the root node */
1604 unsigned int ncliques;
1605 SCIP_CLIQUE** cliques;
1606 unsigned int ncliquevars;
1607 SCIP_VAR** cliquevars;
1608 SCIP_Bool* cliquevals;
1609
1610 unsigned int j;
1611 unsigned int k;
1612 unsigned int v;
1613
1614 /* allocate flag array for neighbor detection */
1615 SCIP_CALL( SCIPallocBufferArray(scip, &isneighbor, (int) graph->maxnodes) );
1616 BMSclearMemoryArray(isneighbor, graph->maxnodes);
1617
1618 nbinvars = (graph->maxnodes)/2;
1619
1620 assert(ncurlevel == 1);
1621 root = u;
1622
1623 /* current node signifies a problem variable */
1624 if( root < nbinvars )
1625 {
1626 varfixing = TRUE;
1627 varsidx = root;
1628 }
1629 /* current node signifies a negated variable */
1630 else
1631 {
1632 varfixing = FALSE;
1633 varsidx = root - nbinvars;
1634 }
1635 assert(varsidx < nbinvars);
1636 assert(! SCIPisFeasIntegral(scip, vals[varsidx]));
1637 nneighbors = 0;
1638
1639 /* count cliques of the root */
1640 ncliques = (unsigned int) SCIPvarGetNCliques(vars[varsidx], varfixing);
1641 if( ncliques > 0 )
1642 {
1643 cliques = SCIPvarGetCliques(vars[varsidx], varfixing);
1644 assert(cliques != NULL);
1645
1646 for( j = 0; j < ncliques; ++j )
1647 {
1648 ncliquevars = (unsigned int) SCIPcliqueGetNVars(cliques[j]);
1649 cliquevars = SCIPcliqueGetVars(cliques[j]);
1650 cliquevals = SCIPcliqueGetValues(cliques[j]);
1651
1652 assert(cliquevars != NULL || ncliquevars == 0);
1653 assert(cliquevals != NULL || ncliquevars == 0);
1654
1655 for( k = 0; k < ncliquevars; ++k )
1656 {
1657 unsigned int kidx;
1658
1659 assert( cliquevars != NULL && cliquevals != NULL ); /* for lint */
1660
1661 kidx = sepadata->mapping[SCIPvarGetProbindex(cliquevars[k])];
1662 assert(kidx < nbinvars);
1663
1664 /* skip root */
1665 if( kidx == varsidx )
1666 continue;
1667
1668 /* skip integral neighbors */
1669 if( SCIPisFeasIntegral(scip, vals[kidx]))
1670 continue;
1671
1672 if( cliquevals[k] == TRUE )
1673 {
1674 if ( ! isneighbor[kidx] )
1675 {
1676 ++nneighbors;
1677 isneighbor[kidx] = TRUE;
1678 }
1679 }
1680 else
1681 {
1682 assert(cliquevals[k] == FALSE);
1683 if ( ! isneighbor[kidx + nbinvars] )
1684 {
1685 ++nneighbors;
1686 isneighbor[kidx+nbinvars] = TRUE;
1687 }
1688 }
1689 }
1690 }
1691 }
1692
1693 /* root cannot be part of the next level */
1694 assert(! isneighbor[root]);
1695
1696 /* allocate memory for sorting of root neighbors */
1697 SCIP_CALL( SCIPallocBufferArray(scip, &neighbors, (int) nneighbors) );
1698 SCIP_CALL( SCIPallocBufferArray(scip, &sortvals, (int) nneighbors) );
1699
1700 k = 0;
1701 for( j = 0; j < graph->maxnodes; ++j )
1702 {
1703 if( isneighbor[j] )
1704 {
1705 assert(j != root);
1706 assert(!SCIPisFeasIntegral(scip, vals[j]));
1707
1708 neighbors[k] = (int) j;
1709 sortvals[k] = MIN(1.0 - vals[j], vals[j]);
1710 ++k;
1711 }
1712 }
1713 assert(k == nneighbors);
1714
1715 /* sort neighbors by fractionality */
1716 SCIPsortDownRealInt(sortvals, neighbors, (int) nneighbors);
1717
1718 /* free temporary memory */
1719 SCIPfreeBufferArray(scip, &sortvals);
1720
1721 /* insert sorted neighbors until level size limit is reached (or all neighbors are inserted) */
1722 for( j = 0; j < nneighbors && (*nnewlevel) <= sepadata->maxlevelsize; ++j )
1723 {
1724 int tmp;
1725
1726 v = (unsigned int) neighbors[j];
1727 assert( v < 2 * nbinvars );
1728
1729 /* only the root is contained in the levelgraph */
1730 assert(! inlevelgraph[v] || v == root+nbinvars || v == root-nbinvars);
1731
1732 /* insert neighbor into levelgraph */
1733 ++(graph->nnodes);
1734 graph->level[v] = level + 1;
1735 inlevelgraph[v] = TRUE;
1736 newlevel[*nnewlevel] = v;
1737 ++(*nnewlevel);
1738
1739 assert(! SCIPisFeasIntegral(scip, vals[varsidx]));
1740 assert(! SCIPisFeasIntegral(scip, vals[v]));
1741
1742 graph->targetForward[graph->lastF] = (int) v;
1743 /* the computation of 1.0 - vals[v] if v is negated is ensured by the fact that v > nbinvars in this case */
1744 if( varfixing )
1745 {
1746 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1.0 - vals[varsidx] - vals[v]));
1747 graph->weightForward[graph->lastF] = (unsigned int) MAX(tmp, sepadata->maxreference);
1748 }
1749 else
1750 {
1751 assert( ! varfixing );
1752 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1.0 - (1.0 - vals[varsidx]) - vals[v]));
1753 graph->weightForward[graph->lastF] = (unsigned int) MAX(tmp, sepadata->maxreference);
1754 }
1755 ++(graph->lastF);
1756 ++(graph->narcs);
1757 if( graph->lastF == graph->sizeForward )
1758 {
1759 SCIP_CALL( checkArraySizesHeur(scip, graph, &(graph->sizeForward), &(graph->targetForward),
1760 &(graph->weightForward), NULL, NULL, success) );
1761
1762 if( !(*success) )
1763 break;
1764 }
1765 }
1766
1767 /* free temporary memory */
1768 SCIPfreeBufferArray(scip, &neighbors);
1769 SCIPfreeBufferArray(scip, &isneighbor);
1770
1771 return SCIP_OKAY;
1772}
1773
1774/** Find shortest path from start node to root
1775 *
1776 * We perform a BFS to find the shortest path to the root. D stores the distance to the start
1777 * node, P stores the partent nodes in the shortest path tree (-1 if node has not been reached).
1778 */
1779static
1781 SCIP* scip, /**< SCIP data structure */
1782 int scale, /**< scaling factor for edge weights */
1783 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
1784 unsigned int startnode, /**< start node for path search */
1785 unsigned int* distance, /**< distances of searched nodes from root */
1786 unsigned int* queue, /**< node queue for path search */
1787 SCIP_Bool* inQueue, /**< whether node is in the queue */
1788 int* parentTree /**< parent tree (-1 if no parent) */
1789 )
1790{
1791 unsigned int i;
1792 int startQueue;
1793 int endQueue;
1794 unsigned int u;
1795 int v;
1796 unsigned int d;
1797
1798 assert(scip != NULL);
1799 assert(graph != NULL);
1800 assert(graph->beginBackward != NULL);
1801 assert(graph->targetBackward != NULL);
1802 assert(graph->weightBackward != NULL);
1803 assert(distance != NULL);
1804 assert(queue != NULL);
1805 assert(inQueue != NULL);
1806 assert(parentTree != NULL);
1807 assert(scale >= 0);
1808
1809 /* initialize distances */
1810 for( i = 0; i < graph->maxnodes; ++i )
1811 {
1812 distance[i] = 2 * (graph->nnodes) * (unsigned) scale;
1813 parentTree[i] = -1;
1814 inQueue[i] = FALSE;
1815 }
1816 distance[startnode] = 0;
1817
1818 /* initialize queue */
1819 startQueue = 0;
1820 endQueue = 0;
1821 queue[0] = startnode;
1822
1823 /* as long as queue is not empty */
1824 while( startQueue <= endQueue )
1825 {
1826 /* pop first node from queue */
1827 u = queue[startQueue];
1828 ++startQueue;
1829
1830 /* check adjacent nodes */
1831 assert(graph->beginBackward[u] >= 0);
1832 i = (unsigned int) graph->beginBackward[u];
1833 for( v = graph->targetBackward[i]; v >= 0; v = graph->targetBackward[++i] )
1834 {
1835 /* distance to u via current arc: */
1836 d = distance[u] + graph->weightBackward[i];
1837
1838 /* if we found a shorter connection */
1839 if( d < distance[v] )
1840 {
1841 distance[v] = d;
1842 parentTree[v] = (int) u;
1843
1844 /* insert in queue if not already present */
1845 if( !inQueue[v] )
1846 {
1847 ++endQueue;
1848 queue[endQueue] = (unsigned int) v;
1849 inQueue[v] = TRUE;
1850 }
1851 }
1852 }
1853 /* it is not necessary to stop if we found the root (in this case there are no arcs left) and we stop anyway */
1854 }
1855 assert(parentTree[u] != -1);
1856
1857 return SCIP_OKAY;
1858}
1859
1860
1861/** Block shortest path
1862 *
1863 * We traverse the shortest path found by findShortestPathToRoot() and block all neighbors (in the
1864 * original graph) of nodes in the path, i.e., we set blocked to TRUE. We do not block neighbors of
1865 * the root node, since they have to be used. For the start node we only block nodes on the
1866 * previous layers,
1867 *
1868 * @see findShortestPathToRoot()
1869 */
1870static
1872 SCIP* scip, /**< SCIP data structure */
1873 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
1874 unsigned int startnode, /**< start node */
1875 SCIP_Bool* inlevelgraph, /**< nodes in new graph corr. to old graph (-1 if unassigned) */
1876 SCIP_Bool* blocked, /**< whether node is blocked */
1877 int* parentTree, /**< parent tree */
1878 unsigned int root /**< root of the current level graph */
1879 )
1880{
1881 unsigned int u;
1882 unsigned int i;
1883 int v;
1884
1885 assert(scip != NULL);
1886 assert(graph != NULL);
1887 assert(graph->level != NULL);
1888 assert(graph->beginForward != NULL);
1889 assert(graph->targetForward != NULL);
1890 assert(graph->beginBackward != NULL);
1891 assert(graph->targetBackward != NULL);
1892 assert(graph->sourceAdj != NULL);
1893 assert(graph->targetAdj != NULL);
1894 assert(inlevelgraph != NULL);
1895 assert(blocked != NULL);
1896 assert(parentTree != NULL);
1897
1898 assert(parentTree[root] >= 0);
1899
1900 /* follow the path from the predecessor of root to the start node and block all neighbors */
1901 u = (unsigned int) parentTree[root];
1902 while( u != startnode )
1903 {
1904 /* block neighbors of u in higher level */
1905 i = (unsigned int) graph->beginForward[u];
1906 for( v = graph->targetForward[i]; v >= 0; v = graph->targetForward[++i] )
1907 {
1908 assert(inlevelgraph[v]);
1909 blocked[v] = TRUE;
1910 }
1911
1912 /* block neighbors of u in lower level */
1913 i = (unsigned int) graph->beginBackward[u];
1914 for( v = graph->targetBackward[i]; v >= 0; v = graph->targetBackward[++i] )
1915 {
1916 assert(inlevelgraph[v]);
1917 blocked[v] = TRUE;
1918 }
1919
1920 /* block neighbors of u in same level */
1921 assert(graph->level[u] > 0);
1922 for( i = graph->levelAdj[graph->level[u]]; i < graph->levelAdj[graph->level[u]+1]; ++i )
1923 {
1924 assert(graph->sourceAdj[i] < graph->targetAdj[i]);
1925 assert(graph->level[graph->sourceAdj[i]] == graph->level[graph->targetAdj[i]]);
1926
1927 /* remember that these arcs are only stored for one direction */
1928 if( graph->sourceAdj[i] == u )
1929 {
1930 blocked[graph->targetAdj[i]] = TRUE;
1931 }
1932 if( graph->targetAdj[i] == u )
1933 {
1934 blocked[graph->sourceAdj[i]] = TRUE;
1935 }
1936 }
1937
1938 /* get next node on the path */
1939 u = (unsigned int) parentTree[u];
1940 }
1941 assert(u == startnode);
1942
1943 /* block nodes adjacent to start node on previous level */
1944 assert(graph->beginBackward[u] > 0);
1945 i = (unsigned int) graph->beginBackward[u];
1946 for( v = graph->targetBackward[i]; v >= 0; v = graph->targetBackward[++i] )
1947 blocked[v] = TRUE;
1948
1949 return SCIP_OKAY;
1950}
1951
1952
1953/** Find shortest path from root to target node
1954 *
1955 * We perform a BFS to find the shortest path from the root. The only difference to
1956 * findShortestPathToRoot() is that we avoid nodes that are blocked.
1957 */
1958static
1961 SCIP* scip, /**< SCIP data structure */
1962 int scale, /**< scaling factor for edge weights */
1963 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
1964 unsigned int startnode, /**< start node for path search */
1965 unsigned int* distance, /**< distances of searched nodes from root */
1966 unsigned int* queue, /**< node queue for path search */
1967 SCIP_Bool* inQueue, /**< whether node is in the queue */
1968 int* parentTreeBackward, /**< parent tree (-1 if no parent) */
1969 unsigned int root, /**< root of the current level graph */
1970 SCIP_Bool* blocked /**< whether nodes can be used */
1971 )
1972{
1973 unsigned int i;
1974 int startQueue;
1975 int endQueue;
1976 unsigned int u;
1977 int v;
1978 unsigned int d;
1979 int* parentTree;
1980 int* transform;
1981
1982 assert(scip != NULL);
1983 assert(graph != NULL);
1984 assert(graph->beginBackward != NULL);
1985 assert(graph->targetBackward != NULL);
1986 assert(graph->weightBackward != NULL);
1987 assert(distance != NULL);
1988 assert(queue != NULL);
1989 assert(inQueue != NULL);
1990 assert(scale >= 0);
1991
1992 /* allocate temporary memory */
1993 SCIP_CALL( SCIPallocBufferArray(scip, &parentTree, (int) graph->maxnodes) );
1994 SCIP_CALL( SCIPallocBufferArray(scip, &transform, (int) graph->maxnodes) );
1995
1996 assert(parentTree != NULL);
1997 assert(transform != NULL);
1998
1999 /* initialize distances */
2000 for( i = 0; i < graph->maxnodes; ++i )
2001 {
2002 distance[i] = 2 * (graph->nnodes) * (unsigned)scale;
2003 parentTree[i] = -1;
2004 parentTreeBackward[i] = -1;
2005 transform[i] = -1;
2006 inQueue[i] = FALSE;
2007 }
2008 distance[startnode] = 0;
2009
2010 /* initialize queue */
2011 startQueue = 0;
2012 endQueue = 0;
2013 queue[0] = startnode;
2014
2015 /* as long as queue is not empty */
2016 while( startQueue <= endQueue )
2017 {
2018 /* pop first node from queue */
2019 u = queue[startQueue];
2020 ++startQueue;
2021
2022 /* check adjacent nodes */
2023 assert(graph->beginBackward[u] >= 0);
2024 i = (unsigned int) graph->beginBackward[u];
2025 for( v = graph->targetBackward[i]; v >= 0; v = graph->targetBackward[++i] )
2026 {
2027 if( blocked[v] && v != (int) root)
2028 continue;
2029
2030 /* distance to u via current arc: */
2031 d = distance[u] + graph->weightBackward[i];
2032
2033 /* if we found a shorter connection */
2034 if( d < distance[v] )
2035 {
2036 distance[v] = d;
2037 parentTree[v] = (int) u;
2038
2039 /* insert in queue if not already present */
2040 if( !inQueue[v] )
2041 {
2042 ++endQueue;
2043 queue[endQueue] = (unsigned int) v;
2044 inQueue[v] = TRUE;
2045 }
2046 }
2047 }
2048 /* it is not necessary to stop if we found the root (in this case there are no arcs left) and we stop anyway */
2049 }
2050
2051 /* reverse order such that it is a path from the root */
2052 v = (int) root;
2053 transform[0] = (int) root;
2054 i = 1;
2055 while(parentTree[v] >= 0)
2056 {
2057 transform[i] = parentTree[v];
2058 ++i;
2059 v = parentTree[v];
2060 }
2061 --i;
2062 while(i > 0)
2063 {
2064 parentTreeBackward[transform[i]] = transform[i-1];
2065 --i;
2066 }
2067
2068 /* free temporary memory */
2069 SCIPfreeBufferArray(scip, &transform);
2070 SCIPfreeBufferArray(scip, &parentTree);
2071
2072 return SCIP_OKAY;
2073}
2074
2075/** create next level of level graph for odd cycle separation
2076 *
2077 * @see separateHeur()
2078 */
2079static
2081 SCIP* scip, /**< SCIP data structure */
2082 SCIP_SEPADATA* sepadata, /**< separator data structure */
2083 SCIP_VAR** vars, /**< problem variables */
2084 SCIP_Real* vals, /**< values of the binary variables in the current LP relaxation */
2085 LEVELGRAPH* graph, /**< LEVELGRAPH data structure */
2086 unsigned int level, /**< number of current level */
2087 SCIP_Bool* inlevelgraph, /**< flag array if node is already inserted in level graph */
2088 unsigned int* curlevel, /**< array of nodes of the current level */
2089 unsigned int ncurlevel, /**< number of nodes of the current level */
2090 unsigned int* newlevel, /**< array of nodes of the next level */
2091 unsigned int* nnewlevel, /**< number of nodes of the next level */
2092 SCIP_Bool* success /**< FALSE, iff memory reallocation fails */
2093 )
2094{
2095 unsigned int i;
2096 unsigned int nbinvars;
2097 unsigned int nAdj;
2098
2099 assert(scip != NULL);
2100 assert(vars != NULL);
2101 assert(vals != NULL);
2102 assert(graph != NULL);
2103 assert(graph->level != NULL);
2104 assert(graph->beginForward != NULL);
2105 assert(graph->targetForward != NULL);
2106 assert(graph->weightForward != NULL);
2107 assert(graph->beginBackward != NULL);
2108 assert(graph->targetBackward != NULL);
2109 assert(graph->weightBackward != NULL);
2110 assert(graph->beginAdj != NULL);
2111 assert(graph->levelAdj != NULL);
2112 assert(graph->sourceAdj != NULL);
2113 assert(graph->targetAdj != NULL);
2114 assert(graph->weightAdj != NULL);
2115 assert(inlevelgraph != NULL);
2116 assert(curlevel != NULL);
2117 assert(newlevel != NULL);
2118 assert(success != NULL);
2119
2120 *nnewlevel = 0;
2121 nAdj = 0;
2122 assert(graph->maxnodes % 2 == 0);
2123 nbinvars = (graph->maxnodes)/2;
2124
2125 /* for every node in current level add its implications and assign its neighbors to the next
2126 * level, if neighbor is not already existing in the level graph
2127 */
2128 for( i = 0; i < ncurlevel; ++i )
2129 {
2130 unsigned int negated;
2131 unsigned int u;
2132
2133 /* get node */
2134 u = curlevel[i];
2135 assert(u < graph->maxnodes);
2136 assert(graph->level[u] == level);
2137 assert(graph->beginForward[u] < 0);
2138 assert(graph->beginBackward[u] < 0);
2139 assert(graph->beginAdj[u] < 0);
2140 assert(inlevelgraph[u]);
2141
2142 /* get negated */
2143 if( u < nbinvars )
2144 negated = u + nbinvars;
2145 else
2146 negated = u - nbinvars;
2147 assert(negated < graph->maxnodes);
2148 assert(negated < nbinvars || u < nbinvars);
2149 assert(negated >= nbinvars || u >= nbinvars);
2150
2151 /* initialize adjacency lists for node u */
2152 graph->beginForward[u] = (int) graph->lastF;
2153 graph->beginBackward[u] = (int) graph->lastB;
2154 graph->beginAdj[u] = (int) (graph->levelAdj[level+1] + nAdj);
2155
2156 /* if we want to add arcs between a variable and its negated */
2157 if( sepadata->addselfarcs )
2158 {
2159 /* add negated variable, if not existing in the levelgraph,
2160 * but if the level contains more nodes than allowed
2161 * (defined by percent per level plus offset),
2162 * we skip the rest of the nodes
2163 */
2164 if( !inlevelgraph[negated] && (*nnewlevel) <= sepadata->maxlevelsize )
2165 {
2166 ++(graph->nnodes);
2167 graph->level[negated] = level+1;
2168 inlevelgraph[negated] = TRUE;
2169 newlevel[*nnewlevel] = negated;
2170 ++(*nnewlevel);
2171 }
2172 assert( *nnewlevel > sepadata->maxlevelsize || inlevelgraph[negated] );
2173
2174 /* add self-arc if negated variable is on a neighbored level */
2175 if( inlevelgraph[negated] && ((graph->level[negated] == level - 1)
2176 || (graph->level[negated] == level) || (graph->level[negated] == level + 1)) )
2177 {
2178 /* add arc from u to its negated variable */
2179 SCIP_CALL( addArc(scip, graph, u, negated, level, 0, &nAdj, success) );
2180 if( !(*success) )
2181 return SCIP_OKAY;
2182 }
2183 }
2184
2185 /* insert level of sorted root neighbors (if requested) */
2186 if( graph->nlevels == 0 && sepadata->sortrootneighbors )
2187 {
2188 SCIP_CALL( insertSortedRootNeighbors(scip, graph, nbinvars, ncurlevel, u, vals, vars,
2189 sepadata, nnewlevel, inlevelgraph, level, newlevel, success) );
2190 }
2191 else
2192 {
2193 SCIP_CALL( addNextLevelCliques(scip, sepadata, vars, vals, u, graph, level, inlevelgraph,
2194 newlevel, nnewlevel, &nAdj, success) );
2195 }
2196 if( !(*success) )
2197 return SCIP_OKAY;
2198
2199 /* every node has a backward arc */
2200 assert(graph->lastB > (unsigned int) graph->beginBackward[u] || graph->nlevels == 0 );
2201
2202 /* root has outgoing arcs otherwise we would have skipped it */
2203 assert(graph->lastF > 0);
2204
2205 /* close adjacency lists */
2206 graph->targetForward[graph->lastF] = -1;
2207 ++(graph->lastF);
2208 if( graph->lastF == graph->sizeForward )
2209 {
2210 SCIP_CALL( checkArraySizesHeur(scip, graph, &(graph->sizeForward), &(graph->targetForward),
2211 &(graph->weightForward), NULL, NULL, success) );
2212
2213 if( !(*success) )
2214 return SCIP_OKAY;
2215 }
2216 graph->targetBackward[graph->lastB] = -1;
2217 ++(graph->lastB);
2218 if( graph->lastB == graph->sizeBackward )
2219 {
2220 SCIP_CALL( checkArraySizesHeur(scip, graph, &(graph->sizeBackward), &(graph->targetBackward),
2221 &(graph->weightBackward), NULL, NULL, success) );
2222
2223 if( !(*success) )
2224 return SCIP_OKAY;
2225 }
2226
2227 /* terminate adjacency list with 0 for current level lifting */
2228 graph->sourceAdj[graph->levelAdj[level+1]+nAdj] = 0;
2229 graph->targetAdj[graph->levelAdj[level+1]+nAdj] = 0;
2230 }
2231 graph->levelAdj[level+2] = graph->levelAdj[level+1]+nAdj;
2232
2233 return SCIP_OKAY;
2234}
2235
2236/** The heuristic method for finding odd cycles by Hoffman, Padberg uses a level graph
2237 * which is constructed as follows:
2238 * First we choose a node (i.e. a variable of the problem or its negated) as root
2239 * and assign it to level 0 (and no other node is assigned to level 0).
2240 * All neighbors of the root are assigned to level 1 and the arcs between are added.
2241 *
2242 * In general:
2243 * All neighbors of nodes in level i that are assigned to level i+1, if they do not already appear in levels <= i.
2244 * All arcs between nodes in level i and their neighbors are added.
2245 *
2246 * In the construction we only take nodes that are contained in the fractional graph,
2247 * i.e., their current LP values are not integral.
2248 *
2249 * Since SCIP stores implications between original and negated variables,
2250 * the level graph has at most twice the number of fractional binary variables of the problem.
2251 *
2252 * Since the implication graph of SCIP is (normally) incomplete,
2253 * it is possible to use arcs between an original variable and its negated
2254 * to obtain more cycles which are valid but not found due to missing links.
2255 */
2256static
2258 SCIP* scip, /**< SCIP data structure */
2259 SCIP_SEPA* sepa, /**< separator */
2260 SCIP_SEPADATA* sepadata, /**< separator data structure */
2261 SCIP_SOL* sol, /**< given primal solution */
2262 SCIP_RESULT* result /**< pointer to store the result of the separation call */
2263 )
2264{
2265 /* memory for variable data */
2266 SCIP_VAR** scipvars; /* variables of the current SCIP (unsorted) */
2267 SCIP_VAR** vars; /* variables of the current SCIP (sorted if requested) */
2268 SCIP_Real* vals; /* LP-values of the variables (and negated variables) */
2269 unsigned int nbinvars; /* number of nodecandidates for implicationgraph */
2270 unsigned int* incut; /* flag array for check if a variable is already covered by a cut */
2271
2272 /* storage for levelgraph */
2273 LEVELGRAPH graph;
2274 unsigned int* curlevel;
2275 unsigned int* newlevel;
2276 unsigned int ncurlevel;
2277 unsigned int nnewlevel;
2278 SCIP_Bool* inlevelgraph;
2279
2280 /* storage for path finding */
2281 unsigned int* queue;
2282 SCIP_Bool* inQueue;
2283 int* parentTree;
2284 int* parentTreeBackward;
2285 unsigned int* distance;
2286 SCIP_Bool* blocked;
2287
2288 /* counter and limits */
2289 unsigned int maxroots; /* maximum of level graph roots */
2290 unsigned int rootcounter; /* counter of tried roots */
2291 unsigned int ncutsroot; /* counter of cuts per root */
2292 unsigned int ncutslevel; /* counter of cuts per level */
2293
2294 unsigned int i;
2295 unsigned int j;
2296 unsigned int k;
2297
2298 int nscipbinvars;
2299 int nscipintvars;
2300 int nscipimplvars;
2301 int nintegral;
2302 int l;
2303
2304 assert(scip != NULL);
2305 assert(sepadata != NULL);
2306 assert(result != NULL);
2307
2308 SCIP_CALL( SCIPgetVarsData(scip, &scipvars, NULL, &nscipbinvars, &nscipintvars, &nscipimplvars, NULL) );
2309 assert(nscipbinvars >= 0);
2310 assert(nscipintvars >= 0);
2311 assert(nscipimplvars >= 0);
2312
2313 nintegral = nscipbinvars + nscipintvars + nscipimplvars;
2314 assert(scipvars != NULL || ((nscipbinvars == 0) && (nscipintvars == 0) && (nscipimplvars == 0) && (nintegral == 0)));
2315
2316 /* collect binary variables, including implicit binary */
2317 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nintegral) );
2318 for (l = 0; l < nscipbinvars; ++l)
2319 vars[l] = scipvars[l]; /*lint !e613*/
2320
2321 nbinvars = (unsigned int) nscipbinvars;
2322 for (l = nscipbinvars; l < nintegral; ++l)
2323 {
2324 assert( SCIPvarIsIntegral(scipvars[l]) ); /*lint !e613*/
2325 if ( SCIPvarIsBinary(scipvars[l]) ) /*lint !e613*/
2326 vars[nbinvars++] = scipvars[l]; /*lint !e613*/
2327 }
2328
2329 if( nbinvars == 0 )
2330 {
2332 return SCIP_OKAY;
2333 }
2334
2335 /* initialize flag array to avoid multiple cuts per variable, if requested by user-flag */
2336 SCIP_CALL( SCIPallocBufferArray(scip, &vals, (int) (2 * nbinvars)) );
2337
2338 /* prepare values */
2339 assert( vars != NULL );
2340 switch( sepadata->sortswitch )
2341 {
2342 case UNSORTED :
2343 /* if no sorting is requested, we use the normal variable array */
2344 break;
2345
2346 case MAXIMAL_LPVALUE :
2347 /* store lp-values */
2348 for( i = 0; i < nbinvars; ++i )
2349 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
2350
2351 /* sort by lp-value, maximal first */
2352 SCIPsortDownRealPtr(vals, (void**)vars, (int) nbinvars);
2353 break;
2354
2355 case MINIMAL_LPVALUE :
2356 /* store lp-values */
2357 for( i = 0; i < nbinvars; ++i )
2358 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
2359
2360 /* sort by lp-value, minimal first */
2361 SCIPsortRealPtr(vals, (void**)vars, (int) nbinvars);
2362 break;
2363
2365 /* store lp-values and determine fractionality */
2366 for( i = 0; i < nbinvars; ++i )
2367 {
2368 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
2369 vals[i] = MIN(1.0 - vals[i], vals[i]);
2370 }
2371
2372 /* sort by fractionality, maximal first */
2373 SCIPsortDownRealPtr(vals, (void**)vars, (int) nbinvars);
2374 break;
2375
2377 /* store lp-values and determine fractionality */
2378 for( i = 0; i < nbinvars; ++i )
2379 {
2380 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
2381 vals[i] = MIN(1.0 - vals[i], vals[i]);
2382 }
2383
2384 /* sort by fractionality, minimal first */
2385 SCIPsortRealPtr(vals, (void**)vars, (int) nbinvars);
2386 break;
2387
2388 default :
2389 SCIPerrorMessage("invalid sortswitch value\n");
2390 SCIPABORT();
2391 return SCIP_INVALIDDATA; /*lint !e527*/
2392 }
2393 assert(vars != NULL);
2394
2395 /* create mapping for getting the index of a variable via its probindex to the index in the sorted variable array */
2396 SCIP_CALL( SCIPallocBufferArray(scip, &(sepadata->mapping), nintegral) );
2397
2398 /* initialize LP value and cut flag for all variables */
2399 for( i = 0; i < nbinvars; ++i )
2400 {
2401 assert( 0 <= SCIPvarGetProbindex(vars[i]) && SCIPvarGetProbindex(vars[i]) < nintegral); /* since binary, integer, and implicit variables are first */
2402 sepadata->mapping[SCIPvarGetProbindex(vars[i])] = i;
2403 vals[i] = SCIPgetSolVal(scip, sol, vars[i]); /* need to get new values, since they might be corrupted */
2404 }
2405
2406 for( i = nbinvars; i < 2*nbinvars; ++i )
2407 vals[i] = 1.0 - vals[i - nbinvars];
2408
2409 /* determine size of level graph */
2410 graph.maxnodes = 2 * nbinvars;
2411
2412 /* the implication graph is redundant and therefore more implications and clique arcs may occur than should be possible
2413 * @todo later: filtering of edges which were already added
2414 */
2415 /* graph.maxarcs = nbinvars*(2*nbinvars-1); */ /* = 2*nbinvars*(2*nbinvars-1)/2 */
2416 graph.maxarcs = UINT_MAX;
2417
2418 /* set sizes for graph memory storage */
2419 graph.sizeForward = 100 * graph.maxnodes;
2420 graph.sizeBackward = 100 * graph.maxnodes;
2421 graph.sizeAdj = 100 * graph.maxnodes;
2422
2423 /* allocate memory for level graph structure */
2424 SCIP_CALL( SCIPallocBufferArray(scip, &graph.level, (int) graph.maxnodes) );
2425 SCIP_CALL( SCIPallocBufferArray(scip, &graph.beginForward, (int) graph.maxnodes) );
2426 SCIP_CALL( SCIPallocBufferArray(scip, &graph.beginBackward, (int) graph.maxnodes) );
2427 SCIP_CALL( SCIPallocBufferArray(scip, &graph.targetForward, (int) MIN(graph.sizeForward, graph.maxarcs)) );
2428 SCIP_CALL( SCIPallocBufferArray(scip, &graph.targetBackward, (int) MIN(graph.sizeBackward, graph.maxarcs)) );
2429 SCIP_CALL( SCIPallocBufferArray(scip, &graph.weightForward, (int) MIN(graph.sizeForward, graph.maxarcs)) );
2430 SCIP_CALL( SCIPallocBufferArray(scip, &graph.weightBackward, (int) MIN(graph.sizeBackward, graph.maxarcs)) );
2431
2432 SCIP_CALL( SCIPallocBufferArray(scip, &curlevel, (int) graph.maxnodes) );
2433 SCIP_CALL( SCIPallocBufferArray(scip, &newlevel, (int) graph.maxnodes) );
2434 SCIP_CALL( SCIPallocBufferArray(scip, &graph.beginAdj, (int) graph.maxnodes) );
2435 SCIP_CALL( SCIPallocBufferArray(scip, &graph.sourceAdj, (int) MIN(graph.sizeAdj, graph.maxarcs)) );
2436 SCIP_CALL( SCIPallocBufferArray(scip, &graph.targetAdj, (int) MIN(graph.sizeAdj, graph.maxarcs)) );
2437 SCIP_CALL( SCIPallocBufferArray(scip, &graph.weightAdj, (int) MIN(graph.sizeAdj, graph.maxarcs)) );
2438 SCIP_CALL( SCIPallocBufferArray(scip, &graph.levelAdj, (int) graph.maxnodes) );
2439 SCIP_CALL( SCIPallocBufferArray(scip, &inlevelgraph, (int) graph.maxnodes) );
2440
2441 SCIP_CALL( SCIPallocBufferArray(scip, &queue, (int) graph.maxnodes) );
2442 SCIP_CALL( SCIPallocBufferArray(scip, &inQueue, (int) graph.maxnodes) );
2443 SCIP_CALL( SCIPallocBufferArray(scip, &parentTree, (int) graph.maxnodes) );
2444 SCIP_CALL( SCIPallocBufferArray(scip, &parentTreeBackward, (int) graph.maxnodes) );
2445 SCIP_CALL( SCIPallocBufferArray(scip, &distance, (int) graph.maxnodes) );
2446 SCIP_CALL( SCIPallocBufferArray(scip, &blocked, (int) graph.maxnodes) );
2447
2448 SCIP_CALL( SCIPallocBufferArray(scip, &incut, (int) (2 * nbinvars)) );
2449
2450 /* initialize cut flag for all variables */
2451 BMSclearMemoryArray(incut, 2*nbinvars);
2452
2453 /* determine the number of level graph roots */
2454 maxroots = (unsigned int) SCIPceil(scip, sepadata->offsettestvars + (0.02 * nbinvars * sepadata->percenttestvars));
2455 sepadata->maxlevelsize = (unsigned int) SCIPceil(scip, sepadata->offsetnodeslevel + 0.01 * sepadata->maxpernodeslevel * graph.maxnodes);
2456 rootcounter = 0;
2457
2458 /* check each node as root */
2459 for( i = (unsigned int) sepadata->lastroot; i < graph.maxnodes && rootcounter < maxroots
2460 && sepadata->ncuts - sepadata->oldncuts < (unsigned int) sepadata->maxsepacutsround
2461 && !SCIPisStopped(scip) ; ++i )
2462 {
2463 /* skip node if it is already covered by a cut and if we do not want to search cycles starting
2464 * with a node already covered by a cut */
2465 if( incut[i] && ! sepadata->multiplecuts )
2466 continue;
2467
2468 /* skip variable if its LP-value is not fractional */
2469 if( SCIPisFeasIntegral(scip, vals[i]) )
2470 continue;
2471
2472 /* consider original and negated variable pair and skip variable if there is only one edge leaving the pair */
2473 if( SCIPvarGetNCliques(vars[i % nbinvars], TRUE) + SCIPvarGetNCliques(vars[i % nbinvars], FALSE) == 0 )
2474 continue;
2475
2476 /* skip variable having too less implics and cliques itself */
2477 if( i < nbinvars )
2478 {
2479 if( SCIPvarGetNCliques(vars[i % nbinvars], TRUE ) == 0 )
2480 continue;
2481 if( !(sepadata->addselfarcs) && SCIPvarGetNCliques(vars[i % nbinvars], TRUE ) == 0 )
2482 continue;
2483 }
2484 else
2485 {
2486 if( SCIPvarGetNCliques(vars[i % nbinvars], FALSE) == 0 )
2487 continue;
2488
2489 if( !(sepadata->addselfarcs) && SCIPvarGetNCliques(vars[i % nbinvars], FALSE) == 0 )
2490 continue;
2491 }
2492
2493 /* node is actually considered as root node for the level graph */
2494 ++rootcounter;
2495 ncutsroot = 0;
2496
2497 /* initialize graph */
2498 for( j = 0; j < graph.maxnodes; ++j)
2499 {
2500 graph.beginForward[j] = -1;
2501 graph.beginBackward[j] = -1;
2502 graph.beginAdj[j] = -1;
2503 inlevelgraph[j] = FALSE;
2504 blocked[j] = FALSE;
2505 }
2506 graph.lastF = 0;
2507 graph.lastB = 0;
2508 graph.nlevels = 0;
2509 graph.narcs = 0;
2510
2511 /* insert root (first level contains root only) */
2512 inlevelgraph[i] = TRUE;
2513 graph.level[i] = 0;
2514 graph.levelAdj[0] = 0;
2515 graph.nnodes = 1;
2516 curlevel[0] = i;
2517 ncurlevel = 1;
2518
2519 /* there are no arcs inside the root level */
2520 graph.levelAdj[graph.nlevels+1] = 0;
2521
2522 /* create new levels until there are not more nodes for a new level */
2523 do
2524 {
2525 SCIP_Bool success;
2526 success = TRUE;
2527
2528 /* all neighbors of nodes in level i that are assigned to level i+1,
2529 if they do not already appear in levels <= i. */
2530 SCIP_CALL( createNextLevel(scip, sepadata, vars, vals, &graph, graph.nlevels, inlevelgraph,
2531 curlevel, ncurlevel, newlevel, &nnewlevel, &success) );
2532
2533 if( !success )
2534 goto TERMINATE;
2535
2536 /* search for odd holes */
2537 if( graph.nlevels > 0 && (sepadata->includetriangles || graph.nlevels > 1) )
2538 {
2539 unsigned int maxcutslevel;
2540
2541 ncutslevel = 0;
2542
2543 /* calculate maximal cuts in this level due to cut limitations (per level, per root, per separation round) */
2544 maxcutslevel = (unsigned int) sepadata->maxcutslevel;
2545 maxcutslevel = (unsigned int) MIN((int) maxcutslevel, (int) ncutsroot - sepadata->maxcutsroot);
2546 maxcutslevel = (unsigned int) MIN((int) maxcutslevel, sepadata->maxsepacutsround + (int) sepadata->oldncuts - (int) sepadata->ncuts);
2547
2548 /* for each cross edge in this level find both shortest paths to root (as long as no limits are reached) */
2549 for( j = graph.levelAdj[graph.nlevels+1]; j < graph.levelAdj[graph.nlevels+2]
2550 && ncutslevel < maxcutslevel && !SCIPisStopped(scip); ++j )
2551 {
2552 unsigned int ncyclevars;
2553 unsigned int u;
2554
2555 /* storage for cut generation */
2556 unsigned int* pred; /* predecessor list */
2557 SCIP_Bool* incycle; /* flag array for check of double variables in found cycle */
2558
2559 assert(graph.sourceAdj[j] < graph.targetAdj[j]);
2560
2561 /* find shortest path from source to root and update weight of cycle */
2562 SCIP_CALL( findShortestPathToRoot(scip, sepadata->scale, &graph, graph.sourceAdj[j], distance, queue, inQueue, parentTree) );
2563
2564#ifndef NDEBUG
2565 /* check that this path ends in the root node */
2566 u = i;
2567 k = 1;
2568 while( u != graph.sourceAdj[j] )
2569 {
2570 assert(parentTree[u] != -1 && k <= graph.maxnodes);
2571 u = (unsigned int) parentTree[u];
2572 ++k;
2573 }
2574#endif
2575
2576 /* block all nodes that are adjacent to nodes of the first path */
2577 for( k = 0; k < graph.nnodes; ++k )
2578 blocked[k] = FALSE;
2579 SCIP_CALL( blockRootPath(scip, &graph, graph.sourceAdj[j], inlevelgraph, blocked, parentTree, i) );
2580
2581 /* if the target is block, no violated odd hole can be found */
2582 if( blocked[graph.targetAdj[j]] )
2583 continue;
2584
2585 /* find shortest path from root to target node avoiding blocked nodes */
2587 graph.targetAdj[j], distance, queue, inQueue, parentTreeBackward, i, blocked) );
2588
2589 /* no odd cycle cut found */
2590 if( parentTreeBackward[graph.targetAdj[j]] < 0 )
2591 continue;
2592
2593 /* allocate and initialize predecessor list and flag array representing odd cycle */
2594 SCIP_CALL( SCIPallocBufferArray(scip, &pred, (int) (2 * nbinvars)) );
2595 SCIP_CALL( SCIPallocBufferArray(scip, &incycle, (int) (2 * nbinvars)) );
2596 for( k = 0; k < 2 * nbinvars; ++k )
2597 {
2598 pred[k] = DIJKSTRA_UNUSED;
2599 incycle[k] = FALSE;
2600 }
2601 ncyclevars = 0;
2602 success = TRUE;
2603
2604 /* check cycle for x-neg(x)-sub-cycles and clean them
2605 * (note that a variable cannot appear twice in a cycle since it is only once in the graph)
2606 * convert parentTreeBackward and parentTree to pred&incycle structure for generateOddCycleCut
2607 */
2608 u = graph.targetAdj[j];
2609
2610 /* add path to root to cycle */
2611 while( success && u != i )
2612 {
2613 /* insert u in predecessor list */
2614 pred[u] = (unsigned int) parentTreeBackward[u];
2615
2616 /* remove pairs of original and negated variable from cycle */
2617 SCIP_CALL( cleanCycle(scip, pred, incycle, incut, u, graph.targetAdj[j], nbinvars, &ncyclevars,
2618 sepadata->repaircycles, sepadata->allowmultiplecuts, &success) );
2619
2620 assert(parentTreeBackward[u] >= 0 || u == i);
2621
2622 /* select next node on path */
2623 u = (unsigned int) parentTreeBackward[u];
2624 }
2625
2626 /* add path from root to cycle */
2627 while( success && u != graph.sourceAdj[j] )
2628 {
2629 /* insert u in predecessor list */
2630 pred[u] = (unsigned int) parentTree[u];
2631
2632 /* remove pairs of original and negated variable from cycle */
2633 SCIP_CALL( cleanCycle(scip, pred, incycle, incut, u, graph.targetAdj[j], nbinvars, &ncyclevars,
2634 sepadata->repaircycles, sepadata->allowmultiplecuts, &success) );
2635
2636 /* select next node on path */
2637 u = (unsigned int) parentTree[u];
2638 }
2639 assert(!success || u == graph.sourceAdj[j]);
2640
2641 /* close the cycle */
2642 if( success )
2643 {
2644 pred[u] = graph.targetAdj[j];
2645
2646 /* remove pairs of original and negated variable from cycle */
2647 SCIP_CALL( cleanCycle(scip, pred, incycle, incut, u, graph.targetAdj[j], nbinvars, &ncyclevars,
2648 sepadata->repaircycles, sepadata->allowmultiplecuts, &success) );
2649 }
2650
2651 /* generate cut (if cycle is valid) */
2652 if(success)
2653 {
2654 GRAPHDATA graphdata;
2655 unsigned int oldncuts;
2656
2657 graphdata.usegls = FALSE;
2658 graphdata.levelgraph = &graph;
2659 graphdata.dijkstragraph = NULL;
2660
2661 oldncuts = sepadata->ncuts;
2662
2663 SCIP_CALL( generateOddCycleCut(scip, sepa, sol, vars, nbinvars, graph.targetAdj[j], pred, ncyclevars,
2664 incut, vals, sepadata, &graphdata, result) );
2665
2666 if(oldncuts < sepadata->ncuts)
2667 {
2668 ++ncutsroot;
2669 ++ncutslevel;
2670 }
2671 }
2672
2673 /* free temporary memory */
2674 SCIPfreeBufferArray(scip, &incycle);
2675 SCIPfreeBufferArray(scip, &pred);
2676
2677 if ( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM )
2678 break;
2679 }
2680 }
2681
2682 if ( *result == SCIP_CUTOFF || *result == SCIP_REDUCEDDOM )
2683 break;
2684
2685 /* copy new level to current one */
2686 ++(graph.nlevels);
2687 for( j = 0; j < nnewlevel; ++j )
2688 curlevel[j] = newlevel[j];
2689 ncurlevel = nnewlevel;
2690 }
2691 /* stop level creation loop if new level is empty or any limit is reached */
2692 while( nnewlevel > 0 && !SCIPisStopped(scip)
2693 && graph.nlevels < (unsigned int) sepadata->maxnlevels
2694 && ncutsroot < (unsigned int) sepadata->maxcutsroot
2695 && sepadata->ncuts - sepadata->oldncuts < (unsigned int) sepadata->maxsepacutsround);
2696 }
2697
2698 /* store the last tried root (when running without sorting the variable array, we don't want
2699 * to always check the same variables and therefore start next time where we stopped last time)
2700 */
2701 if( sepadata->sortswitch == UNSORTED )
2702 {
2703 if( i == graph.maxnodes )
2704 sepadata->lastroot = 0;
2705 else
2706 sepadata->lastroot = (int) i;
2707 }
2708
2709 TERMINATE:
2710 /* free memory */
2711 SCIPfreeBufferArray(scip, &incut);
2712
2713 SCIPfreeBufferArray(scip, &blocked);
2714 SCIPfreeBufferArray(scip, &distance);
2715 SCIPfreeBufferArray(scip, &parentTreeBackward);
2716 SCIPfreeBufferArray(scip, &parentTree);
2717 SCIPfreeBufferArray(scip, &inQueue);
2718 SCIPfreeBufferArray(scip, &queue);
2719
2720 SCIPfreeBufferArray(scip, &inlevelgraph);
2721 SCIPfreeBufferArray(scip, &graph.levelAdj);
2722 SCIPfreeBufferArray(scip, &graph.weightAdj);
2723 SCIPfreeBufferArray(scip, &graph.targetAdj);
2724 SCIPfreeBufferArray(scip, &graph.sourceAdj);
2725 SCIPfreeBufferArray(scip, &graph.beginAdj);
2726 SCIPfreeBufferArray(scip, &newlevel);
2727 SCIPfreeBufferArray(scip, &curlevel);
2728
2729 SCIPfreeBufferArray(scip, &graph.weightBackward);
2730 SCIPfreeBufferArray(scip, &graph.weightForward);
2731 SCIPfreeBufferArray(scip, &graph.targetBackward);
2732 SCIPfreeBufferArray(scip, &graph.targetForward);
2733 SCIPfreeBufferArray(scip, &graph.beginBackward);
2734 SCIPfreeBufferArray(scip, &graph.beginForward);
2735 SCIPfreeBufferArray(scip, &graph.level);
2736
2737 SCIPfreeBufferArray(scip, &(sepadata->mapping));
2738 SCIPfreeBufferArray(scip, &vals);
2740
2741 return SCIP_OKAY;
2742}
2743
2744
2745/* methods for separateGLS() */
2746
2747/** memory reallocation method (the graph is normally very dense, so we dynamically allocate only the memory we need) */
2748static
2750 SCIP* scip, /**< SCIP data structure */
2751 unsigned int maxarcs, /**< maximal size of graph->head and graph->weight */
2752 unsigned int* arraysize, /**< current size of graph->head and graph->weight */
2753 DIJKSTRA_GRAPH* graph, /**< Dijkstra Graph data structure */
2754 SCIP_Bool* success /**< FALSE, iff memory reallocation fails */
2755 )
2756{
2757 SCIP_Real memorylimit;
2758 unsigned int additional;
2759 unsigned int j;
2760 unsigned int oldarraysize;
2761
2762 assert(scip != NULL);
2763 assert(arraysize != NULL);
2764 assert(graph != NULL);
2765 assert(graph->head != NULL);
2766 assert(graph->weight != NULL);
2767 assert(success != NULL);
2768
2769 SCIPdebugMsg(scip, "reallocating graph->head and graph->weight...\n");
2770
2771 additional = (MIN(maxarcs, 2 * (*arraysize)) - (*arraysize)) * ((int) sizeof(*(graph->head)));
2772 additional += (MIN(maxarcs, 2 * (*arraysize)) - (*arraysize)) * ((int) sizeof(*(graph->weight)));
2773
2774 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
2775 if( !SCIPisInfinity(scip, memorylimit) )
2776 {
2777 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
2778 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
2779 }
2780
2781 /* if memorylimit would be exceeded or any other limit is reached free all data and exit */
2782 if( memorylimit <= additional/1048576.0 || SCIPisStopped(scip) )
2783 {
2784 *success = FALSE;
2785 SCIPdebugMsg(scip, "...memory limit exceeded\n");
2786 return SCIP_OKAY;
2787 }
2788
2789 oldarraysize = *arraysize;
2790 *arraysize = 2*(*arraysize);
2791
2792 SCIP_CALL( SCIPreallocBufferArray(scip, &(graph->head), (int) MIN(maxarcs, (*arraysize))) );
2793 SCIP_CALL( SCIPreallocBufferArray(scip, &(graph->weight), (int) MIN(maxarcs, (*arraysize))) );
2794
2795 /* if memorylimit exceeded, leave the separator */
2796 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
2797
2798 if( !SCIPisInfinity(scip, memorylimit) )
2799 {
2800 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
2801 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
2802 }
2803
2804 if( memorylimit <= 2.0*SCIPgetMemExternEstim(scip)/1048576.0 )
2805 {
2806 SCIPdebugMsg(scip, "...memory limit exceeded - freeing all arrays\n");
2807 *success = FALSE;
2808 return SCIP_OKAY;
2809 }
2810
2811 /* initialize new segments of graph as empty graph */
2812 for( j = oldarraysize; j < MIN(maxarcs,(*arraysize)); ++j )
2813 {
2814 (graph->head)[j] = DIJKSTRA_UNUSED;
2815 (graph->weight)[j] = DIJKSTRA_UNUSED;
2816 }
2817
2818 SCIPdebugMsg(scip, "...with success\n");
2819
2820 return SCIP_OKAY;
2821}
2822
2823/** add implications from cliques of the given node */
2824static
2826 SCIP* scip, /**< SCIP data structure */
2827 SCIP_SEPADATA* sepadata, /**< separator data structure */
2828 SCIP_VAR** vars, /**< problem variables */
2829 unsigned int varsidx, /**< index of current variable inside the problem variables */
2830 unsigned int dijkindex, /**< index of current variable inside the Dijkstra Graph */
2831 SCIP_Real* vals, /**< value of the variables in the given solution */
2832 unsigned int nbinvars, /**< number of binary problem variables */
2833 unsigned int ncliques, /**< number of cliques of the current node */
2834 DIJKSTRA_GRAPH* graph, /**< Dijkstra Graph data structure */
2835 unsigned int* narcs, /**< current number of arcs inside the Dijkstra Graph */
2836 unsigned int maxarcs, /**< maximal number of arcs inside the Dijkstra Graph */
2837 SCIP_Bool original, /**< TRUE, iff variable is a problem variable */
2838 SCIP_Bool* emptygraph, /**< TRUE, iff there is no arc in the implication graph of the binary variables of SCIP */
2839 unsigned int* arraysize, /**< current size of graph->head and graph->weight */
2840 SCIP_Bool* success /**< FALSE, iff memory reallocation fails */
2841 )
2842{
2843 SCIP_VAR* neighbor; /* current neighbor of the current variable */
2844 unsigned int neighindex;
2845 SCIP_CLIQUE** cliques; /* cliques of the current variable (with x==0/1) */
2846 unsigned int ncliquevars; /* number of variables of a clique */
2847 SCIP_VAR** cliquevars; /* variables of a clique */
2848 SCIP_Bool* cliquevals; /* is the cliquevariable fixed to TRUE or to FALSE */
2849 unsigned int k;
2850 unsigned int m;
2851
2852 assert(scip != NULL);
2853 assert(sepadata != NULL);
2854 assert(vars != NULL);
2855 assert(graph != NULL);
2856 assert(graph->head != NULL);
2857 assert(graph->weight != NULL);
2858 assert(narcs != NULL);
2859 assert(emptygraph != NULL);
2860 assert(arraysize != NULL);
2861 assert(success != NULL);
2862
2863 /* if current variable has cliques of current clique-type */
2864 cliques = SCIPvarGetCliques(vars[varsidx], original);
2865 assert(cliques != NULL || ncliques == 0);
2866
2867 for( k = 0; k < ncliques; ++k )
2868 {
2869 assert( cliques != NULL ); /* for lint */
2870
2871 /* get clique data */
2872 cliquevars = SCIPcliqueGetVars(cliques[k]);
2873 ncliquevars = (unsigned int) SCIPcliqueGetNVars(cliques[k]);
2874 cliquevals = SCIPcliqueGetValues(cliques[k]);
2875
2876 assert(cliquevars != NULL || ncliquevars == 0);
2877 assert(cliquevals != NULL || ncliquevars == 0);
2878
2879 /* add arcs for all fractional variables in clique */
2880 for( m = 0; m < ncliquevars; ++m )
2881 {
2882 int tmp;
2883
2884 assert( cliquevars != NULL && cliquevals != NULL ); /* for lint */
2885 neighbor = cliquevars[m];
2886
2887 neighindex = sepadata->mapping[SCIPvarGetProbindex(neighbor)];
2888 assert(neighindex < nbinvars);
2889
2890 /* ignore current variable */
2891 if( neighindex == varsidx )
2892 continue;
2893
2894 /* we use only variables with fractional LP-solution values */
2895 if( SCIPisFeasIntegral(scip, vals[neighindex]) )
2896 continue;
2897
2898 /* forward direction (the backward is created at the occurrence of the current variable in the cliquevars of the neighbor) */
2899 /* x==1 */
2900 if( original )
2901 {
2902 /* implication to y=0 (I->III) */
2903 if( cliquevals[m] )
2904 {
2905 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1 - vals[varsidx] - vals[neighindex] ));
2906 graph->weight[*narcs] = (unsigned int) MAX(0, tmp);
2907 graph->head[*narcs] = neighindex + 2 * nbinvars;
2908 }
2909 /* implication to y=1 (I->IV) (cliquevals[m] == FALSE) */
2910 else
2911 {
2912 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1 - vals[varsidx] - (1 - vals[neighindex]) ));
2913 graph->weight[*narcs] = (unsigned int) MAX(0, tmp);
2914 graph->head[*narcs] = neighindex + 3 * nbinvars;
2915 }
2916 }
2917 /* x==0 */
2918 else
2919 {
2920 /* implication to y=0 (II->III) */
2921 if( cliquevals[m] )
2922 {
2923 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1 - (1 - vals[varsidx]) - vals[neighindex] ));
2924 graph->weight[*narcs] = (unsigned int) MAX(0, tmp);
2925 graph->head[*narcs] = neighindex + 2 * nbinvars;
2926 }
2927 /* implication to y=1 (II->IV) (cliquevals[m] == FALSE) */
2928 else
2929 {
2930 tmp = (int) SCIPfeasCeil(scip, sepadata->scale * (1 - (1 - vals[varsidx]) - (1-vals[neighindex]) )) ;
2931 graph->weight[*narcs] = (unsigned int) MAX(0, tmp);
2932 graph->head[*narcs] = neighindex + 3 * nbinvars;
2933 }
2934 }
2935
2936 /* update minimum and maximum weight values */
2937 if( graph->weight[*narcs] < graph->minweight )
2938 graph->minweight = graph->weight[*narcs];
2939
2940 if( graph->weight[*narcs] > graph->maxweight )
2941 graph->maxweight = graph->weight[*narcs];
2942
2943 ++(*narcs);
2944 if( *arraysize == *narcs )
2945 {
2946 SCIP_CALL( checkArraySizesGLS(scip, maxarcs, arraysize, graph, success) );
2947
2948 if( !(*success) )
2949 return SCIP_OKAY;
2950 }
2951 assert((*narcs) < maxarcs);
2952 ++(graph->outcnt[dijkindex]);
2953
2954 *emptygraph = FALSE;
2955 }
2956 }
2957
2958 return SCIP_OKAY;
2959}
2960
2961/** The classical method for finding odd cycles by Groetschel, Lovasz, Schrijver uses a bipartite graph
2962 * which contains in each partition a node for every node in the original graph.
2963 * All arcs uv of the original graph are copied to arcs from u of the first partition to v' of the second partition
2964 * and from u' of the second partition to v of the first partition.
2965 * A Dijkstra algorithm is used to find a path from a node x to its copy x', if existing.
2966 * The nodes in the original graph corresponding to the nodes on the path form an odd cycle.
2967 *
2968 * Since SCIP stores implications between original and negated variables,
2969 * our original graph has at most twice the number of binary variables of the problem.
2970 * By creating the bipartite graph we gain 4 segments of the graph:
2971 *
2972 * I - nodes of the original variables in the first bipartition \n
2973 * II - nodes of the negated variables in the first bipartition \n
2974 * III - nodes of the original variables in the second bipartition \n
2975 * IV - nodes of the negated variables in the second bipartition
2976 *
2977 * The length of every segment if the number of binary variables in the original problem.
2978 *
2979 * Since the implication graph of SCIP is (normally) incomplete,
2980 * it is possible to use arcs between an original variable and its negated
2981 * to obtain more cycles which are valid but not found due to missing links.
2982 */
2983static
2985 SCIP* scip, /**< SCIP data structure */
2986 SCIP_SEPA* sepa, /**< separator */
2987 SCIP_SEPADATA* sepadata, /**< separator data structure */
2988 SCIP_SOL* sol, /**< given primal solution */
2989 SCIP_RESULT* result /**< pointer to store the result of the separation call */
2990 )
2991{
2992 SCIP_Bool emptygraph; /* flag if graph contains an arc */
2993
2994 SCIP_Real* vals; /* values of the variables in the given solution */
2995 unsigned int* incut;
2996
2997 unsigned int i;
2998 unsigned int j;
2999
3000 SCIP_VAR** scipvars; /* variables of the current SCIP (unsorted) */
3001 SCIP_VAR** vars; /* variables of the current SCIP (sorted if requested) */
3002 unsigned int nbinvars; /* number of binary problem variables */
3003 SCIP_Bool original; /* flag if the current variable is original or negated */
3004
3005 unsigned int ncliques; /* number of cliques of the current variable */
3006
3007 DIJKSTRA_GRAPH graph; /* Dijkstra graph data structure */
3008 unsigned int arraysize; /* current size of graph->head and graph->weight */
3009 unsigned int narcs; /* number of arcs in the Dijkstra graph */
3010 unsigned int maxarcs; /* maximum number of arcs in the Dijkstra graph */
3011 unsigned int maxstarts; /* maximum number of start nodes */
3012 unsigned int startcounter; /* counter of tried start nodes */
3013 unsigned long long cutoff; /* cutoff value for Dijkstra algorithm */
3014
3015 unsigned int startnode; /* start node for Dijkstra algorithm */
3016 unsigned int endnode; /* target node for Dijkstra algorithm */
3017 unsigned long long* dist; /* distance matrix for Dijkstra algorithm */
3018 unsigned int* pred; /* predecessor list for found cycle */
3019 unsigned int* entry; /* storage for Dijkstra algorithm */
3020 unsigned int* order; /* storage for Dijkstra algorithm */
3021 unsigned int dijkindex;
3022 SCIP_Bool success; /* flag for check for several errors */
3023
3024 SCIP_Bool* incycle; /* flag array if variable is contained in the found cycle */
3025 unsigned int* pred2; /* temporary predecessor list for backprojection of found cycle */
3026
3027 int nscipbinvars;
3028 int nscipintvars;
3029 int nscipimplvars;
3030 int nintegral;
3031 int k;
3032
3033 assert(scip != NULL);
3034 assert(sepadata != NULL);
3035 assert(result != NULL);
3036
3037 success = TRUE;
3038 emptygraph = TRUE;
3039
3040 SCIP_CALL( SCIPgetVarsData(scip, &scipvars, NULL, &nscipbinvars, &nscipintvars, &nscipimplvars, NULL) );
3041 assert(nscipbinvars >= 0);
3042 assert(nscipintvars >= 0);
3043 assert(nscipimplvars >= 0);
3044
3045 nintegral = nscipbinvars + nscipintvars + nscipimplvars;
3046 assert(scipvars != NULL || ((nscipbinvars == 0) && (nscipintvars == 0) && (nscipimplvars == 0) && (nintegral == 0)));
3047
3048 /* collect binary variables, including implicit binary */
3049 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nintegral) );
3050 for (k = 0; k < nscipbinvars; ++k)
3051 vars[k] = scipvars[k]; /*lint !e613*/
3052
3053 nbinvars = (unsigned int) nscipbinvars;
3054 for (k = nscipbinvars; k < nintegral; ++k)
3055 {
3056 assert( SCIPvarIsIntegral(scipvars[k]) ); /*lint !e613*/
3057 if ( SCIPvarIsBinary(scipvars[k]) ) /*lint !e613*/
3058 vars[nbinvars++] = scipvars[k]; /*lint !e613*/
3059 }
3060
3061 if( nbinvars == 0 )
3062 {
3064 return SCIP_OKAY;
3065 }
3066
3067 /* initialize flag array to avoid multiple cuts per variable, if requested by user-flag */
3068 SCIP_CALL( SCIPallocBufferArray(scip, &vals, (int) (2 * nbinvars)) );
3069
3070 /* prepare values */
3071 assert( vars != NULL );
3072 switch( sepadata->sortswitch )
3073 {
3074 case UNSORTED :
3075 /* if no sorting is requested, we use the normal variable array */
3076 break;
3077
3078 case MAXIMAL_LPVALUE :
3079 /* store lp-values */
3080 for( i = 0; i < nbinvars; ++i )
3081 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
3082
3083 /* sort by lp-value, maximal first */
3084 SCIPsortDownRealPtr(vals, (void**)vars, (int) nbinvars);
3085 break;
3086
3087 case MINIMAL_LPVALUE :
3088 /* store lp-values */
3089 for( i = 0; i < nbinvars; ++i )
3090 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
3091
3092 /* sort by lp-value, minimal first */
3093 SCIPsortRealPtr(vals, (void**)vars, (int) nbinvars);
3094 break;
3095
3097 /* store lp-values and determine fractionality */
3098 for( i = 0; i < nbinvars; ++i )
3099 {
3100 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
3101 vals[i] = MIN(1.0 - vals[i], vals[i]);
3102 }
3103
3104 /* sort by fractionality, maximal first */
3105 SCIPsortDownRealPtr(vals, (void**)vars, (int) nbinvars);
3106 break;
3107
3109 /* store lp-values and determine fractionality */
3110 for( i = 0; i < nbinvars; ++i )
3111 {
3112 vals[i] = SCIPgetSolVal(scip, sol, vars[i]);
3113 vals[i] = MIN(1.0 - vals[i], vals[i]);
3114 }
3115
3116 /* sort by fractionality, minimal first */
3117 SCIPsortRealPtr(vals, (void**)vars, (int) nbinvars);
3118 break;
3119
3120 default :
3121 SCIPerrorMessage("invalid sortswitch value\n");
3122 SCIPABORT();
3123 return SCIP_INVALIDDATA; /*lint !e527*/
3124 }
3125 assert(vars != NULL);
3126
3127 /* create mapping for getting the index of a variable via its probindex to the index in the sorted variable array */
3128 SCIP_CALL( SCIPallocBufferArray(scip, &(sepadata->mapping), nintegral) );
3129 SCIP_CALL( SCIPallocBufferArray(scip, &incut, (int) (4 * nbinvars)) );
3130 BMSclearMemoryArray(incut, 4 * nbinvars);
3131
3132 /* initialize LP value and cut flag for all variables */
3133 for( i = 0; i < nbinvars; ++i )
3134 {
3135 assert( 0 <= SCIPvarGetProbindex(vars[i]) && SCIPvarGetProbindex(vars[i]) < nintegral); /* since binary, integer, and implicit variables are first */
3136 sepadata->mapping[SCIPvarGetProbindex(vars[i])] = i;
3137 vals[i] = SCIPgetSolVal(scip, sol, vars[i]); /* need to get new values, since they might be corrupted */
3138 }
3139
3140 for( i = nbinvars; i < 2*nbinvars; ++i )
3141 vals[i] = 1 - vals[i - nbinvars];
3142
3143 /* initialize number of nodes in Dijkstra graph (2*2*n nodes in a mirrored bipartite graph with negated variables) */
3144 graph.nodes = 4 * nbinvars;
3145
3146 /* Initialize number of arcs in Dijkstra graph, should be (nbinvars+1) * graph.nodes, but might deviate, because
3147 * there might be parallel arcs:
3148 * nbinvars-1 possible arcs per node (it is not possible to be linked to variable and negated)
3149 * + 1 self-arc (arc to negated variable)
3150 * + 1 dummy arc for Dijkstra data structure
3151 * = nbinvars+1 arcs per node
3152 * * graph.nodes
3153 * = (nbinvars+1)*graph.nodes
3154 * + graph.nodes => separating entries for arclist)
3155 *
3156 * Number is corrected below.
3157 */
3158 graph.arcs = 0;
3159
3160 /* the implication graph is redundant and therefore more implications and clique arcs may occur than should be possible
3161 * @todo later: filtering of edges which were already added, maxarcs should be graph.arcs rather than INT_MAX;
3162 */
3163 maxarcs = UINT_MAX;
3164
3165 /* allocate memory for Dijkstra graph arrays */
3166 arraysize = 100 * graph.nodes;
3167 SCIP_CALL( SCIPallocBufferArray(scip, &graph.outbeg, (int) graph.nodes) );
3168 SCIP_CALL( SCIPallocBufferArray(scip, &graph.outcnt, (int) graph.nodes) );
3169 SCIP_CALL( SCIPallocBufferArray(scip, &graph.head, (int) MIN(maxarcs, arraysize)) );
3170 SCIP_CALL( SCIPallocBufferArray(scip, &graph.weight, (int) MIN(maxarcs, arraysize)) );
3171 SCIP_CALL( SCIPallocBufferArray(scip, &dist, (int) graph.nodes) );
3172 SCIP_CALL( SCIPallocBufferArray(scip, &pred, (int) graph.nodes) );
3173 SCIP_CALL( SCIPallocBufferArray(scip, &entry, (int) graph.nodes) );
3174 SCIP_CALL( SCIPallocBufferArray(scip, &order, (int) graph.nodes) );
3175
3176 /* initialize Dijkstra graph as empty graph */
3177 for( i = 0; i < MIN(arraysize, maxarcs); ++i )
3178 {
3179 graph.head[i] = DIJKSTRA_UNUSED;
3180 graph.weight[i] = DIJKSTRA_UNUSED;
3181 }
3183 graph.maxweight = 0;
3184 narcs = 0;
3185
3186#ifndef NDEBUG
3187 for( i = 0; i < graph.nodes; ++i )
3188 {
3189 graph.outbeg[i] = 0;
3190 graph.outcnt[i] = 0;
3191 }
3192#endif
3193
3194 /* add arcs from first to second partition to Dijkstra graph (based on the original fractional implication graph) */
3195 for( dijkindex = 0; dijkindex < 2 * nbinvars; ++dijkindex )
3196 {
3197 graph.outbeg[dijkindex] = narcs;
3198 graph.outcnt[dijkindex] = 0;
3199
3200 /* decide if we have original or negated variable */
3201 if( dijkindex < nbinvars )
3202 {
3203 i = dijkindex;
3204 original = TRUE;
3205 }
3206 else
3207 {
3208 i = dijkindex - nbinvars;
3209 original = FALSE;
3210 }
3211 assert(i < nbinvars);
3212
3213 /* if the variable has a fractional value we add it to the graph */
3214 if( ! SCIPisFeasIntegral(scip, vals[i]) )
3215 {
3216 ncliques = (unsigned int) SCIPvarGetNCliques(vars[i], original);
3217
3218 /* insert arcs for cliques (take var => getCliques => take cliquevar => add forward-arc) */
3219 /* add clique arcs of clique-type "original" if current variable has them */
3220 if( ncliques >= 1 )
3221 {
3222 /* x==1/0 -> y==0/1 (I/II -> III/IV) */
3223 SCIP_CALL( addGLSCliques(scip, sepadata, vars, i, dijkindex, vals, nbinvars, ncliques, &graph,
3224 &narcs, maxarcs, original, &emptygraph, &arraysize, &success) );
3225
3226 if( !success )
3227 goto TERMINATE;
3228 }
3229 }
3230
3231 /* add link to copy of negated variable (useful if/because the implication graph is incomplete) */
3232 if( sepadata->addselfarcs && graph.outcnt[dijkindex] > 0 )
3233 {
3234 /* I -> IV */
3235 if( original )
3236 {
3237 assert(dijkindex < nbinvars);
3238 graph.head[narcs] = dijkindex + 3*nbinvars;
3239 }
3240 /* II -> III */
3241 else
3242 {
3243 assert(dijkindex >= nbinvars && dijkindex < 2*nbinvars);
3244 graph.head[narcs] = dijkindex + nbinvars;
3245 }
3246 graph.weight[narcs] = 0;
3247
3248 /* update minimum and maximum weight values */
3249 if( graph.weight[narcs] < graph.minweight )
3250 graph.minweight = graph.weight[narcs];
3251
3252 if( graph.weight[narcs] > graph.maxweight )
3253 graph.maxweight = graph.weight[narcs];
3254
3255 ++narcs;
3256 if( arraysize == narcs )
3257 {
3258 SCIP_CALL( checkArraySizesGLS(scip, maxarcs, &arraysize, &graph, &success) );
3259 if( !success )
3260 goto TERMINATE;
3261 }
3262 assert(narcs < maxarcs);
3263 ++(graph.outcnt[dijkindex]);
3264 }
3265
3266 /* add separating arc */
3267 graph.head[narcs] = DIJKSTRA_UNUSED;
3268 graph.weight[narcs] = DIJKSTRA_UNUSED;
3269 ++narcs;
3270 if( arraysize == narcs )
3271 {
3272 SCIP_CALL( checkArraySizesGLS(scip, maxarcs, &arraysize, &graph, &success) );
3273 if( !success )
3274 goto TERMINATE;
3275 }
3276 assert(narcs < maxarcs);
3277 }
3278
3279 /* if the graph is empty, there is nothing to do */
3280 if( emptygraph )
3281 goto TERMINATE;
3282
3283 /* add arcs from second to first partition to Dijkstra graph */
3284 for( i = 0; i < 2*nbinvars; ++i )
3285 {
3286 graph.outbeg[2 * nbinvars + i] = narcs;
3287 graph.outcnt[2 * nbinvars + i] = 0;
3288
3289 /* copy all arcs to head from the second to the first bipartition */
3290 for( j = graph.outbeg[i]; j < graph.outbeg[i] + graph.outcnt[i]; ++j )
3291 {
3292 /* there are only arcs from first bipartition to the second */
3293 assert(graph.head[j] >= 2*nbinvars && graph.head[j] < 4*nbinvars);
3294
3295 /* the backward arcs head from III->I or IV->II */
3296 graph.head[narcs] = graph.head[j] - 2 * nbinvars;
3297 graph.weight[narcs] = graph.weight[j];
3298 ++narcs;
3299 if( arraysize == narcs )
3300 {
3301 SCIP_CALL( checkArraySizesGLS(scip, maxarcs, &arraysize, &graph, &success) );
3302
3303 if( !success )
3304 goto TERMINATE;
3305 }
3306 assert(narcs < maxarcs);
3307 ++(graph.outcnt[2*nbinvars+i]);
3308 }
3309
3310 /* add separating arc */
3311 graph.head[narcs] = DIJKSTRA_UNUSED;
3312 graph.weight[narcs] = DIJKSTRA_UNUSED;
3313 ++narcs;
3314
3315 if( arraysize == narcs )
3316 {
3317 SCIP_CALL( checkArraySizesGLS(scip, maxarcs, &arraysize, &graph, &success) );
3318
3319 if( !success )
3320 goto TERMINATE;
3321 }
3322 assert(narcs < maxarcs);
3323 }
3324
3325 /* correct number of arcs */
3326 graph.arcs = narcs;
3327
3328 SCIPdebugMsg(scip, "--- graph successfully created (%u nodes, %u arcs) ---\n", graph.nodes, narcs);
3329
3330 /* graph is now prepared for Dijkstra methods */
3331 assert( dijkstraGraphIsValid(&graph) );
3332
3333#ifdef SCIP_ODDCYCLE_WRITEGRAPH
3334 {
3335 char probname [SCIP_MAXSTRLEN];
3336 char filename [SCIP_MAXSTRLEN];
3337 char* name;
3338
3339 (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPgetProbName(scip));
3340 SCIPsplitFilename(probname, NULL, &name, NULL, NULL);
3341 (void) SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s_%d.gml", name, SCIPgetNLPs(scip));
3343 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Wrote clique/implication graph to <%s>.\n", filename);
3344 }
3345#endif
3346
3347 /* determine the number of start nodes */
3348 maxstarts = (unsigned int) SCIPceil(scip, sepadata->offsettestvars + (0.02 * nbinvars * sepadata->percenttestvars));
3349 startcounter = 0;
3350
3351 /* allocate and initialize predecessor list and flag array representing odd cycle */
3352 SCIP_CALL( SCIPallocBufferArray(scip, &pred2, (int) (2 * nbinvars)) );
3353 SCIP_CALL( SCIPallocBufferArray(scip, &incycle, (int) (2 * nbinvars)) );
3354
3355 /* separate odd cycle inequalities by GLS method */
3356 cutoff = (unsigned long long) (0.5 * sepadata->scale);
3357 for( i = (unsigned int) sepadata->lastroot; i < 2 * nbinvars
3358 && startcounter < maxstarts
3359 && sepadata->ncuts - sepadata->oldncuts < (unsigned int) sepadata->maxsepacutsround
3360 && !SCIPisStopped(scip); ++i )
3361 {
3362 unsigned int ncyclevars; /* cycle length */
3363 SCIP_Bool edgedirection; /* partitionindicator for backprojection from bipartite graph to original graph:
3364 * is the current edge a backwards edge, i.e., from second to first partition? */
3365
3366 /* skip isolated node */
3367 if( graph.head[graph.outbeg[i]] == DIJKSTRA_UNUSED )
3368 continue;
3369
3370 /* if node has only one arc, there is no odd cycle containing this node
3371 * (but there are invalid odd circuits containing the only neighbor twice)
3372 */
3373 if( graph.head[graph.outbeg[i]+1] == DIJKSTRA_UNUSED )
3374 continue;
3375
3376 /* search shortest path from node to its counter part in the other partition */
3377 startnode = i;
3378 endnode = i + 2 * nbinvars;
3379
3380 /* skip node if it is already covered by a cut and
3381 * we do not want to search cycles starting with a node already covered by a cut
3382 */
3383 if( incut[startnode] && ! sepadata->multiplecuts )
3384 continue;
3385
3386 ++startcounter;
3387
3388 if ( sepadata->allowmultiplecuts )
3389 (void) dijkstraPairCutoffIgnore(&graph, startnode, endnode, incut, cutoff, dist, pred, entry, order);
3390 else
3391 (void) dijkstraPairCutoff(&graph, startnode, endnode, cutoff, dist, pred, entry, order);
3392
3393 /* no odd cycle cut found */
3394 if( dist[endnode] == DIJKSTRA_FARAWAY )
3395 continue;
3396
3397 /* skip check if cutoff has been exceeded */
3398 if ( dist[endnode] >= cutoff )
3399 continue;
3400
3401 /* detect cycle including:
3402 * project bipartitioned graph to original graph of variables and their negated
3403 * (pred&incycle-structure for generateOddCycleCut)
3404 * check cycles for double variables and try to clean variable-negated-sub-cycles if existing
3405 */
3406 for( j = 0; j < 2 * nbinvars; ++j )
3407 {
3408 pred2[j] = DIJKSTRA_UNUSED;
3409 incycle[j] = FALSE;
3410 }
3411
3412 ncyclevars = 0;
3413 edgedirection = TRUE;
3414 success = TRUE;
3415
3416 /* construct odd cycle in implication graph from shortest path on bipartite graph */
3417 for( dijkindex = endnode; dijkindex != startnode && success; dijkindex = pred[dijkindex], edgedirection = !edgedirection )
3418 {
3419 if( edgedirection )
3420 {
3421 /* check that current node is in second partition and next node is in first partition */
3422 assert(dijkindex >= 2 * nbinvars && dijkindex < 4 * nbinvars);
3423 assert(pred[dijkindex] < 2*nbinvars);
3424
3425 pred2[dijkindex - 2 * nbinvars] = pred[dijkindex];
3426
3427 /* check whether the object found is really a cycle without sub-cycles
3428 * (sub-cycles may occur in case there is not violated odd cycle inequality)
3429 * and remove pairs of original and negated variable from cycle
3430 */
3431 SCIP_CALL( cleanCycle(scip, pred2, incycle, incut, dijkindex-2*nbinvars, endnode-2*nbinvars, nbinvars,
3432 &ncyclevars, sepadata->repaircycles, sepadata->allowmultiplecuts, &success) );
3433 }
3434 else
3435 {
3436 /* check that current node is in first partition and next node is in second partition */
3437 assert(dijkindex < 2 * nbinvars);
3438 assert(pred[dijkindex] >= 2 * nbinvars && pred[dijkindex] < 4 * nbinvars);
3439
3440 pred2[dijkindex] = pred[dijkindex] - 2 * nbinvars;
3441
3442 /* check whether the object found is really a cycle without sub-cycles
3443 * (sub-cycles may occur in case there is not violated odd cycle inequality)
3444 * and remove pairs of original and negated variable from cycle
3445 */
3446 SCIP_CALL( cleanCycle(scip, pred2, incycle, incut, dijkindex, endnode-2*nbinvars, nbinvars, &ncyclevars,
3447 sepadata->repaircycles, sepadata->allowmultiplecuts, &success) );
3448 }
3449 }
3450
3451 if( success )
3452 {
3453 GRAPHDATA graphdata;
3454
3455 /* generate cut */
3456 graphdata.usegls = TRUE;
3457 graphdata.dijkstragraph = &graph;
3458 graphdata.levelgraph = NULL;
3459
3460 SCIP_CALL( generateOddCycleCut(scip, sepa, sol, vars, nbinvars, startnode, pred2, ncyclevars, incut, vals, sepadata, &graphdata, result) );
3461 }
3462 }
3463
3464 /* free temporary memory */
3465 SCIPfreeBufferArray(scip, &incycle);
3466 SCIPfreeBufferArray(scip, &pred2);
3467
3468 /* store the last tried root (when running without sorting the variable array, we don't want
3469 * to always check the same variables and therefore start next time where we stopped last time)
3470 */
3471 if( sepadata->sortswitch == UNSORTED )
3472 {
3473 if( i == 2 * nbinvars )
3474 sepadata->lastroot = 0;
3475 else
3476 sepadata->lastroot = (int) i;
3477 }
3478
3479 TERMINATE:
3480 /* free temporary memory */
3481 SCIPfreeBufferArray(scip, &order);
3482 SCIPfreeBufferArray(scip, &entry);
3483 SCIPfreeBufferArray(scip, &pred);
3484 SCIPfreeBufferArray(scip, &dist);
3486 SCIPfreeBufferArray(scip, &graph.head);
3489 SCIPfreeBufferArray(scip, &incut);
3490 SCIPfreeBufferArray(scip, &(sepadata->mapping));
3491 SCIPfreeBufferArray(scip, &vals);
3493
3494 return SCIP_OKAY;
3495}
3496
3497
3498/** separation method */
3499static
3501 SCIP* scip, /**< SCIP data structure */
3502 SCIP_SEPA* sepa, /**< separator */
3503 SCIP_SOL* sol, /**< given primal solution */
3504 int depth, /**< current depth */
3505 SCIP_RESULT* result /**< pointer to store the result of the separation call */
3506 )
3507{
3509 int ncalls;
3510 SCIPdebug( int oldnliftedcuts; )
3511 int nfrac = 0;
3512
3514
3515 /* get separator data */
3516 sepadata = SCIPsepaGetData(sepa);
3517 assert(sepadata != NULL);
3518
3520
3521 /* only call separator a given number of rounds at each b&b node */
3522 if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
3523 || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
3524 return SCIP_OKAY;
3525
3526 /* only call separator if enough binary variables are present */
3527 if( SCIPgetNBinVars(scip) < 3 || (! sepadata->includetriangles && SCIPgetNBinVars(scip) < 5) )
3528 {
3529 SCIPdebugMsg(scip, "skipping separator: not enough binary variables\n");
3530 return SCIP_OKAY;
3531 }
3532
3533 /* only call separator if enough fractional variables are present */
3534 if ( sol != NULL )
3535 {
3536 SCIP_VAR** vars;
3537 SCIP_Real solval;
3538 int nvars;
3539 int v;
3540
3542
3543 /* first compute fractional variables */
3544 for( v = 0; v < nvars; ++v )
3545 {
3546 solval = SCIPgetSolVal(scip, sol, vars[v]);
3547
3548 if ( ! SCIPisFeasIntegral(scip, solval) )
3549 ++nfrac;
3550 }
3551 }
3552 else
3554
3555 if( nfrac < 3 || (! sepadata->includetriangles && nfrac < 5) )
3556 {
3557 SCIPdebugMsg(scip, "skipping separator: not enough fractional variables\n");
3558 return SCIP_OKAY;
3559 }
3560
3561 /* only call separator if enough implications and cliques are present */
3563 {
3564 SCIPdebugMsg(scip, "skipping separator: not enough implications present\n");
3565 return SCIP_OKAY;
3566 }
3567
3568 /* only run if number of cuts already found is small enough */
3569 if ( sepadata->cutthreshold >= 0 && SCIPgetNCutsFoundRound(scip) >= sepadata->cutthreshold )
3570 return SCIP_OKAY;
3571
3572 /* store node number and reset number of unsuccessful calls */
3574 {
3575 sepadata->nunsucessfull = 0;
3577 }
3578 else
3579 {
3580 if ( sepadata->nunsucessfull > sepadata->maxunsucessfull )
3581 {
3582 SCIPdebugMsg(scip, "skipping separator: number of unsucessfull calls = %d.\n", sepadata->nunsucessfull);
3583 return SCIP_OKAY;
3584 }
3585 }
3586
3588 sepadata->oldncuts = sepadata->ncuts;
3589 SCIPdebug( oldnliftedcuts = sepadata->nliftedcuts; )
3590
3591 if( depth == 0 )
3592 sepadata->maxsepacutsround = sepadata->maxsepacutsroot;
3593 else
3594 sepadata->maxsepacutsround = sepadata->maxsepacuts;
3595
3596 /* perform the actual separation routines */
3597 if( sepadata->usegls )
3598 {
3599 SCIPdebugMsg(scip, "using GLS method for finding odd cycles\n");
3601 }
3602 else
3603 {
3604 SCIPdebugMsg(scip, "using level graph heuristic for finding odd cycles\n");
3606 }
3607
3608 if( sepadata->ncuts - sepadata->oldncuts > 0 )
3609 {
3610 SCIPdebug( SCIPdebugMsg(scip, "added %u cuts (%d allowed), %d lifted.\n", sepadata->ncuts - sepadata->oldncuts,
3611 sepadata->maxsepacutsround, sepadata->nliftedcuts - oldnliftedcuts); )
3612 sepadata->nunsucessfull = 0;
3613 }
3614 else
3615 {
3616 SCIPdebugMsg(scip, "no cuts added (%d allowed)\n", sepadata->maxsepacutsround);
3617 ++sepadata->nunsucessfull;
3618 }
3619 SCIPdebugMsg(scip, "total sepatime: %.2f - total number of added cuts: %u\n", SCIPsepaGetTime(sepa), sepadata->ncuts);
3620
3621 return SCIP_OKAY;
3622}
3623
3624
3625/*
3626 * Callback methods of separator
3627 */
3628
3629/** copy method for separator plugins (called when SCIP copies plugins) */
3630static
3631SCIP_DECL_SEPACOPY(sepaCopyOddcycle)
3632{ /*lint --e{715}*/
3633 assert(scip != NULL);
3634 assert(sepa != NULL);
3635
3637
3638 /* call inclusion method of constraint handler */
3640
3641 return SCIP_OKAY;
3642}
3643
3644
3645/** destructor of separator to free user data (called when SCIP is exiting) */
3646static
3647SCIP_DECL_SEPAFREE(sepaFreeOddcycle)
3648{
3650
3651 sepadata = SCIPsepaGetData(sepa);
3652 assert(sepadata != NULL);
3653
3655 SCIPsepaSetData(sepa, NULL);
3656
3657 return SCIP_OKAY;
3658}
3659
3660
3661/** initialization method of separator (called after problem was transformed) */
3662static
3663SCIP_DECL_SEPAINIT(sepaInitOddcycle)
3664{
3666
3667 sepadata = SCIPsepaGetData(sepa);
3668 assert(sepadata != NULL);
3669
3670 sepadata->ncuts = 0;
3671 sepadata->oldncuts = 0;
3672 sepadata->nliftedcuts = 0;
3673 sepadata->lastroot = 0;
3674
3675 return SCIP_OKAY;
3676}
3677
3678
3679/** solving process initialization method of separator (called when branch and bound process is about to begin) */
3680static
3681SCIP_DECL_SEPAINITSOL(sepaInitsolOddcycle)
3682{
3684
3685 assert(sepa != NULL);
3686
3687 sepadata = SCIPsepaGetData(sepa);
3688 assert(sepadata != NULL);
3689
3690 sepadata->nunsucessfull = 0;
3691 sepadata->lastnode = -1;
3692
3693 return SCIP_OKAY;
3694}
3695
3696
3697/** LP solution separation method of separator */
3698static
3699SCIP_DECL_SEPAEXECLP(sepaExeclpOddcycle)
3700{ /*lint --e{715}*/
3701 assert(sepa != NULL);
3702 assert(scip != NULL);
3703 assert(result != NULL);
3704
3706
3708
3709 return SCIP_OKAY;
3710}
3711
3712/** arbitrary primal solution separation method of separator */
3713static
3714SCIP_DECL_SEPAEXECSOL(sepaExecsolOddcycle)
3715{ /*lint --e{715}*/
3716 assert(sepa != NULL);
3717 assert(scip != NULL);
3718 assert(result != NULL);
3719
3721
3723
3724 return SCIP_OKAY;
3725}
3726
3727
3728/*
3729 * separator specific interface methods
3730 */
3731
3732/** creates the oddcycle separator and includes it in SCIP */
3734 SCIP* scip /**< SCIP data structure */
3735 )
3736{
3738 SCIP_SEPA* sepa;
3739
3740 /* create oddcycle separator data */
3742 sepadata->nunsucessfull = 0;
3743 sepadata->lastnode = -1;
3744
3745 /* include separator */
3748 sepaExeclpOddcycle, sepaExecsolOddcycle,
3749 sepadata) );
3750
3751 assert(sepa != NULL);
3752
3753 /* set non-NULL pointers to callback methods */
3754 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyOddcycle) );
3755 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeOddcycle) );
3756 SCIP_CALL( SCIPsetSepaInit(scip, sepa, sepaInitOddcycle) );
3757 SCIP_CALL( SCIPsetSepaInitsol(scip, sepa, sepaInitsolOddcycle) );
3758
3759 /* add oddcycle separator parameters */
3760 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/usegls",
3761 "Should the search method by Groetschel, Lovasz, Schrijver be used? Otherwise use levelgraph method by Hoffman, Padberg.",
3762 &sepadata->usegls, FALSE, DEFAULT_USEGLS, NULL, NULL) );
3763
3764 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/liftoddcycles",
3765 "Should odd cycle cuts be lifted?",
3766 &sepadata->liftoddcycles, FALSE, DEFAULT_LIFTODDCYCLES, NULL, NULL) );
3767
3768 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxsepacuts",
3769 "maximal number of oddcycle cuts separated per separation round",
3770 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
3771
3772 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxsepacutsroot",
3773 "maximal number of oddcycle cuts separated per separation round in the root node",
3774 &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
3775
3776 /* add advanced parameters */
3777 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxrounds",
3778 "maximal number of oddcycle separation rounds per node (-1: unlimited)",
3779 &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
3780
3781 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxroundsroot",
3782 "maximal number of oddcycle separation rounds in the root node (-1: unlimited)",
3783 &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
3784
3785 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/scalingfactor",
3786 "factor for scaling of the arc-weights",
3787 &sepadata->scale, TRUE, DEFAULT_SCALEFACTOR, 1, INT_MAX, NULL, NULL) );
3788
3789 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/addselfarcs",
3790 "add links between a variable and its negated",
3791 &sepadata->addselfarcs, TRUE, DEFAULT_ADDSELFARCS, NULL, NULL) );
3792
3793 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/repaircycles",
3794 "try to repair violated cycles with double appearance of a variable",
3795 &sepadata->repaircycles, TRUE, DEFAULT_REPAIRCYCLES, NULL, NULL) );
3796
3797 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/includetriangles",
3798 "separate triangles found as 3-cycles or repaired larger cycles",
3799 &sepadata->includetriangles, TRUE, DEFAULT_INCLUDETRIANGLES, NULL, NULL) );
3800
3801 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/multiplecuts",
3802 "Even if a variable is already covered by a cut, still try it as start node for a cycle search?",
3803 &sepadata->multiplecuts, TRUE, DEFAULT_MULTIPLECUTS, NULL, NULL) );
3804
3805 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/allowmultiplecuts",
3806 "Even if a variable is already covered by a cut, still allow another cut to cover it too?",
3807 &sepadata->allowmultiplecuts, TRUE, DEFAULT_ALLOWMULTIPLECUTS, NULL, NULL) );
3808
3809 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/lpliftcoef",
3810 "Choose lifting candidate by coef*lpvalue or only by coef?",
3811 &sepadata->lpliftcoef, TRUE, DEFAULT_LPLIFTCOEF, NULL, NULL) );
3812
3813 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/recalcliftcoef",
3814 "Calculate lifting coefficient of every candidate in every step (or only if its chosen)?",
3815 &sepadata->recalcliftcoef, TRUE, DEFAULT_RECALCLIFTCOEF, NULL, NULL) );
3816
3817 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/sortswitch",
3818 "use sorted variable array (unsorted(0), maxlp(1), minlp(2), maxfrac(3), minfrac(4))",
3819 (int*) &sepadata->sortswitch, TRUE, DEFAULT_SORTSWITCH, 0, 4, NULL, NULL) );
3820
3821 SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/sortrootneighbors",
3822 "sort level of the root neighbors by fractionality (maxfrac)",
3823 &sepadata->sortrootneighbors, TRUE, DEFAULT_SORTROOTNEIGHBORS, NULL, NULL) );
3824
3825 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/percenttestvars",
3826 "percentage of variables to try the chosen method on [0-100]",
3827 &sepadata->percenttestvars, TRUE, DEFAULT_PERCENTTESTVARS, 0, 100, NULL, NULL) );
3828
3829 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/offsettestvars",
3830 "offset of variables to try the chosen method on (additional to the percentage of testvars)",
3831 &sepadata->offsettestvars, TRUE, DEFAULT_OFFSETTESTVARS, 0, INT_MAX, NULL, NULL) );
3832
3833 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxpernodeslevel",
3834 "percentage of nodes allowed in the same level of the level graph [0-100]",
3835 &sepadata->maxpernodeslevel, TRUE, DEFAULT_MAXPERNODESLEVEL, 0, 100, NULL, NULL) );
3836
3837 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/offsetnodeslevel",
3838 "offset of nodes allowed in the same level of the level graph (additional to the percentage of levelnodes)",
3839 &sepadata->offsetnodeslevel, TRUE, DEFAULT_OFFSETNODESLEVEL, 0, INT_MAX, NULL, NULL) );
3840
3841 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxnlevels",
3842 "maximal number of levels in level graph",
3843 &sepadata->maxnlevels, TRUE, DEFAULT_MAXNLEVELS, 0, INT_MAX, NULL, NULL) );
3844
3845 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxcutsroot",
3846 "maximal number of oddcycle cuts generated per chosen variable as root of the level graph",
3847 &sepadata->maxcutsroot, TRUE, DEFAULT_MAXCUTSROOT, 0, INT_MAX, NULL, NULL) );
3848
3849 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxcutslevel",
3850 "maximal number of oddcycle cuts generated in every level of the level graph",
3851 &sepadata->maxcutslevel, TRUE, DEFAULT_MAXCUTSLEVEL, 0, INT_MAX, NULL, NULL) );
3852
3853 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxreference",
3854 "minimal weight on an edge (in level graph or bipartite graph)",
3855 &sepadata->maxreference, TRUE, DEFAULT_MAXREFERENCE, 0, INT_MAX, NULL, NULL) );
3856
3857 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxunsucessfull",
3858 "number of unsuccessful calls at current node",
3859 &sepadata->maxunsucessfull, TRUE, DEFAULT_MAXUNSUCESSFULL, 0, INT_MAX, NULL, NULL) );
3860
3861 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/cutthreshold",
3862 "maximal number of other cuts s.t. separation is applied (-1 for direct call)",
3863 &sepadata->cutthreshold, TRUE, DEFAULT_CUTTHRESHOLD, -1, INT_MAX, NULL, NULL) );
3864
3865 return SCIP_OKAY;
3866}
SCIP_VAR * a
SCIP_VAR ** b
SCIP_VAR ** x
#define DEFAULT_MAXROUNDSROOT
#define DEFAULT_MAXSEPACUTSROOT
#define DEFAULT_MAXSEPACUTS
#define DEFAULT_MAXROUNDS
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Longint
Definition def.h:150
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define MAX(x, y)
Definition def.h:229
#define SCIPABORT()
Definition def.h:336
#define SCIP_CALL(x)
Definition def.h:364
unsigned int dijkstraPairCutoffIgnore(const DIJKSTRA_GRAPH *G, unsigned int source, unsigned int target, unsigned int *ignore, unsigned long long cutoff, unsigned long long *dist, unsigned int *pred, unsigned int *entry, unsigned int *order)
Definition dijkstra.c:508
DIJKSTRA_Bool dijkstraGraphIsValid(const DIJKSTRA_GRAPH *G)
Definition dijkstra.c:42
unsigned int dijkstraPairCutoff(const DIJKSTRA_GRAPH *G, unsigned int source, unsigned int target, unsigned long long cutoff, unsigned long long *dist, unsigned int *pred, unsigned int *entry, unsigned int *order)
Definition dijkstra.c:397
Definitions for Disjkstra's shortest path algorithm.
#define DIJKSTRA_UNUSED
Definition dijkstra.h:48
#define DIJKSTRA_FARAWAY
Definition dijkstra.h:47
struct DIJKSTRA_Graph DIJKSTRA_GRAPH
Definition dijkstra.h:65
#define nnodes
Definition gastrans.c:74
#define narcs
Definition gastrans.c:77
void SCIPsplitFilename(char *filename, char **path, char **name, char **extension, char **compression)
Definition misc.c:11073
SCIP_Bool SCIPisStopped(SCIP *scip)
const char * SCIPgetProbName(SCIP *scip)
Definition scip_prob.c:1242
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition scip_prob.c:2115
int SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition scip_param.c:250
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition scip_param.c:307
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
int SCIPgetNLPBranchCands(SCIP *scip)
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition scip_cut.c:336
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition scip_mem.c:126
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition scip_mem.c:100
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition scip_mem.h:136
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition tree.c:8513
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition lp.c:17696
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1429
void SCIProwChgRank(SCIP_ROW *row, int rank)
Definition lp.c:17928
SCIP_RETCODE SCIPchgRowRhs(SCIP *scip, SCIP_ROW *row, SCIP_Real rhs)
Definition scip_lp.c:1553
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition scip_sepa.c:115
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:173
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition sepa.c:746
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition sepa.c:893
SCIP_Real SCIPsepaGetTime(SCIP_SEPA *sepa)
Definition sepa.c:863
SCIP_RETCODE SCIPsetSepaInit(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:189
SCIP_RETCODE SCIPsetSepaInitsol(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:221
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition sepa.c:636
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition sepa.c:646
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa,)
Definition scip_sepa.c:157
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
int SCIPgetNImplications(SCIP *scip)
int SCIPgetNCutsFoundRound(SCIP *scip)
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition scip_tree.c:91
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:5697
SCIP_RETCODE SCIPwriteCliqueGraph(SCIP *scip, const char *fname, SCIP_Bool writenodeweights)
Definition scip_var.c:9647
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:5875
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23694
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition var.c:23522
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24674
int SCIPgetNCliques(SCIP *scip)
Definition scip_var.c:9512
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24685
SCIP_RETCODE SCIPincludeSepaOddcycle(SCIP *scip)
void SCIPsortRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
void SCIPsortDownRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
return SCIP_OKAY
SCIP_Longint ncalls
int c
int depth
SCIP_Bool cutoff
int nfrac
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
int bestcand
static SCIP_VAR ** vars
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition implics.c:3384
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition implics.c:3374
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition implics.c:3396
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for separators
public methods for branch and bound tree
public methods for problem variables
public methods for branching rule plugins and branching
public methods for cuts and aggregation rows
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for separator plugins
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
#define SEPA_PRIORITY
#define SEPA_DELAY
#define SEPA_DESC
#define SEPA_USESSUBSCIP
#define SEPA_MAXBOUNDDIST
#define SEPA_FREQ
#define SEPA_NAME
static SCIP_RETCODE blockRootPath(SCIP *scip, LEVELGRAPH *graph, unsigned int startnode, SCIP_Bool *inlevelgraph, SCIP_Bool *blocked, int *parentTree, unsigned int root)
#define DEFAULT_SORTROOTNEIGHBORS
static SCIP_Bool isNeighbor(SCIP_VAR **vars, unsigned int nbinvars, GRAPHDATA *graphdata, unsigned int a, unsigned int b)
static SCIP_RETCODE separateOddCycles(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, int depth, SCIP_RESULT *result)
static SCIP_RETCODE addNextLevelCliques(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_VAR **vars, SCIP_Real *vals, unsigned int u, LEVELGRAPH *graph, unsigned int level, SCIP_Bool *inlevelgraph, unsigned int *newlevel, unsigned int *nnewlevel, unsigned int *nAdj, SCIP_Bool *success)
static SCIP_RETCODE findUnblockedShortestPathToRoot(SCIP *scip, int scale, LEVELGRAPH *graph, unsigned int startnode, unsigned int *distance, unsigned int *queue, SCIP_Bool *inQueue, int *parentTreeBackward, unsigned int root, SCIP_Bool *blocked)
static void checkBlocking(unsigned int a, unsigned int b, unsigned int c, unsigned int i, unsigned int *cycle, unsigned int ncyclevars, SCIP_VAR **vars, unsigned int nbinvars, unsigned int *lifted, unsigned int *nlifted, GRAPHDATA *graphdata, SCIP_Bool *myi)
#define DEFAULT_REPAIRCYCLES
static SCIP_RETCODE addArc(SCIP *scip, LEVELGRAPH *graph, unsigned int u, unsigned int v, unsigned int level, unsigned int weight, unsigned int *nAdj, SCIP_Bool *success)
sorttype
@ UNSORTED
@ MAXIMAL_LPVALUE
@ MINIMAL_FRACTIONALITY
@ MINIMAL_LPVALUE
@ MAXIMAL_FRACTIONALITY
#define DEFAULT_MAXCUTSROOT
static unsigned int getCoef(SCIP *scip, unsigned int i, unsigned int *cycle, unsigned int ncyclevars, SCIP_VAR **vars, unsigned int nbinvars, unsigned int *lifted, unsigned int *nlifted, GRAPHDATA *graphdata, SCIP_Bool *myi)
static SCIP_RETCODE checkArraySizesHeur(SCIP *scip, LEVELGRAPH *graph, unsigned int *size, int **targetArray, unsigned int **weightArray, unsigned int **sourceAdjArray, unsigned int **targetAdjArray, SCIP_Bool *success)
static SCIP_RETCODE separateHeur(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, SCIP_RESULT *result)
static SCIP_RETCODE liftOddCycleCut(SCIP *scip, unsigned int *nlifted, unsigned int *lifted, unsigned int *liftcoef, SCIP_SEPADATA *sepadata, GRAPHDATA *graphdata, SCIP_VAR **vars, unsigned int nbinvars, unsigned int startnode, unsigned int *pred, unsigned int ncyclevars, SCIP_Real *vals, SCIP_RESULT *result)
static SCIP_RETCODE findShortestPathToRoot(SCIP *scip, int scale, LEVELGRAPH *graph, unsigned int startnode, unsigned int *distance, unsigned int *queue, SCIP_Bool *inQueue, int *parentTree)
static SCIP_RETCODE createNextLevel(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_VAR **vars, SCIP_Real *vals, LEVELGRAPH *graph, unsigned int level, SCIP_Bool *inlevelgraph, unsigned int *curlevel, unsigned int ncurlevel, unsigned int *newlevel, unsigned int *nnewlevel, SCIP_Bool *success)
#define DEFAULT_SCALEFACTOR
#define DEFAULT_MAXNLEVELS
static SCIP_RETCODE addGLSCliques(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_VAR **vars, unsigned int varsidx, unsigned int dijkindex, SCIP_Real *vals, unsigned int nbinvars, unsigned int ncliques, DIJKSTRA_GRAPH *graph, unsigned int *narcs, unsigned int maxarcs, SCIP_Bool original, SCIP_Bool *emptygraph, unsigned int *arraysize, SCIP_Bool *success)
static SCIP_RETCODE insertSortedRootNeighbors(SCIP *scip, LEVELGRAPH *graph, unsigned int nbinvars, unsigned int ncurlevel, unsigned int u, SCIP_Real *vals, SCIP_VAR **vars, SCIP_SEPADATA *sepadata, unsigned int *nnewlevel, SCIP_Bool *inlevelgraph, unsigned int level, unsigned int *newlevel, SCIP_Bool *success)
#define DEFAULT_ALLOWMULTIPLECUTS
#define DEFAULT_RECALCLIFTCOEF
#define DEFAULT_MAXCUTSLEVEL
#define DEFAULT_LPLIFTCOEF
#define DEFAULT_MAXPERNODESLEVEL
#define DEFAULT_USEGLS
static SCIP_RETCODE generateOddCycleCut(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_VAR **vars, unsigned int nbinvars, unsigned int startnode, unsigned int *pred, unsigned int ncyclevars, unsigned int *incut, SCIP_Real *vals, SCIP_SEPADATA *sepadata, GRAPHDATA *graphdata, SCIP_RESULT *result)
#define DEFAULT_INCLUDETRIANGLES
#define DEFAULT_MULTIPLECUTS
#define DEFAULT_SORTSWITCH
enum sorttype SORTTYPE
#define DEFAULT_MAXUNSUCESSFULL
#define DEFAULT_OFFSETTESTVARS
static SCIP_RETCODE separateGLS(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, SCIP_RESULT *result)
struct levelGraph LEVELGRAPH
static SCIP_RETCODE checkArraySizesGLS(SCIP *scip, unsigned int maxarcs, unsigned int *arraysize, DIJKSTRA_GRAPH *graph, SCIP_Bool *success)
#define DEFAULT_PERCENTTESTVARS
struct GraphData GRAPHDATA
#define DEFAULT_ADDSELFARCS
#define DEFAULT_OFFSETNODESLEVEL
static SCIP_RETCODE cleanCycle(SCIP *scip, unsigned int *pred, SCIP_Bool *incycle, unsigned int *incut, unsigned int x, unsigned int startnode, unsigned int nbinvars, unsigned int *ncyclevars, SCIP_Bool repaircycles, SCIP_Bool allowmultiplecuts, SCIP_Bool *success)
#define DEFAULT_MAXREFERENCE
#define DEFAULT_CUTTHRESHOLD
#define DEFAULT_LIFTODDCYCLES
oddcycle separator
unsigned int arcs
Definition dijkstra.h:57
unsigned int minweight
Definition dijkstra.h:60
unsigned int * head
Definition dijkstra.h:59
unsigned int * outbeg
Definition dijkstra.h:55
unsigned int nodes
Definition dijkstra.h:54
unsigned int * weight
Definition dijkstra.h:58
unsigned int * outcnt
Definition dijkstra.h:56
unsigned int maxweight
Definition dijkstra.h:61
LEVELGRAPH * levelgraph
SCIP_Bool usegls
DIJKSTRA_GRAPH * dijkstragraph
struct SCIP_Clique SCIP_CLIQUE
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_VERBLEVEL_HIGH
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_SEPARATED
Definition type_result.h:49
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDDATA
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_SepaData SCIP_SEPADATA
Definition type_sepa.h:52
#define SCIP_DECL_SEPAINITSOL(x)
Definition type_sepa.h:96
#define SCIP_DECL_SEPAEXECSOL(x)
Definition type_sepa.h:166
#define SCIP_DECL_SEPAEXECLP(x)
Definition type_sepa.h:136
#define SCIP_DECL_SEPAFREE(x)
Definition type_sepa.h:69
struct SCIP_Sepa SCIP_SEPA
Definition type_sepa.h:51
#define SCIP_DECL_SEPACOPY(x)
Definition type_sepa.h:61
#define SCIP_DECL_SEPAINIT(x)
Definition type_sepa.h:77
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166