Scippy

GCG

Branch-and-Price & Column Generation for Everyone

cons_integralorig.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program */
4 /* GCG --- Generic Column Generation */
5 /* a Dantzig-Wolfe decomposition based extension */
6 /* of the branch-cut-and-price framework */
7 /* SCIP --- Solving Constraint Integer Programs */
8 /* */
9 /* Copyright (C) 2010-2021 Operations Research, RWTH Aachen University */
10 /* Zuse Institute Berlin (ZIB) */
11 /* */
12 /* This program is free software; you can redistribute it and/or */
13 /* modify it under the terms of the GNU Lesser General Public License */
14 /* as published by the Free Software Foundation; either version 3 */
15 /* of the License, or (at your option) any later version. */
16 /* */
17 /* This program is distributed in the hope that it will be useful, */
18 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
19 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
20 /* GNU Lesser General Public License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with this program; if not, write to the Free Software */
24 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
25 /* */
26 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
27 
28 /**@file cons_integralorig.c
29  * @ingroup CONSHDLRS
30  * @brief constraint handler for enforcing integrality of the transferred master solution in the original problem
31  * @author Gerald Gamrath
32  * Marcel Schmickerath
33  */
34 
35 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36 /* #define SCIP_DEBUG */
37 #include <assert.h>
38 #include <string.h>
39 
40 #include "cons_integralorig.h"
41 #include "pricer_gcg.h"
42 #include "cons_masterbranch.h"
43 #include "pub_gcgvar.h"
44 #include "scip/struct_branch.h"
45 #include "relax_gcg.h"
46 #include "gcg.h"
47 
48 #include "branch_orig.h"
49 
50 #define CONSHDLR_NAME "integralorig"
51 #define CONSHDLR_DESC "integrality constraint"
52 #define CONSHDLR_ENFOPRIORITY 1000 /**< priority of the constraint handler for constraint enforcing */
53 #define CONSHDLR_CHECKPRIORITY 1000 /**< priority of the constraint handler for checking feasibility */
54 #define CONSHDLR_EAGERFREQ -1 /**< frequency for using all instead of only the useful constraints in separation,
55  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
56 #define CONSHDLR_NEEDSCONS FALSE /**< should the constraint handler be skipped, if no constraints are available? */
57 
58 
59 /** constraint handler data */
60 struct SCIP_ConshdlrData
61 {
62  SCIP_BRANCHRULE** branchrules; /**< stack for storing active branchrules */
63  int nbranchrules; /**< number of active branchrules */
64 };
65 
66 /** insert branchrule in constraint handler data */
68  SCIP* scip,
69  SCIP_BRANCHRULE* branchrule
70  )
71 {
72  SCIP_CONSHDLR* conshdlr;
73  SCIP_CONSHDLRDATA* conshdlrdata;
74 
75  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
76  assert(conshdlr != NULL);
77 
78  conshdlrdata = SCIPconshdlrGetData(conshdlr);
79  assert(conshdlrdata != NULL);
80 
81  assert(conshdlrdata->nbranchrules >= 0);
82  if( conshdlrdata->nbranchrules == 0 )
83  {
84  SCIP_CALL( SCIPallocMemoryArray(scip, &(conshdlrdata->branchrules), 1) ); /*lint !e506*/
85  conshdlrdata->nbranchrules = 1;
86  }
87  else
88  {
89  SCIP_CALL( SCIPreallocMemoryArray(scip, &(conshdlrdata->branchrules), (size_t)conshdlrdata->nbranchrules+1) );
90  ++conshdlrdata->nbranchrules;
91  }
92 
93  assert(conshdlrdata->nbranchrules > 0);
94 
95  conshdlrdata->branchrules[conshdlrdata->nbranchrules-1] = branchrule;
96 
97  return SCIP_OKAY;
98 }
99 
100 /** sort branchrules with respect to priority */
101 static
103  SCIP_BRANCHRULE** branchrules,
104  int nbranchrules
105  )
106 {
107  SCIP_BRANCHRULE* tmp;
108  int pos;
109  int i;
110 
111  tmp = NULL;
112 
113  assert(nbranchrules >= 0);
114  assert(branchrules != NULL);
115 
116  for( pos=0; pos<nbranchrules; ++pos )
117  {
118  int maxi = pos;
119  for( i=pos+1; i<nbranchrules; ++i )
120  {
121  if( branchrules[i]->priority > branchrules[maxi]->priority )
122  {
123  maxi = i;
124  }
125  }
126  if( maxi != pos )
127  {
128  tmp = branchrules[pos];
129  branchrules[pos] = branchrules[maxi];
130  branchrules[maxi] = tmp;
131  }
132  }
133 }
134 
135 /*
136  * Callback methods
137  */
138 
139 /** constraint enforcing method of constraint handler for LP solutions */
140 static
141 SCIP_DECL_CONSENFOLP(consEnfolpIntegralOrig)
142 { /*lint --e{715}*/
143  SCIP* origprob;
144  SCIP_Bool discretization;
145  int i;
146  SCIP_CONSHDLRDATA* conshdlrdata;
147 
148  assert(conshdlr != NULL);
149  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
150  assert(scip != NULL);
151  assert(conss == NULL);
152  assert(nconss == 0);
153  assert(result != NULL);
154  assert(conshdlr != NULL);
155  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
156  assert(scip != NULL);
157 
158  origprob = GCGmasterGetOrigprob(scip);
159  assert(origprob != NULL);
160  conshdlrdata = SCIPconshdlrGetData(conshdlr);
161  assert(conshdlrdata != NULL);
162 
163  SCIPdebugMessage("LP solution enforcing method of integralorig constraint\n");
164 
165  *result = SCIP_FEASIBLE;
166 
167  /* if we use the discretization without continuous variables, we do not have to check for integrality of the solution in the
168  * original variable space, we obtain it by enforcing integrality of the master solution*/
169  SCIP_CALL( SCIPgetBoolParam(origprob, "relaxing/gcg/discretization", &discretization) );
170  if( discretization && SCIPgetNContVars(origprob) == 0 )
171  {
172  return SCIP_OKAY;
173  }
174 
175  /* if the transferred master solution is feasible, the current node is solved to optimality and can be pruned */
176  if( GCGrelaxIsOrigSolFeasible(origprob) )
177  {
178  SCIPdebugMessage("Orig sol is feasible\n");
179  *result = SCIP_FEASIBLE;
180  return SCIP_OKAY;
181  }
182 
183  sortBranchrules(conshdlrdata->branchrules, conshdlrdata->nbranchrules);
184 
185  i = 0;
186 
187  while( *result != SCIP_BRANCHED &&
188  *result != SCIP_REDUCEDDOM &&
189  i < conshdlrdata->nbranchrules )
190  {
191  assert(conshdlrdata->branchrules[i] != NULL);
192 
193  if( conshdlrdata->branchrules[i]->branchexeclp == NULL )
194  {
195  ++i;
196  continue;
197  }
198 
199  SCIPdebugMessage("Call exec lp method of %s\n", SCIPbranchruleGetName(conshdlrdata->branchrules[i]));
200  /** todo handle bool allowaddcons; here default TRUE */
201  SCIP_CALL( conshdlrdata->branchrules[i]->branchexeclp(scip, conshdlrdata->branchrules[i], TRUE, result) );
202  ++i;
203  }
204 
205  return SCIP_OKAY;
206 
207 }
208 
209 
210 /** constraint enforcing method of constraint handler for pseudo solutions */
211 static
212 SCIP_DECL_CONSENFOPS(consEnfopsIntegralOrig)
213 { /*lint --e{715}*/
214  SCIP* origprob;
215  SCIP_Bool discretization;
216  SCIP_CONSHDLRDATA* conshdlrdata;
217  int i;
218 
219  assert(conshdlr != NULL);
220  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
221  assert(scip != NULL);
222  assert(conss == NULL);
223  assert(nconss == 0);
224  assert(result != NULL);
225 
226  origprob = GCGmasterGetOrigprob(scip);
227  assert(origprob != NULL);
228  conshdlrdata = SCIPconshdlrGetData(conshdlr);
229  assert(conshdlrdata != NULL);
230 
231  *result = SCIP_FEASIBLE;
232  i = 0;
233 
234  /* if we use the discretization without continuous variables, we do not have to check for integrality of the solution in the
235  * original variable space, we obtain it by enforcing integrality of the master solution*/
236  SCIP_CALL( SCIPgetBoolParam(origprob, "relaxing/gcg/discretization", &discretization) );
237  if( discretization && SCIPgetNContVars(origprob) == 0 )
238  {
239  return SCIP_OKAY;
240  }
241 
242  assert(SCIPgetNPseudoBranchCands(origprob) > 0);
243 
244  sortBranchrules(conshdlrdata->branchrules, conshdlrdata->nbranchrules);
245 
246  while( *result != SCIP_BRANCHED && i < conshdlrdata->nbranchrules )
247  {
248  assert(conshdlrdata->branchrules[i] != NULL);
249 
250  if( conshdlrdata->branchrules[i]->branchexecps == NULL )
251  {
252  ++i;
253  continue;
254  }
255  /** todo handle bool allowaddcons; here default TRUE */
256  SCIP_CALL( conshdlrdata->branchrules[i]->branchexecps(scip, conshdlrdata->branchrules[i], TRUE, result) );
257  ++i;
258  }
259 
260  return SCIP_OKAY;
261 }
262 
263 
264 /** feasibility check method of constraint handler for integral solutions */
265 static
266 SCIP_DECL_CONSCHECK(consCheckIntegralOrig)
267 { /*lint --e{715}*/
268  SCIP* origprob;
269  SCIP_SOL* origsol;
270  SCIP_VAR** origvars;
271  int norigvars;
272  SCIP_Real solval;
273  SCIP_Bool discretization;
274  int v;
275 
276  assert(conshdlr != NULL);
277  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
278  assert(scip != NULL);
279 
280  origprob = GCGmasterGetOrigprob(scip);
281  assert(origprob != NULL);
282 
283  SCIPdebugMessage("Check method of integralorig constraint\n");
284 
285  *result = SCIP_FEASIBLE;
286 
287  /* if we use the discretization without continuous variables, we do not have to check for integrality of the solution in the
288  * original variable space, we obtain it by enforcing integrality of the master solution*/
289  SCIP_CALL( SCIPgetBoolParam(origprob, "relaxing/gcg/discretization", &discretization) );
290  if( discretization && SCIPgetNContVars(origprob) == 0 )
291  {
292  return SCIP_OKAY;
293  }
294 
295  /* get corresponding origsol in order to check integrality */
296  SCIP_CALL( GCGtransformMastersolToOrigsol(origprob, sol, &origsol) );
297 
298  origvars = SCIPgetOrigVars(origprob);
299  norigvars = SCIPgetNOrigVars(origprob);
300 
301  /* check for each integral original variable whether it has a fractional value */
302  for( v = 0; v < norigvars && *result == SCIP_FEASIBLE; v++ )
303  {
304  if( SCIPvarGetType(origvars[v]) == SCIP_VARTYPE_CONTINUOUS )
305  continue;
306 
307  solval = 0.0;
308  assert(GCGvarIsOriginal(origvars[v]));
309 
310  solval = SCIPgetSolVal(origprob, origsol, origvars[v]);
311 
312  if( !SCIPisFeasIntegral(origprob, solval) )
313  {
314  *result = SCIP_INFEASIBLE;
315 
316  if( printreason )
317  {
318  SCIPinfoMessage(scip, NULL, "violation: integrality condition of variable <%s> = %.15g\n",
319  SCIPvarGetName(origvars[v]), solval);
320  }
321  }
322  }
323 
324  SCIPfreeSol(origprob, &origsol);
325 
326  return SCIP_OKAY;
327 }
328 
329 
330 /** variable rounding lock method of constraint handler */
331 static
332 SCIP_DECL_CONSLOCK(consLockIntegralOrig)
333 { /*lint --e{715}*/
334  return SCIP_OKAY;
335 }
336 
337 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
338 static
339 SCIP_DECL_CONSFREE(consFreeIntegralOrig)
340 {
341  SCIP_CONSHDLRDATA* conshdlrdata;
342 
343  assert(scip != NULL);
344  assert(conshdlr != NULL);
345  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
346 
347  conshdlrdata = SCIPconshdlrGetData(conshdlr);
348  assert(conshdlrdata != NULL);
349 
350  SCIPdebugMessage("freeing integralorig constraint handler\n");
351 
352  if( conshdlrdata->nbranchrules > 0 )
353  {
354  assert(conshdlrdata->branchrules != NULL);
355  SCIPfreeMemoryArray(scip, &(conshdlrdata->branchrules) );
356  conshdlrdata->branchrules = NULL;
357  conshdlrdata->nbranchrules = 0;
358  }
359 
360  /* free constraint handler storage */
361  assert(conshdlrdata->branchrules == NULL);
362  SCIPfreeMemory(scip, &conshdlrdata);
363 
364  return SCIP_OKAY;
365 }
366 
367 /*
368  * constraint specific interface methods
369  */
370 
371 /** creates the handler for integrality constraint and includes it in SCIP */
373  SCIP* scip /**< SCIP data structure */
374  )
375 {
376  SCIP_CONSHDLR* conshdlr;
377  SCIP_CONSHDLRDATA* conshdlrdata;
378 
379  /* create integral constraint handler data */
380  conshdlrdata = NULL;
381  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
382  conshdlrdata->branchrules = NULL;
383  conshdlrdata->nbranchrules = 0;
384 
385  /* include constraint handler */
386  SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
388  consEnfolpIntegralOrig, consEnfopsIntegralOrig, consCheckIntegralOrig, consLockIntegralOrig,
389  conshdlrdata) );
390  assert(conshdlr != NULL);
391 
392  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeIntegralOrig) );
393 
394  return SCIP_OKAY;
395 }
#define CONSHDLR_EAGERFREQ
GCG interface methods.
SCIP_Bool GCGrelaxIsOrigSolFeasible(SCIP *scip)
Definition: relax_gcg.c:4202
#define CONSHDLR_DESC
#define CONSHDLR_NAME
SCIP_BRANCHRULE ** branchrules
static SCIP_DECL_CONSLOCK(consLockIntegralOrig)
static SCIP_DECL_CONSFREE(consFreeIntegralOrig)
static SCIP_DECL_CONSENFOLP(consEnfolpIntegralOrig)
branching rule for original problem in GCG
SCIP_Bool GCGvarIsOriginal(SCIP_VAR *var)
Definition: gcgvar.c:166
GCG variable pricer.
constraint handler for the integrality constraint
constraint handler for storing the branching decisions at each node of the tree
SCIP_RETCODE GCGtransformMastersolToOrigsol(SCIP *scip, SCIP_SOL *mastersol, SCIP_SOL **origsol)
Definition: misc.c:120
#define CONSHDLR_NEEDSCONS
SCIP * GCGmasterGetOrigprob(SCIP *scip)
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSCHECK(consCheckIntegralOrig)
static SCIP_DECL_CONSENFOPS(consEnfopsIntegralOrig)
GCG relaxator.
SCIP_RETCODE SCIPincludeConshdlrIntegralOrig(SCIP *scip)
public methods for GCG variables
#define CONSHDLR_CHECKPRIORITY
static void sortBranchrules(SCIP_BRANCHRULE **branchrules, int nbranchrules)
SCIP_RETCODE GCGconsIntegralorigAddBranchrule(SCIP *scip, SCIP_BRANCHRULE *branchrule)