Scippy

GCG

Branch-and-Price & Column Generation for Everyone

heur_relaxcolsel.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 heur_relaxcolsel.c
29  * @brief relaxation based column selection primal heuristic
30  * @author Christian Puchert
31  */
32 
33 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34 
35 #include <assert.h>
36 
37 #include "heur_relaxcolsel.h"
38 #include "gcg.h"
39 #include "pricer_gcg.h"
40 
41 
42 #define HEUR_NAME "relaxcolsel"
43 #define HEUR_DESC "column selection heuristic that tries to round a master LP solution in promising directions"
44 #define HEUR_DISPCHAR 'x'
45 #define HEUR_PRIORITY -100
46 #define HEUR_FREQ 1
47 #define HEUR_FREQOFS 0
48 #define HEUR_MAXDEPTH -1
49 #define HEUR_TIMING SCIP_HEURTIMING_AFTERLPNODE
50 #define HEUR_USESSUBSCIP FALSE
51 
52 #define DEFAULT_MINCOLUMNS 200 /**< minimum number of columns to regard in the master problem */
53 
54 
55 
56 
57 /*
58  * Data structures
59  */
60 
61 /** primal heuristic data */
62 struct SCIP_HeurData
63 {
64  /* parameters */
65  int mincolumns; /**< minimum number of columns to regard in the master problem */
66 
67  /* data */
68  SCIP_VAR** zerovars; /**< array of master variables corresponding to zero solutions */
69  int maxzerovars; /**< capacity of zerovars */
70  int lastncols; /**< number of columns in the last call of the heuristic */
71 };
72 
73 
74 
75 
76 /*
77  * Local methods
78  */
79 
80 
81 /**
82  * initialize working solution as the rounded down master LP solution (and its original counterpart)
83  * and the master variable candidates for rounding up
84  */
85 static
86 SCIP_RETCODE initializeStartsol(
87  SCIP* scip,
88  SCIP_SOL* mastersol,
89  SCIP_SOL* origsol,
90  int* blocknr,
91  int* mastercands,
92  SCIP_Real* candfracs,
93  int* nmastercands,
94  SCIP_Bool* success
95  )
96 {
97  SCIP* origprob;
98  SCIP_VAR** mastervars;
99  SCIP_Real* mastervals;
100  int nmastervars;
101  int nblocks;
102 
103  int i;
104  int j;
105  int k;
106 
107  /* get original problem */
108  origprob = GCGmasterGetOrigprob(scip);
109  assert(origprob != NULL);
110 
111  /* get variable data of the master problem */
112  SCIP_CALL( SCIPgetVarsData(scip, &mastervars, &nmastervars, NULL, NULL, NULL, NULL) );
113  assert(nmastervars >= 0);
114 
115  /* get number of blocks */
116  nblocks = GCGgetNPricingprobs(origprob);
117  assert( nblocks >= 0 );
118 
119  /* get master LP solution values */
120  SCIP_CALL( SCIPallocBufferArray(scip, &mastervals, nmastervars) );
121  SCIP_CALL( SCIPgetSolVals(scip, NULL, nmastervars, mastervars, mastervals) );
122 
123  *nmastercands = 0;
124  *success = TRUE;
125 
126  /* loop over all given master variables */
127  for( i = 0; i < nmastervars && *success; ++i )
128  {
129  SCIP_VAR* mastervar;
130  SCIP_VARTYPE vartype;
131  SCIP_Real solval;
132  SCIP_Real roundval;
133  SCIP_Real frac;
134  int block;
135  SCIP_VAR** origvars;
136  SCIP_Real* origvals;
137  int norigvars;
138 
139  /* get master variable */
140  mastervar = mastervars[i];
141  assert(GCGvarIsMaster(mastervar));
142  vartype = SCIPvarGetType(mastervar);
143 
144  /* get solution value, its integer part and its fractionality */
145  solval = mastervals[i];
146  roundval = SCIPfeasFloor(scip, solval);
147  frac = SCIPfeasFrac(scip, solval);
148 
149  /* get blocknr and corresponding original variables */
150  block = GCGvarGetBlock(mastervar);
151  origvars = GCGmasterVarGetOrigvars(mastervar);
152  origvals = GCGmasterVarGetOrigvals(mastervar);
153  norigvars = GCGmasterVarGetNOrigvars(mastervar);
154 
155  if( GCGmasterVarIsArtificial(mastervar) )
156  continue;
157 
158  /* update master solution and original solution */
159 
160  /* treat variables representing rays separately */
161  if( GCGmasterVarIsRay(mastervar) )
162  {
163  assert(block >= 0);
164 
165  if( SCIPisFeasPositive(scip, roundval) )
166  {
167  SCIPdebugMessage(" -> (block %d) select ray master variable %s (%d times)\n",
168  block, SCIPvarGetName(mastervar), (int) roundval);
169 
170  /* set master solution value to rounded down solution */
171  SCIP_CALL( SCIPsetSolVal(scip, mastersol, mastervar, roundval) );
172 
173  /* loop over all original variables contained in the current master variable */
174  for( j = 0; j < norigvars; ++j )
175  {
176  SCIP_VAR* origvar;
177  SCIP_Real origval;
178 
179  /* get original variable and its value in the master variable */
180  origvar = origvars[j];
181  origval = origvals[j];
182  assert(GCGvarIsOriginal(origvar));
183 
184  if( SCIPisZero(scip, origval) )
185  continue;
186 
187  assert(!SCIPisZero(scip, origval));
188 
189  /* the original variable is a linking variable: just transfer the solution value of the direct copy (this is done later) */
190  if( GCGoriginalVarIsLinking(origvar) )
191  continue;
192 
193  /* increase the corresponding value */
194  SCIP_CALL( SCIPincSolVal(scip, origsol, origvar, origval * roundval) );
195  }
196 
197  /* if the master variable is fractional, add it as a candidate */
198  if( !SCIPisFeasFracIntegral(scip, frac) )
199  {
200  mastercands[*nmastercands] = i;
201  candfracs[*nmastercands] = frac;
202  ++(*nmastercands);
203  }
204  }
205 
206  continue;
207  }
208 
209  assert(!GCGmasterVarIsRay(mastervar));
210 
211  /* treat variables directly transferred to the master problem (but not linking variables) */
212  if( block == -1 )
213  {
214  SCIP_VAR* origvar;
215  int origblock;
216 
217  /* get original variable and the block it belongs to */
218  assert(norigvars == 1);
219  origvar = origvars[0];
220  assert(GCGvarIsOriginal(origvar));
221  assert(origvals[0] == 1.0);
222  origblock = GCGvarGetBlock(origvar);
223  assert(origblock == -2 || origblock == -1);
224 
225  /* only increase solution value if the variable is not a linking variable
226  * (these are treated later) */
227  if( origblock == -2 )
228  continue;
229 
230  /* if the variable should be integral but is not, add rounded down value;
231  * otherwise, add (possibly fractional) value */
232  if( (vartype == SCIP_VARTYPE_BINARY || vartype == SCIP_VARTYPE_INTEGER )
233  && !SCIPisFeasFracIntegral(scip, frac) )
234  {
235  SCIP_CALL( SCIPsetSolVal(scip, mastersol, mastervar, roundval) );
236  SCIP_CALL( SCIPsetSolVal(origprob, origsol, origvar, roundval) );
237  mastercands[*nmastercands] = i;
238  candfracs[*nmastercands] = frac;
239  ++(*nmastercands);
240  }
241  else
242  {
243  SCIP_CALL( SCIPsetSolVal(scip, mastersol, mastervar, solval) );
244  SCIP_CALL( SCIPsetSolVal(origprob, origsol, origvar, solval) );
245  }
246  }
247 
248  /* then, treat master variables representing extreme points and rays */
249  else
250  {
251  if( !SCIPisFeasZero(scip, roundval) )
252  {
253  /* set master solution value to rounded down solution */
254  SCIP_CALL( SCIPsetSolVal(scip, mastersol, mastervar, roundval) );
255 
256  SCIPdebugMessage(" -> (block %d) select master variable %s (%d times)\n",
257  block, SCIPvarGetName(mastervar), (int) roundval);
258 
259  for( j = 0; j < norigvars; ++j )
260  {
261  SCIP_VAR* origvar;
262  SCIP_Real origval;
263 
264  /* get original variable and its value in the master variable */
265  origvar = origvars[j];
266  origval = origvals[j];
267  assert(GCGvarIsOriginal(origvar));
268 
269  /* if the variable is zero, nothing happens */
270  if( SCIPisZero(scip, origval) )
271  continue;
272 
273  /* linking variables are treated differently; if the variable already has been assigned a value,
274  * one must check whether the value for the current block is the same (otherwise, the resulting
275  * solution will be infeasible in any case) */
276  if( GCGoriginalVarIsLinking(origvar) )
277  {
278  SCIP_VAR** linkingpricingvars;
279  SCIP_Bool hasvalue;
280 
281  /* check whether linking variable has already been assigned a value */
282  linkingpricingvars = GCGlinkingVarGetPricingVars(origvar);
283  hasvalue = FALSE;
284  for( k = 0; k < nblocks; ++k )
285  if( linkingpricingvars[k] != NULL )
286  if( blocknr[k] > 0 )
287  {
288  hasvalue = TRUE;
289  break;
290  }
291 
292  /* if the linking variable has not been assigned a value yet, assign a value to
293  * the variable and the corresponding copy in the master problem */
294  if( !hasvalue )
295  {
296  SCIP_VAR* linkingmastervar;
297 
298  linkingmastervar = GCGoriginalVarGetMastervars(origvar)[0];
299  assert(linkingmastervar != NULL);
300  SCIP_CALL( SCIPsetSolVal(origprob, origsol, origvar, origval) );
301  SCIP_CALL( SCIPsetSolVal(scip, mastersol, linkingmastervar, origval) );
302  }
303  /* otherwise, exclude the current master variable, if the point has a different value for it */
304  else
305  {
306  SCIP_Real value;
307  value = SCIPgetSolVal(origprob, origsol, origvar);
308  if( !SCIPisEQ(origprob, value, origval) )
309  {
310  SCIPdebugMessage(" -> cannot use mastervar: origvar %s already has value %g in block %d, different to %g\n",
311  SCIPvarGetName(origvar), value, j, origval);
312  *success = FALSE;
313  break;
314  }
315  }
316  }
317  else
318  {
319  SCIP_VAR* pricingvar;
320  SCIP_VAR** origpricingvars;
321 #ifndef NDEBUG
322  int norigpricingvars;
323 #endif
324 
325  assert(GCGvarGetBlock(origvar) == block);
326 
327  /* get the corresponding pricing variable */
328  pricingvar = GCGoriginalVarGetPricingVar(origvar);
329  assert(pricingvar != NULL);
330  assert(GCGvarIsPricing(pricingvar));
331 
332  /* get original variables represented by origvar */
333  origpricingvars = GCGpricingVarGetOrigvars(pricingvar);
334 #ifndef NDEBUG
335  norigpricingvars = GCGpricingVarGetNOrigvars(pricingvar);
336 #endif
337 
338  /* increase the corresponding value */
339  for( k = 0; k < (int) roundval; ++k )
340  {
341  int blockidx;
342  blockidx = blocknr[block] + k;
343 #ifndef NDEBUG
344  assert(blockidx < norigpricingvars);
345 #endif
346  SCIP_CALL( SCIPincSolVal(origprob, origsol, origpricingvars[blockidx], origval) );
347  }
348  }
349  }
350 
351  /* blocks have been filled, so increase blocknr */
352  blocknr[block] += (int) roundval;
353  }
354 
355  /* if the master variable is fractional, add it as a candidate */
356  if( !SCIPisFeasFracIntegral(scip, frac) )
357  {
358  mastercands[*nmastercands] = i;
359  candfracs[*nmastercands] = frac;
360  ++(*nmastercands);
361  }
362  }
363  }
364 
365  SCIPfreeBufferArray(scip, &mastervals);
366 
367  return SCIP_OKAY;
368 }
369 
370 /** for a given block, search if there is a master variable corresponding to the zero solution;
371  * @todo it would be more efficient to "mark" master variables as being trivial */
372 static
373 SCIP_RETCODE searchZeroMastervar(
374  SCIP* scip,
375  int block,
376  SCIP_VAR** zeromastervar
377  )
378 {
379  SCIP_VAR** mastervars;
380  int nmastervars;
381 
382  int i;
383  int j;
384 
385  /* get variable data of the master problem */
386  SCIP_CALL( SCIPgetVarsData(scip, &mastervars, &nmastervars, NULL, NULL, NULL, NULL) );
387 
388  *zeromastervar = NULL;
389 
390  /* go through all master variables */
391  for( i = 0; i < nmastervars && *zeromastervar == NULL; ++i )
392  {
393  SCIP_VAR* mastervar;
394  int b;
395 
396  mastervar = mastervars[i];
397  b = GCGvarGetBlock(mastervar);
398 
399  /* only regard master variables belonging to the block we are searching for */
400  if( b == block )
401  {
402  SCIP_Real* origvals;
403  int norigvars;
404 
405  origvals = GCGmasterVarGetOrigvals(mastervar);
406  norigvars = GCGmasterVarGetNOrigvars(mastervar);
407 
408  /* check if all original variables contained in the master variable have value zero */
409  for( j = 0; j < norigvars; ++j )
410  if( !SCIPisZero(scip, origvals[j]) )
411  break;
412 
413  /* if so, we have found the right master variable */
414  if( j == norigvars )
415  *zeromastervar = mastervar;
416  }
417  }
418 
419  return SCIP_OKAY;
420 }
421 
422 /** for a given block, return the master variable corresponding to the zero solution,
423  * or NULL is there is no such variable available */
424 static
425 SCIP_RETCODE getZeroMastervar(
426  SCIP* scip,
427  SCIP_HEURDATA* heurdata,
428  int block,
429  SCIP_VAR** zeromastervar
430  )
431 {
432  /* if no zero solution is known for the block, look if a master variable has been added
433  * and remember the variable for future use */
434  if( heurdata->zerovars[block] == NULL )
435  SCIP_CALL( searchZeroMastervar(scip, block, zeromastervar) );
436  else
437  *zeromastervar = heurdata->zerovars[block];
438 
439  return SCIP_OKAY;
440 }
441 
442 
443 
444 /*
445  * Callback methods of primal heuristic
446  */
447 
448 
449 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
450 #define heurCopyRelaxcolsel NULL
451 
452 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
453 static
454 SCIP_DECL_HEURFREE(heurFreeRelaxcolsel)
455 { /*lint --e{715}*/
456  SCIP_HEURDATA* heurdata;
457 
458  assert(heur != NULL);
459  assert(scip != NULL);
460 
461  /* get heuristic data */
462  heurdata = SCIPheurGetData(heur);
463  assert(heurdata != NULL);
464 
465  /* free heuristic data */
466  SCIPfreeMemory(scip, &heurdata);
467  SCIPheurSetData(heur, NULL);
468 
469  return SCIP_OKAY;
470 }
471 
472 
473 /** initialization method of primal heuristic (called after problem was transformed) */
474 static
475 SCIP_DECL_HEURINIT(heurInitRelaxcolsel)
476 { /*lint --e{715}*/
477  SCIP* origprob;
478  SCIP_HEURDATA* heurdata;
479  int nblocks;
480 
481  int i;
482 
483  assert(heur != NULL);
484  assert(scip != NULL);
485 
486  /* get original problem */
487  origprob = GCGmasterGetOrigprob(scip);
488  assert(origprob != NULL);
489 
490  /* get heuristic's data */
491  heurdata = SCIPheurGetData(heur);
492  assert(heurdata != NULL);
493 
494  /* get number of blocks */
495  nblocks = GCGgetNPricingprobs(origprob);
496 
497  heurdata->lastncols = 0;
498 
499  /* allocate memory and initialize array with NULL pointers */
500  if( nblocks > 0 )
501  {
502  heurdata->maxzerovars = SCIPcalcMemGrowSize(scip, nblocks);
503  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &heurdata->zerovars, heurdata->maxzerovars) );
504  }
505 
506  for( i = 0; i < nblocks; ++i )
507  heurdata->zerovars[i] = NULL;
508 
509  return SCIP_OKAY;
510 }
511 
512 
513 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
514 static
515 SCIP_DECL_HEUREXIT(heurExitRelaxcolsel)
516 { /*lint --e{715}*/
517  SCIP_HEURDATA* heurdata;
518 
519  assert(heur != NULL);
520  assert(scip != NULL);
521 
522  /* get heuristic data */
523  heurdata = SCIPheurGetData(heur);
524  assert(heurdata != NULL);
525 
526  /* free memory */
527  SCIPfreeBlockMemoryArrayNull(scip, &heurdata->zerovars, heurdata->maxzerovars);
528 
529  return SCIP_OKAY;
530 }
531 
532 
533 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
534 #define heurInitsolRelaxcolsel NULL
535 
536 
537 /** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
538 #define heurExitsolRelaxcolsel NULL
539 
540 
541 /** execution method of primal heuristic */
542 static
543 SCIP_DECL_HEUREXEC(heurExecRelaxcolsel)
544 { /*lint --e{715}*/
545  SCIP* origprob; /* SCIP structure of original problem */
546  SCIP_HEURDATA* heurdata; /* heuristic's data */
547  SCIP_SOL* mastersol; /* working master solution */
548  SCIP_SOL* origsol; /* working original solution */
549  SCIP_VAR** mastervars;
550  SCIP_Real* candfracs; /* fractionalities of candidate variables */
551  int* blocknr; /* for each pricing problem, block we are currently working in */
552  int* mastercands; /* master variables which are considered first for rounding up */
553  SCIP_Bool allblocksfull; /* indicates if all blocks are full, i.e. all convexity constraints are satisfied */
554  SCIP_Bool masterfeas;
555  SCIP_Bool success;
556  int minnewcols; /* minimum number of new columns necessary for calling the heuristic */
557  int nmastervars;
558  int nmastercands;
559  int nblocks;
560 
561  int i;
562  int j;
563  int k;
564 
565  assert(heur != NULL);
566  assert(scip != NULL);
567  assert(result != NULL);
568 
569  /* get original problem */
570  origprob = GCGmasterGetOrigprob(scip);
571  assert(origprob != NULL);
572 
573  /* get heuristic's data */
574  heurdata = SCIPheurGetData(heur);
575  assert(heurdata != NULL);
576 
577  *result = SCIP_DELAYED;
578 
579  /* only call heuristic, if an optimal relaxation solution is at hand */
580  if( SCIPgetStage(scip) > SCIP_STAGE_SOLVING || SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
581  return SCIP_OKAY;
582 
583  assert(SCIPhasCurrentNodeLP(scip));
584 
585  /* get variable data of the master problem */
586  SCIP_CALL( SCIPgetVarsData(scip, &mastervars, &nmastervars, NULL, NULL, NULL, NULL) );
587  assert(mastervars != NULL);
588  assert(nmastervars >= 0);
589 
590  /* calculate minimum number of new columns necessary for calling the heuristic;
591  * this number is influenced by how successful the heuristic was in the past */
592  minnewcols = heurdata->mincolumns * (int) (1.0 * ((1.0 + SCIPheurGetNCalls(heur)) / (1.0 + SCIPheurGetNBestSolsFound(heur))));
593 
594  /* if there are not enough new columns since last call, abort heuristic */
595  if( nmastervars - heurdata->lastncols < minnewcols )
596  return SCIP_OKAY;
597 
598  *result = SCIP_DIDNOTFIND;
599 
600  SCIPdebugMessage("Executing Relaxation Based Column Selection heuristic (nmastervars = %d) ...\n", nmastervars);
601 
602  /* get number of blocks */
603  nblocks = GCGgetNPricingprobs(origprob);
604  assert(nblocks >= 0);
605 
606  /* allocate memory and create working solutions */
607  SCIP_CALL( SCIPcreateSol(scip, &mastersol, heur) );
608  SCIP_CALL( SCIPcreateSol(origprob, &origsol, heur) );
609  SCIP_CALL( SCIPallocBufferArray(scip, &blocknr, nblocks) );
610  SCIP_CALL( SCIPallocBufferArray(scip, &mastercands, nmastervars) );
611  SCIP_CALL( SCIPallocBufferArray(scip, &candfracs, nmastervars) );
612 
613  /* initialize the block information */
614  BMSclearMemoryArray(blocknr, nblocks);
615  BMSclearMemoryArray(candfracs, nmastervars);
616  allblocksfull = FALSE;
617 
618  /* initialize empty candidate list */
619  for( i = 0; i < nmastervars; ++i )
620  mastercands[i] = -1;
621 
622  /* initialize working original solution as transformation of rounded down master LP solution
623  * and get the candidate master variables for rounding up */
624  SCIPdebugMessage("initializing starting solution...\n");
625  SCIP_CALL( initializeStartsol(scip, mastersol, origsol, blocknr,
626  mastercands, candfracs, &nmastercands, &success) );
627 
628  if( !success )
629  {
630  SCIPdebugMessage(" -> not successful.\n");
631  goto TERMINATE;
632  }
633 
634  masterfeas = FALSE;
635  success = FALSE;
636 
637  SCIPdebugMessage("trying to round up...\n");
638 
639  /* first, loop over all candidates for rounding up */
640  while( !allblocksfull && !success )
641  {
642  SCIP_VAR* mastervar;
643  int candidx;
644  SCIP_Real frac;
645  SCIP_Bool compatible;
646 
647  SCIP_VAR** origvars;
648  SCIP_Real* origvals;
649  int norigvars;
650  int block;
651 
652  /* search the candidate list for a master variable that can be rounded up;
653  * take the variable with the highest fractionality */
654  mastervar = NULL;
655  candidx = -1;
656  frac = 0.0;
657  compatible = TRUE;
658  for( i = 0; i < nmastercands; ++i )
659  {
660  int idx;
661  SCIP_Real tmpfrac;
662 
663  idx = mastercands[i];
664  tmpfrac = candfracs[i];
665  if( idx != -1 && SCIPisFeasGT(scip, tmpfrac, frac) )
666  {
667  SCIP_VAR* tmpvar;
668 
669  tmpvar = mastervars[idx];
670  block = GCGvarGetBlock(tmpvar);
671 
672  /* consider only variables whose block is not already full
673  * or copied master variables */
674  if( block == -1 || blocknr[block] < GCGgetNIdenticalBlocks(origprob, block) )
675  {
676  mastervar = tmpvar;
677  candidx = i;
678  frac = tmpfrac;
679  }
680  }
681  }
682 
683  /* if no variable could be found, abort */
684  if( candidx == -1 )
685  {
686  assert(mastervar == NULL);
687  break;
688  }
689 
690  /* remove the chosen variable from the candidate list */
691  assert(candidx >= 0 && candidx < nmastercands);
692  mastercands[candidx] = -1;
693  candfracs[candidx] = 0.0;
694 
695  assert(mastervar != NULL);
696  block = GCGvarGetBlock(mastervar);
697 
698  SCIPdebugMessage(" -> (block %d) selected master variable %s; frac=%g\n",
699  block, SCIPvarGetName(mastervar), frac);
700 
701  /* get original variables */
702  origvars = GCGmasterVarGetOrigvars(mastervar);
703  origvals = GCGmasterVarGetOrigvals(mastervar);
704  norigvars = GCGmasterVarGetNOrigvars(mastervar);
705 
706  /* increase master value by one and increase solution values in current original solution accordingly */
707  SCIP_CALL( SCIPincSolVal(scip, mastersol, mastervar, 1.0) );
708 
709  /* update original solution accordingly
710  * first, treat variables directly transferred to the master problem (but not linking variables) */
711  if( block == -1 )
712  {
713  SCIP_VAR* origvar;
714 #ifndef NDEBUG
715  int origblock;
716 #endif
717 
718  /* get original variable and the block it belongs to;
719  * the variable should not be a linking variable
720  * as those have not been added to the candidate list */
721  assert(norigvars == 1);
722  origvar = origvars[0];
723  assert(GCGvarIsOriginal(origvar));
724  assert(origvals[0] == 1.0);
725 #ifndef NDEBUG
726  origblock = GCGvarGetBlock(origvar);
727  assert(origblock == -1);
728 #endif
729 
730  /* set solution value to rounded up value */
731  SCIP_CALL( SCIPincSolVal(origprob, origsol, origvar, 1.0) );
732  }
733 
734  /* then, treat master variables representing extreme points and rays */
735  else
736  {
737  for( i = 0; i < norigvars; ++i )
738  {
739  SCIP_VAR* origvar;
740  SCIP_Real origval;
741 
742  origvar = origvars[i];
743  origval = origvals[i];
744 
745  assert(GCGvarIsOriginal(origvar));
746 
747  /* linking variables are treated differently; if the variable already has been assigned a value,
748  * one must check whether the value for the current block is the same (otherwise, the resulting
749  * solution will be infeasible in any case) */
750  if( GCGoriginalVarIsLinking(origvar) )
751  {
752  SCIP_VAR** linkingpricingvars;
753  SCIP_Bool hasvalue;
754 
755  /* check whether linking variable has already been assigned a value */
756  linkingpricingvars = GCGlinkingVarGetPricingVars(origvar);
757  hasvalue = FALSE;
758  for( j = 0; j < nblocks; ++j )
759  if( linkingpricingvars[j] != NULL )
760  if( blocknr[j] > 0 )
761  {
762  hasvalue = TRUE;
763  break;
764  }
765 
766  /* if the linking variable has not been assigned a value yet, assign a value to
767  * the variable and the corresponding copy in the master problem */
768  if( !hasvalue )
769  {
770  SCIP_VAR* linkingmastervar;
771 
772  linkingmastervar = GCGoriginalVarGetMastervars(origvar)[0];
773  assert(linkingmastervar != NULL);
774  SCIP_CALL( SCIPincSolVal(origprob, origsol, origvar, origval) );
775  SCIP_CALL( SCIPincSolVal(scip, mastersol, linkingmastervar, origval) );
776  }
777  /* otherwise do not take this variable */
778  else
779  {
780  SCIP_Real value;
781  value = SCIPgetSolVal(origprob, origsol, origvar);
782  if( !SCIPisEQ(origprob, value, origval) )
783  {
784  SCIPdebugMessage(" -> cannot use mastervar: origvar %s already has value %g in block %d, different to %g\n",
785  SCIPvarGetName(origvar), value, j, origval);
786  compatible = FALSE;
787  break;
788  }
789  }
790  }
791  else
792  {
793  SCIP_VAR* pricingvar;
794  SCIP_VAR** origpricingvars;
795 #ifndef NDEBUG
796  int norigpricingvars;
797 #endif
798 
799  /* if the variable is zero, nothing happens */
800  if( SCIPisZero(scip, origval) )
801  continue;
802 
803  pricingvar = GCGoriginalVarGetPricingVar(origvar);
804  assert(pricingvar != NULL);
805  assert(GCGvarIsPricing(pricingvar));
806 
807  origpricingvars = GCGpricingVarGetOrigvars(pricingvar);
808 
809 #ifndef NDEBUG
810  norigpricingvars = GCGpricingVarGetNOrigvars(pricingvar);
811  assert(blocknr[block] < norigpricingvars);
812 #endif
813 
814  /* increase the corresponding value */
815  SCIP_CALL( SCIPincSolVal(origprob, origsol, origpricingvars[blocknr[block]], origval) );
816  }
817  }
818 
819  /* if the current master variable cannot be selected (due to conflicting linking variables),
820  * reset solution values and choose a new one */
821  if( !compatible )
822  {
823  SCIP_CALL( SCIPincSolVal(scip, mastersol, mastervar, -1.0) );
824  for( k = 0; k < i; ++k )
825  {
826  SCIP_VAR* origvar;
827  SCIP_Real origval;
828 
829  origvar = origvars[k];
830  origval = origvals[k];
831 
832  if( GCGoriginalVarIsLinking(origvar) )
833  {
834  SCIP_VAR** linkingpricingvars;
835  SCIP_Bool hasvalue;
836 
837  /* check whether linking variable has already been assigned a value */
838  linkingpricingvars = GCGlinkingVarGetPricingVars(origvar);
839  hasvalue = FALSE;
840  for( j = 0; j < nblocks; ++j )
841  if( linkingpricingvars[j] != NULL )
842  if( blocknr[j] > 0 && j != block )
843  {
844  hasvalue = TRUE;
845  break;
846  }
847 
848  /* if the linking variable has not had a value before, set it back to zero */
849  if( !hasvalue )
850  {
851  SCIP_VAR* linkingmastervar;
852 
853  linkingmastervar = GCGoriginalVarGetMastervars(origvar)[0];
854  SCIP_CALL( SCIPincSolVal(origprob, origsol, origvar, -origval) );
855  SCIP_CALL( SCIPincSolVal(scip, mastersol, linkingmastervar, -origval) );
856  }
857  }
858  else
859  {
860  SCIP_VAR* pricingvar;
861  SCIP_VAR** origpricingvars;
862 #ifndef NDEBUG
863  int norigpricingvars;
864 #endif
865 
866  pricingvar = GCGoriginalVarGetPricingVar(origvar);
867  assert(pricingvar != NULL);
868  assert(GCGvarIsPricing(pricingvar));
869 
870  origpricingvars = GCGpricingVarGetOrigvars(pricingvar);
871 
872 #ifndef NDEBUG
873  norigpricingvars = GCGpricingVarGetNOrigvars(pricingvar);
874  assert(blocknr[block] < norigpricingvars);
875 #endif
876 
877  /* decrease the corresponding value */
878  SCIP_CALL( SCIPincSolVal(origprob, origsol, origpricingvars[blocknr[block]], -origval) );
879  }
880  }
881  continue;
882  }
883 
884  blocknr[block]++;
885  }
886 
887  /* try to add the solution to (original) solution pool */
888  SCIP_CALL( SCIPtrySol(origprob, origsol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
889 
890  /* check if all blocks are full */
891  allblocksfull = TRUE;
892  for( i = 0; i < nblocks && allblocksfull; ++i )
893  {
894  int nidentblocks;
895 
896  nidentblocks = GCGgetNIdenticalBlocks(origprob, i);
897 
898  /* in case the solution is feasible but the block is not full,
899  * we need a zero solution for this block in order to generate
900  * a corresponding master solution */
901  if( success && blocknr[i] < nidentblocks )
902  {
903  SCIP_VAR* zeromastervar;
904 
905  /* fill the block with the zero solution */
906  zeromastervar = NULL;
907  SCIP_CALL( getZeroMastervar(scip, heurdata, i, &zeromastervar) );
908  if( zeromastervar != NULL )
909  {
910  SCIPdebugMessage(" -> (block %d) selected zero master variable %s (%d times)\n",
911  i, SCIPvarGetName(zeromastervar), nidentblocks - blocknr[i]);
912 
913  SCIP_CALL( SCIPincSolVal(scip, mastersol, zeromastervar,
914  (SCIP_Real) nidentblocks - blocknr[i]) );
915  blocknr[i] = nidentblocks;
916  }
917  }
918 
919  /** @todo >= should not happen, replace it by == ? */
920  if( !(blocknr[i] >= nidentblocks) )
921  allblocksfull = FALSE;
922  }
923 
924  /* if we found a solution for the original instance,
925  * also add the corresponding master solution */
926  if( success && allblocksfull )
927  {
928 #ifdef SCIP_DEBUG
929  SCIP_CALL( SCIPtrySol(scip, mastersol, TRUE, TRUE, TRUE, TRUE, TRUE, &masterfeas) );
930 #else
931  SCIP_CALL( SCIPtrySol(scip, mastersol, FALSE, FALSE, TRUE, TRUE, TRUE, &masterfeas) );
932 #endif
933  if( !masterfeas )
934  {
935  SCIPdebugMessage("WARNING: original solution feasible, but no solution has been added to master problem.\n");
936  }
937  }
938  }
939 
940  if( success )
941  {
942  *result = SCIP_FOUNDSOL;
943  SCIPdebugMessage(" -> heuristic successful - feasible solution found.\n");
944  }
945  else
946  {
947  SCIPdebugMessage(" -> no feasible solution found.\n");
948  }
949 
950 TERMINATE:
951  SCIP_CALL( SCIPfreeSol(origprob, &origsol) );
952  SCIP_CALL( SCIPfreeSol(scip, &mastersol) );
953  SCIPfreeBufferArray(scip, &candfracs);
954  SCIPfreeBufferArray(scip, &mastercands);
955  SCIPfreeBufferArray(scip, &blocknr);
956 
957  heurdata->lastncols = nmastervars;
958 
959  return SCIP_OKAY;
960 }
961 
962 
963 
964 
965 /*
966  * primal heuristic specific interface methods
967  */
968 
969 /** creates the relaxation based column selection primal heuristic and includes it in SCIP */
971  SCIP* scip /**< SCIP data structure */
972  )
973 {
974  SCIP_HEURDATA* heurdata;
975 
976  /* create relaxation based column selection primal heuristic data */
977  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
978  heurdata->zerovars = NULL;
979  heurdata->maxzerovars = 0;
980 
981  /* include primal heuristic */
982  SCIP_CALL( SCIPincludeHeur(scip, HEUR_NAME, HEUR_DESC, HEUR_DISPCHAR, HEUR_PRIORITY, HEUR_FREQ, HEUR_FREQOFS,
984  heurCopyRelaxcolsel, heurFreeRelaxcolsel, heurInitRelaxcolsel, heurExitRelaxcolsel,
985  heurInitsolRelaxcolsel, heurExitsolRelaxcolsel, heurExecRelaxcolsel,
986  heurdata) );
987 
988  /* add relaxation based column selection primal heuristic parameters */
989  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/relaxcolsel/mincolumns",
990  "minimum number of columns to regard in the master problem",
991  &heurdata->mincolumns, FALSE, DEFAULT_MINCOLUMNS, 1, INT_MAX, NULL, NULL) );
992 
993  return SCIP_OKAY;
994 }
#define HEUR_MAXDEPTH
SCIP_VAR ** zerovars
int GCGmasterVarGetNOrigvars(SCIP_VAR *var)
Definition: gcgvar.c:886
GCG interface methods.
SCIP_Bool GCGvarIsMaster(SCIP_VAR *var)
Definition: gcgvar.c:150
#define heurExitsolRelaxcolsel
#define HEUR_DISPCHAR
SCIP_VAR ** GCGoriginalVarGetMastervars(SCIP_VAR *var)
Definition: gcgvar.c:587
SCIP_VAR ** GCGmasterVarGetOrigvars(SCIP_VAR *var)
Definition: gcgvar.c:908
SCIP_Real * GCGmasterVarGetOrigvals(SCIP_VAR *var)
Definition: gcgvar.c:932
int GCGvarGetBlock(SCIP_VAR *var)
Definition: gcgvar.c:1033
SCIP_Bool GCGvarIsPricing(SCIP_VAR *var)
Definition: gcgvar.c:134
#define HEUR_NAME
#define heurCopyRelaxcolsel
SCIP_VAR * GCGoriginalVarGetPricingVar(SCIP_VAR *var)
Definition: gcgvar.c:216
int GCGgetNPricingprobs(SCIP *scip)
Definition: relax_gcg.c:3979
static SCIP_RETCODE searchZeroMastervar(SCIP *scip, int block, SCIP_VAR **zeromastervar)
SCIP_Bool GCGvarIsOriginal(SCIP_VAR *var)
Definition: gcgvar.c:166
GCG variable pricer.
#define HEUR_PRIORITY
static SCIP_DECL_HEURFREE(heurFreeRelaxcolsel)
static SCIP_RETCODE initializeStartsol(SCIP *scip, SCIP_SOL *mastersol, SCIP_SOL *origsol, int *blocknr, int *mastercands, SCIP_Real *candfracs, int *nmastercands, SCIP_Bool *success)
SCIP_RETCODE SCIPincludeHeurRelaxcolsel(SCIP *scip)
static SCIP_DECL_HEUREXIT(heurExitRelaxcolsel)
int GCGpricingVarGetNOrigvars(SCIP_VAR *var)
Definition: gcgvar.c:997
#define HEUR_USESSUBSCIP
relaxation based column selection primal heuristic
int GCGgetNIdenticalBlocks(SCIP *scip, int pricingprobnr)
Definition: relax_gcg.c:4053
#define DEFAULT_MINCOLUMNS
static SCIP_DECL_HEUREXEC(heurExecRelaxcolsel)
SCIP * GCGmasterGetOrigprob(SCIP *scip)
#define HEUR_DESC
#define HEUR_FREQ
#define heurInitsolRelaxcolsel
#define HEUR_FREQOFS
SCIP_VAR ** GCGpricingVarGetOrigvars(SCIP_VAR *var)
Definition: gcgvar.c:1015
SCIP_Bool GCGmasterVarIsArtificial(SCIP_VAR *var)
Definition: gcgvar.c:869
static SCIP_RETCODE getZeroMastervar(SCIP *scip, SCIP_HEURDATA *heurdata, int block, SCIP_VAR **zeromastervar)
SCIP_Bool GCGmasterVarIsRay(SCIP_VAR *var)
Definition: gcgvar.c:852
static SCIP_DECL_HEURINIT(heurInitRelaxcolsel)
#define HEUR_TIMING
SCIP_Bool GCGoriginalVarIsLinking(SCIP_VAR *var)
Definition: gcgvar.c:182
SCIP_VAR ** GCGlinkingVarGetPricingVars(SCIP_VAR *var)
Definition: gcgvar.c:409