Scippy

GCG

Branch-and-Price & Column Generation for Everyone

sepa_master.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 sepa_master.c
29  * @brief master separator
30  * @author Gerald Gamrath
31  */
32 
33 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34 
35 #include <assert.h>
36 #include <stdio.h>
37 #include <string.h>
38 
39 #include "scip/scip.h"
40 #include "scip/lp.h"
41 #include "sepa_master.h"
42 #include "gcg.h"
43 #include "relax_gcg.h"
44 #include "pricer_gcg.h"
45 
46 
47 #define SEPA_NAME "master"
48 #define SEPA_DESC "separator for separating cuts in the original problem, called in the master"
49 #define SEPA_PRIORITY 1000
50 
51 #define SEPA_FREQ 1
52 #define SEPA_MAXBOUNDDIST 1.0
53 #define SEPA_USESSUBSCIP FALSE
54 #define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
55 
56 #define STARTMAXCUTS 50 /**< maximal cuts used at the beginning */
57 
58 
59 /*
60  * Data structures
61  */
62 
63 /** separator data */
64 struct SCIP_SepaData
65 {
66  SCIP_ROW** mastercuts; /**< cuts in the master problem */
67  SCIP_ROW** origcuts; /**< cuts in the original problem */
68  int ncuts; /**< number of cuts in the original problem */
69  int maxcuts; /**< maximal number of allowed cuts */
70  SCIP_Bool enable; /**< parameter returns if master separator is enabled */
71  int separationsetting; /**< parameter returns which parameter setting is used for separation */
72 };
73 
74 
75 /*
76  * Local methods
77  */
78 
79 
80 /** allocates enough memory to hold more cuts */
81 static
82 SCIP_RETCODE ensureSizeCuts(
83  SCIP* scip, /**< SCIP data structure */
84  SCIP_SEPADATA* sepadata, /**< separator data data structure */
85  int size /**< new size of cut arrays */
86  )
87 {
88  assert(scip != NULL);
89  assert(sepadata != NULL);
90  assert(sepadata->mastercuts != NULL);
91  assert(sepadata->origcuts != NULL);
92  assert(sepadata->ncuts <= sepadata->maxcuts);
93  assert(sepadata->ncuts >= 0);
94 
95  if( sepadata->maxcuts < size )
96  {
97  int newmaxcuts = SCIPcalcMemGrowSize(scip, size);
98  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(sepadata->mastercuts), sepadata->maxcuts, newmaxcuts) );
99  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(sepadata->origcuts), sepadata->maxcuts, newmaxcuts) );
100  sepadata->maxcuts = newmaxcuts;
101  }
102  assert(sepadata->maxcuts >= size);
103 
104  return SCIP_OKAY;
105 }
106 
107 /*
108  * Callback methods of separator
109  */
110 
111 #define sepaCopyMaster NULL
112 #define sepaInitMaster NULL
113 #define sepaInitsolMaster NULL
114 #define sepaExecsolMaster NULL
115 
116 /** destructor of separator to free user data (called when SCIP is exiting) */
117 static
118 SCIP_DECL_SEPAFREE(sepaFreeMaster)
119 {
120  SCIP_SEPADATA* sepadata;
121 
122  sepadata = SCIPsepaGetData(sepa);
123 
124  SCIPfreeBlockMemoryArray(scip, &(sepadata->origcuts), sepadata->maxcuts);
125  SCIPfreeBlockMemoryArray(scip, &(sepadata->mastercuts), sepadata->maxcuts);
126 
127  SCIPfreeBlockMemory(scip, &sepadata);
128 
129  return SCIP_OKAY;
130 }
131 
132 /** deinitialization method of separator (called before transformed problem is freed) */
133 static
134 SCIP_DECL_SEPAEXIT(sepaExitMaster)
135 {
136  SCIP* origscip;
137  SCIP_SEPADATA* sepadata;
138  int i;
139 
140  sepadata = SCIPsepaGetData(sepa);
141  assert(sepadata != NULL);
142 
143  origscip = GCGmasterGetOrigprob(scip);
144  assert(origscip != NULL);
145 
146  for( i = 0; i < sepadata->ncuts; i++ )
147  {
148  SCIP_CALL( SCIPreleaseRow(origscip, &(sepadata->origcuts[i])) );
149  }
150 
151  sepadata->ncuts = 0;
152 
153  return SCIP_OKAY;
154 }
155 
156 /** solving process deinitialization method of separator (called before branch and bound process data is freed) */
157 static
158 SCIP_DECL_SEPAEXITSOL(sepaExitsolMaster)
159 {
160  SCIP_SEPADATA* sepadata;
161  int i;
162 
163  sepadata = SCIPsepaGetData(sepa);
164  assert(sepadata != NULL);
165 
166  assert(GCGmasterGetOrigprob(scip) != NULL);
167 
168  for( i = 0; i < sepadata->ncuts; i++ )
169  {
170  SCIP_CALL( SCIPreleaseRow(scip, &(sepadata->mastercuts[i])) );
171  }
172 
173  return SCIP_OKAY;
174 }
175 
176 /** LP solution separation method of separator */
177 static
178 SCIP_DECL_SEPAEXECLP(sepaExeclpMaster)
179 {
180  SCIP* origscip;
181  SCIP_Bool delayed;
182  SCIP_Bool cutoff;
183  SCIP_ROW** cuts;
184  SCIP_ROW* mastercut;
185  SCIP_VAR** rowvars;
186  SCIP_SEPADATA* sepadata;
187 
188  SCIP_VAR** mastervars;
189  SCIP_Real* mastervals;
190  int nmastervars;
191 
192  char name[SCIP_MAXSTRLEN];
193 
194  int ncuts;
195  int norigcuts;
196  int i;
197  int j;
198  SCIP_Bool feasible;
199 
200  SCIP_Bool isroot;
201 
202  assert(scip != NULL);
203  assert(result != NULL);
204 
205  origscip = GCGmasterGetOrigprob(scip);
206  assert(origscip != NULL);
207 
208  sepadata = SCIPsepaGetData(sepa);
209  assert(sepadata != NULL);
210 
211  SCIPdebugMessage("sepaExeclpMaster\n");
212 
213  *result = SCIP_DIDNOTFIND;
214 
215  if( !sepadata->enable )
216  {
217  *result = SCIP_DIDNOTRUN;
218  return SCIP_OKAY;
219  }
220 
221  if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
222  {
223  SCIPdebugMessage("master LP not solved to optimality, do no separation!\n");
224  return SCIP_OKAY;
225  }
226 
227  if( GCGgetNRelPricingprobs(origscip) < GCGgetNPricingprobs(origscip) )
228  {
229  SCIPdebugMessage("aggregated pricing problems, do no separation!\n");
230  *result = SCIP_DIDNOTRUN;
231  return SCIP_OKAY;
232  }
233 
234  /* ensure to separate current sol */
235  SCIP_CALL( GCGrelaxUpdateCurrentSol(origscip) );
236 
237  if( GCGrelaxIsOrigSolFeasible(origscip) )
238  {
239  SCIPdebugMessage("Current solution is feasible, no separation necessary!\n");
240  *result = SCIP_DIDNOTRUN;
241  return SCIP_OKAY;
242  }
243 
244  isroot = SCIPgetCurrentNode(scip) == SCIPgetRootNode(scip);
245 
246  /* set parameter setting for separation */
247  SCIP_CALL( SCIPsetSeparating(origscip, (SCIP_PARAMSETTING) sepadata->separationsetting, TRUE) );
248 
249  SCIP_CALL( SCIPseparateSol(origscip, GCGrelaxGetCurrentOrigSol(origscip),
250  isroot, TRUE, FALSE, &delayed, &cutoff) );
251 
252  SCIPdebugMessage("SCIPseparateSol() found %d cuts!\n", SCIPgetNCuts(origscip));
253 
254  if( delayed && !cutoff )
255  {
256  SCIPdebugMessage("call delayed separators\n");
257 
258  SCIP_CALL( SCIPseparateSol(origscip, GCGrelaxGetCurrentOrigSol(origscip),
259  isroot, TRUE, TRUE, &delayed, &cutoff) );
260  }
261 
262  /* if cut off is detected set result pointer and return SCIP_OKAY */
263  if( cutoff )
264  {
265  *result = SCIP_CUTOFF;
266  SCIP_CALL( SCIPendProbing(origscip) );
267 
268  /* disable separating again */
269  SCIP_CALL( SCIPsetSeparating(origscip, SCIP_PARAMSETTING_OFF, TRUE) );
270 
271  return SCIP_OKAY;
272  }
273 
274  cuts = SCIPgetCuts(origscip);
275  ncuts = SCIPgetNCuts(origscip);
276 
277  /* save cuts in the origcuts array in the separator data */
278  norigcuts = sepadata->ncuts;
279  SCIP_CALL( ensureSizeCuts(scip, sepadata, sepadata->ncuts + ncuts) );
280 
281  for( i = 0; i < ncuts; i++ )
282  {
283  sepadata->origcuts[norigcuts] = cuts[i];
284  SCIP_CALL( SCIPcaptureRow(origscip, sepadata->origcuts[norigcuts]) );
285  norigcuts++;
286  }
287 
288  SCIP_CALL( SCIPclearCuts(origscip) );
289 
290  mastervars = SCIPgetVars(scip);
291  nmastervars = SCIPgetNVars(scip);
292  SCIP_CALL( SCIPallocBufferArray(scip, &mastervals, nmastervars) );
293 
294  for( i = 0; i < ncuts; i++ )
295  {
296  SCIP_ROW* origcut;
297  SCIP_COL** cols;
298  int ncols;
299  SCIP_Real* vals;
300  SCIP_Real shift;
301 
302  origcut = sepadata->origcuts[norigcuts-ncuts+i]; /*lint !e679*/
303 
304  /* get columns and vals of the cut */
305  ncols = SCIProwGetNNonz(origcut);
306  cols = SCIProwGetCols(origcut);
307  vals = SCIProwGetVals(origcut);
308 
309  /* get the variables corresponding to the columns in the cut */
310  SCIP_CALL( SCIPallocBufferArray(scip, &rowvars, ncols) );
311  for( j = 0; j < ncols; j++ )
312  {
313  rowvars[j] = SCIPcolGetVar(cols[j]);
314  }
315 
316  /* transform the original variables to master variables */
317  shift = GCGtransformOrigvalsToMastervals(GCGmasterGetOrigprob(scip), rowvars, vals, ncols, mastervars, mastervals,
318  nmastervars);
319 
320  /* create new cut in the master problem */
321  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "mc_%s", SCIProwGetName(origcut));
322  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &mastercut, sepa, name,
323  ( SCIPisInfinity(scip, -SCIProwGetLhs(origcut)) ?
324  SCIProwGetLhs(origcut) : SCIProwGetLhs(origcut) - SCIProwGetConstant(origcut) - shift),
325  ( SCIPisInfinity(scip, SCIProwGetRhs(origcut)) ?
326  SCIProwGetRhs(origcut) : SCIProwGetRhs(origcut) - SCIProwGetConstant(origcut) - shift),
327  SCIProwIsLocal(origcut), TRUE, FALSE) );
328 
329  /* add master variables to the cut */
330  SCIP_CALL( SCIPaddVarsToRow(scip, mastercut, nmastervars, mastervars, mastervals) );
331 
332  /* add the cut to the master problem */
333  SCIP_CALL( SCIPaddRow(scip, mastercut, FALSE, &feasible) );
334  sepadata->mastercuts[sepadata->ncuts] = mastercut;
335  sepadata->ncuts++;
336 
337 #ifdef SCIP_DEBUG
338  SCIPdebugMessage("Cut %d:\n", i);
339  SCIP_CALL( SCIPprintRow(scip, mastercut, NULL) );
340  SCIPdebugMessage("\n\n");
341 #endif
342 
343  SCIPfreeBufferArray(scip, &rowvars);
344  }
345 
346  assert(norigcuts == sepadata->ncuts);
347 
348  if( ncuts > 0 )
349  *result = SCIP_SEPARATED;
350 
351  SCIPdebugMessage("%d cuts are in the original sepastore!\n", SCIPgetNCuts(origscip));
352  SCIPdebugMessage("%d cuts are in the master sepastore!\n", SCIPgetNCuts(scip));
353 
354  /* disable separation for original problem again */
355  SCIP_CALL( SCIPsetSeparating(origscip, SCIP_PARAMSETTING_OFF, TRUE) );
356 
357  SCIPfreeBufferArray(scip, &mastervals);
358 
359  return SCIP_OKAY;
360 }
361 
362 
363 /*
364  * separator specific interface methods
365  */
366 
367 /** creates the master separator and includes it in SCIP */
369  SCIP* scip /**< SCIP data structure */
370  )
371 {
372  SCIP_SEPADATA* sepadata;
373 
374  /* create master separator data */
375  SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
376 
377  sepadata->maxcuts = SCIPcalcMemGrowSize(scip, STARTMAXCUTS);
378  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->origcuts), sepadata->maxcuts) ); /*lint !e506*/
379  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->mastercuts), sepadata->maxcuts) ); /*lint !e506*/
380  sepadata->ncuts = 0;
381 
382  /* include separator */
384  sepaCopyMaster, sepaFreeMaster, sepaInitMaster, sepaExitMaster,
385  sepaInitsolMaster, sepaExitsolMaster,
386  sepaExeclpMaster, sepaExecsolMaster,
387  sepadata) );
388 
389  SCIP_CALL( SCIPaddBoolParam(GCGmasterGetOrigprob(scip), "sepa/" SEPA_NAME "/enable", "enable master separator",
390  &(sepadata->enable), FALSE, TRUE, NULL, NULL) );
391 
392  SCIP_CALL( SCIPaddIntParam(GCGmasterGetOrigprob(scip), "sepa/" SEPA_NAME "/paramsetting", "parameter returns which parameter setting is used for "
393  "separation (default = 0, aggressive = 1, fast = 2", &(sepadata->separationsetting), FALSE, 1, 0, 2, NULL, NULL) );
394 
395  return SCIP_OKAY;
396 }
397 
398 
399 /** returns the array of original cuts saved in the separator data */
401  SCIP* scip /**< SCIP data structure */
402  )
403 {
404  SCIP_SEPA* sepa;
405  SCIP_SEPADATA* sepadata;
406 
407  assert(scip != NULL);
408 
409  sepa = SCIPfindSepa(scip, SEPA_NAME);
410  assert(sepa != NULL);
411 
412  sepadata = SCIPsepaGetData(sepa);
413  assert(sepadata != NULL);
414 
415  return sepadata->origcuts;
416 }
417 
418 /** returns the number of cuts saved in the separator data */
420  SCIP* scip /**< SCIP data structure */
421  )
422 {
423  SCIP_SEPA* sepa;
424  SCIP_SEPADATA* sepadata;
425 
426  assert(scip != NULL);
427 
428  sepa = SCIPfindSepa(scip, SEPA_NAME);
429  assert(sepa != NULL);
430 
431  sepadata = SCIPsepaGetData(sepa);
432  assert(sepadata != NULL);
433 
434  return sepadata->ncuts;
435 }
436 
437 /** returns the array of master cuts saved in the separator data */
439  SCIP* scip /**< SCIP data structure */
440  )
441 {
442  SCIP_SEPA* sepa;
443  SCIP_SEPADATA* sepadata;
444 
445  assert(scip != NULL);
446 
447  sepa = SCIPfindSepa(scip, SEPA_NAME);
448  assert(sepa != NULL);
449 
450  sepadata = SCIPsepaGetData(sepa);
451  assert(sepadata != NULL);
452 
453  return sepadata->mastercuts;
454 }
455 
456 /** adds given original and master cut to master separator data */
457 SCIP_RETCODE GCGsepaAddMastercuts(
458  SCIP* scip, /**< SCIP data structure */
459  SCIP_ROW* origcut, /**< pointer to orginal cut */
460  SCIP_ROW* mastercut /**< pointer to master cut */
461 )
462 {
463  SCIP_SEPA* sepa;
464  SCIP_SEPADATA* sepadata;
465 
466  assert(scip != NULL);
467 
468  sepa = SCIPfindSepa(scip, SEPA_NAME);
469  assert(sepa != NULL);
470 
471  sepadata = SCIPsepaGetData(sepa);
472  assert(sepadata != NULL);
473 
474  SCIP_CALL( ensureSizeCuts(scip, sepadata, sepadata->ncuts + 1) );
475 
476  sepadata->origcuts[sepadata->ncuts] = origcut;
477  sepadata->mastercuts[sepadata->ncuts] = mastercut;
478  SCIP_CALL( SCIPcaptureRow(scip, sepadata->origcuts[sepadata->ncuts]) );
479  SCIP_CALL( SCIPcaptureRow(scip, sepadata->mastercuts[sepadata->ncuts]) );
480 
481  ++(sepadata->ncuts);
482 
483  return SCIP_OKAY;
484 }
GCG interface methods.
SCIP_Bool GCGrelaxIsOrigSolFeasible(SCIP *scip)
Definition: relax_gcg.c:4202
SCIP_ROW ** mastercuts
Definition: sepa_basis.c:75
#define SEPA_MAXBOUNDDIST
Definition: sepa_master.c:52
SCIP_ROW ** origcuts
Definition: sepa_basis.c:76
static SCIP_DECL_SEPAEXIT(sepaExitMaster)
Definition: sepa_master.c:134
#define sepaInitsolMaster
Definition: sepa_master.c:113
#define sepaInitMaster
Definition: sepa_master.c:112
SCIP_Bool enable
Definition: sepa_basis.c:86
#define SEPA_DELAY
Definition: sepa_master.c:54
int GCGgetNPricingprobs(SCIP *scip)
Definition: relax_gcg.c:3979
GCG variable pricer.
SCIP_RETCODE GCGrelaxUpdateCurrentSol(SCIP *scip)
Definition: relax_gcg.c:4796
int GCGsepaGetNCuts(SCIP *scip)
Definition: sepa_master.c:419
#define STARTMAXCUTS
Definition: sepa_master.c:56
SCIP_ROW ** GCGsepaGetOrigcuts(SCIP *scip)
Definition: sepa_master.c:400
#define SEPA_PRIORITY
Definition: sepa_master.c:49
master separator
int separationsetting
Definition: sepa_basis.c:92
int GCGgetNRelPricingprobs(SCIP *scip)
Definition: relax_gcg.c:3959
#define sepaCopyMaster
Definition: sepa_master.c:111
SCIP * GCGmasterGetOrigprob(SCIP *scip)
#define SEPA_USESSUBSCIP
Definition: sepa_master.c:53
SCIP_SOL * GCGrelaxGetCurrentOrigSol(SCIP *scip)
Definition: relax_gcg.c:4183
#define SEPA_FREQ
Definition: sepa_master.c:51
static SCIP_DECL_SEPAEXITSOL(sepaExitsolMaster)
Definition: sepa_master.c:158
GCG relaxator.
SCIP_Real GCGtransformOrigvalsToMastervals(SCIP *scip, SCIP_VAR **origvars, SCIP_Real *origvals, int norigvars, SCIP_VAR **mastervars, SCIP_Real *mastervals, int nmastervars)
Definition: misc.c:545
#define SEPA_DESC
Definition: sepa_master.c:48
static SCIP_DECL_SEPAEXECLP(sepaExeclpMaster)
Definition: sepa_master.c:178
static SCIP_RETCODE ensureSizeCuts(SCIP *scip, SCIP_SEPADATA *sepadata, int size)
Definition: sepa_master.c:82
SCIP_RETCODE GCGsepaAddMastercuts(SCIP *scip, SCIP_ROW *origcut, SCIP_ROW *mastercut)
Definition: sepa_master.c:457
#define SEPA_NAME
Definition: sepa_master.c:47
SCIP_ROW ** GCGsepaGetMastercuts(SCIP *scip)
Definition: sepa_master.c:438
static SCIP_DECL_SEPAFREE(sepaFreeMaster)
Definition: sepa_master.c:118
#define sepaExecsolMaster
Definition: sepa_master.c:114
SCIP_RETCODE SCIPincludeSepaMaster(SCIP *scip)
Definition: sepa_master.c:368