Scippy

GCG

Branch-and-Price & Column Generation for Everyone

dec_varclass.cpp
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 dec_varclass.cpp
29  * @ingroup DETECTORS
30  * @brief detector varclass
31  * @author Julius Hense
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include "dec_varclass.h"
37 #include "cons_decomp.h"
38 #include "class_partialdecomp.h"
39 #include "class_detprobdata.h"
40 #include "class_varpartition.h"
41 #include "gcg.h"
42 #include "scip/cons_setppc.h"
43 #include "scip/scip.h"
44 #include "scip_misc.h"
45 #include "scip/clock.h"
46 
47 #include <sstream>
48 
49 #include <iostream>
50 #include <algorithm>
51 
52 /* constraint handler properties */
53 #define DEC_DETECTORNAME "varclass" /**< name of detector */
54 #define DEC_DESC "detector varclass" /**< description of detector*/
55 #define DEC_FREQCALLROUND 1 /**< frequency the detector gets called in detection loop ,ie it is called in round r if and only if minCallRound <= r <= maxCallRound AND (r - minCallRound) mod freqCallRound == 0 */
56 #define DEC_MAXCALLROUND 0 /**< last round the detector gets called */
57 #define DEC_MINCALLROUND 0 /**< first round the detector gets called */
58 #define DEC_FREQCALLROUNDORIGINAL 1 /**< frequency the detector gets called in detection loop while detecting the original problem */
59 #define DEC_MAXCALLROUNDORIGINAL INT_MAX /**< last round the detector gets called while detecting the original problem */
60 #define DEC_MINCALLROUNDORIGINAL 0 /**< first round the detector gets called while detecting the original problem */
61 #define DEC_PRIORITY 0 /**< priority of the constraint handler for separation */
62 #define DEC_DECCHAR 'v' /**< display character of detector */
63 #define DEC_ENABLED TRUE /**< should the detection be enabled */
64 #define DEC_ENABLEDFINISHING FALSE /**< should the finishing be enabled */
65 #define DEC_ENABLEDPOSTPROCESSING FALSE /**< should the postprocessing be enabled */
66 #define DEC_SKIP FALSE /**< should detector be skipped if other detectors found decompositions */
67 #define DEC_USEFULRECALL FALSE /**< is it useful to call this detector on a descendant of the propagated partialdec */
68 
69 #define DEFAULT_MAXIMUMNCLASSES 8
70 #define AGGRESSIVE_MAXIMUMNCLASSES 10
71 #define FAST_MAXIMUMNCLASSES 6
72 
73 #define SET_MULTIPLEFORSIZETRANSF 12500
74 
75 /*
76  * Data structures
77  */
78 
79 /** @todo fill in the necessary detector data */
80 
81 /** detector handler data */
82 struct DEC_DetectorData
83 {
84 };
85 
86 /*
87  * Local methods
88  */
89 
90 /* put your local methods here, and declare them static */
91 
92 /*
93  * detector callback methods
94  */
95 
96 /** destructor of detector to free user data (called when GCG is exiting) */
97 #define freeVarclass NULL
98 
99 /** destructor of detector to free detector data (called before the solving process begins) */
100 #define exitVarclass NULL
101 
102 /** detection initialization function of detector (called before solving is about to begin) */
103 #define initVarclass NULL
104 
105 #define finishPartialdecVarclass NULL
106 
107 static DEC_DECL_PROPAGATEPARTIALDEC(propagatePartialdecVarclass)
108 {
109  *result = SCIP_DIDNOTFIND;
110  char decinfo[SCIP_MAXSTRLEN];
111 
112  SCIP_CLOCK* temporaryClock;
113 
114  if (partialdecdetectiondata->workonpartialdec->getNOpenconss() != partialdecdetectiondata->detprobdata->getNConss() || partialdecdetectiondata->workonpartialdec->getNOpenvars() != partialdecdetectiondata->detprobdata->getNVars() )
115  {
116  *result = SCIP_SUCCESS;
117  return SCIP_OKAY;
118  }
119 
120  SCIP_CALL_ABORT( SCIPcreateClock(scip, &temporaryClock) );
121  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
122 
123  std::vector<gcg::PARTIALDECOMP*> foundpartialdecs(0);
124 
125  gcg::PARTIALDECOMP* partialdecOrig;
126  gcg::PARTIALDECOMP* partialdec;
127 
128  int maximumnclasses;
129 
130  if( partialdecdetectiondata->detprobdata->getNConss() + partialdecdetectiondata->detprobdata->getNVars() >= 50000 )
131  SCIPgetIntParam(scip, "detection/classification/maxnclassesperpartitionforlargeprobs", &maximumnclasses);
132  else
133  SCIPgetIntParam(scip, "detection/classification/maxnclassesperpartition", &maximumnclasses);
134 
135  for( int classifierIndex = 0; classifierIndex < partialdecdetectiondata->detprobdata->getNVarPartitions(); ++classifierIndex )
136  {
137  gcg::VarPartition* classifier = partialdecdetectiondata->detprobdata->getVarPartition(classifierIndex);
138  std::vector<int> varclassindices_master = std::vector<int>(0);
139  std::vector<int> varclassindices_linking = std::vector<int>(0);
140 
141  if ( classifier->getNClasses() > maximumnclasses )
142  {
143  std::cout << " the current varclass distribution includes " << classifier->getNClasses() << " classes but only " << maximumnclasses << " are allowed for propagatePartialdec() of var class detector" << std::endl;
144  continue;
145  }
146 
147  partialdecOrig = partialdecdetectiondata->workonpartialdec;
148 
149  for( int i = 0; i < classifier->getNClasses(); ++ i )
150  {
151  switch( classifier->getClassDecompInfo(i) )
152  {
153  case gcg::ALL:
154  break;
155  case gcg::LINKING:
156  varclassindices_linking.push_back(i);
157  break;
158  case gcg::MASTER:
159  varclassindices_master.push_back(i);
160  break;
161  case gcg::BLOCK:
162  break;
163  }
164  }
165 
166  std::vector< std::vector<int> > subsetsOfVarclasses = classifier->getAllSubsets( true, false, false, false );
167 
168  for( auto& subset : subsetsOfVarclasses )
169  {
170  if( subset.empty() && varclassindices_master.empty() && varclassindices_linking.empty() )
171  continue;
172 
173  partialdec = new gcg::PARTIALDECOMP(partialdecOrig);
174 
175  /* fix open vars that have a) type of the current subset or b) decomp info LINKING as linking vars */
176  auto& openvars = partialdec->getOpenvarsVec();
177  for( auto itr = openvars.cbegin(); itr != openvars.cend(); )
178  {
179  bool foundVar = false;
180  for( int varclassId : subset )
181  {
182  if( classifier->getClassOfVar(*itr) == varclassId )
183  {
184  itr = partialdec->fixVarToLinking(itr);
185  foundVar = true;
186  break;
187  }
188  }
189  /* only check varclassindices_linking if current var has not already been found in a subset */
190  if ( !foundVar )
191  {
192  for( int varclassId : varclassindices_linking )
193  {
194  if( classifier->getClassOfVar(*itr) == varclassId )
195  {
196  itr = partialdec->fixVarToLinking(itr);
197  foundVar = true;
198  break;
199  }
200  }
201  }
202  /* only check varclassindices_master if current var has not already been found in a subset */
203  if ( !foundVar )
204  {
205  for( int varclassId : varclassindices_master )
206  {
207  if( classifier->getClassOfVar(*itr) == varclassId )
208  {
209  itr = partialdec->fixVarToMaster(itr);
210  foundVar = true;
211  break;
212  }
213  }
214  }
215  if( !foundVar )
216  {
217  ++itr;
218  }
219  }
220 
221  /* set decinfo to: varclass_<classfier_name>:<linking_class_name#1>-...-<linking_class_name#n> */
222  std::stringstream decdesc;
223  decdesc << "varclass" << "\\_" << classifier->getName() << ": \\\\ ";
224  std::vector<int> curlinkingclasses( varclassindices_linking );
225  for ( size_t varclassId = 0; varclassId < subset.size(); ++varclassId )
226  {
227  if ( varclassId > 0 )
228  {
229  decdesc << "-";
230  }
231  decdesc << classifier->getClassName(subset[varclassId]);
232 
233  if( std::find( varclassindices_linking.begin(), varclassindices_linking.end(),
234  subset[varclassId] ) == varclassindices_linking.end() )
235  {
236  curlinkingclasses.push_back(subset[varclassId]);
237  }
238  }
239  for( int varclassId : varclassindices_linking )
240  {
241  if( varclassId > 0 || !subset.empty() )
242  {
243  decdesc << "-";
244  }
245  decdesc << classifier->getClassName(varclassId);
246  }
247 
248  partialdec->sort();
249  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, decdesc.str().c_str());
250  partialdec->addDetectorChainInfo(decinfo);
251  partialdec->setVarPartitionStatistics(partialdec->getNDetectors(), classifier, curlinkingclasses,
252  varclassindices_master);
253 
254  foundpartialdecs.push_back(partialdec);
255  }
256  }
257 
258  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
259 
260  partialdecdetectiondata->detectiontime = SCIPgetClockTime(scip, temporaryClock);
261  SCIP_CALL( SCIPallocMemoryArray(scip, &(partialdecdetectiondata->newpartialdecs), foundpartialdecs.size()) );
262  partialdecdetectiondata->nnewpartialdecs = foundpartialdecs.size();
263 
264  for( int s = 0; s < partialdecdetectiondata->nnewpartialdecs; ++s )
265  {
266  partialdecdetectiondata->newpartialdecs[s] = foundpartialdecs[s];
267  partialdecdetectiondata->newpartialdecs[s]->addClockTime(partialdecdetectiondata->detectiontime / partialdecdetectiondata->nnewpartialdecs);
268  }
269 
270  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
271 
272  *result = SCIP_SUCCESS;
273 
274  return SCIP_OKAY;
275 }
276 
277 
278 #define detectorPostprocessPartialdecVarclass NULL
279 
280 static
281 DEC_DECL_SETPARAMAGGRESSIVE(setParamAggressiveVarclass)
282 {
283  char setstr[SCIP_MAXSTRLEN];
284  SCIP_Real modifier;
285 
286  int newval;
287  const char* name = DECdetectorGetName(detector);
288 
289  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
290  SCIP_CALL( SCIPsetBoolParam(scip, setstr, TRUE) );
291 
292  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
293  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE ) );
294 
295  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
296  return SCIP_OKAY;
297 
298  modifier = ((SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
299  modifier = log(modifier) / log(2.);
300 
301  if (!SCIPisFeasPositive(scip, modifier) )
302  modifier = -1.;
303 
304  modifier = SCIPfloor(scip, modifier);
305 
306  newval = MAX( 2, AGGRESSIVE_MAXIMUMNCLASSES - modifier );
307  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
308 
309  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
310  SCIPverbMessage(scip, SCIP_VERBLEVEL_DIALOG, NULL, "\n%s = %d\n", setstr, newval);
311 
312  return SCIP_OKAY;
313 }
314 
315 
316 static
317 DEC_DECL_SETPARAMDEFAULT(setParamDefaultVarclass)
318 {
319  char setstr[SCIP_MAXSTRLEN];
320  SCIP_Real modifier;
321 
322  int newval;
323  const char* name = DECdetectorGetName(detector);
324 
325  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
326  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLED) );
327 
328  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
329  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLEDFINISHING ) );
330 
331  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
332  return SCIP_OKAY;
333 
334  modifier = ( (SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
335  modifier = log(modifier) / log(2);
336 
337  if (!SCIPisFeasPositive(scip, modifier) )
338  modifier = -1.;
339 
340  modifier = SCIPfloor(scip, modifier);
341 
342  newval = MAX( 2, DEFAULT_MAXIMUMNCLASSES - modifier );
343  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
344 
345  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
346  SCIPverbMessage(scip, SCIP_VERBLEVEL_DIALOG, NULL, "\n%s = %d\n", setstr, newval);
347 
348  return SCIP_OKAY;
349 
350 }
351 
352 static
353 DEC_DECL_SETPARAMFAST(setParamFastVarclass)
354 {
355  char setstr[SCIP_MAXSTRLEN];
356  SCIP_Real modifier;
357  int newval;
358 
359  const char* name = DECdetectorGetName(detector);
360 
361  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
362  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE) );
363 
364  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
365  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE ) );
366 
367  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
368  return SCIP_OKAY;
369 
370  modifier = ( (SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
371 
372  modifier = log(modifier) / log(2);
373 
374  if (!SCIPisFeasPositive(scip, modifier) )
375  modifier = -1.;
376 
377  modifier = SCIPfloor(scip, modifier);
378 
379  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
380 
381  newval = MAX( 2, FAST_MAXIMUMNCLASSES - modifier );
382 
383  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
384  SCIPverbMessage(scip, SCIP_VERBLEVEL_DIALOG, NULL, "\n%s = %d\n", setstr, newval);
385 
386  return SCIP_OKAY;
387 }
388 
389 
390 
391 /*
392  * detector specific interface methods
393  */
394 
395 /** creates the handler for varclass detector and includes it in SCIP */
396 SCIP_RETCODE SCIPincludeDetectorVarclass(SCIP* scip /**< SCIP data structure */
397 )
398 {
399  DEC_DETECTORDATA* detectordata;
400  char setstr[SCIP_MAXSTRLEN];
401 
402  /**@todo create varclass detector data here*/
403  detectordata = NULL;
404 
405  SCIP_CALL(
408  freeVarclass, initVarclass, exitVarclass, propagatePartialdecVarclass, finishPartialdecVarclass, detectorPostprocessPartialdecVarclass, setParamAggressiveVarclass, setParamDefaultVarclass, setParamFastVarclass));
409 
410  /**@todo add varclass detector parameters */
411 
412  const char* name = DEC_DETECTORNAME;
413  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
414  SCIP_CALL( SCIPaddIntParam(scip, setstr, "maximum number of classes ", NULL, FALSE, DEFAULT_MAXIMUMNCLASSES, 1, INT_MAX, NULL, NULL ) );
415 
416  return SCIP_OKAY;
417 }
#define FAST_MAXIMUMNCLASSES
const char * DECdetectorGetName(DEC_DETECTOR *detector)
returns the name of the provided detector
#define DEC_MINCALLROUNDORIGINAL
#define DEC_DETECTORNAME
GCG interface methods.
void fixVarToMaster(int var)
adds a variable to the master variables
std::vector< int > & getOpenvarsVec()
class representing a partition of a set of variables
void addDetectorChainInfo(const char *decinfo)
add information about the detector chain
#define DEC_ENABLEDPOSTPROCESSING
int getClassOfVar(int varindex)
#define initVarclass
#define DEC_ENABLED
#define DEC_DECCHAR
constraint handler for structure detection
#define AGGRESSIVE_MAXIMUMNCLASSES
void fixVarToLinking(int var)
adds a variable to the linking variables
static DEC_DECL_SETPARAMDEFAULT(setParamDefaultVarclass)
#define DEFAULT_MAXIMUMNCLASSES
various SCIP helper methods
#define DEC_MINCALLROUND
const char * getClassName(int classindex)
#define detectorPostprocessPartialdecVarclass
#define DEC_FREQCALLROUND
#define DEC_SKIP
#define finishPartialdecVarclass
#define DEC_FREQCALLROUNDORIGINAL
bool sort()
sorts the vars and conss data structures by their indices
#define DEC_DESC
#define SET_MULTIPLEFORSIZETRANSF
#define DEC_USEFULRECALL
#define DEC_ENABLEDFINISHING
static DEC_DECL_SETPARAMAGGRESSIVE(setParamAggressiveVarclass)
static DEC_DECL_SETPARAMFAST(setParamFastVarclass)
int getNDetectors()
Gets the number of detectors the partialdec is propagated by.
#define DEC_MAXCALLROUNDORIGINAL
class to manage partial decompositions
std::vector< std::vector< int > > getAllSubsets(bool all, bool linking, bool master, bool block)
struct gcg::subset subset
void setVarPartitionStatistics(int detectorchainindex, VarPartition *partition, std::vector< int > &varclasseslinking, std::vector< int > &varclassesmaster)
registers statistics for a used varpartition
SCIP_RETCODE DECincludeDetector(SCIP *scip, const char *name, const char decchar, const char *description, int freqCallRound, int maxCallRound, int minCallRound, int freqCallRoundOriginal, int maxCallRoundOriginal, int minCallRoundOriginal, int priority, SCIP_Bool enabled, SCIP_Bool enabledFinishing, SCIP_Bool enabledPostprocessing, SCIP_Bool skip, SCIP_Bool usefulRecall, DEC_DETECTORDATA *detectordata, DEC_DECL_FREEDETECTOR((*freeDetector)), DEC_DECL_INITDETECTOR((*initDetector)), DEC_DECL_EXITDETECTOR((*exitDetector)), DEC_DECL_PROPAGATEPARTIALDEC((*propagatePartialdecDetector)), DEC_DECL_FINISHPARTIALDEC((*finishPartialdecDetector)), DEC_DECL_POSTPROCESSPARTIALDEC((*postprocessPartialdecDetector)), DEC_DECL_SETPARAMAGGRESSIVE((*setParamAggressiveDetector)), DEC_DECL_SETPARAMDEFAULT((*setParamDefaultDetector)),)
varclass detector
#define exitVarclass
SCIP_RETCODE SCIPincludeDetectorVarclass(SCIP *scip)
static DEC_DECL_PROPAGATEPARTIALDEC(propagatePartialdecVarclass)
class storing (potentially incomplete) decompositions
#define DEC_MAXCALLROUND
VAR_DECOMPINFO getClassDecompInfo(int classindex)
#define freeVarclass
class storing partialdecs and the problem matrix
#define DEC_PRIORITY