Scippy

SCIP

Solving Constraint Integer Programs

ConshdlrSubtour.cpp
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-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License. */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file ConshdlrSubtour.cpp
17  * @brief Subtour elimination constraint handler for TSP problems, written in C++
18  * @author Timo Berthold
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <cassert>
24 #include <string>
25 #include <iostream>
26 #include "ConshdlrSubtour.h"
27 #include "GomoryHuTree.h"
28 
29 #include "objscip/objscip.h"
30 
31 #include "scip/cons_linear.h"
32 
33 #include "GomoryHuTree.h"
34 
35 using namespace tsp;
36 using namespace scip;
37 using namespace std;
38 
39 /** data structure for subtour elimination constraints */
40 struct SCIP_ConsData
41 {
42  GRAPH* graph;
43 };
44 
45 
46 /** checks whether proposed solution contains a subtour
47  *
48  * We assume that the solution is binary.
49  */
50 static
52  SCIP* scip, /**< SCIP data structure */
53  GRAPH* graph, /**< underlying graph */
54  SCIP_SOL* sol /**< proposed solution */
55  )
56 {
57  GRAPHNODE* node;
58  GRAPHNODE* startnode;
59  GRAPHEDGE* edge;
60  GRAPHEDGE* nextedge;
61  GRAPHEDGE* lastedge = NULL;
62  int tourlength = 0;
63 
64  assert(scip != NULL);
65  assert(graph != NULL);
66 
67  if( graph->nnodes <= 1 )
68  return FALSE;
69 
70  startnode = &graph->nodes[0];
71  node = startnode;
72 
73  /* follow the (sub?)tour until you come back to the startnode */
74  do
75  {
76  edge = node->first_edge;
77  nextedge = NULL;
78 
79  /* look for an outgoing edge to proceed */
80  while( edge != NULL )
81  {
82  /* if a new edge with value 1 is found, we proceed */
83  if( edge->back != lastedge && SCIPgetSolVal(scip, sol, edge->var) > 0.5 )
84  {
85  ++tourlength;
86 
87  /* if we found a subtour without the starting node, e.g. 0 - 1 - 2 - 3 - 1 - 2 - ...;
88  * this can only happen, if the degree constraints are violated; */
89  if( nextedge != NULL || tourlength > graph->nnodes )
90  return TRUE;
91 
92  nextedge = edge;
93 
94  /* only use the first edge for the start node */
95  if( node == startnode )
96  break;
97  }
98 
99  edge = edge->next;
100  }
101 
102  /* no outgoing edge found in the solution: the degree constraints must be violated; abort! */
103  if( nextedge == NULL )
104  return TRUE;
105 
106  node = nextedge->adjac;
107  lastedge = nextedge;
108  }
109  while( node != startnode );
110 
111  assert(tourlength <= graph->nnodes);
112 
113  return ( graph->nnodes != tourlength );
114 }
115 
116 
117 /** separates subtour elemination cuts */
118 static
120  SCIP* scip, /**< SCIP data structure */
121  SCIP_CONSHDLR* conshdlr, /**< the constraint handler itself */
122  SCIP_CONS** conss, /**< array of constraints to process */
123  int nconss, /**< number of constraints to process */
124  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
125  SCIP_SOL* sol, /**< primal solution that should be separated */
126  SCIP_Bool enforce, /**< whether we are in enforcing */
127  SCIP_RESULT* result /**< pointer to store the result of the separation call */
128  )
129 { /*lint --e{715}*/
130  assert(result != NULL);
131 
132  *result = SCIP_DIDNOTFIND;
133 
134  for(int c = 0; c < nusefulconss && *result != SCIP_CUTOFF; ++c)
135  {
136  // get all required structures
137  SCIP_CONSDATA* consdata;
138  GRAPH* graph;
139 
140  consdata = SCIPconsGetData(conss[c]);
141  assert(consdata != NULL);
142 
143  graph = consdata->graph;
144  assert(graph != NULL);
145 
146  // store the suggested, but infeasible solution into the capacity of the edges
147  for(int i = 0; i < graph->nedges; i++)
148  {
149  double cap = SCIPgetSolVal(scip, sol, graph->edges[i].var);
150  graph->edges[i].rcap = cap;
151  graph->edges[i].cap = cap;
152  graph->edges[i].back->rcap = cap;
153  graph->edges[i].back->cap = cap;
154  }
155 
156  SCIP_Bool** cuts = NULL;
157  int ncuts;
158 
159  SCIP_CALL( SCIPallocBufferArray(scip, &cuts, graph->nnodes) );
160  for(int i = 0; i < graph->nnodes; i++)
161  {
162  SCIP_CALL( SCIPallocBufferArray(scip, &cuts[i], graph->nnodes) ); /*lint !e866*/
163  }
164 
165  // try to find cuts
166  if( ghc_tree(graph, cuts, &ncuts, SCIPfeastol(scip)) )
167  {
168  // create a new cutting plane for every suitable arc (representing a cut with value < 2) of the Gomory Hu Tree
169  for(int i = 0; i < ncuts && *result != SCIP_CUTOFF; ++i)
170  {
171  SCIP_ROW* row;
172  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, "subtour", 2.0, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
173 
174  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
175 
176  for(int j = 0; j < graph->nnodes; j++)
177  {
178  // in gmincut the graph has been partitioned into two parts, represented by bools
179  if( cuts[i][j] )
180  {
181  GRAPHEDGE* edge = graph->nodes[j].first_edge;
182 
183  // take every edge with nodes in different parts into account
184  while( edge != NULL )
185  {
186  if( ! cuts[i][edge->adjac->id] )
187  {
188  SCIP_CALL( SCIPaddVarToRow(scip, row, edge->var, 1.0) );
189  }
190  edge = edge->next;
191  }
192  }
193  }
194 
195  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
196 
197  // Add violated cut. The cuts produced by ghc_tree are violated by at least the feasibility tolerance. If we
198  // are enforcing, then this is enough to add the cut. Otherwise (we are separating), we check whether the
199  // cut is efficacious.
200  if( enforce || SCIPisCutEfficacious(scip, sol, row) )
201  {
202  SCIP_Bool infeasible;
203  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
204  if ( infeasible )
205  *result = SCIP_CUTOFF;
206  else
207  *result = SCIP_SEPARATED;
208  }
209  SCIP_CALL( SCIPreleaseRow(scip, &row) );
210  }
211  }
212 
213  for(int i = graph->nnodes - 1; i >= 0; i--)
214  SCIPfreeBufferArray(scip, &cuts[i]);
215  SCIPfreeBufferArray(scip, &cuts);
216  }
217 
218  return SCIP_OKAY;
219 }
220 
221 
222 /** frees specific constraint data */
223 SCIP_DECL_CONSDELETE(ConshdlrSubtour::scip_delete)
224 { /*lint --e{715}*/
225  assert(consdata != NULL);
226 
227  release_graph(&(*consdata)->graph);
228  SCIPfreeBlockMemory(scip, consdata);
229 
230  return SCIP_OKAY;
231 }
232 
233 
234 /** transforms constraint data into data belonging to the transformed problem */
235 SCIP_DECL_CONSTRANS(ConshdlrSubtour::scip_trans)
236 {
237  SCIP_CONSDATA* sourcedata;
238  SCIP_CONSDATA* targetdata = NULL;
239 
240  sourcedata = SCIPconsGetData(sourcecons);
241  assert( sourcedata != NULL );
242 
243  SCIP_CALL( SCIPallocBlockMemory(scip, &targetdata) );
244  targetdata->graph = sourcedata->graph;
245  capture_graph(targetdata->graph);
246 
247  /* create target constraint */
248  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
249  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
250  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
251  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
252  SCIPconsIsStickingAtNode(sourcecons)) );
253 
254  return SCIP_OKAY;
255 }
256 
257 
258 /** separation method of constraint handler for LP solution
259  *
260  * Separates all constraints of the constraint handler. The method is called in the LP solution loop,
261  * which means that a valid LP solution exists.
262  *
263  * The first nusefulconss constraints are the ones, that are identified to likely be violated. The separation
264  * method should process only the useful constraints in most runs, and only occasionally the remaining
265  * nconss - nusefulconss constraints.
266  *
267  * possible return values for *result (if more than one applies, the first in the list should be used):
268  * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
269  * - SCIP_CONSADDED : an additional constraint was generated
270  * - SCIP_REDUCEDDOM : a variable's domain was reduced
271  * - SCIP_SEPARATED : a cutting plane was generated
272  * - SCIP_DIDNOTFIND : the separator searched, but did not find domain reductions, cutting planes, or cut constraints
273  * - SCIP_DIDNOTRUN : the separator was skipped
274  * - SCIP_DELAYED : the separator was skipped, but should be called again
275  */
276 SCIP_DECL_CONSSEPALP(ConshdlrSubtour::scip_sepalp)
277 {
278  SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, NULL, FALSE, result) );
279 
280  return SCIP_OKAY;
281 }
282 
283 
284 /** separation method of constraint handler for arbitrary primal solution
285  *
286  * Separates all constraints of the constraint handler. The method is called outside the LP solution loop (e.g., by
287  * a relaxator or a primal heuristic), which means that there is no valid LP solution.
288  * Instead, the method should produce cuts that separate the given solution.
289  *
290  * The first nusefulconss constraints are the ones, that are identified to likely be violated. The separation
291  * method should process only the useful constraints in most runs, and only occasionally the remaining
292  * nconss - nusefulconss constraints.
293  *
294  * possible return values for *result (if more than one applies, the first in the list should be used):
295  * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
296  * - SCIP_CONSADDED : an additional constraint was generated
297  * - SCIP_REDUCEDDOM : a variable's domain was reduced
298  * - SCIP_SEPARATED : a cutting plane was generated
299  * - SCIP_DIDNOTFIND : the separator searched, but did not find domain reductions, cutting planes, or cut constraints
300  * - SCIP_DIDNOTRUN : the separator was skipped
301  * - SCIP_DELAYED : the separator was skipped, but should be called again
302  */
303 SCIP_DECL_CONSSEPASOL(ConshdlrSubtour::scip_sepasol)
304 {
305  SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, result) );
306 
307  return SCIP_OKAY;
308 }
309 
310 
311 /** constraint enforcing method of constraint handler for LP solutions
312  *
313  * The method is called at the end of the node processing loop for a node where the LP was solved.
314  * The LP solution has to be checked for feasibility. If possible, an infeasibility should be resolved by
315  * branching, reducing a variable's domain to exclude the solution or separating the solution with a valid
316  * cutting plane.
317  *
318  * The enforcing methods of the active constraint handlers are called in decreasing order of their enforcing
319  * priorities until the first constraint handler returned with the value SCIP_CUTOFF, SCIP_SEPARATED,
320  * SCIP_REDUCEDDOM, SCIP_CONSADDED, or SCIP_BRANCHED.
321  * The integrality constraint handler has an enforcing priority of zero. A constraint handler which can
322  * (or wants) to enforce its constraints only for integral solutions should have a negative enforcing priority
323  * (e.g. the alldiff-constraint can only operate on integral solutions).
324  * A constraint handler which wants to incorporate its own branching strategy even on non-integral
325  * solutions must have an enforcing priority greater than zero (e.g. the SOS-constraint incorporates
326  * SOS-branching on non-integral solutions).
327  *
328  * The first nusefulconss constraints are the ones, that are identified to likely be violated. The enforcing
329  * method should process the useful constraints first. The other nconss - nusefulconss constraints should only
330  * be enforced, if no violation was found in the useful constraints.
331  *
332  * possible return values for *result (if more than one applies, the first in the list should be used):
333  * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
334  * - SCIP_CONSADDED : an additional constraint was generated
335  * - SCIP_REDUCEDDOM : a variable's domain was reduced
336  * - SCIP_SEPARATED : a cutting plane was generated
337  * - SCIP_BRANCHED : no changes were made to the problem, but a branching was applied to resolve an infeasibility
338  * - SCIP_INFEASIBLE : at least one constraint is infeasible, but it was not resolved
339  * - SCIP_FEASIBLE : all constraints of the handler are feasible
340  */
341 SCIP_DECL_CONSENFOLP(ConshdlrSubtour::scip_enfolp)
342 { /*lint --e{715}*/
343  assert(result != NULL);
344 
345  // search for subtour elimination cuts
346  SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, NULL, TRUE, result) );
347 
348  // if separation could not find a subtour, then the solution is feasible for this constraint
349  if( *result == SCIP_DIDNOTFIND )
350  *result = SCIP_FEASIBLE;
351 
352  return SCIP_OKAY;
353 }
354 
355 /** constraint enforcing method of constraint handler for pseudo solutions
356  *
357  * The method is called at the end of the node processing loop for a node where the LP was not solved.
358  * The pseudo solution has to be checked for feasibility. If possible, an infeasibility should be resolved by
359  * branching, reducing a variable's domain to exclude the solution or adding an additional constraint.
360  * Separation is not possible, since the LP is not processed at the current node. All LP informations like
361  * LP solution, slack values, or reduced costs are invalid and must not be accessed.
362  *
363  * Like in the enforcing method for LP solutions, the enforcing methods of the active constraint handlers are
364  * called in decreasing order of their enforcing priorities until the first constraint handler returned with
365  * the value SCIP_CUTOFF, SCIP_REDUCEDDOM, SCIP_CONSADDED, SCIP_BRANCHED, or SCIP_SOLVELP.
366  *
367  * The first nusefulconss constraints are the ones, that are identified to likely be violated. The enforcing
368  * method should process the useful constraints first. The other nconss - nusefulconss constraints should only
369  * be enforced, if no violation was found in the useful constraints.
370  *
371  * If the pseudo solution's objective value is lower than the lower bound of the node, it cannot be feasible
372  * and the enforcing method may skip it's check and set *result to SCIP_DIDNOTRUN. However, it can also process
373  * its constraints and return any other possible result code.
374  *
375  * possible return values for *result (if more than one applies, the first in the list should be used):
376  * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
377  * - SCIP_CONSADDED : an additional constraint was generated
378  * - SCIP_REDUCEDDOM : a variable's domain was reduced
379  * - SCIP_BRANCHED : no changes were made to the problem, but a branching was applied to resolve an infeasibility
380  * - SCIP_SOLVELP : at least one constraint is infeasible, and this can only be resolved by solving the SCIP_LP
381  * - SCIP_INFEASIBLE : at least one constraint is infeasible, but it was not resolved
382  * - SCIP_FEASIBLE : all constraints of the handler are feasible
383  * - SCIP_DIDNOTRUN : the enforcement was skipped (only possible, if objinfeasible is true)
384  */
385 SCIP_DECL_CONSENFOPS(ConshdlrSubtour::scip_enfops)
386 { /*lint --e{715}*/
387  assert(result != NULL);
388 
389  // search for subtour elimination cuts
390  SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, NULL, TRUE, result) );
391 
392  // if separation could not find a subtour, then the solution is feasible for this constraint
393  if( *result == SCIP_DIDNOTFIND )
394  *result = SCIP_FEASIBLE;
395 
396  return SCIP_OKAY;
397 }
398 
399 /** feasibility check method of constraint handler for primal solutions
400  *
401  * The given solution has to be checked for feasibility.
402  *
403  * The check methods of the active constraint handlers are called in decreasing order of their check
404  * priorities until the first constraint handler returned with the result SCIP_INFEASIBLE.
405  * The integrality constraint handler has a check priority of zero. A constraint handler which can
406  * (or wants) to check its constraints only for integral solutions should have a negative check priority
407  * (e.g. the alldiff-constraint can only operate on integral solutions).
408  * A constraint handler which wants to check feasibility even on non-integral solutions must have a
409  * check priority greater than zero (e.g. if the check is much faster than testing all variables for
410  * integrality).
411  *
412  * In some cases, integrality conditions or rows of the current LP don't have to be checked, because their
413  * feasibility is already checked or implicitly given. In these cases, 'checkintegrality' or
414  * 'checklprows' is FALSE.
415  *
416  * possible return values for *result:
417  * - SCIP_INFEASIBLE : at least one constraint of the handler is infeasible
418  * - SCIP_FEASIBLE : all constraints of the handler are feasible
419  */
420 SCIP_DECL_CONSCHECK(ConshdlrSubtour::scip_check)
421 { /*lint --e{715}*/
422  assert(result != NULL);
423  *result = SCIP_FEASIBLE;
424 
425  for( int i = 0; i < nconss; ++i )
426  {
427  SCIP_CONSDATA* consdata;
428  GRAPH* graph;
429  SCIP_Bool found;
430 
431  assert(conss != NULL);
432  assert(conss[i] != NULL);
433  consdata = SCIPconsGetData(conss[i]);
434  assert(consdata != NULL);
435  graph = consdata->graph;
436  assert(graph != NULL);
437 
438  // if a subtour is found, the solution must be infeasible
439  found = findSubtour(scip, graph, sol);
440  if( found )
441  {
442  *result = SCIP_INFEASIBLE;
443  if( printreason )
444  {
445  SCIP_CALL( SCIPprintCons(scip, conss[i], NULL) );
446  SCIPinfoMessage(scip, NULL, "violation: graph has a subtour\n");
447  }
448  }
449  }
450 
451  return SCIP_OKAY;
452 }
453 
454 /** domain propagation method of constraint handler
455  *
456  * The first nusefulconss constraints are the ones, that are identified to likely be violated. The propagation
457  * method should process only the useful constraints in most runs, and only occasionally the remaining
458  * nconss - nusefulconss constraints.
459  *
460  * possible return values for *result:
461  * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
462  * - SCIP_REDUCEDDOM : at least one domain reduction was found
463  * - SCIP_DIDNOTFIND : the propagator searched, but did not find any domain reductions
464  * - SCIP_DIDNOTRUN : the propagator was skipped
465  * - SCIP_DELAYED : the propagator was skipped, but should be called again
466  */
467 SCIP_DECL_CONSPROP(ConshdlrSubtour::scip_prop)
468 { /*lint --e{715}*/
469  assert(result != NULL);
470 
471  *result = SCIP_DIDNOTRUN;
472  return SCIP_OKAY;
473 }
474 
475 /** variable rounding lock method of constraint handler
476  *
477  * This method is called, after a constraint is added or removed from the transformed problem.
478  * It should update the rounding locks of all associated variables with calls to SCIPaddVarLocksType(),
479  * depending on the way, the variable is involved in the constraint:
480  * - If the constraint may get violated by decreasing the value of a variable, it should call
481  * SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, nlockspos, nlocksneg), saying that rounding down is
482  * potentially rendering the (positive) constraint infeasible and rounding up is potentially rendering the
483  * negation of the constraint infeasible.
484  * - If the constraint may get violated by increasing the value of a variable, it should call
485  * SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos), saying that rounding up is
486  * potentially rendering the constraint's negation infeasible and rounding up is potentially rendering the
487  * constraint itself infeasible.
488  * - If the constraint may get violated by changing the variable in any direction, it should call
489  * SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, nlockspos + nlocksneg, nlockspos + nlocksneg).
490  *
491  * Consider the linear constraint "3x -5y +2z <= 7" as an example. The variable rounding lock method of the
492  * linear constraint handler should call SCIPaddVarLocksType(scip, x, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos),
493  * SCIPaddVarLocksType(scip, y, SCIP_LOCKTYPE_MODEL, nlockspos, nlocksneg) and
494  * SCIPaddVarLocksType(scip, z, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos) to tell SCIP,
495  * that rounding up of x and z and rounding down of y can destroy the feasibility of the constraint, while rounding
496  * down of x and z and rounding up of y can destroy the feasibility of the constraint's negation "3x -5y +2z > 7".
497  * A linear constraint "2 <= 3x -5y +2z <= 7" should call
498  * SCIPaddVarLocksType(scip, ..., SCIP_LOCKTYPE_MODEL, nlockspos + nlocksneg, nlockspos + nlocksneg) on all variables,
499  * since rounding in both directions of each variable can destroy both the feasibility of the constraint and it's negation
500  * "3x -5y +2z < 2 or 3x -5y +2z > 7".
501  *
502  * If the constraint itself contains other constraints as sub constraints (e.g. the "or" constraint concatenation
503  * "c(x) or d(x)"), the rounding lock methods of these constraints should be called in a proper way.
504  * - If the constraint may get violated by the violation of the sub constraint c, it should call
505  * SCIPaddConsLocks(scip, c, nlockspos, nlocksneg), saying that infeasibility of c may lead to infeasibility of
506  * the (positive) constraint, and infeasibility of c's negation (i.e. feasibility of c) may lead to infeasibility
507  * of the constraint's negation (i.e. feasibility of the constraint).
508  * - If the constraint may get violated by the feasibility of the sub constraint c, it should call
509  * SCIPaddConsLocks(scip, c, nlocksneg, nlockspos), saying that infeasibility of c may lead to infeasibility of
510  * the constraint's negation (i.e. feasibility of the constraint), and infeasibility of c's negation (i.e. feasibility
511  * of c) may lead to infeasibility of the (positive) constraint.
512  * - If the constraint may get violated by any change in the feasibility of the sub constraint c, it should call
513  * SCIPaddConsLocks(scip, c, nlockspos + nlocksneg, nlockspos + nlocksneg).
514  *
515  * Consider the or concatenation "c(x) or d(x)". The variable rounding lock method of the or constraint handler
516  * should call SCIPaddConsLocks(scip, c, nlockspos, nlocksneg) and SCIPaddConsLocks(scip, d, nlockspos, nlocksneg)
517  * to tell SCIP, that infeasibility of c and d can lead to infeasibility of "c(x) or d(x)".
518  *
519  * As a second example, consider the equivalence constraint "y <-> c(x)" with variable y and constraint c. The
520  * constraint demands, that y == 1 if and only if c(x) is satisfied. The variable lock method of the corresponding
521  * constraint handler should call SCIPaddVarLocksType(scip, y, SCIP_LOCKTYPE_MODEL, nlockspos + nlocksneg, nlockspos + nlocksneg) and
522  * SCIPaddConsLocks(scip, c, nlockspos + nlocksneg, nlockspos + nlocksneg), because any modification to the
523  * value of y or to the feasibility of c can alter the feasibility of the equivalence constraint.
524  */
525 SCIP_DECL_CONSLOCK(ConshdlrSubtour::scip_lock)
526 { /*lint --e{715}*/
527  SCIP_CONSDATA* consdata;
528  GRAPH* g;
529 
530  consdata = SCIPconsGetData(cons);
531  assert(consdata != NULL);
532 
533  g = consdata->graph;
534  assert(g != NULL);
535 
536  for( int i = 0; i < g->nedges; ++i )
537  {
538  SCIP_CALL( SCIPaddVarLocksType(scip, g->edges[i].var, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos) );
539  }
540 
541  return SCIP_OKAY;
542 }
543 
544 /** variable deletion method of constraint handler
545  *
546  * This method should iterate over all constraints of the constraint handler and delete all variables
547  * that were marked for deletion by SCIPdelVar().
548  *
549  * input:
550  * - scip : SCIP main data structure
551  * - conshdlr : the constraint handler itself
552  * - conss : array of constraints in transformed problem
553  * - nconss : number of constraints in transformed problem
554  */
555 SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
556 { /*lint --e{715}*/
557  return SCIP_OKAY;
558 }
559 
560 
561 /** constraint display method of constraint handler
562  *
563  * The constraint handler should store a representation of the constraint into the given text file.
564  */
565 SCIP_DECL_CONSPRINT(ConshdlrSubtour::scip_print)
566 { /*lint --e{715}*/
567  SCIP_CONSDATA* consdata;
568  GRAPH* g;
569 
570  consdata = SCIPconsGetData(cons);
571  assert(consdata != NULL);
572 
573  g = consdata->graph;
574  assert(g != NULL);
575 
576  SCIPinfoMessage(scip, file, "subtour of Graph G with %d nodes and %d edges\n", g->nnodes, g->nedges);
577 
578  return SCIP_OKAY;
579 }
580 
581 /** clone method which will be used to copy a objective plugin */
582 SCIP_DECL_CONSHDLRCLONE(ObjProbCloneable* ConshdlrSubtour::clone) /*lint !e665*/
583 {
584  assert(valid != NULL);
585  *valid = TRUE;
586  return new ConshdlrSubtour(scip);
587 }
588 
589 /** constraint copying method of constraint handler
590  *
591  * The constraint handler can provide a copy method, which copies a constraint from one SCIP data structure into a other
592  * SCIP data structure.
593  */
594 SCIP_DECL_CONSCOPY(ConshdlrSubtour::scip_copy)
595 { /*lint --e{715}*/
596  SCIP_CONSHDLR* conshdlr;
597  SCIP_CONSDATA* consdata = NULL;
598 
599  assert(valid != NULL);
600 
601  /* find the subtour constraint handler */
602  conshdlr = SCIPfindConshdlr(scip, "subtour");
603  if( conshdlr == NULL )
604  {
605  SCIPerrorMessage("subtour constraint handler not found\n");
606  return SCIP_PLUGINNOTFOUND;
607  }
608 
609  /* create constraint data */
610  SCIP_CALL( SCIPallocBlockMemory( scip, &consdata) );
611  ProbDataTSP* probdatatsp;
612  probdatatsp = dynamic_cast<ProbDataTSP*>(SCIPgetObjProbData(scip));
613  assert( probdatatsp != NULL );
614 
615  GRAPH * graph = probdatatsp->getGraph();
616  consdata->graph = graph;
617  capture_graph( consdata->graph );
618 
619  /* create constraint */
620  SCIP_CALL( SCIPcreateCons(scip, cons, (name == NULL) ? SCIPconsGetName(sourcecons) : name,
621  conshdlr, consdata, initial, separate, enforce, check,
622  propagate, local, modifiable, dynamic, removable, FALSE) );
623 
624  *valid = TRUE;
625 
626  return SCIP_OKAY;
627 }
628 
629 /** creates and captures a TSP subtour constraint */
631  SCIP* scip, /**< SCIP data structure */
632  SCIP_CONS** cons, /**< pointer to hold the created constraint */
633  const char* name, /**< name of constraint */
634  GRAPH* graph, /**< the underlying graph */
635  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
636  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
637  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
638  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
639  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
640  SCIP_Bool local, /**< is constraint only valid locally? */
641  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
642  SCIP_Bool dynamic, /**< is constraint dynamic? */
643  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
644  )
645 {
646  SCIP_CONSHDLR* conshdlr;
647  SCIP_CONSDATA* consdata;
648 
649  /* find the subtour constraint handler */
650  conshdlr = SCIPfindConshdlr(scip, "subtour");
651  if( conshdlr == NULL )
652  {
653  SCIPerrorMessage("subtour constraint handler not found\n");
654  return SCIP_PLUGINNOTFOUND;
655  }
656 
657  /* create constraint data */
658  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) ); /*lint !e530*/
659  consdata->graph = graph;
660  capture_graph(consdata->graph);
661 
662  /* create constraint */
663  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
664  local, modifiable, dynamic, removable, FALSE) );
665 
666  return SCIP_OKAY;
667 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
struct GraphEdge * next
Definition: GomoryHuTree.h:60
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1626
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8344
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1649
SCIP_DECL_CONSSEPALP(ConshdlrSubtour::scip_sepalp)
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1686
SCIP_DECL_CONSENFOPS(ConshdlrSubtour::scip_enfops)
#define FALSE
Definition: def.h:87
SCIP_Real SCIPinfinity(SCIP *scip)
#define TRUE
Definition: def.h:86
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8364
generator for global cuts in undirected graphs
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
SCIP_DECL_CONSSEPASOL(ConshdlrSubtour::scip_sepasol)
SCIP_DECL_CONSDELETE(ConshdlrSubtour::scip_delete)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8354
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:934
SCIP_DECL_CONSENFOLP(ConshdlrSubtour::scip_enfolp)
static SCIP_RETCODE sepaSubtour(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool enforce, SCIP_RESULT *result)
SCIP_DECL_CONSCHECK(ConshdlrSubtour::scip_check)
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4256
SCIP_VAR * var
Definition: GomoryHuTree.h:65
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:108
SCIP_RETCODE SCIPcreateConsSubtour(SCIP *scip, SCIP_CONS **cons, const char *name, GRAPH *graph, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
#define SCIPerrorMessage
Definition: pub_message.h:55
Definition: pqueue.h:28
GRAPHNODE * adjac
Definition: GomoryHuTree.h:63
struct GraphEdge * back
Definition: GomoryHuTree.h:61
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8085
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8304
struct GraphEdge * first_edge
Definition: GomoryHuTree.h:44
SCIP_DECL_CONSTRANS(ConshdlrSubtour::scip_trans)
#define NULL
Definition: lpi_spx1.cpp:155
C++ wrapper classes for SCIP.
SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
#define SCIP_CALL(x)
Definition: def.h:384
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8324
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:241
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
GRAPH * getGraph()
Definition: ProbDataTSP.h:88
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define SCIP_Bool
Definition: def.h:84
SCIP_DECL_CONSPROP(ConshdlrSubtour::scip_prop)
C++ constraint handler for TSP subtour elimination constraints.
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8284
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8254
Constraint handler for linear constraints in their most general form, .
scip::ObjProbData * SCIPgetObjProbData(SCIP *scip)
Definition of base class for all clonable classes which define problem data.
SCIP_DECL_CONSHDLRCLONE(ObjProbCloneable *ConshdlrSubtour::clone)
SCIP_Bool ghc_tree(GRAPH *gr, SCIP_Bool **cuts, int *ncuts, double minviol)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1553
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8115
SCIP_DECL_CONSLOCK(ConshdlrSubtour::scip_lock)
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8334
SCIP_DECL_CONSPRINT(ConshdlrSubtour::scip_print)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8274
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8264
int edges
Definition: graphdefs.h:219
static SCIP_Bool findSubtour(SCIP *scip, GRAPH *graph, SCIP_SOL *sol)
void capture_graph(GRAPH *gr)
SCIP_DECL_CONSCOPY(ConshdlrSubtour::scip_copy)
void release_graph(GRAPH **gr)
#define nnodes
Definition: gastrans.c:65
SCIPallocBlockMemory(scip, subsol))
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1382
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352