Scippy

GCG

Branch-and-Price & Column Generation for Everyone

dec_consclass.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_consclass.cpp
29  * @ingroup DETECTORS
30  * @brief detector consclass (put your description here)
31  * @author Michael Bastubbe
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include "dec_consclass.h"
37 #include "cons_decomp.h"
38 #include "class_partialdecomp.h"
39 #include "class_detprobdata.h"
40 #include "class_conspartition.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 "consclass" /**< name of detector */
54 #define DEC_DESC "detector consclass" /**< 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 'c' /**< display character of detector */
63 #define DEC_ENABLED TRUE /**< should the detection be enabled */
64 #define DEC_ENABLEDFINISHING FALSE /**< should the detection be enabled */
65 #define DEC_ENABLEDPOSTPROCESSING FALSE /**< should the finishing 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 5
70 #define AGGRESSIVE_MAXIMUMNCLASSES 9
71 #define FAST_MAXIMUMNCLASSES 3
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 freeConsclass NULL
98 
99 /** destructor of detector to free detector data (called before the solving process begins) */
100 #define exitConsclass NULL
101 
102 /** detection initialization function of detector (called before solving is about to begin) */
103 #define initConsclass NULL
104 
105 #define detectConsclass NULL
106 
107 #define finishPartialdecConsclass NULL
108 
109 static DEC_DECL_PROPAGATEPARTIALDEC(propagatePartialdecConsclass)
110 {
111  *result = SCIP_DIDNOTFIND;
112  char decinfo[SCIP_MAXSTRLEN];
113 
114  SCIP_CLOCK* temporaryClock;
115 
116  SCIP_CALL_ABORT( SCIPcreateClock(scip, &temporaryClock) );
117  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
118 
119  std::vector<gcg::PARTIALDECOMP*> foundpartialdecs(0);
120 
121  gcg::PARTIALDECOMP* partialdecOrig;
122  gcg::PARTIALDECOMP* partialdec;
123 
124  int maximumnclasses;
125 
126  if( partialdecdetectiondata->detprobdata->getNConss() + partialdecdetectiondata->detprobdata->getNVars() >= 50000 )
127  SCIPgetIntParam(scip, "detection/classification/maxnclassesperpartitionforlargeprobs", &maximumnclasses);
128  else
129  SCIPgetIntParam(scip, "detection/classification/maxnclassesperpartition", &maximumnclasses);
130 
131  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " in dec_consclass: there are %d different constraint classes \n ",
132  partialdecdetectiondata->detprobdata->getNConsPartitions() );
133 
134 
135  for( int classifierIndex = 0; classifierIndex < partialdecdetectiondata->detprobdata->getNConsPartitions(); ++classifierIndex )
136  {
137  gcg::ConsPartition* classifier = partialdecdetectiondata->detprobdata->getConsPartition(classifierIndex);
138  std::vector<int> consclassindices_master;
139 
140  if( classifier->getNClasses() > maximumnclasses )
141  {
142  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL,
143  " the current consclass distribution includes %d classes but only %d are allowed for propagatePartialdec() of cons class detector\n",
144  classifier->getNClasses(), maximumnclasses);
145  continue;
146  }
147 
148  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " the current constraint classifier \"%s\" consists of %d different classes \n ", classifier->getName(), classifier->getNClasses() );
149 
150  partialdecOrig = partialdecdetectiondata->workonpartialdec;
151 
152  for( int i = 0; i < classifier->getNClasses(); ++ i )
153  {
154  if ( classifier->getClassDecompInfo(i) == gcg::ONLY_MASTER )
155  consclassindices_master.push_back(i);
156  }
157 
158  std::vector< std::vector<int> > subsetsOfConsclasses = classifier->getAllSubsets( true, false, false );
159 
160  for( auto& subset : subsetsOfConsclasses )
161  {
162  if( subset.empty() && consclassindices_master.empty() )
163  continue;
164 
165  partialdec = new gcg::PARTIALDECOMP(partialdecOrig);
166 
167  /* fix open conss that have a) type of the current subset or b) decomp info ONLY_MASTER as master conss */
168  auto& openconss = partialdec->getOpenconssVec();
169  for( auto itr = openconss.cbegin(); itr != openconss.cend(); )
170  {
171  bool foundCons = false;
172  for( int consclassId : subset )
173  {
174  if( classifier->getClassOfCons(*itr) == consclassId )
175  {
176  itr = partialdec->fixConsToMaster(itr);
177  foundCons = true;
178  break;
179  }
180  }
181  /* only check consclassindices_master if current cons has not already been found in a subset */
182  if ( !foundCons )
183  {
184  for(int consclassId : consclassindices_master )
185  {
186  if( classifier->getClassOfCons(*itr) == consclassId )
187  {
188  itr = partialdec->fixConsToMaster(itr);
189  foundCons = true;
190  break;
191  }
192  }
193  }
194  if( !foundCons )
195  {
196  ++itr;
197  }
198  }
199 
200  if( partialdec->getNOpenconss() < partialdecOrig->getNOpenconss() )
201  {
202  /* set decinfo to: consclass_<classfier_name>:<master_class_name#1>-...-<master_class_name#n> */
203  std::stringstream decdesc;
204  decdesc << "consclass" << "\\_" << classifier->getName() << ": \\\\ ";
205  std::vector<int> curmasterclasses(consclassindices_master);
206  for( size_t consclassId = 0; consclassId < subset.size(); ++consclassId )
207  {
208  if( consclassId > 0 )
209  {
210  decdesc << "-";
211  }
212  decdesc << classifier->getClassName(subset[consclassId]);
213  if( std::find(consclassindices_master.begin(), consclassindices_master.end(),
214  subset[consclassId]) == consclassindices_master.end())
215  {
216  curmasterclasses.push_back(subset[consclassId]);
217  }
218  }
219  for( size_t consclassId = 0; consclassId < consclassindices_master.size(); ++consclassId )
220  {
221  if( consclassId > 0 || !subset.empty())
222  {
223  decdesc << "-";
224  }
225  decdesc << classifier->getClassName(consclassindices_master[consclassId]);
226  }
227 
228  partialdec->sort();
229  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, decdesc.str().c_str());
230  partialdec->addDetectorChainInfo(decinfo);
231  partialdec->setConsPartitionStatistics(partialdec->getNDetectors(), classifier, curmasterclasses);
232 
233  foundpartialdecs.push_back(partialdec);
234  }
235  else
236  delete partialdec;
237  }
238  }
239 
240  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
241 
242  partialdecdetectiondata->detectiontime = SCIPgetClockTime(scip, temporaryClock);
243  SCIP_CALL( SCIPallocMemoryArray(scip, &(partialdecdetectiondata->newpartialdecs), foundpartialdecs.size()) );
244  partialdecdetectiondata->nnewpartialdecs = foundpartialdecs.size();
245 
246  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "dec_consclass found %d new partialdecs \n", partialdecdetectiondata->nnewpartialdecs );
247 
248  for( int s = 0; s < partialdecdetectiondata->nnewpartialdecs; ++s )
249  {
250  partialdecdetectiondata->newpartialdecs[s] = foundpartialdecs[s];
251  partialdecdetectiondata->newpartialdecs[s]->addClockTime(partialdecdetectiondata->detectiontime / partialdecdetectiondata->nnewpartialdecs);
252  }
253 
254  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
255 
256  *result = SCIP_SUCCESS;
257 
258  return SCIP_OKAY;
259 }
260 
261 
262 #define detectorPostprocessPartialdecConsclass NULL
263 
264 static
265 DEC_DECL_SETPARAMAGGRESSIVE(setParamAggressiveConsclass)
266 {
267  char setstr[SCIP_MAXSTRLEN];
268  SCIP_Real modifier;
269 
270  int newval;
271  const char* name = DECdetectorGetName(detector);
272 
273  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
274  SCIP_CALL( SCIPsetBoolParam(scip, setstr, TRUE) );
275 
276  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
277  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE ) );
278 
279  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
280  {
281  return SCIP_OKAY;
282  }
283 
284  modifier = ((SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
285  modifier = log(modifier) / log(2.);
286 
287  if (!SCIPisFeasPositive(scip, modifier) )
288  modifier = -1.;
289 
290  modifier = SCIPfloor(scip, modifier);
291 
292  newval = MAX( 6, AGGRESSIVE_MAXIMUMNCLASSES - modifier );
293  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
294 
295  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
296  SCIPverbMessage(scip, SCIP_VERBLEVEL_DIALOG, NULL, "\n%s = %d\n", setstr, newval);
297 
298 
299  return SCIP_OKAY;
300 
301 }
302 
303 
304 static
305 DEC_DECL_SETPARAMDEFAULT(setParamDefaultConsclass)
306 {
307  char setstr[SCIP_MAXSTRLEN];
308  SCIP_Real modifier;
309 
310  int newval;
311  const char* name = DECdetectorGetName(detector);
312 
313  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
314  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLED) );
315 
316  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
317  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLEDFINISHING ) );
318 
319  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
320  {
321  return SCIP_OKAY;
322  }
323 
324 
325  modifier = ( (SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
326  modifier = log(modifier) / log(2);
327 
328  if (!SCIPisFeasPositive(scip, modifier) )
329  modifier = -1.;
330 
331  modifier = SCIPfloor(scip, modifier);
332 
333  newval = MAX( 6, DEFAULT_MAXIMUMNCLASSES - modifier );
334  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
335 
336  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
337  SCIPverbMessage(scip, SCIP_VERBLEVEL_DIALOG, NULL, "\n%s = %d\n", setstr, newval);
338 
339  return SCIP_OKAY;
340 
341 }
342 
343 static
344 DEC_DECL_SETPARAMFAST(setParamFastConsclass)
345 {
346  char setstr[SCIP_MAXSTRLEN];
347  SCIP_Real modifier;
348  int newval;
349 
350  const char* name = DECdetectorGetName(detector);
351 
352  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
353  SCIP_CALL( SCIPsetBoolParam(scip, setstr, TRUE) );
354 
355  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
356  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE ) );
357 
358  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
359  {
360  return SCIP_OKAY;
361  }
362 
363 
364  modifier = ( (SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
365 
366  modifier = log(modifier) / log(2);
367 
368  if (!SCIPisFeasPositive(scip, modifier) )
369  modifier = -1.;
370 
371  modifier = SCIPfloor(scip, modifier);
372 
373  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
374 
375  newval = MAX( 6, FAST_MAXIMUMNCLASSES - modifier );
376 
377  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
378  SCIPverbMessage(scip, SCIP_VERBLEVEL_DIALOG, NULL, "\n%s = %d\n", setstr, newval);
379 
380  return SCIP_OKAY;
381 
382 }
383 
384 
385 /*
386  * detector specific interface methods
387  */
388 
389 /** creates the handler for consclass detector and includes it in SCIP */
390 SCIP_RETCODE SCIPincludeDetectorConsclass(SCIP* scip /**< SCIP data structure */
391 )
392 {
393  DEC_DETECTORDATA* detectordata;
394  char setstr[SCIP_MAXSTRLEN];
395 
396  /**@todo create consclass detector data here*/
397  detectordata = NULL;
398 
399  SCIP_CALL(
402  freeConsclass, initConsclass, exitConsclass, propagatePartialdecConsclass, finishPartialdecConsclass, detectorPostprocessPartialdecConsclass, setParamAggressiveConsclass, setParamDefaultConsclass, setParamFastConsclass));
403 
404  /**@todo add consclass detector parameters */
405 
406  const char* name = DEC_DETECTORNAME;
407  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnclasses", name);
408  SCIP_CALL( SCIPaddIntParam(scip, setstr, "maximum number of classes ", NULL, FALSE, DEFAULT_MAXIMUMNCLASSES, 1, INT_MAX, NULL, NULL ) );
409 
410  return SCIP_OKAY;
411 }
const char * DECdetectorGetName(DEC_DETECTOR *detector)
returns the name of the provided detector
static DEC_DECL_PROPAGATEPARTIALDEC(propagatePartialdecConsclass)
GCG interface methods.
#define detectorPostprocessPartialdecConsclass
#define DEFAULT_MAXIMUMNCLASSES
std::vector< int >::const_iterator fixConsToMaster(std::vector< int >::const_iterator itr)
fixes a constraint to the master constraints
void addDetectorChainInfo(const char *decinfo)
add information about the detector chain
std::vector< int > & getOpenconssVec()
Gets a vector containing constraint ids not assigned yet as vector.
#define DEC_DESC
#define SET_MULTIPLEFORSIZETRANSF
constraint handler for structure detection
#define DEC_DECCHAR
#define DEC_DETECTORNAME
class representing a partition of a set of constraints
#define DEC_ENABLED
#define DEC_MINCALLROUNDORIGINAL
various SCIP helper methods
CONS_DECOMPINFO getClassDecompInfo(int classindex)
const char * getClassName(int classindex)
#define exitConsclass
#define initConsclass
#define FAST_MAXIMUMNCLASSES
void setConsPartitionStatistics(int detectorchainindex, ConsPartition *partition, std::vector< int > &consclassesmaster)
registers statistics for a used conspartition
bool sort()
sorts the vars and conss data structures by their indices
#define DEC_MAXCALLROUND
int getClassOfCons(int consindex)
#define finishPartialdecConsclass
SCIP_RETCODE SCIPincludeDetectorConsclass(SCIP *scip)
consclass detector
#define DEC_SKIP
int getNDetectors()
Gets the number of detectors the partialdec is propagated by.
#define DEC_USEFULRECALL
#define DEC_MAXCALLROUNDORIGINAL
class to manage partial decompositions
static DEC_DECL_SETPARAMDEFAULT(setParamDefaultConsclass)
struct gcg::subset subset
static DEC_DECL_SETPARAMAGGRESSIVE(setParamAggressiveConsclass)
#define freeConsclass
#define DEC_ENABLEDPOSTPROCESSING
std::vector< std::vector< int > > getAllSubsets(bool both, bool only_master, bool only_pricing)
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)),)
int getNOpenconss()
Gets size of vector containing constraints not assigned yet.
#define DEC_FREQCALLROUNDORIGINAL
#define DEC_PRIORITY
class storing (potentially incomplete) decompositions
#define DEC_ENABLEDFINISHING
class storing partialdecs and the problem matrix
#define DEC_MINCALLROUND
#define DEC_FREQCALLROUND
static DEC_DECL_SETPARAMFAST(setParamFastConsclass)
#define AGGRESSIVE_MAXIMUMNCLASSES