Scippy

SCIP

Solving Constraint Integer Programs

cons_components.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_components.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for handling independent components
28 * @author Gerald Gamrath
29 *
30 * This constraint handler looks for independent components.
31 */
32/*#define DETAILED_OUTPUT*/
33/*#define SCIP_DEBUG*/
34/*#define SCIP_MORE_DEBUG*/
35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
36
39#include "scip/debug.h"
40#include "scip/pub_cons.h"
41#include "scip/pub_heur.h"
42#include "scip/pub_message.h"
43#include "scip/pub_misc.h"
44#include "scip/pub_misc_sort.h"
45#include "scip/pub_sol.h"
46#include "scip/pub_tree.h"
47#include "scip/pub_var.h"
48#include "scip/scip_cons.h"
49#include "scip/scip_copy.h"
51#include "scip/scip_general.h"
52#include "scip/scip_heur.h"
53#include "scip/scip_mem.h"
54#include "scip/scip_message.h"
55#include "scip/scip_numerics.h"
56#include "scip/scip_param.h"
57#include "scip/scip_pricer.h"
58#include "scip/scip_prob.h"
59#include "scip/scip_probing.h"
60#include "scip/scip_sol.h"
61#include "scip/scip_solve.h"
63#include "scip/scip_timing.h"
64#include "scip/scip_tree.h"
65#include "scip/scip_var.h"
66#include <string.h>
67
68#define CONSHDLR_NAME "components"
69#define CONSHDLR_DESC "independent components constraint handler"
70#define CONSHDLR_ENFOPRIORITY 0 /**< priority of the constraint handler for constraint enforcing */
71#define CONSHDLR_CHECKPRIORITY -9999999 /**< priority of the constraint handler for checking feasibility */
72#define CONSHDLR_EAGERFREQ -1 /**< frequency for using all instead of only the useful constraints in separation,
73 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
74#define CONSHDLR_NEEDSCONS FALSE /**< should the constraint handler be skipped, if no constraints are available? */
75
76#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
77#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
78#define CONSHDLR_DELAYPROP TRUE /**< should propagation method be delayed, if other propagators found reductions? */
79
80#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FINAL /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
81#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
82
83#define DEFAULT_MAXDEPTH -1 /**< maximum depth of a node to run components detection (-1: disable component detection during solving) */
84#define DEFAULT_MAXINTVARS 200 /**< maximum number of integer (or binary) variables to solve a subproblem directly in presolving (-1: no solving) */
85#define DEFAULT_MINSIZE 50 /**< minimum absolute size (in terms of variables) to solve a component individually during branch-and-bound */
86#define DEFAULT_MINRELSIZE 0.1 /**< minimum relative size (in terms of variables) to solve a component individually during branch-and-bound */
87#define DEFAULT_NODELIMIT 10000LL /**< maximum number of nodes to be solved in subproblems during presolving */
88#define DEFAULT_MAXCOMPWEIGHT 200.0 /**< The maximum weight of a component to be presolved*/
89#define DEFAULT_INTFACTOR 1.0 /**< the weight of an integer variable compared to binary variables */
90#define DEFAULT_CONTFACTOR 0.2 /**< the weight of a continuous variable compared to a binary variable */
91#define DEFAULT_FEASTOLFACTOR 1.0 /**< default value for parameter to increase the feasibility tolerance in all sub-SCIPs */
92
93/*
94 * Data structures
95 */
96
97/** data related to one problem (see below) */
98typedef struct Problem PROBLEM;
99
100/** data related to one component */
101typedef struct Component
102{
103 PROBLEM* problem; /**< the problem this component belongs to */
104 SCIP* subscip; /**< sub-SCIP representing the component */
105 SCIP_SOL* workingsol; /**< working solution for transferring solutions into the sub-SCIP */
106 SCIP_VAR** vars; /**< variables belonging to this component (in complete problem) */
107 SCIP_VAR** subvars; /**< variables belonging to this component (in subscip) */
108 SCIP_VAR** fixedvars; /**< variables in the original SCIP which were copied while copying the component's
109 * constraints, but do not count to the subvars, because they were locally fixed */
110 SCIP_VAR** fixedsubvars; /**< variables in the sub-SCIP which were copied while copying the component's
111 * constraints, but do not count to the subvars, because they were locally fixed */
112 SCIP_Real fixedvarsobjsum; /**< objective contribution of all locally fixed variables */
113 SCIP_Real lastdualbound; /**< dual bound after last optimization call for this component */
114 SCIP_Real lastprimalbound; /**< primal bound after last optimization call for this component */
115 SCIP_STATUS laststatus; /**< solution status of last optimization call for the sub-SCIP of this component */
116 SCIP_Bool solved; /**< was this component solved already? */
117 int ncalls; /**< number of optimization calls for this component */
118 int lastsolindex; /**< index of best solution after last optimization call for this component */
119 int lastbestsolindex; /**< index of last best solution transferred to this component from the main problem */
120 int nvars; /**< number of variables belonging to this component */
121 int nfixedvars; /**< number of fixed variables copied during constraint copying */
122 int fixedvarssize; /**< size of fixedvars and fixedsubvars arrays */
123 int number; /**< component number */
125
126/** data related to one problem
127 * (corresponding to one node in the branch-and-bound tree and consisting of multiple components)
128 */
129struct Problem
130{
131 SCIP* scip; /**< the SCIP instance this problem belongs to */
132 COMPONENT* components; /**< independent components into which the problem can be divided */
133 SCIP_PQUEUE* compqueue; /**< priority queue for components */
134 SCIP_SOL* bestsol; /**< best solution found so far for the problem */
135 char* name; /**< name of the problem */
136 SCIP_Real fixedvarsobjsum; /**< objective contribution of all locally fixed variables */
137 SCIP_Real lowerbound; /**< lower bound of the problem */
138 int ncomponents; /**< number of independent components into which the problem can be divided */
139 int componentssize; /**< size of components array */
140 int nfeascomps; /**< number of components for which a feasible solution was found */
141 int nsolvedcomps; /**< number of components solved to optimality */
142 int nlowerboundinf; /**< number of components with lower bound equal to -infinity */
143};
144
145
146/** constraint handler data */
147struct SCIP_ConshdlrData
148{
149 SCIP_Longint nodelimit; /**< maximum number of nodes to be solved in subproblems */
150 SCIP_Real maxcompweight; /**< The maximum weight sum of a component */
151 SCIP_Real intfactor; /**< the weight of an integer variable compared to binary variables */
152 SCIP_Real contfactor; /**< the weight of a continuous variable compared to binary variables */
153 SCIP_Real feastolfactor; /**< parameter to increase the feasibility tolerance in all sub-SCIPs */
154 int maxintvars; /**< maximum number of integer (or binary) variables to solve a subproblem
155 * directly (-1: no solving) */
156 int maxdepth; /**< maximum depth of a node to run components detection (-1: disable
157 * component detection during solving) */
158 int minsize; /**< minimum absolute size (in terms of variables) to solve a component
159 * individually during branch-and-bound */
160 SCIP_Real minrelsize; /**< minimum relative size (in terms of variables) to solve a component
161 * individually during branch-and-bound */
162 int subscipdepth; /**< depth offset of the current (sub-)problem compared to the original
163 * problem */
164};
165
166
167/** comparison method for sorting components */
168static
170{
171 SCIP* scip;
172 COMPONENT* comp1;
173 COMPONENT* comp2;
174 SCIP_Real gap1;
175 SCIP_Real gap2;
176
177 assert(elem1 != NULL);
178 assert(elem2 != NULL);
179
180 comp1 = (COMPONENT*)elem1;
181 comp2 = (COMPONENT*)elem2;
182
183 if( comp1->ncalls == 0 )
184 if( comp2->ncalls == 0 )
185 return comp1->number - comp2->number;
186 else
187 return -1;
188 else if( comp2->ncalls == 0 )
189 return 1;
190
191 /* the main sorting criterion is the absolute gap; however, we divide it by the number of solving calls for this
192 * component to diversify the search if one component does not improve
193 * @todo investigate other sorting criteria
194 */
195 gap1 = SQR(comp1->lastprimalbound - comp1->lastdualbound) / comp1->ncalls;
196 gap2 = SQR(comp2->lastprimalbound - comp2->lastdualbound) / comp2->ncalls;
197
198 assert(comp1->problem != NULL);
199 assert(comp1->problem == comp2->problem);
200 assert(comp1->problem->scip == comp2->problem->scip);
201
202 scip = comp1->problem->scip;
203 assert(scip != NULL);
204
205 if( SCIPisFeasGT(scip, gap1, gap2) )
206 return -1;
207 else if( SCIPisFeasLT(scip, gap1, gap2) )
208 return +1;
209 else
210 return comp1->number - comp2->number;
211}
212
213/** returns minimum size of components to be solved individually during the branch-and-bound search */
214static
216 SCIP* scip, /**< main SCIP data structure */
217 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
218 )
219{
220 int minsize;
221
222 assert(conshdlrdata != NULL);
223
224 minsize = (int)(conshdlrdata->minrelsize * SCIPgetNVars(scip));
225 minsize = MAX(minsize, conshdlrdata->minsize);
226
227 return minsize;
228}
229
230/** initialize component structure */
231static
233 PROBLEM* problem /**< subproblem structure */
234 )
235{
236 COMPONENT* component;
237 SCIP* scip;
238
239 assert(problem != NULL);
240 assert(problem->ncomponents < problem->componentssize);
241
242 scip = problem->scip;
243 assert(scip != NULL);
244
245 component = &problem->components[problem->ncomponents];
246
247 component->problem = problem;
248 component->subscip = NULL;
249 component->workingsol = NULL;
250 component->vars = NULL;
251 component->subvars = NULL;
252 component->fixedvars = NULL;
253 component->fixedsubvars = NULL;
254 component->fixedvarsobjsum = 0.0;
255 component->lastdualbound = -SCIPinfinity(scip);
256 component->lastprimalbound = SCIPinfinity(scip);
257 component->laststatus = SCIP_STATUS_UNKNOWN;
258 component->solved = FALSE;
259 component->ncalls = 0;
260 component->lastsolindex = -1;
261 component->lastbestsolindex = -1;
262 component->nvars = 0;
263 component->nfixedvars = 0;
264 component->fixedvarssize = 0;
265 component->number = problem->ncomponents;
266
267 ++problem->ncomponents;
268
269 return SCIP_OKAY;
270}
271
272/** free component structure */
273static
275 COMPONENT* component /**< pointer to component structure */
276 )
277{
278 PROBLEM* problem;
279 SCIP* scip;
280
281 assert(component != NULL);
282
283 problem = component->problem;
284 assert(problem != NULL);
285
286 scip = problem->scip;
287 assert(scip != NULL);
288
289 SCIPdebugMsg(scip, "freeing component %d of problem <%s>\n", component->number, component->problem->name);
290
291 assert((component->vars != NULL) == (component->subvars != NULL));
292 if( component->vars != NULL )
293 {
294 SCIPfreeBlockMemoryArray(scip, &component->vars, component->nvars);
295 SCIPfreeBlockMemoryArray(scip, &component->subvars, component->nvars);
296 }
297
298 assert((component->fixedvars != NULL) == (component->fixedsubvars != NULL));
299 if( component->fixedvars != NULL )
300 {
302 SCIPfreeBlockMemoryArray(scip, &component->fixedvars, component->fixedvarssize);
303 }
304
305 /* free sub-SCIP belonging to this component and the working solution */
306 if( component->subscip != NULL )
307 {
308 if( component->workingsol != NULL )
309 {
310 SCIP_CALL( SCIPfreeSol(component->subscip, &component->workingsol) );
311 }
312
313 SCIP_CALL( SCIPfree(&component->subscip) );
314 }
315
316 return SCIP_OKAY;
317}
318
319
320/** create the working solution for a given component, store fixed variables and the corresponding objective offset */
321static
323 COMPONENT* component, /**< component structure */
324 SCIP_HASHMAP* varmap /**< variable hashmap */
325 )
326{
327 SCIP* subscip;
328
329 assert(component != NULL);
330
331 subscip = component->subscip;
332 assert(subscip != NULL);
333 assert(SCIPgetStage(subscip) == SCIP_STAGE_PROBLEM);
334
335 /* the solution should live in the primal, not the origprimal, of the sub-SCIP, so we need to transform it first */
336 SCIP_CALL( SCIPtransformProb(subscip) );
337 SCIP_CALL( SCIPcreateOrigSol(subscip, &(component->workingsol), NULL) );
338
339 /* the number of variables was increased by copying the constraints */
340 if( SCIPgetNOrigVars(subscip) > component->nvars )
341 {
342 PROBLEM* problem;
343 SCIP* scip;
344 SCIP_VAR** sourcevars;
345 SCIP_VAR* subvar;
346 int nsourcevars;
347 int nnewvars;
348 int idx = 0;
349 int nvars;
350 int v;
351
352 problem = component->problem;
353 assert(problem != NULL);
354
355 scip = problem->scip;
356 assert(scip != NULL);
357
358 sourcevars = SCIPgetVars(scip);
359 nsourcevars = SCIPgetNVars(scip);
360 nnewvars = SCIPgetNOrigVars(subscip);
361 nvars = component->nvars;
362
363 component->fixedvarssize = nnewvars - nvars;
366
367 for( v = 0; v < nsourcevars; ++v )
368 {
369 subvar = (SCIP_VAR*)SCIPhashmapGetImage(varmap, sourcevars[v]);
370 if( subvar != NULL && SCIPvarGetIndex(subvar) >= nvars )
371 {
372 /* the variable is either locally fixed or could be an inactive variable present in a constraint
373 * for which an aggregation constraint linking it to the active variable was created in the subscip
374 */
375 assert(SCIPisZero(subscip, SCIPvarGetObj(subvar)) ||
376 SCIPisEQ(subscip, SCIPvarGetLbGlobal(subvar), SCIPvarGetUbGlobal(subvar)));
377
378 /* variable is globally fixed in sub-SCIP, so it was locally fixed in the main-SCIP */
379 if( SCIPisEQ(subscip, SCIPvarGetLbGlobal(subvar), SCIPvarGetUbGlobal(subvar)) )
380 {
381 assert(SCIPisEQ(scip, SCIPvarGetLbLocal(sourcevars[v]), SCIPvarGetUbLocal(sourcevars[v])));
382
383 component->fixedvarsobjsum += SCIPvarGetLbGlobal(subvar) * SCIPvarGetObj(subvar);
384 component->fixedvars[idx] = sourcevars[v];
385 component->fixedsubvars[idx] = subvar;
386 ++idx;
387
388 SCIP_CALL( SCIPsetSolVal(subscip, component->workingsol, subvar, SCIPvarGetLbGlobal(subvar)) );
389 }
390 /* inactive variable */
391 else
392 {
393 assert(SCIPisZero(subscip, SCIPvarGetObj(subvar)));
394 }
395 }
396 else
397 {
398 assert(subvar == NULL || SCIPisLT(scip, SCIPvarGetLbGlobal(sourcevars[v]), SCIPvarGetUbGlobal(sourcevars[v])));
399 assert(subvar == NULL || SCIPisLT(subscip, SCIPvarGetLbGlobal(subvar), SCIPvarGetUbGlobal(subvar)));
400 }
401 }
402 component->nfixedvars = idx;
403 assert(component->nfixedvars <= component->fixedvarssize);
404 SCIPdebugMsg(scip, "%d locally fixed variables have been copied, objective contribution: %g\n",
405 component->nfixedvars, component->fixedvarsobjsum);
406 }
407
408 /* set up debug solution */
409#ifdef WITH_DEBUG_SOLUTION
410 if( SCIPdebugSolIsEnabled(component->problem->scip) )
411 {
412 PROBLEM* problem;
413 SCIP* scip;
414 SCIP_Bool isvalid = FALSE;
415
416 problem = component->problem;
417 assert(problem != NULL);
418
419 scip = problem->scip;
420 assert(scip != NULL);
421
423
424 if( isvalid )
425 {
426 SCIP_Real val;
427 int i;
428
429 SCIPdebugSolEnable(component->subscip);
430
431 for( i = 0; i < component->nvars; ++i )
432 {
433 if( component->subvars[i] != NULL )
434 {
435 SCIP_CALL( SCIPdebugGetSolVal(scip, component->vars[i], &val) );
436 SCIP_CALL( SCIPdebugAddSolVal(component->subscip, component->subvars[i], val) );
437 }
438 }
439 for( i = 0; i < component->nfixedvars; ++i )
440 {
441 if( component->fixedsubvars[i] != NULL )
442 {
443 SCIP_CALL( SCIPdebugGetSolVal(scip, component->fixedvars[i], &val) );
444 SCIP_CALL( SCIPdebugAddSolVal(component->subscip, component->fixedsubvars[i], val) );
445 }
446 }
447 }
448 }
449#endif
450
451 return SCIP_OKAY;
452}
453
454/** create a sub-SCIP for the given variables and constraints */
455static
457 SCIP* scip, /**< main SCIP data structure */
458 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
459 SCIP** subscip /**< pointer to store created sub-SCIP */
460 )
461{
462 SCIP_Bool success;
463
464 assert(conshdlrdata != NULL);
465
466 /* create a new SCIP instance */
467 SCIP_CALL( SCIPcreate(subscip) );
468
469 /* copy plugins, we omit pricers (because we do not run if there are active pricers) and dialogs */
470#ifdef SCIP_MORE_DEBUG /* we print statistics later, so we need to copy statistics tables */
472 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, &success) );
473#else
475 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
476#endif
477
478 /* the plugins were successfully copied */
479 if( success )
480 {
481 SCIP_CONSHDLR* newconshdlr;
482 SCIP_CONSHDLRDATA* newconshdlrdata;
483#ifdef WITH_DEBUG_SOLUTION
484 SCIP_Bool isvalid = FALSE;
485#endif
486
487 /* copy parameter settings */
489
490 /* some general settings should not be fixed */
491 assert(!SCIPisParamFixed(*subscip, "limits/solutions"));
492 assert(!SCIPisParamFixed(*subscip, "limits/bestsol"));
493 assert(!SCIPisParamFixed(*subscip, "misc/usevartable"));
494 assert(!SCIPisParamFixed(*subscip, "misc/useconstable"));
495 assert(!SCIPisParamFixed(*subscip, "numerics/feastol"));
496 assert(!SCIPisParamFixed(*subscip, "misc/usesmalltables"));
497
498 /* disable solution limits */
499 SCIP_CALL( SCIPsetIntParam(*subscip, "limits/solutions", -1) );
500 SCIP_CALL( SCIPsetIntParam(*subscip, "limits/bestsol", -1) );
501
502 /* disable bound limits */
503 SCIP_CALL( SCIPsetRealParam(*subscip, "limits/primal", SCIP_INVALID) );
504 SCIP_CALL( SCIPsetRealParam(*subscip, "limits/dual", SCIP_INVALID) );
505
506 /* reduce the effort spent for hash tables; however, if the debug solution is enabled and valid in this subtree,
507 * hash tables are needed for installing the debug solution
508 */
509#ifdef WITH_DEBUG_SOLUTION
511 if( !isvalid && SCIPgetStage(scip) > SCIP_STAGE_PRESOLVING )
512#endif
513 {
514 SCIP_CALL( SCIPsetBoolParam(*subscip, "misc/usevartable", FALSE) );
515 SCIP_CALL( SCIPsetBoolParam(*subscip, "misc/useconstable", FALSE) );
516 }
517
518 /* disable presolving */
520
521 /* disable component presolving and fix the parameter */
522 SCIP_CALL( SCIPsetIntParam(*subscip, "constraints/" CONSHDLR_NAME "/maxprerounds", 0) );
523 SCIP_CALL( SCIPfixParam(*subscip, "constraints/" CONSHDLR_NAME "/maxprerounds") );
524
525 /* find the components constraint handler in the sub-SCIP and inform it about the actual depth in the tree */
526 newconshdlr = SCIPfindConshdlr(*subscip, CONSHDLR_NAME);
527 assert(newconshdlr != NULL);
528
529 newconshdlrdata = SCIPconshdlrGetData(newconshdlr);
530 assert(newconshdlrdata != NULL);
531 newconshdlrdata->subscipdepth = conshdlrdata->subscipdepth + SCIPgetDepth(scip);
532
533 /* disable output, unless in extended debug mode */
534#ifndef SCIP_MORE_DEBUG
535 SCIP_CALL( SCIPsetIntParam(*subscip, "display/verblevel", 0) );
536#endif
537 }
538 else
539 {
540 SCIP_CALL( SCIPfree(subscip) );
541 *subscip = NULL;
542 }
543
544 return SCIP_OKAY;
545}
546
547/** copies the given variables and constraints to the given sub-SCIP */
548static
550 SCIP* scip, /**< source SCIP */
551 SCIP* subscip, /**< target SCIP */
552 const char* name, /**< name for copied problem */
553 SCIP_VAR** vars, /**< array of variables to copy */
554 SCIP_VAR** subvars, /**< array to fill with copied vars */
555 SCIP_CONS** conss, /**< constraint to copy */
556 SCIP_HASHMAP* varmap, /**< hashmap used for the copy process of variables */
557 SCIP_HASHMAP* consmap, /**< hashmap used for the copy process of constraints */
558 int nvars, /**< number of variables to copy */
559 int nconss, /**< number of constraints to copy */
560 SCIP_Bool* success /**< pointer to store whether copying was successful */
561 )
562{
563 SCIP_CONS* newcons;
564 int i;
565
566 assert(scip != NULL);
567 assert(subscip != NULL);
568 assert(vars != NULL);
569 assert(subvars != NULL);
570 assert(conss != NULL);
571 assert(varmap != NULL);
572 assert(consmap != NULL);
573 assert(success != NULL);
574
575 *success = TRUE;
576
577 /* create problem in sub-SCIP */
578 SCIP_CALL( SCIPcopyProb(scip, subscip, varmap, consmap, FALSE, name) );
579
580 /* copy variables */
581 for( i = 0; i < nvars; ++i )
582 {
583 SCIP_CALL( SCIPgetVarCopy(scip, subscip, vars[i], &subvars[i], varmap, consmap, FALSE, success) );
584
585 /* abort if variable was not successfully copied */
586 if( !(*success) )
587 return SCIP_OKAY;
588 }
589
590 /* copy constraints */
591 for( i = 0; i < nconss; ++i )
592 {
593 assert(!SCIPconsIsModifiable(conss[i]));
594
595 /* copy the constraint */
596 SCIP_CALL( SCIPgetConsCopy(scip, subscip, conss[i], &newcons, SCIPconsGetHdlr(conss[i]), varmap, consmap, NULL,
597 SCIPconsIsInitial(conss[i]), SCIPconsIsSeparated(conss[i]), SCIPconsIsEnforced(conss[i]),
598 SCIPconsIsChecked(conss[i]), SCIPconsIsPropagated(conss[i]), FALSE, FALSE,
599 SCIPconsIsDynamic(conss[i]), SCIPconsIsRemovable(conss[i]), FALSE, FALSE, success) );
600
601 /* abort if constraint was not successfully copied */
602 if( !(*success) )
603 return SCIP_OKAY;
604
605 SCIP_CALL( SCIPaddCons(subscip, newcons) );
606 SCIP_CALL( SCIPreleaseCons(subscip, &newcons) );
607 }
608
609 return SCIP_OKAY;
610}
611
612/** create the sub-SCIP for a given component */
613static
615 COMPONENT* component, /**< component structure */
616 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
617 SCIP_HASHMAP* varmap, /**< variable hashmap used to improve performance */
618 SCIP_HASHMAP* consmap, /**< constraint hashmap used to improve performance */
619 SCIP_CONS** conss, /**< constraints contained in this component */
620 int nconss, /**< number of constraints contained in this component */
621 SCIP_Bool* success /**< pointer to store whether the copying process was successful */
622 )
623{
624 char name[SCIP_MAXSTRLEN];
625 PROBLEM* problem;
626 SCIP* scip;
627 int minsize;
628
629 assert(component != NULL);
630 assert(consmap != NULL);
631 assert(conss != NULL);
632 assert(success != NULL);
633 assert(component->nvars > 0);
634
635 problem = component->problem;
636 assert(problem != NULL);
637
638 scip = problem->scip;
639 assert(scip != NULL);
640
641 (*success) = TRUE;
642
643 SCIP_CALL( createSubscip(scip, conshdlrdata, &component->subscip) );
644
645 if( component->subscip != NULL )
646 {
647 /* get minimum size of components to solve individually and set the parameter in the sub-SCIP */
648 minsize = getMinsize(scip, conshdlrdata);
649
650 SCIP_CALL( SCIPsetIntParam(component->subscip, "constraints/" CONSHDLR_NAME "/minsize", minsize) );
651
652 /* get name of the original problem and add "comp_nr" */
653 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp_%d", problem->name, component->number);
654
655 SCIP_CALL( copyToSubscip(scip, component->subscip, name, component->vars, component->subvars,
656 conss, varmap, consmap, component->nvars, nconss, success) );
657
658 if( !(*success) )
659 {
660 SCIP_CALL( SCIPfree(&component->subscip) );
661 component->subscip = NULL;
662 }
663 }
664 else
665 (*success) = FALSE;
666
667 return SCIP_OKAY;
668}
669
670/** solve a given sub-SCIP up to the given limits */
671static
673 SCIP* scip, /**< main SCIP */
674 SCIP* subscip, /**< sub-SCIP to solve */
675 SCIP_Longint nodelimit, /**< node limit */
676 SCIP_Real gaplimit /**< gap limit */
677 )
678{
679 SCIP_Real timelimit;
680 SCIP_Real memorylimit;
681 SCIP_Bool avoidmemout;
682
683 assert(scip != NULL);
684 assert(subscip != NULL);
685
686 /* set time limit */
687 SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
688 if( !SCIPisInfinity(scip, timelimit) )
689 {
690 timelimit -= SCIPgetSolvingTime(scip);
691 timelimit += SCIPgetSolvingTime(subscip);
692 }
693
694 /* subtract the memory already used by the main SCIP and the estimated memory usage of external software */
695 /* @todo count memory of other components */
696 SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
697 if( !SCIPisInfinity(scip, memorylimit) )
698 {
699 memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
700 memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
701 }
702
703 /* check if mem limit needs to be avoided */
704 SCIP_CALL( SCIPgetBoolParam(scip, "misc/avoidmemout", &avoidmemout) );
705
706 /* abort if no time is left or not enough memory (we don't abort in this case if misc_avoidmemout == TRUE)
707 * to create a copy of SCIP, including external memory usage */
708 if( avoidmemout && memorylimit <= 0.0 )
709 {
710 SCIPdebugMsg(scip, "--> not solved (not enough memory left)\n");
711 return SCIP_OKAY;
712 }
713 else if( timelimit <= 0.0 )
714 {
715 SCIPdebugMsg(scip, "--> not solved (not enough time left)\n");
716 return SCIP_OKAY;
717 }
718
719 /* SCIP copy limits will set wrong time limits since it does not take into account time spent already in the
720 * sub-SCIP; nevertheless, we call it to set the memory limit and unset all other limits, if set in the main SCIP
721 */
722 SCIP_CALL( SCIPcopyLimits(scip, subscip) );
723
724 /* set time and memory limit for the subproblem */
725 SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
726
727 /* only set soft time limit if it exists */
728 if( SCIPgetParam(scip, "limits/softtime") != NULL )
729 {
730 SCIP_Real softtimelimit;
731
732 /* set soft time limit, if specified in main SCIP and if it exists */
733 SCIP_CALL( SCIPgetRealParam(scip, "limits/softtime", &softtimelimit) );
734 if( softtimelimit > -0.5 )
735 {
736 softtimelimit -= SCIPgetSolvingTime(scip);
737 softtimelimit += SCIPgetSolvingTime(subscip);
738 softtimelimit = MAX(softtimelimit, 0.0);
739 }
740
741 SCIP_CALL( SCIPsetRealParam(subscip, "limits/softtime", softtimelimit) );
742 }
743
744 /* set gap limit */
745 SCIP_CALL( SCIPsetRealParam(subscip, "limits/gap", gaplimit) );
746
747 /* set node limit */
748 SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit) );
749
750 /* solve the subproblem */
751 SCIP_CALL( SCIPsolve(subscip) );
752
753#ifdef SCIP_MORE_DEBUG
754 SCIP_CALL( SCIPprintBestSol(subscip, NULL, FALSE) );
756#endif
757
758 return SCIP_OKAY;
759}
760
761/** solve a connected component during presolving and evaluate the result */
762static
764 SCIP* scip, /**< SCIP main data structure */
765 SCIP_CONSHDLRDATA* conshdlrdata, /**< the components constraint handler data */
766 SCIP* subscip, /**< sub-SCIP to be solved */
767 SCIP_VAR** vars, /**< array of variables copied to this component */
768 SCIP_VAR** subvars, /**< array of sub-SCIP variables corresponding to the vars array */
769 SCIP_CONS** conss, /**< array of constraints copied to this component */
770 int nvars, /**< number of variables copied to this component */
771 int nconss, /**< number of constraints copied to this component */
772 int* ndeletedconss, /**< pointer to store the number of deleted constraints */
773 int* nfixedvars, /**< pointer to store the number of fixed variables */
774 int* ntightenedbounds, /**< pointer to store the number of bound tightenings */
775 SCIP_RESULT* result, /**< pointer to store the result of the component solving */
776 SCIP_Bool* solved /**< pointer to store if the problem was solved to optimality */
777 )
778{
779 int i;
780
781 assert(scip != NULL);
782 assert(conshdlrdata != NULL);
783 assert(subscip != NULL);
784 assert(vars != NULL);
785 assert(conss != NULL);
786 assert(ndeletedconss != NULL);
787 assert(nfixedvars != NULL);
788 assert(ntightenedbounds != NULL);
789 assert(result != NULL);
790
791 *solved = FALSE;
792
793 SCIP_CALL( solveSubscip(scip, subscip, conshdlrdata->nodelimit, 0.0) );
794
795 if( SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL )
796 {
797 SCIP_SOL* sol;
798 SCIP_VAR* var;
799 SCIP_VAR* subvar;
800 SCIP_Real* fixvals;
801 SCIP_Bool feasible;
802 SCIP_Bool infeasible;
803 SCIP_Bool fixed;
804
805 sol = SCIPgetBestSol(subscip);
806
807#ifdef SCIP_DEBUG
808 SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, TRUE, TRUE) );
809#else
810 SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE) );
811#endif
812
813 SCIPdebugMsg(scip, "--> solved to optimality: time = %.2f, solution is%s feasible\n", SCIPgetSolvingTime(subscip), feasible ? "" : " not");
814
815 SCIP_CALL( SCIPallocBufferArray(scip, &fixvals, nvars) );
816
817 if( feasible )
818 {
819 SCIP_Real glb;
820 SCIP_Real gub;
821
822 /* get values of variables in the optimal solution */
823 for( i = 0; i < nvars; ++i )
824 {
825 var = vars[i];
826 subvar = subvars[i];
827
828 /* get global bounds */
829 glb = SCIPvarGetLbGlobal(var);
830 gub = SCIPvarGetUbGlobal(var);
831
832 if( subvar != NULL )
833 {
834 /* get solution value from optimal solution of the sub-SCIP */
835 fixvals[i] = SCIPgetSolVal(subscip, sol, subvar);
836
837 assert(SCIPisFeasLE(scip, fixvals[i], SCIPvarGetUbLocal(var)));
838 assert(SCIPisFeasGE(scip, fixvals[i], SCIPvarGetLbLocal(var)));
839
840 /* checking a solution is done with a relative tolerance of feasibility epsilon, if we really want to
841 * change the bounds of the variables by fixing them, the old bounds must not be violated by more than
842 * the absolute epsilon; therefore, we change the fixing values, if needed, and mark that the solution
843 * has to be checked again
844 */
845 if( SCIPisGT(scip, fixvals[i], gub) )
846 {
847 SCIPdebugMsg(scip, "variable <%s> fixval: %f violates global upperbound: %f\n",
848 SCIPvarGetName(var), fixvals[i], gub);
849 fixvals[i] = gub;
850 feasible = FALSE;
851 }
852 else if( SCIPisLT(scip, fixvals[i], glb) )
853 {
854 SCIPdebugMsg(scip, "variable <%s> fixval: %f violates global lowerbound: %f\n",
855 SCIPvarGetName(var), fixvals[i], glb);
856 fixvals[i] = glb;
857 feasible = FALSE;
858 }
859 assert(SCIPisLE(scip, fixvals[i], SCIPvarGetUbLocal(var)));
860 assert(SCIPisGE(scip, fixvals[i], SCIPvarGetLbLocal(var)));
861 }
862 else
863 {
864 /* the variable was not copied, so it was cancelled out of constraints during copying;
865 * thus, the variable is not constrained and we fix it to its best bound
866 */
868 fixvals[i] = glb;
869 else if( SCIPisNegative(scip, SCIPvarGetObj(var)) )
870 fixvals[i] = gub;
871 else
872 {
873 fixvals[i] = 0.0;
874 fixvals[i] = MIN(fixvals[i], gub);
875 fixvals[i] = MAX(fixvals[i], glb);
876 }
877 }
878 }
879
880 /* the solution value of at least one variable is feasible with a relative tolerance of feasibility epsilon,
881 * but infeasible with an absolute tolerance of epsilon; try to set the variables to the bounds and check
882 * solution again in the original space (changing the values might now introduce infeasibilities of constraints)
883 */
884 if( !feasible )
885 {
886 SCIP_Real origobj;
887
888 SCIPdebugMsg(scip, "solution violates bounds by more than epsilon, check the corrected solution...\n");
889
890 origobj = SCIPgetSolOrigObj(subscip, SCIPgetBestSol(subscip));
891
892 SCIP_CALL( SCIPfreeTransform(subscip) );
893
894 SCIP_CALL( SCIPcreateOrigSol(subscip, &sol, NULL) );
895
896 /* set solution values of variables */
897 for( i = 0; i < nvars; ++i )
898 {
899 if( subvars[i] != NULL )
900 {
901 SCIP_CALL( SCIPsetSolVal(subscip, sol, subvars[i], fixvals[i]) );
902 }
903 }
904
905 /* check the solution; integrality and bounds should be fulfilled and do not have to be checked */
906 SCIP_CALL( SCIPcheckSol(subscip, sol, FALSE, FALSE, FALSE, FALSE, TRUE, &feasible) );
907
908#ifndef NDEBUG
909 /* in debug mode, we additionally check integrality and bounds */
910 if( feasible )
911 {
912 SCIP_CALL( SCIPcheckSol(subscip, sol, FALSE, FALSE, TRUE, TRUE, FALSE, &feasible) );
913 assert(feasible);
914 }
915#endif
916
917 SCIPdebugMsg(scip, "--> corrected solution is%s feasible\n", feasible ? "" : " not");
918
919 if( !SCIPisFeasEQ(subscip, SCIPsolGetOrigObj(sol), origobj) )
920 {
921 SCIPdebugMsg(scip, "--> corrected solution has a different objective value (old = %.9g, corrected = %.9g)\n",
922 origobj, SCIPsolGetOrigObj(sol));
923
924 feasible = FALSE;
925 }
926
927 SCIP_CALL( SCIPfreeSol(subscip, &sol) );
928 }
929
930 /* if the solution is feasible, fix variables and delete constraints of the component */
931 if( feasible )
932 {
933 /* fix variables */
934 for( i = 0; i < nvars; ++i )
935 {
936 assert(SCIPisLE(scip, fixvals[i], SCIPvarGetUbLocal(vars[i])));
937 assert(SCIPisGE(scip, fixvals[i], SCIPvarGetLbLocal(vars[i])));
938 assert(SCIPisLE(scip, fixvals[i], SCIPvarGetUbGlobal(vars[i])));
939 assert(SCIPisGE(scip, fixvals[i], SCIPvarGetLbGlobal(vars[i])));
940
941 SCIP_CALL( SCIPfixVar(scip, vars[i], fixvals[i], &infeasible, &fixed) );
943 assert(!infeasible);
944 assert(fixed);
945 (*nfixedvars)++;
946 }
947
948 /* delete constraints */
949 for( i = 0; i < nconss; ++i )
950 {
951 SCIP_CALL( SCIPdelCons(scip, conss[i]) );
952 (*ndeletedconss)++;
953 }
954
955 *result = SCIP_SUCCESS;
956 *solved = TRUE;
957 }
958 }
959
960 SCIPfreeBufferArray(scip, &fixvals);
961 }
962 else if( SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE )
963 {
964 *result = SCIP_CUTOFF;
965 }
966 else if( SCIPgetStatus(subscip) == SCIP_STATUS_UNBOUNDED || SCIPgetStatus(subscip) == SCIP_STATUS_INFORUNBD )
967 {
968 /* TODO: store unbounded ray in original SCIP data structure */
969 *result = SCIP_UNBOUNDED;
970 }
971 else
972 {
973 SCIPdebugMsg(scip, "--> solving interrupted (status = %d, time = %.2f)\n",
974 SCIPgetStatus(subscip), SCIPgetSolvingTime(subscip));
975
976 /* transfer global fixings to the original problem; we can only do this, if we did not find a solution in the
977 * subproblem, because otherwise, the primal bound might lead to dual reductions that cannot be transferred to
978 * the original problem without also transferring the possibly suboptimal solution (which is currently not
979 * possible)
980 */
981 if( SCIPgetNSols(subscip) == 0 )
982 {
983 SCIP_Bool infeasible;
984 SCIP_Bool tightened;
985 int ntightened;
986
987 ntightened = 0;
988
989 for( i = 0; i < nvars; ++i )
990 {
991 if( subvars[i] == NULL )
992 continue;
993
995 &infeasible, &tightened) );
996 assert(!infeasible);
997 if( tightened )
998 ntightened++;
999
1000 SCIP_CALL( SCIPtightenVarUb(scip, vars[i], SCIPvarGetUbGlobal(subvars[i]), FALSE,
1001 &infeasible, &tightened) );
1002 assert(!infeasible);
1003 if( tightened )
1004 ntightened++;
1005 }
1006
1007 *result = SCIP_SUCCESS;
1008
1009 *ntightenedbounds += ntightened;
1010
1011 SCIPdebugMsg(scip, "--> tightened %d bounds of variables due to global bounds in the sub-SCIP\n", ntightened);
1012 }
1013 }
1014
1015 return SCIP_OKAY;
1016}
1017
1018/** (continues) solving a connected component */
1019static
1021 COMPONENT* component, /**< component structure */
1022 SCIP_Bool lastcomponent, /**< is this the last component to be solved? */
1023 SCIP_RESULT* result /**< pointer to store the result of the solving process */
1024 )
1025{
1026 PROBLEM* problem;
1027 SCIP* scip;
1028 SCIP* subscip;
1029 SCIP_SOL* bestsol;
1030 SCIP_Longint nodelimit;
1031 SCIP_Longint lastnnodes;
1032 SCIP_Real gaplimit;
1033 SCIP_STATUS status;
1034
1035 assert(component != NULL);
1036
1037 problem = component->problem;
1038 assert(problem != NULL);
1039
1040 scip = problem->scip;
1041 assert(scip != NULL);
1042
1043 subscip = component->subscip;
1044 assert(subscip != NULL);
1045
1046 *result = SCIP_DIDNOTRUN;
1047
1048 SCIPdebugMsg(scip, "solve component <%s> (ncalls = %d, absgap = %.9g)\n",
1049 SCIPgetProbName(subscip), component->ncalls, component->lastprimalbound - component->lastdualbound);
1050
1051 bestsol = SCIPgetBestSol(scip);
1052
1053 /* update best solution of component */
1054 if( bestsol != NULL && SCIPsolGetIndex(bestsol) != component->lastbestsolindex )
1055 {
1056 SCIP_SOL* compsol = component->workingsol;
1057 SCIP_VAR** vars = component->vars;
1058 SCIP_VAR** subvars = component->subvars;
1059 int nvars = component->nvars;
1060 int v;
1061
1062 component->lastbestsolindex = SCIPsolGetIndex(bestsol);
1063
1064 /* set solution values of component variables */
1065 for( v = 0; v < nvars; ++v )
1066 {
1067 if( subvars[v] != NULL )
1068 {
1069 SCIP_CALL( SCIPsetSolVal(subscip, compsol, subvars[v], SCIPgetSolVal(scip, bestsol, vars[v])) );
1070 }
1071 }
1072#ifndef NDEBUG
1073 for( v = 0; v < component->nfixedvars; ++v )
1074 {
1075 if( component->fixedsubvars[v] != NULL )
1076 assert(SCIPisEQ(scip, SCIPgetSolVal(subscip, compsol, component->fixedsubvars[v]),
1077 SCIPvarGetLbGlobal(component->fixedsubvars[v])));
1078 }
1079#endif
1080
1081 if( SCIPgetStage(subscip) == SCIP_STAGE_PROBLEM
1082 || SCIPisLT(subscip, SCIPgetSolOrigObj(subscip, compsol), SCIPgetPrimalbound(subscip)) )
1083 {
1084 SCIP_Bool feasible;
1085
1086 SCIPdebugMsg(scip, "checking new solution in component <%s> inherited from problem <%s>: primal bound %.9g --> %.9g\n",
1087 SCIPgetProbName(subscip), problem->name,
1088 SCIPgetStage(subscip) == SCIP_STAGE_PROBLEM ? SCIPinfinity(subscip) : SCIPgetPrimalbound(subscip),
1089 SCIPgetSolOrigObj(subscip, compsol));
1090
1091 SCIP_CALL( SCIPcheckSolOrig(subscip, compsol, &feasible, FALSE, FALSE) );
1092 if( feasible )
1093 {
1094 SCIPdebugMsg(scip,"... feasible, adding solution.\n");
1095
1096 SCIP_CALL( SCIPaddSol(subscip, compsol, &feasible) );
1097 }
1098
1099 /* We cannot take the value of compsol as a cutoff bound if it was not feasible; some of the fixed connecting
1100 * variables are different and might not allow for a better solution in this component, but still for far
1101 * better solutions in other components. Therefore, the only cutoffbound we can apply is the cutoffbound
1102 * of the problem reduced by the dual bounds of the other components
1103 */
1104 if( problem->nlowerboundinf == 0 || (problem->nlowerboundinf == 1
1105 && SCIPisInfinity(scip, -component->lastdualbound)) )
1106 {
1107 SCIP_Real newcutoffbound = SCIPgetSolTransObj(scip, bestsol);
1108
1109 assert(problem->nlowerboundinf > 0 || SCIPisGE(scip, newcutoffbound, problem->lowerbound));
1110
1111 newcutoffbound = newcutoffbound - problem->lowerbound + component->fixedvarsobjsum;
1112
1113 if( problem->nlowerboundinf == 0 )
1114 newcutoffbound += component->lastdualbound;
1115
1116 if( SCIPisSumLT(subscip, newcutoffbound, SCIPgetCutoffbound(subscip)) )
1117 {
1118 SCIPdebugMsg(scip, "update cutoff bound to %.9g\n", newcutoffbound);
1119
1120 SCIP_CALL( SCIPupdateCutoffbound(subscip, newcutoffbound) );
1121 }
1122 }
1123 }
1124 }
1125
1126 assert(component->laststatus != SCIP_STATUS_OPTIMAL);
1127
1128 SCIPdebugMsg(scip, "solve sub-SCIP for component <%s> (ncalls = %d, absgap = %.9g)\n",
1129 SCIPgetProbName(component->subscip), component->ncalls, component->lastprimalbound - component->lastdualbound);
1130
1131 if( component->ncalls == 0 )
1132 {
1133 nodelimit = 1LL;
1134 gaplimit = 0.0;
1135
1136 lastnnodes = 0;
1137 }
1138 else
1139 {
1140 SCIP_Longint mainnodelimit;
1141
1142 lastnnodes = SCIPgetNNodes(component->subscip);
1143
1144 SCIP_CALL( SCIPgetLongintParam(scip, "limits/nodes", &mainnodelimit) );
1145
1146 nodelimit = 2 * lastnnodes;
1147 nodelimit = MAX(nodelimit, 10LL);
1148
1149 if( mainnodelimit != -1 )
1150 {
1151 assert(mainnodelimit >= lastnnodes);
1152 nodelimit = MIN(nodelimit, mainnodelimit - lastnnodes);
1153 }
1154
1155 /* set a gap limit of half the current gap (at most 10%) */
1156 if( SCIPgetGap(component->subscip) < 0.2 )
1157 gaplimit = 0.5 * SCIPgetGap(component->subscip);
1158 else
1159 gaplimit = 0.1;
1160
1161 if( lastcomponent )
1162 gaplimit = 0.0;
1163 }
1164
1165 SCIP_CALL( solveSubscip(scip, subscip, nodelimit, gaplimit) );
1166
1167 SCIPaddNNodes(scip, SCIPgetNNodes(subscip) - lastnnodes);
1168
1170
1171 status = SCIPgetStatus(subscip);
1172
1173 component->laststatus = status;
1174 ++component->ncalls;
1175
1176 SCIPdebugMsg(scip, "--> (status = %d, nodes = %lld, time = %.2f): gap = %.5g%%, absgap = %.9g\n",
1177 status, SCIPgetNNodes(subscip), SCIPgetSolvingTime(subscip), 100.0*SCIPgetGap(subscip),
1178 SCIPgetPrimalbound(subscip) - SCIPgetDualbound(subscip));
1179
1180 *result = SCIP_SUCCESS;
1181
1182 switch( status )
1183 {
1185 component->solved = TRUE;
1186 break;
1188 component->solved = TRUE;
1189
1190 /* the problem is really infeasible */
1191 if( SCIPisInfinity(subscip, SCIPgetPrimalbound(subscip)) )
1192 {
1193 *result = SCIP_CUTOFF;
1194 }
1195 /* the cutoff bound was reached; no solution better than the cutoff bound exists */
1196 else
1197 {
1198 *result = SCIP_SUCCESS;
1199 component->laststatus = SCIP_STATUS_OPTIMAL;
1200 assert(SCIPisLE(subscip, SCIPgetDualbound(subscip), SCIPgetPrimalbound(subscip)));
1201 }
1202 break;
1205 /* TODO: store unbounded ray in original SCIP data structure */
1206 *result = SCIP_UNBOUNDED;
1207 component->solved = TRUE;
1208 break;
1211 break;
1225 default:
1226 break;
1227 }
1228
1229 /* evaluate call */
1230 if( *result == SCIP_SUCCESS )
1231 {
1232 SCIP_SOL* sol = SCIPgetBestSol(subscip);
1233 SCIP_VAR* var;
1234 SCIP_VAR* subvar;
1235 SCIP_Real newdualbound;
1236 int v;
1237
1238 /* get dual bound as the minimum of SCIP dual bound and sub-problems dual bound */
1239 newdualbound = SCIPgetDualbound(subscip) - component->fixedvarsobjsum;
1240
1241 /* update dual bound of problem */
1242 if( !SCIPisEQ(scip, component->lastdualbound, newdualbound) )
1243 {
1244 assert(!SCIPisInfinity(scip, -newdualbound));
1245
1246 /* first finite dual bound: decrease inf counter and add dual bound to problem dualbound */
1247 if( SCIPisInfinity(scip, -component->lastdualbound) )
1248 {
1249 --problem->nlowerboundinf;
1250 problem->lowerbound += newdualbound;
1251 }
1252 /* increase problem dual bound by dual bound delta */
1253 else
1254 {
1255 problem->lowerbound += (newdualbound - component->lastdualbound);
1256 }
1257
1258 /* update problem dual bound if all problem components have a finite dual bound */
1259 if( problem->nlowerboundinf == 0 )
1260 {
1261 SCIPdebugMsg(scip, "component <%s>: dual bound increased from %.9g to %.9g, new dual bound of problem <%s>: %.9g (gap = %.9g, absgap = %.9g)\n",
1262 SCIPgetProbName(subscip), component->lastdualbound, newdualbound, problem->name,
1263 SCIPretransformObj(scip, problem->lowerbound),
1264 problem->nfeascomps == problem->ncomponents ?
1265 (SCIPgetSolOrigObj(scip, problem->bestsol) - SCIPretransformObj(scip, problem->lowerbound)) /
1266 MAX( ABS( SCIPretransformObj(scip, problem->lowerbound) ), SCIPgetSolOrigObj(scip, problem->bestsol) ) /*lint !e666*/
1267 : SCIPinfinity(scip),
1268 problem->nfeascomps == problem->ncomponents ?
1269 SCIPgetSolOrigObj(scip, problem->bestsol) - SCIPretransformObj(scip, problem->lowerbound) : SCIPinfinity(scip));
1270 SCIP_CALL( SCIPupdateLocalLowerbound(scip, problem->lowerbound) );
1271 }
1272
1273 /* store dual bound of this call */
1274 component->lastdualbound = newdualbound;
1275 }
1276
1277 /* update primal solution of problem */
1278 if( sol != NULL && component->lastsolindex != SCIPsolGetIndex(sol) )
1279 {
1280 component->lastsolindex = SCIPsolGetIndex(sol);
1281
1282 if( SCIPsolGetHeur(sol) != NULL )
1284 else
1285 SCIPsolSetHeur(problem->bestsol, NULL);
1286
1287 /* increase counter for feasible problems if no solution was known before */
1288 if( SCIPisInfinity(scip, component->lastprimalbound) )
1289 ++(problem->nfeascomps);
1290
1291 /* update working best solution in problem */
1292 for( v = 0; v < component->nvars; ++v )
1293 {
1294 var = component->vars[v];
1295 subvar = component->subvars[v];
1296 assert(var != NULL);
1297 assert(SCIPvarIsActive(var));
1298
1299 if( subvar == NULL )
1300 continue;
1301
1302 SCIP_CALL( SCIPsetSolVal(scip, problem->bestsol, var, SCIPgetSolVal(subscip, sol, subvar)) );
1303 }
1304
1305 /* if we have a feasible solution for each component, add the working solution to the main problem */
1306 if( problem->nfeascomps == problem->ncomponents )
1307 {
1308 SCIP_Bool feasible;
1309#ifdef SCIP_MORE_DEBUG
1310 SCIP_CALL( SCIPcheckSol(scip, problem->bestsol, TRUE, FALSE, TRUE, TRUE, TRUE, &feasible) );
1311 assert(feasible);
1312#endif
1313 SCIP_CALL( SCIPaddSol(scip, problem->bestsol, &feasible) );
1314
1315 SCIPdebugMsg(scip, "component <%s>: primal bound decreased from %.9g to %.9g, new primal bound of problem <%s>: %.9g (gap = %.9g, absgap = %.9g)\n",
1316 SCIPgetProbName(subscip), component->lastprimalbound, SCIPgetPrimalbound(subscip), problem->name,
1317 SCIPgetSolOrigObj(scip, problem->bestsol),
1318 problem->nfeascomps == problem->ncomponents ?
1319 (SCIPgetSolOrigObj(scip, problem->bestsol) - SCIPretransformObj(scip, problem->lowerbound)) /
1320 MAX( ABS( SCIPretransformObj(scip, problem->lowerbound) ),SCIPgetSolOrigObj(scip, problem->bestsol) ) /*lint !e666*/
1321 : SCIPinfinity(scip),
1322 problem->nfeascomps == problem->ncomponents ?
1323 SCIPgetSolOrigObj(scip, problem->bestsol) - SCIPretransformObj(scip, problem->lowerbound) : SCIPinfinity(scip));
1324 }
1325
1326 /* store primal bound of this call */
1327 component->lastprimalbound = SCIPgetPrimalbound(subscip) - component->fixedvarsobjsum;
1328 }
1329
1330 /* if the component was solved to optimality, we increase the respective counter and free the subscip */
1331 if( component->laststatus == SCIP_STATUS_OPTIMAL || component->laststatus == SCIP_STATUS_INFEASIBLE ||
1332 component->laststatus == SCIP_STATUS_UNBOUNDED || component->laststatus == SCIP_STATUS_INFORUNBD )
1333 {
1334 ++(problem->nsolvedcomps);
1335 component->solved = TRUE;
1336
1337 /* free working solution and component */
1338 SCIP_CALL( SCIPfreeSol(subscip, &component->workingsol) );
1339
1340 SCIP_CALL( SCIPfree(&subscip) );
1341 component->subscip = NULL;
1342 }
1343 }
1344
1345 return SCIP_OKAY;
1346}
1347
1348/** initialize subproblem structure */
1349static
1351 SCIP* scip, /**< SCIP data structure */
1352 PROBLEM** problem, /**< pointer to subproblem structure */
1353 SCIP_Real fixedvarsobjsum, /**< objective contribution of all locally fixed variables */
1354 int ncomponents /**< number of independent components */
1355 )
1356{
1357 char name[SCIP_MAXSTRLEN];
1358 SCIP_VAR** vars;
1359 int nvars;
1360 int v;
1361
1362 assert(scip != NULL);
1363 assert(problem != NULL);
1364
1365 vars = SCIPgetVars(scip);
1366 nvars = SCIPgetNVars(scip);
1367
1368 SCIP_CALL( SCIPallocBlockMemory(scip, problem) );
1369 assert(*problem != NULL);
1370
1371 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*problem)->components, ncomponents) );
1372
1373 /* create a priority queue for the components: we need exactly ncomponents slots in the queue so it should never be
1374 * resized
1375 */
1376 SCIP_CALL( SCIPpqueueCreate(&(*problem)->compqueue, ncomponents, 1.2, componentSort, NULL) );
1377
1378 (*problem)->scip = scip;
1379 (*problem)->lowerbound = fixedvarsobjsum;
1380 (*problem)->fixedvarsobjsum = fixedvarsobjsum;
1381 (*problem)->ncomponents = 0;
1382 (*problem)->componentssize = ncomponents;
1383 (*problem)->nlowerboundinf = ncomponents;
1384 (*problem)->nfeascomps = 0;
1385 (*problem)->nsolvedcomps = 0;
1386
1387 if( SCIPgetDepth(scip) == 0 )
1388 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPgetProbName(scip));
1389 else
1391
1392 SCIP_CALL( SCIPduplicateMemoryArray(scip, &(*problem)->name, name, strlen(name)+1) );
1393
1394 SCIP_CALL( SCIPcreateSol(scip, &(*problem)->bestsol, NULL) );
1395
1396 for( v = 0; v < nvars; v++ )
1397 {
1398 if( SCIPisFeasEQ(scip, SCIPvarGetLbLocal(vars[v]), SCIPvarGetUbLocal(vars[v])) )
1399 {
1400 SCIP_CALL( SCIPsetSolVal(scip, (*problem)->bestsol, vars[v],
1401 (SCIPvarGetUbLocal(vars[v]) + SCIPvarGetLbLocal(vars[v]))/2) );
1402 }
1403 }
1404
1405 SCIPdebugMsg(scip, "initialized problem <%s>\n", (*problem)->name);
1406
1407 return SCIP_OKAY;
1408}
1409
1410/** free subproblem structure */
1411static
1413 PROBLEM** problem /**< pointer to problem to free */
1414 )
1415{
1416 SCIP* scip;
1417 int c;
1418
1419 assert(problem != NULL);
1420 assert(*problem != NULL);
1421
1422 scip = (*problem)->scip;
1423 assert(scip != NULL);
1424
1425 /* free best solution */
1426 if( (*problem)->bestsol != NULL )
1427 {
1428 SCIP_CALL( SCIPfreeSol(scip, &(*problem)->bestsol) );
1429 }
1430
1431 /* free all components */
1432 for( c = (*problem)->ncomponents - 1; c >= 0; --c )
1433 {
1434 SCIP_CALL( freeComponent(&(*problem)->components[c]) );
1435 }
1436 if( (*problem)->components != NULL )
1437 {
1438 SCIPfreeBlockMemoryArray(scip, &(*problem)->components, (*problem)->componentssize);
1439 }
1440
1441 /* free priority queue */
1442 SCIPpqueueFree(&(*problem)->compqueue);
1443
1444 /* free problem name */
1445 SCIPfreeMemoryArray(scip, &(*problem)->name);
1446
1447 /* free PROBLEM struct and set the pointer to NULL */
1448 SCIPfreeBlockMemory(scip, problem);
1449 *problem = NULL;
1450
1451 return SCIP_OKAY;
1452}
1453
1454/** creates and captures a components constraint */
1455static
1457 SCIP* scip, /**< SCIP data structure */
1458 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1459 const char* name, /**< name of constraint */
1460 PROBLEM* problem /**< problem to be stored in the constraint */
1461 )
1462{
1463 SCIP_CONSHDLR* conshdlr;
1464
1465 /* find the components constraint handler */
1466 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
1467 if( conshdlr == NULL )
1468 {
1469 SCIPerrorMessage("components constraint handler not found\n");
1470 return SCIP_PLUGINNOTFOUND;
1471 }
1472
1473 /* create constraint */
1474 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, (SCIP_CONSDATA*)problem,
1476 TRUE, FALSE, FALSE, FALSE, TRUE) );
1477
1478 return SCIP_OKAY;
1479}
1480
1481
1482/** sort the components by size and sort vars and conss arrays by component numbers */
1483static
1485 SCIP* scip, /**< SCIP data structure */
1486 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1487 SCIP_DIGRAPH* digraph, /**< directed graph */
1488 SCIP_CONS** conss, /**< constraints */
1489 SCIP_VAR** vars, /**< variables */
1490 int* varcomponent, /**< component numbers for the variables */
1491 int* conscomponent, /**< array to store component numbers for the constraints */
1492 int nconss, /**< number of constraints */
1493 int nvars, /**< number of variables */
1494 int* firstvaridxpercons, /**< array with index of first variable in vars array for each constraint */
1495 int* ncompsminsize, /**< pointer to store the number of components not exceeding the minimum size */
1496 int* ncompsmaxsize /**< pointer to store the number of components not exceeding the maximum size */
1497 )
1498{
1499 SCIP_Real* compsize;
1500 int* permu;
1501 int ncomponents;
1502 int nbinvars;
1503 int nintvars;
1504 int ndiscvars;
1505 int ncontvars;
1506 int minsize;
1507 int v;
1508 int c;
1509
1510 assert(scip != NULL);
1511 assert(conshdlrdata != NULL);
1512 assert(digraph != NULL);
1513 assert(conss != NULL);
1514 assert(vars != NULL);
1515 assert(firstvaridxpercons != NULL);
1516
1517 /* compute minimum size of components to solve individually */
1518 minsize = getMinsize(scip, conshdlrdata);
1519
1520 ncomponents = SCIPdigraphGetNComponents(digraph);
1521 *ncompsminsize = 0;
1522 *ncompsmaxsize = 0;
1523
1524 /* We want to sort the components in increasing complexity (number of discrete variables,
1525 * integer weighted with factor intfactor, continuous used as tie-breaker).
1526 * Therefore, we now get the variables for each component, count the different variable types
1527 * and compute a size as described above. Then, we rename the components
1528 * such that for i < j, component i has no higher complexity than component j.
1529 */
1530 SCIP_CALL( SCIPallocBufferArray(scip, &compsize, ncomponents) );
1531 SCIP_CALL( SCIPallocBufferArray(scip, &permu, ncomponents) );
1532
1533 /* get number of variables in the components */
1534 for( c = 0; c < ncomponents; ++c )
1535 {
1536 int* cvars;
1537 int ncvars;
1538
1539 SCIPdigraphGetComponent(digraph, c, &cvars, &ncvars);
1540 permu[c] = c;
1541 nbinvars = 0;
1542 nintvars = 0;
1543
1544 for( v = 0; v < ncvars; ++v )
1545 {
1546 /* check whether variable is of binary or integer type */
1547 if( SCIPvarGetType(vars[cvars[v]]) == SCIP_VARTYPE_BINARY )
1548 nbinvars++;
1549 else if( SCIPvarGetType(vars[cvars[v]]) == SCIP_VARTYPE_INTEGER )
1550 nintvars++;
1551 }
1552 ncontvars = ncvars - nintvars - nbinvars;
1553 /* TODO: come up with a more reasonable formula based on data.
1554 * This formula weights integer variables very strongly, but ignores the impact of continuous variables somewhat*/
1555 ndiscvars = (int)(nbinvars + conshdlrdata->intfactor * nintvars);
1556 compsize[c] = nbinvars + conshdlrdata->intfactor * nintvars + conshdlrdata->contfactor * ncontvars;
1557
1558 /* component fulfills the maxsize and maxcompweight requirement */
1559 if( ndiscvars <= conshdlrdata->maxintvars && compsize[c] <= conshdlrdata->maxcompweight )
1560 ++(*ncompsmaxsize);
1561
1562 /* component fulfills the minsize requirement */
1563 if( ncvars >= minsize )
1564 ++(*ncompsminsize);
1565 }
1566
1567 /* get permutation of component numbers such that the size of the components is increasing */
1568 SCIPsortRealInt(compsize, permu, ncomponents);
1569
1570 /* now, we need the reverse direction, i.e., for each component number, we store its new number
1571 * such that the components are sorted; for this, we abuse the conscomponent array
1572 */
1573 for( c = 0; c < ncomponents; ++c )
1574 conscomponent[permu[c]] = c;
1575
1576 /* for each variable, replace the old component number by the new one */
1577 for( c = 0; c < nvars; ++c )
1578 varcomponent[c] = conscomponent[varcomponent[c]];
1579
1580 SCIPfreeBufferArray(scip, &permu);
1581 SCIPfreeBufferArray(scip, &compsize);
1582
1583 /* do the mapping from calculated components per variable to corresponding
1584 * constraints and sort the component-arrays for faster finding the
1585 * actual variables and constraints belonging to one component
1586 */
1587 for( c = 0; c < nconss; c++ )
1588 conscomponent[c] = (firstvaridxpercons[c] == -1 ? -1 : varcomponent[firstvaridxpercons[c]]);
1589
1590 SCIPsortIntPtr(varcomponent, (void**)vars, nvars);
1591 SCIPsortIntPtr(conscomponent, (void**)conss, nconss);
1592
1593 return SCIP_OKAY;
1594}
1595
1596
1597
1598/** create PROBLEM structure for the current node and split it into components */
1599static
1601 SCIP* scip, /**< SCIP data structure */
1602 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1603 SCIP_Real fixedvarsobjsum, /**< objective contribution of all locally fixed variables */
1604 SCIP_VAR** sortedvars, /**< array of unfixed variables sorted by components */
1605 SCIP_CONS** sortedconss, /**< array of (checked) constraints sorted by components */
1606 int* compstartsvars, /**< start points of components in sortedvars array */
1607 int* compstartsconss, /**< start points of components in sortedconss array */
1608 int ncomponents, /**< number of components */
1609 PROBLEM** problem /**< pointer to store problem structure */
1610 )
1611{
1612 COMPONENT* component;
1613 SCIP_HASHMAP* consmap;
1614 SCIP_HASHMAP* varmap;
1615 SCIP_VAR** compvars;
1616 SCIP_CONS** compconss;
1617 SCIP_Bool success = TRUE;
1618 int nfixedvars = SCIPgetNVars(scip) - compstartsvars[ncomponents];
1619 int ncompconss;
1620 int comp;
1621
1622 /* init subproblem data structure */
1623 SCIP_CALL( initProblem(scip, problem, fixedvarsobjsum, ncomponents) );
1624 assert((*problem)->components != NULL);
1625
1626 /* hashmap mapping from original constraints to constraints in the sub-SCIPs (for performance reasons) */
1627 SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), compstartsconss[ncomponents]) );
1628
1629 /* loop over all components */
1630 for( comp = 0; comp < ncomponents; comp++ )
1631 {
1632 SCIP_CALL( initComponent(*problem) );
1633 assert((*problem)->ncomponents == comp+1);
1634
1635 component = &(*problem)->components[comp];
1636
1637 /* get component variables and store them in component structure */
1638 compvars = &(sortedvars[compstartsvars[comp]]);
1639 component->nvars = compstartsvars[comp + 1 ] - compstartsvars[comp];
1640 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &component->vars, compvars, component->nvars) );
1641 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &component->subvars, component->nvars) );
1642 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), component->nvars + nfixedvars) );
1643
1644 /* get component constraints */
1645 compconss = &(sortedconss[compstartsconss[comp]]);
1646 ncompconss = compstartsconss[comp + 1] - compstartsconss[comp];
1647
1648#ifdef DETAILED_OUTPUT
1649 /* print details about the component including its size */
1650 if( component->nvars > 1 && ncompconss > 1 )
1651 {
1652 int nbinvars = 0;
1653 int nintvars = 0;
1654 int ncontvars = 0;
1655 int i;
1656
1657 for( i = 0; i < component->nvars; ++i )
1658 {
1659 if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_BINARY )
1660 ++nbinvars;
1661 else if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_INTEGER )
1662 ++nintvars;
1663 else
1664 ++ncontvars;
1665 }
1666 SCIPdebugMsg(scip, "component %d at node %lld, depth %d (%d): %d vars (%d bin, %d int, %d cont), %d conss\n",
1667 comp, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), SCIPgetDepth(scip), SCIPgetDepth(scip) + conshdlrdata->subscipdepth,
1668 component->nvars, nbinvars, nintvars, ncontvars, ncompconss);
1669 }
1670#endif
1671 assert(ncompconss > 0 || component->nvars == 1);
1672
1673 SCIPdebugMsg(scip, "build sub-SCIP for component %d of problem <%s>: %d vars, %d conss\n",
1674 component->number, (*problem)->name, component->nvars, ncompconss);
1675
1676#ifndef NDEBUG
1677 {
1678 int i;
1679 for( i = 0; i < component->nvars; ++i )
1680 assert(SCIPvarIsActive(component->vars[i]));
1681 }
1682#endif
1683
1684 /* build subscip for component */
1685 SCIP_CALL( componentCreateSubscip(component, conshdlrdata, varmap, consmap, compconss, ncompconss, &success) );
1686
1687 if( success )
1688 {
1689 SCIP_CALL( componentSetupWorkingSol(component, varmap) );
1690
1691 /* add component to the priority queue of the problem structure */
1692 SCIP_CALL( SCIPpqueueInsert((*problem)->compqueue, component) );
1693 }
1694
1695 SCIPhashmapFree(&varmap);
1696
1697 if( !success )
1698 break;
1699 }
1700
1701 SCIPhashmapFree(&consmap);
1702
1703 if( !success )
1704 {
1705 /* free subproblem data structure since not all component could be copied */
1706 SCIP_CALL( freeProblem(problem) );
1707 }
1708
1709 return SCIP_OKAY;
1710}
1711
1712/** continue solving a problem */
1713static
1715 PROBLEM* problem, /**< problem structure */
1716 SCIP_RESULT* result /**< result pointer for the problem solve */
1717 )
1718{
1719 COMPONENT* component;
1720 SCIP_RESULT subscipresult;
1721
1722 assert(problem != NULL);
1723
1724 *result = SCIP_SUCCESS;
1725
1726 component = (COMPONENT*)SCIPpqueueRemove(problem->compqueue);
1727
1728 /* continue solving the component */
1729 SCIP_CALL( solveComponent(component, SCIPpqueueNElems(problem->compqueue) == 0, &subscipresult) );
1730
1731 /* if infeasibility or unboundedness was detected, return this */
1732 if( subscipresult == SCIP_CUTOFF || subscipresult == SCIP_UNBOUNDED )
1733 {
1734 *result = subscipresult;
1735 }
1736 /* the component was not solved to optimality, so we need to re-insert it in the components queue */
1737 else if( !component->solved )
1738 {
1739 SCIP_CALL( SCIPpqueueInsert(problem->compqueue, component) );
1740 *result = SCIP_DELAYNODE;
1741 }
1742 /* no unsolved components are left, so this problem has be completely evaluated and the node can be pruned */
1743 else if( SCIPpqueueNElems(problem->compqueue) == 0 )
1744 *result = SCIP_CUTOFF;
1745 /* there are some unsolved components left, so we delay this node */
1746 else
1747 *result = SCIP_DELAYNODE;
1748
1749 return SCIP_OKAY;
1750}
1751
1752/*
1753 * Local methods
1754 */
1755
1756/** loop over constraints, get active variables and fill directed graph */
1757static
1759 SCIP* scip, /**< SCIP data structure */
1760 SCIP_DIGRAPH* digraph, /**< directed graph */
1761 SCIP_CONS** conss, /**< constraints */
1762 int nconss, /**< number of constraints */
1763 int* unfixedvarpos, /**< mapping from variable problem index to unfixed var index */
1764 int nunfixedvars, /**< number of unfixed variables */
1765 int* firstvaridxpercons, /**< array to store for each constraint the index in the local vars array
1766 * of the first variable of the constraint */
1767 SCIP_Bool* success /**< flag indicating successful directed graph filling */
1768 )
1769{
1770 SCIP_VAR** consvars;
1771 int requiredsize;
1772 int nconsvars;
1773 int nvars;
1774 int idx1;
1775 int idx2;
1776 int c;
1777 int v;
1778
1779 assert(scip != NULL);
1780 assert(digraph != NULL);
1781 assert(conss != NULL);
1782 assert(firstvaridxpercons != NULL);
1783 assert(success != NULL);
1784
1785 *success = TRUE;
1786
1787 nconsvars = 0;
1788 requiredsize = 0;
1789 nvars = SCIPgetNVars(scip);
1790
1791 /* allocate buffer for storing active variables per constraint; size = nvars ensures that it will be big enough */
1792 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
1793
1794 for( c = 0; c < nconss; ++c )
1795 {
1796 /* check for reached timelimit */
1797 if( (c % 1000 == 0) && SCIPisStopped(scip) )
1798 {
1799 *success = FALSE;
1800 break;
1801 }
1802
1803 /* get number of variables for this constraint */
1804 SCIP_CALL( SCIPgetConsNVars(scip, conss[c], &nconsvars, success) );
1805
1806 if( !(*success) )
1807 break;
1808
1809 /* reallocate consvars array, if needed */
1810 if( nconsvars > nvars )
1811 {
1812 nvars = nconsvars;
1813 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, nvars) );
1814 }
1815
1816#ifndef NDEBUG
1817 /* clearing variables array to check for consistency */
1818 if( nconsvars == nvars )
1819 {
1820 BMSclearMemoryArray(consvars, nconsvars);
1821 }
1822 else
1823 {
1824 assert(nconsvars < nvars);
1825 BMSclearMemoryArray(consvars, nconsvars + 1);
1826 }
1827#endif
1828
1829 /* get variables for this constraint */
1830 SCIP_CALL( SCIPgetConsVars(scip, conss[c], consvars, nvars, success) );
1831
1832 if( !(*success) )
1833 {
1834#ifndef NDEBUG
1835 /* it looks strange if returning the number of variables was successful but not returning the variables */
1836 SCIPwarningMessage(scip, "constraint <%s> returned number of variables but returning variables failed\n", SCIPconsGetName(conss[c]));
1837#endif
1838 break;
1839 }
1840
1841#ifndef NDEBUG
1842 /* check if returned variables are consistent with the number of variables that were returned */
1843 for( v = nconsvars - 1; v >= 0; --v )
1844 assert(consvars[v] != NULL);
1845 if( nconsvars < nvars )
1846 assert(consvars[nconsvars] == NULL);
1847#endif
1848
1849 /* transform given variables to active variables */
1850 SCIP_CALL( SCIPgetActiveVars(scip, consvars, &nconsvars, nvars, &requiredsize) );
1851 assert(requiredsize <= nvars);
1852
1853 firstvaridxpercons[c] = -1;
1854
1855 /* store the index of the first unfixed variable and add edges to the directed graph */
1856 if( nconsvars > 0 )
1857 {
1858 v = 0;
1859 idx1 = -1;
1860
1861 /* go through variables until the first unfixed one is reached (which has unfixedvarpos >= 0) */
1862 while( idx1 == -1 && v < nconsvars )
1863 {
1864 idx1 = SCIPvarGetProbindex(consvars[v]);
1865 assert(idx1 >= 0);
1866 idx1 = unfixedvarpos[idx1];
1867 assert(idx1 < nunfixedvars);
1868 ++v;
1869 }
1870
1871 if( idx1 >= 0 )
1872 {
1873 /* save index of the first variable for later component assignment */
1874 firstvaridxpercons[c] = idx1;
1875
1876 /* create sparse directed graph; sparse means to add only those edges necessary for component calculation,
1877 * i.e., add edges from the first variable to all others
1878 */
1879 for(; v < nconsvars; ++v )
1880 {
1881 idx2 = SCIPvarGetProbindex(consvars[v]);
1882 assert(idx2 >= 0);
1883 idx2 = unfixedvarpos[idx2];
1884 assert(idx2 < nunfixedvars);
1885
1886 /* variable is fixed */
1887 if( idx2 < 0 )
1888 continue;
1889
1890 /* we add only one directed edge, because the other direction is automatically added for component computation */
1891 SCIP_CALL( SCIPdigraphAddArc(digraph, idx1, idx2, NULL) );
1892 }
1893 }
1894 }
1895 }
1896
1897 SCIPfreeBufferArray(scip, &consvars);
1898
1899 return SCIP_OKAY;
1900}
1901
1902/** search for components in the problem */
1903static
1905 SCIP* scip, /**< SCIP main data structure */
1906 SCIP_CONSHDLRDATA* conshdlrdata, /**< the components constraint handler data */
1907 SCIP_Real* fixedvarsobjsum, /**< objective contribution of all locally fixed variables, or NULL if
1908 * fixed variables should not be disregarded */
1909 SCIP_VAR** sortedvars, /**< array to store variables sorted by components, should have enough size
1910 * for all variables */
1911 SCIP_CONS** sortedconss, /**< array to store (checked) constraints sorted by components, should have
1912 * enough size for all constraints */
1913 int* compstartsvars, /**< start points of components in sortedvars array */
1914 int* compstartsconss, /**< start points of components in sortedconss array */
1915 int* nsortedvars, /**< pointer to store the number of variables belonging to any component */
1916 int* nsortedconss, /**< pointer to store the number of (checked) constraints in components */
1917 int* ncomponents, /**< pointer to store the number of components */
1918 int* ncompsminsize, /**< pointer to store the number of components not exceeding the minimum size */
1919 int* ncompsmaxsize /**< pointer to store the number of components not exceeding the maximum size */
1920
1921 )
1922{
1923 SCIP_CONS** tmpconss;
1924 SCIP_VAR** vars;
1925 SCIP_Bool success;
1926 int ntmpconss;
1927 int nvars;
1928 int c;
1929
1930 assert(scip != NULL);
1931 assert(conshdlrdata != NULL);
1932 assert(sortedvars != NULL);
1933 assert(sortedconss != NULL);
1934 assert(compstartsvars != NULL);
1935 assert(compstartsconss != NULL);
1936 assert(nsortedvars != NULL);
1937 assert(nsortedconss != NULL);
1938 assert(ncomponents != NULL);
1939 assert(ncompsminsize != NULL);
1940 assert(ncompsmaxsize != NULL);
1941
1942 vars = SCIPgetVars(scip);
1943 nvars = SCIPgetNVars(scip);
1944
1945 if( fixedvarsobjsum != NULL )
1946 *fixedvarsobjsum = 0.0;
1947
1948 *ncomponents = 0;
1949 *ncompsminsize = 0;
1950 *ncompsmaxsize = 0;
1951
1952 /* collect checked constraints for component detection */
1953 ntmpconss = SCIPgetNConss(scip);
1954 tmpconss = SCIPgetConss(scip);
1955 (*nsortedconss) = 0;
1956 for( c = 0; c < ntmpconss; c++ )
1957 {
1958 sortedconss[(*nsortedconss)] = tmpconss[c];
1959 (*nsortedconss)++;
1960 }
1961
1962 if( nvars > 1 && *nsortedconss > 1 )
1963 {
1964 int* unfixedvarpos;
1965 int* firstvaridxpercons;
1966 int* varlocks;
1967 int nunfixedvars = 0;
1968 int v;
1969
1970 /* arrays for storing the first variable in each constraint (for later component assignment), the number of
1971 * variable locks, and the positions in the sortedvars array for all unfixed variables
1972 */
1973 SCIP_CALL( SCIPallocBufferArray(scip, &firstvaridxpercons, *nsortedconss) );
1974 SCIP_CALL( SCIPallocBufferArray(scip, &varlocks, nvars) );
1975 SCIP_CALL( SCIPallocBufferArray(scip, &unfixedvarpos, nvars) );
1976
1977 /* count number of varlocks for each variable (up + down locks) and multiply it by 2;
1978 * that value is used as an estimate of the number of arcs incident to the variable's node in the digraph
1979 * to be safe, we double this value
1980 */
1981 for( v = 0; v < nvars; ++v )
1982 {
1983 /* variable is not fixed or we do not want to disregard fixed variables */
1984 if( (fixedvarsobjsum == NULL) || SCIPisLT(scip, SCIPvarGetLbLocal(vars[v]), SCIPvarGetUbLocal(vars[v])) )
1985 {
1986 assert(nunfixedvars <= v);
1987 sortedvars[nunfixedvars] = vars[v];
1988 varlocks[nunfixedvars] = 4 * (SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL)
1990 unfixedvarpos[v] = nunfixedvars;
1991 ++nunfixedvars;
1992 }
1993 /* variable is fixed; update the objective sum of all fixed variables */
1994 else
1995 {
1996 unfixedvarpos[v] = -1;
1997 (*fixedvarsobjsum) += SCIPvarGetObj(vars[v]) * SCIPvarGetLbLocal(vars[v]);
1998 }
1999 }
2000 *nsortedvars = nunfixedvars;
2001
2002 if( nunfixedvars > 0 )
2003 {
2004 SCIP_DIGRAPH* digraph;
2005
2006 /* create and fill directed graph */
2007 SCIP_CALL( SCIPcreateDigraph(scip, &digraph, nunfixedvars) );
2008 SCIP_CALL( SCIPdigraphSetSizes(digraph, varlocks) );
2009 SCIP_CALL( fillDigraph(scip, digraph, sortedconss, *nsortedconss, unfixedvarpos, nunfixedvars, firstvaridxpercons, &success) );
2010
2011 if( success )
2012 {
2013 int* varcomponent;
2014 int* conscomponent;
2015
2016 SCIP_CALL( SCIPallocBufferArray(scip, &varcomponent, nunfixedvars) );
2017 SCIP_CALL( SCIPallocBufferArray(scip, &conscomponent, MAX(nunfixedvars,*nsortedconss)) );
2018
2019 /* compute independent components */
2020 SCIP_CALL( SCIPdigraphComputeUndirectedComponents(digraph, 1, varcomponent, ncomponents) );
2021
2022 if( *ncomponents > 1 )
2023 {
2024 int nconss = *nsortedconss;
2025 int i;
2026
2027 nvars = *nsortedvars;
2028
2030 "cons components found %d undirected components at node %lld, depth %d (%d)\n",
2031 *ncomponents, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), SCIPgetDepth(scip), SCIPgetDepth(scip) + conshdlrdata->subscipdepth);
2032
2033 /* sort components by size and sort variables and constraints by component number */
2034 SCIP_CALL( sortComponents(scip, conshdlrdata, digraph, sortedconss, sortedvars, varcomponent, conscomponent, nconss, *nsortedvars,
2035 firstvaridxpercons, ncompsminsize, ncompsmaxsize) );
2036
2037 /* determine start indices of components in sortedvars and sortedconss array */
2038 i = 0;
2039
2040 while( i < nconss && conscomponent[i] == -1 )
2041 ++i;
2042
2043 for( c = 0; c < *ncomponents + 1; ++c )
2044 {
2045 assert(i == nconss || conscomponent[i] >= c);
2046
2047 compstartsconss[c] = i;
2048
2049 while( i < nconss && conscomponent[i] == c )
2050 ++i;
2051 }
2052
2053 for( c = 0, i = 0; c < *ncomponents + 1; ++c )
2054 {
2055 assert(i == nvars || varcomponent[i] >= c);
2056
2057 compstartsvars[c] = i;
2058
2059 while( i < nvars && varcomponent[i] == c )
2060 ++i;
2061 }
2062
2063#ifndef NDEBUG
2064 for( c = 0; c < *ncomponents; ++c )
2065 {
2066 for( i = compstartsconss[c]; i < compstartsconss[c+1]; ++i )
2067 assert(conscomponent[i] == c);
2068 for( i = compstartsvars[c]; i < compstartsvars[c+1]; ++i )
2069 assert(varcomponent[i] == c);
2070 }
2071#endif
2072 }
2073
2074 SCIPfreeBufferArray(scip, &conscomponent);
2075 SCIPfreeBufferArray(scip, &varcomponent);
2076 }
2077
2078 SCIPdigraphFree(&digraph);
2079 }
2080
2081 SCIPfreeBufferArray(scip, &unfixedvarpos);
2082 SCIPfreeBufferArray(scip, &varlocks);
2083 SCIPfreeBufferArray(scip, &firstvaridxpercons);
2084 }
2085
2086 return SCIP_OKAY;
2087}
2088
2089
2090/*
2091 * Callback methods of constraint handler
2092 */
2093
2094/** copy method for constraint handler plugins (called when SCIP copies plugins) */
2095static
2096SCIP_DECL_CONSHDLRCOPY(conshdlrCopyComponents)
2097{ /*lint --e{715}*/
2098 assert(scip != NULL);
2099 assert(conshdlr != NULL);
2100 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2101
2102 /* call inclusion method of constraint handler */
2104
2105 *valid = TRUE;
2106
2107 return SCIP_OKAY;
2108}
2109
2110/** destructor of constraint handler to free user data (called when SCIP is exiting) */
2111static
2112SCIP_DECL_CONSFREE(conshdlrFreeComponents)
2113{ /*lint --e{715}*/
2114 SCIP_CONSHDLRDATA* conshdlrdata;
2115
2116 /* free constraint handler data */
2117 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2118 assert(conshdlrdata != NULL);
2119
2120 SCIPfreeBlockMemory(scip, &conshdlrdata);
2121 SCIPconshdlrSetData(conshdlr, NULL);
2122
2123 return SCIP_OKAY;
2124}
2125
2126/** domain propagation method of constraint handler */
2127static
2128SCIP_DECL_CONSPROP(consPropComponents)
2129{ /*lint --e{715}*/
2130 PROBLEM* problem;
2131 SCIP_CONSHDLRDATA* conshdlrdata;
2132 SCIP_Longint nodelimit;
2133
2134 assert(conshdlr != NULL);
2135 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2136 assert(result != NULL);
2137 assert(SCIPconshdlrGetNActiveConss(conshdlr) >= 0);
2138 assert(SCIPconshdlrGetNActiveConss(conshdlr) <= 1);
2139
2140 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2141 assert(conshdlrdata != NULL);
2142
2143 *result = SCIP_DIDNOTRUN;
2144
2145 /* do not try to detect independent components if the depth is too high */
2146 if( SCIPgetDepth(scip) + conshdlrdata->subscipdepth > conshdlrdata->maxdepth
2147 && SCIPconshdlrGetNActiveConss(conshdlr) == 0 )
2148 return SCIP_OKAY;
2149
2150 /* don't run in probing or in repropagation */
2152 return SCIP_OKAY;
2153
2154 /* do not run, if not all variables are explicitly known */
2155 if( SCIPgetNActivePricers(scip) > 0 )
2156 return SCIP_OKAY;
2157
2158 /* we do not want to run, if there are no variables left */
2159 if( SCIPgetNVars(scip) == 0 )
2160 return SCIP_OKAY;
2161
2162 /* check for a reached timelimit */
2163 if( SCIPisStopped(scip) )
2164 return SCIP_OKAY;
2165
2166 /* the components constraint handler does kind of dual reductions */
2168 return SCIP_OKAY;
2169
2170 problem = NULL;
2171 *result = SCIP_DIDNOTFIND;
2172
2173 /* the current node already has a components constraint storing a problem split into individual components */
2174 if( SCIPconshdlrGetNActiveConss(conshdlr) >= 1 )
2175 {
2176 assert(SCIPconshdlrGetNActiveConss(conshdlr) == 1);
2177
2178 problem = (PROBLEM*)SCIPconsGetData(SCIPconshdlrGetConss(conshdlr)[0]);
2179 }
2180 /* no components constraint at the current node, search for components */
2181 else
2182 {
2183 SCIP_Real fixedvarsobjsum;
2184 SCIP_VAR** sortedvars;
2185 SCIP_CONS** sortedconss;
2186 int* compstartsvars;
2187 int* compstartsconss;
2188 int nsortedvars;
2189 int nsortedconss;
2190 int ncomponents;
2191 int ncompsminsize;
2192 int ncompsmaxsize;
2193
2194 assert(SCIPconshdlrGetNActiveConss(conshdlr) == 0);
2195
2196 /* allocate memory for sorted components */
2199 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsvars, SCIPgetNVars(scip) + 1) );
2200 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsconss, SCIPgetNVars(scip) + 1) );
2201
2202 /* search for components */
2203 SCIP_CALL( findComponents(scip, conshdlrdata, &fixedvarsobjsum, sortedvars, sortedconss, compstartsvars,
2204 compstartsconss, &nsortedvars, &nsortedconss, &ncomponents, &ncompsminsize, &ncompsmaxsize) );
2205
2206 if( ncompsminsize > 1 )
2207 {
2208 SCIP_CONS* cons;
2209
2210 SCIPdebugMsg(scip, "found %d components (%d fulfilling the minsize requirement) at node %lld at depth %d (%d)\n",
2211 ncomponents, ncompsminsize, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), SCIPgetDepth(scip),
2212 SCIPgetDepth(scip) + conshdlrdata->subscipdepth);
2213
2214 /* if there are components with size smaller than the limit, we merge them with the smallest component */
2215 if( ncomponents > ncompsminsize )
2216 {
2217 int minsize;
2218 int size;
2219 int c;
2220 int m = 0;
2221
2222 /* compute minimum size of components to solve individually */
2223 minsize = getMinsize(scip, conshdlrdata);
2224
2225 for( c = 0; c < ncomponents; ++c )
2226 {
2227 size = compstartsvars[c+1] - compstartsvars[c];
2228
2229 if( size >= minsize )
2230 {
2231 ++m;
2232 compstartsvars[m] = compstartsvars[c+1];
2233 compstartsconss[m] = compstartsconss[c+1];
2234 }
2235 /* the last component is too small */
2236 else if( c == ncomponents - 1 )
2237 {
2238 assert(m == ncompsminsize);
2239 compstartsvars[m] = compstartsvars[c+1];
2240 compstartsconss[m] = compstartsconss[c+1];
2241 }
2242 }
2243 assert(m == ncompsminsize);
2244 assert(compstartsvars[m] == nsortedvars);
2245 assert(compstartsconss[m] == nsortedconss);
2246
2247 ncomponents = m;
2248 }
2249
2250 SCIP_CALL( createAndSplitProblem(scip, conshdlrdata, fixedvarsobjsum, sortedvars, sortedconss, compstartsvars,
2251 compstartsconss, ncomponents, &problem) );
2252
2253 /* if the problem is not NULL, copying worked fine */
2254 if( problem != NULL )
2255 {
2256 SCIP_CALL( createConsComponents(scip, &cons, problem->name, problem) );
2258 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2259 }
2260 }
2261
2262 SCIPfreeBufferArray(scip, &compstartsconss);
2263 SCIPfreeBufferArray(scip, &compstartsvars);
2264 SCIPfreeBufferArray(scip, &sortedconss);
2265 SCIPfreeBufferArray(scip, &sortedvars);
2266 }
2267
2268 /* (continue to) solve the problem
2269 *
2270 * If the problem was not solved to optimality yet, the result code is set to SCIP_DELAYNODE, so that after the
2271 * propagation is finished, the node is put back into the queue of open nodes and solving the components of the
2272 * problem will be continued when the node is focused and propagated the next time.
2273 * However, if we are at the root node, we continue solving the problem until it is solved or some limit is reached
2274 * since there are no other nodes to process and we want to avoid calling other propagation methods or heuristics
2275 * again and again
2276 */
2277 SCIP_CALL( SCIPgetLongintParam(scip, "limits/nodes", &nodelimit) );
2278 if( nodelimit == -1 )
2279 nodelimit = SCIP_LONGINT_MAX;
2280
2281 do
2282 {
2283 if( problem != NULL )
2284 {
2285 SCIP_CALL( solveProblem(problem, result) );
2286 }
2287 } while( *result == SCIP_DELAYNODE && SCIPgetDepth(scip) == 0 && !SCIPisStopped(scip) && SCIPgetNNodes(scip) < nodelimit);
2288
2289 return SCIP_OKAY;
2290}
2291
2292/** presolving method of constraint handler */
2293static
2294SCIP_DECL_CONSPRESOL(consPresolComponents)
2295{ /*lint --e{715}*/
2296 SCIP_CONSHDLRDATA* conshdlrdata;
2297 SCIP_VAR** sortedvars;
2298 SCIP_CONS** sortedconss;
2299 int* compstartsvars;
2300 int* compstartsconss;
2301 int nsortedvars;
2302 int nsortedconss;
2303 int ncomponents;
2304 int ncompsminsize;
2305 int ncompsmaxsize;
2306 int nvars;
2307
2308 assert(conshdlr != NULL);
2309 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2310 assert(result != NULL);
2311 assert(SCIPconshdlrGetNActiveConss(conshdlr) >= 0);
2312 assert(SCIPconshdlrGetNActiveConss(conshdlr) <= 1);
2313
2314 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2315 assert(conshdlrdata != NULL);
2316
2317 *result = SCIP_DIDNOTRUN;
2318
2320 return SCIP_OKAY;
2321
2322 /* do not run, if not all variables are explicitly known */
2323 if( SCIPgetNActivePricers(scip) > 0 )
2324 return SCIP_OKAY;
2325
2326 nvars = SCIPgetNVars(scip);
2327
2328 /* we do not want to run, if there are no variables left */
2329 if( nvars == 0 )
2330 return SCIP_OKAY;
2331
2332 /* only call the components presolving, if presolving would be stopped otherwise */
2334 return SCIP_OKAY;
2335
2336 /* the components constraint handler does kind of dual reductions */
2338 return SCIP_OKAY;
2339
2340 /* check for a reached timelimit */
2341 if( SCIPisStopped(scip) )
2342 return SCIP_OKAY;
2343
2344 *result = SCIP_DIDNOTFIND;
2345
2346 assert(SCIPconshdlrGetNActiveConss(conshdlr) == 0);
2347
2348 /* allocate memory for sorted components */
2351 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsvars, SCIPgetNVars(scip) + 1) );
2352 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsconss, SCIPgetNVars(scip) + 1) );
2353
2354 /* search for components */
2355 SCIP_CALL( findComponents(scip, conshdlrdata, NULL, sortedvars, sortedconss, compstartsvars,
2356 compstartsconss, &nsortedvars, &nsortedconss, &ncomponents, &ncompsminsize, &ncompsmaxsize) );
2357
2358 if( ncompsmaxsize > 0 )
2359 {
2360 char name[SCIP_MAXSTRLEN];
2361 SCIP* subscip;
2362 SCIP_HASHMAP* consmap;
2363 SCIP_HASHMAP* varmap;
2364 SCIP_VAR** compvars;
2365 SCIP_VAR** subvars;
2366 SCIP_CONS** compconss;
2367 SCIP_Bool success;
2368 SCIP_Bool solved;
2369 int nsolved = 0;
2370 int ncompvars;
2371 int ncompconss;
2372 int comp;
2373
2374 SCIPdebugMsg(scip, "found %d components (%d with small size) during presolving; overall problem size: %d vars (%d int, %d bin, %d cont), %d conss\n",
2376
2377 /* build subscip */
2378 SCIP_CALL( createSubscip(scip, conshdlrdata, &subscip) );
2379
2380 if( subscip == NULL )
2381 goto TERMINATE;
2382
2383 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/usesmalltables", TRUE) );
2384 SCIP_CALL( SCIPsetIntParam(subscip, "constraints/" CONSHDLR_NAME "/propfreq", -1) );
2385
2386 /* hashmap mapping from original constraints to constraints in the sub-SCIPs (for performance reasons) */
2387 SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), nsortedconss) );
2388
2389 SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nsortedvars) );
2390
2391 /* loop over all components */
2392 for( comp = 0; comp < ncompsmaxsize && !SCIPisStopped(scip); comp++ )
2393 {
2394#ifdef WITH_DEBUG_SOLUTION
2395 if( SCIPgetStage(subscip) > SCIP_STAGE_INIT )
2396 {
2397 SCIP_CALL( SCIPfree(&subscip) );
2398 SCIP_CALL( createSubscip(scip, conshdlrdata, &subscip) );
2399 }
2400#endif
2401 /* get component variables */
2402 compvars = &(sortedvars[compstartsvars[comp]]);
2403 ncompvars = compstartsvars[comp + 1 ] - compstartsvars[comp];
2404
2405 /* get component constraints */
2406 compconss = &(sortedconss[compstartsconss[comp]]);
2407 ncompconss = compstartsconss[comp + 1] - compstartsconss[comp];
2408
2409 /* if we have an unlocked variable, let duality fixing do the job! */
2410 if( ncompconss == 0 )
2411 {
2412 assert(ncompvars == 1);
2413 continue;
2414 }
2415
2416 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), ncompvars) );
2417#ifdef DETAILED_OUTPUT
2418 {
2419 int nbinvars = 0;
2420 int nintvars = 0;
2421 int ncontvars = 0;
2422 int i;
2423
2424 for( i = 0; i < ncompvars; ++i )
2425 {
2426 if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_BINARY )
2427 ++nbinvars;
2428 else if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_INTEGER )
2429 ++nintvars;
2430 else
2431 ++ncontvars;
2432 }
2433 SCIPdebugMsg(scip, "solve component %d: %d vars (%d bin, %d int, %d cont), %d conss\n",
2434 comp, ncompvars, nbinvars, nintvars, ncontvars, ncompconss);
2435 }
2436#endif
2437#ifndef NDEBUG
2438 {
2439 int i;
2440 for( i = 0; i < ncompvars; ++i )
2441 assert(SCIPvarIsActive(compvars[i]));
2442 }
2443#endif
2444
2445 /* get name of the original problem and add "comp_nr" */
2446 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp_%d", SCIPgetProbName(scip), comp);
2447
2448 SCIP_CALL( copyToSubscip(scip, subscip, name, compvars, subvars,
2449 compconss, varmap, consmap, ncompvars, ncompconss, &success) );
2450
2451 if( !success )
2452 {
2453 SCIPhashmapFree(&varmap);
2454 continue;
2455 }
2456
2457 /* set up debug solution */
2458#ifdef WITH_DEBUG_SOLUTION
2460 {
2461 SCIP_SOL* debugsol;
2462 SCIP_Real val;
2463 int i;
2464
2465 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
2466
2467 /* set solution values in the debug solution if it is available */
2468 if( debugsol != NULL )
2469 {
2470 SCIPdebugSolEnable(subscip);
2471
2472 for( i = 0; i < ncompvars; ++i )
2473 {
2474 if( subvars[i] != NULL )
2475 {
2476 SCIP_CALL( SCIPdebugGetSolVal(scip, compvars[i], &val) );
2477 SCIP_CALL( SCIPdebugAddSolVal(subscip, subvars[i], val) );
2478 }
2479 }
2480 }
2481 }
2482#endif
2483
2484 /* solve the subproblem and evaluate the result, i.e. apply fixings of variables and remove constraints */
2485 SCIP_CALL( solveAndEvalSubscip(scip, conshdlrdata, subscip, compvars, subvars, compconss,
2486 ncompvars, ncompconss, ndelconss, nfixedvars, nchgbds, result, &solved) );
2487
2488 /* free variable hash map */
2489 SCIPhashmapFree(&varmap);
2490
2491 if( solved )
2492 ++nsolved;
2493
2494 /* if the component is unbounded or infeasible, this holds for the complete problem as well */
2495 if( *result == SCIP_UNBOUNDED || *result == SCIP_CUTOFF )
2496 break;
2497 /* if there is only one component left, let's solve this in the main SCIP */
2498 else if( nsolved == ncomponents - 1 )
2499 break;
2500 }
2501
2502 SCIPfreeBufferArray(scip, &subvars);
2503 SCIPhashmapFree(&consmap);
2504
2505 SCIP_CALL( SCIPfree(&subscip) );
2506 }
2507
2508 TERMINATE:
2509 SCIPfreeBufferArray(scip, &compstartsconss);
2510 SCIPfreeBufferArray(scip, &compstartsvars);
2511 SCIPfreeBufferArray(scip, &sortedconss);
2512 SCIPfreeBufferArray(scip, &sortedvars);
2513
2514 return SCIP_OKAY;
2515}
2516
2517/** frees specific constraint data */
2518static
2519SCIP_DECL_CONSDELETE(consDeleteComponents)
2520{ /*lint --e{715}*/
2521 assert(conshdlr != NULL);
2522 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2523 assert(consdata != NULL);
2524 assert(*consdata != NULL);
2525
2526 SCIP_CALL( freeProblem((PROBLEM**) consdata) );
2527
2528 return SCIP_OKAY;
2529}
2530
2531/** constraint enforcing method of constraint handler for relaxation solutions */
2532static
2533SCIP_DECL_CONSENFORELAX(consEnforelaxComponents)
2534{ /*lint --e{715}*/
2535 assert(result != NULL);
2536
2537 /* no enforcement is performed, but the callback is needed for all constraint handlers with needscons = FALSE */
2538 *result = SCIP_FEASIBLE;
2539
2540 return SCIP_OKAY;
2541}
2542
2543/** variable rounding lock method of constraint handler */
2544static
2545SCIP_DECL_CONSLOCK(consLockComponents)
2546{ /*lint --e{715}*/
2547 return SCIP_OKAY;
2548}
2549
2550#ifndef NDEBUG
2551/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
2552static
2553SCIP_DECL_CONSINITSOL(consInitsolComponents)
2554{ /*lint --e{715}*/
2555 assert(nconss == 0);
2556
2557 return SCIP_OKAY;
2558}
2559#endif
2560
2561#define consEnfolpComponents NULL
2562#define consEnfopsComponents NULL
2563#define consCheckComponents NULL
2564
2565/** creates the components constraint handler and includes it in SCIP */
2567 SCIP* scip /**< SCIP data structure */
2568 )
2569{
2570 SCIP_CONSHDLRDATA* conshdlrdata;
2571 SCIP_CONSHDLR* conshdlr;
2572
2573 /* create components constraint data */
2574 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
2575 conshdlrdata->subscipdepth = 0;
2576
2577 /* include constraint handler */
2581 conshdlrdata) );
2582 assert(conshdlr != NULL);
2583
2584 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropComponents,
2586 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolComponents,
2588
2589 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, conshdlrFreeComponents) );
2590 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxComponents) );
2591#ifndef NDEBUG
2592 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolComponents) );
2593#endif
2594 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyComponents, NULL) );
2595 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteComponents) );
2596
2598 "constraints/" CONSHDLR_NAME "/maxdepth",
2599 "maximum depth of a node to run components detection (-1: disable component detection during solving)",
2600 &conshdlrdata->maxdepth, FALSE, DEFAULT_MAXDEPTH, -1, INT_MAX, NULL, NULL) );
2602 "constraints/" CONSHDLR_NAME "/maxintvars",
2603 "maximum number of integer (or binary) variables to solve a subproblem during presolving (-1: unlimited)",
2604 &conshdlrdata->maxintvars, TRUE, DEFAULT_MAXINTVARS, -1, INT_MAX, NULL, NULL) );
2606 "constraints/" CONSHDLR_NAME "/minsize",
2607 "minimum absolute size (in terms of variables) to solve a component individually during branch-and-bound",
2608 &conshdlrdata->minsize, TRUE, DEFAULT_MINSIZE, 0, INT_MAX, NULL, NULL) );
2610 "constraints/" CONSHDLR_NAME "/minrelsize",
2611 "minimum relative size (in terms of variables) to solve a component individually during branch-and-bound",
2612 &conshdlrdata->minrelsize, TRUE, DEFAULT_MINRELSIZE, 0.0, 1.0, NULL, NULL) );
2614 "constraints/" CONSHDLR_NAME "/nodelimit",
2615 "maximum number of nodes to be solved in subproblems during presolving",
2616 &conshdlrdata->nodelimit, FALSE, DEFAULT_NODELIMIT, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
2618 "constraints/" CONSHDLR_NAME "/maxcompweight",
2619 "the maximum weight of a component, in terms of the used factors",
2620 &conshdlrdata->maxcompweight, FALSE, DEFAULT_MAXCOMPWEIGHT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2622 "constraints/" CONSHDLR_NAME "/intfactor",
2623 "the weight of an integer variable compared to binary variables",
2624 &conshdlrdata->intfactor, FALSE, DEFAULT_INTFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2626 "constraints/" CONSHDLR_NAME "/contfactor",
2627 "the weight of a continuous variable compared to binary variables",
2628 &conshdlrdata->contfactor, FALSE, DEFAULT_CONTFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2630 "constraints/" CONSHDLR_NAME "/feastolfactor",
2631 "factor to increase the feasibility tolerance of the main SCIP in all sub-SCIPs, default value 1.0",
2632 &conshdlrdata->feastolfactor, TRUE, DEFAULT_FEASTOLFACTOR, 0.0, 1000000.0, NULL, NULL) );
2633
2634 return SCIP_OKAY;
2635}
static SCIP_RETCODE copyToSubscip(SCIP *scip, SCIP *subscip, const char *name, SCIP_VAR **vars, SCIP_VAR **subvars, SCIP_CONS **conss, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, int nvars, int nconss, SCIP_Bool *success)
#define CONSHDLR_NEEDSCONS
#define CONSHDLR_CHECKPRIORITY
#define DEFAULT_CONTFACTOR
#define CONSHDLR_DESC
#define DEFAULT_MINRELSIZE
static SCIP_RETCODE createConsComponents(SCIP *scip, SCIP_CONS **cons, const char *name, PROBLEM *problem)
static SCIP_RETCODE createAndSplitProblem(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Real fixedvarsobjsum, SCIP_VAR **sortedvars, SCIP_CONS **sortedconss, int *compstartsvars, int *compstartsconss, int ncomponents, PROBLEM **problem)
static SCIP_RETCODE initComponent(PROBLEM *problem)
static SCIP_RETCODE fillDigraph(SCIP *scip, SCIP_DIGRAPH *digraph, SCIP_CONS **conss, int nconss, int *unfixedvarpos, int nunfixedvars, int *firstvaridxpercons, SCIP_Bool *success)
static int getMinsize(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
#define CONSHDLR_PROP_TIMING
#define DEFAULT_FEASTOLFACTOR
#define consEnfolpComponents
static SCIP_DECL_CONSDELETE(consDeleteComponents)
#define CONSHDLR_MAXPREROUNDS
#define consEnfopsComponents
#define DEFAULT_MAXINTVARS
static SCIP_RETCODE componentSetupWorkingSol(COMPONENT *component, SCIP_HASHMAP *varmap)
static SCIP_DECL_SORTPTRCOMP(componentSort)
static SCIP_RETCODE freeProblem(PROBLEM **problem)
static SCIP_DECL_CONSENFORELAX(consEnforelaxComponents)
#define DEFAULT_MAXDEPTH
static SCIP_RETCODE componentCreateSubscip(COMPONENT *component, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_CONS **conss, int nconss, SCIP_Bool *success)
static SCIP_RETCODE createSubscip(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP **subscip)
#define DEFAULT_INTFACTOR
#define DEFAULT_NODELIMIT
static SCIP_DECL_CONSFREE(conshdlrFreeComponents)
static SCIP_RETCODE sortComponents(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *digraph, SCIP_CONS **conss, SCIP_VAR **vars, int *varcomponent, int *conscomponent, int nconss, int nvars, int *firstvaridxpercons, int *ncompsminsize, int *ncompsmaxsize)
#define DEFAULT_MAXCOMPWEIGHT
#define consCheckComponents
static SCIP_RETCODE solveProblem(PROBLEM *problem, SCIP_RESULT *result)
static SCIP_DECL_CONSPROP(consPropComponents)
#define CONSHDLR_PROPFREQ
static SCIP_RETCODE solveSubscip(SCIP *scip, SCIP *subscip, SCIP_Longint nodelimit, SCIP_Real gaplimit)
static SCIP_RETCODE solveComponent(COMPONENT *component, SCIP_Bool lastcomponent, SCIP_RESULT *result)
#define CONSHDLR_PRESOLTIMING
static SCIP_DECL_CONSINITSOL(consInitsolComponents)
static SCIP_RETCODE freeComponent(COMPONENT *component)
static SCIP_DECL_CONSLOCK(consLockComponents)
#define CONSHDLR_EAGERFREQ
#define DEFAULT_MINSIZE
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyComponents)
#define CONSHDLR_ENFOPRIORITY
struct Problem PROBLEM
static SCIP_DECL_CONSPRESOL(consPresolComponents)
static SCIP_RETCODE solveAndEvalSubscip(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP *subscip, SCIP_VAR **vars, SCIP_VAR **subvars, SCIP_CONS **conss, int nvars, int nconss, int *ndeletedconss, int *nfixedvars, int *ntightenedbounds, SCIP_RESULT *result, SCIP_Bool *solved)
static SCIP_RETCODE findComponents(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Real *fixedvarsobjsum, SCIP_VAR **sortedvars, SCIP_CONS **sortedconss, int *compstartsvars, int *compstartsconss, int *nsortedvars, int *nsortedconss, int *ncomponents, int *ncompsminsize, int *ncompsmaxsize)
static SCIP_RETCODE initProblem(SCIP *scip, PROBLEM **problem, SCIP_Real fixedvarsobjsum, int ncomponents)
#define CONSHDLR_NAME
struct Component COMPONENT
#define CONSHDLR_DELAYPROP
constraint handler for handling independent components
methods for debugging
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:299
#define SCIPdebugSolEnable(scip)
Definition: debug.h:301
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:298
#define SCIPdebugSolIsEnabled(scip)
Definition: debug.h:303
#define SCIPdebugSolIsValidInSubtree(scip, isvalidinsubtree)
Definition: debug.h:300
#define NULL
Definition: def.h:266
#define SCIP_MAXSTRLEN
Definition: def.h:287
#define SCIP_Longint
Definition: def.h:157
#define SCIP_REAL_MAX
Definition: def.h:173
#define SCIP_INVALID
Definition: def.h:192
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:242
#define SCIP_Real
Definition: def.h:172
#define ABS(x)
Definition: def.h:234
#define SQR(x)
Definition: def.h:213
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:238
#define SCIP_LONGINT_FORMAT
Definition: def.h:164
#define SCIP_LONGINT_MAX
Definition: def.h:158
#define SCIP_CALL(x)
Definition: def.h:373
SCIP_RETCODE SCIPincludeConshdlrComponents(SCIP *scip)
SCIP_RETCODE SCIPcopyPlugins(SCIP *sourcescip, SCIP *targetscip, SCIP_Bool copyreaders, SCIP_Bool copypricers, SCIP_Bool copyconshdlrs, SCIP_Bool copyconflicthdlrs, SCIP_Bool copypresolvers, SCIP_Bool copyrelaxators, SCIP_Bool copyseparators, SCIP_Bool copycutselectors, SCIP_Bool copypropagators, SCIP_Bool copyheuristics, SCIP_Bool copyeventhdlrs, SCIP_Bool copynodeselectors, SCIP_Bool copybranchrules, SCIP_Bool copydisplays, SCIP_Bool copydialogs, SCIP_Bool copytables, SCIP_Bool copyexprhdlrs, SCIP_Bool copynlpis, SCIP_Bool passmessagehdlr, SCIP_Bool *valid)
Definition: scip_copy.c:275
SCIP_RETCODE SCIPgetConsCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_CONS *sourcecons, SCIP_CONS **targetcons, SCIP_CONSHDLR *sourceconshdlr, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *name, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
Definition: scip_copy.c:1591
SCIP_RETCODE SCIPcopyProb(SCIP *sourcescip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, const char *name)
Definition: scip_copy.c:527
SCIP_RETCODE SCIPcopyParamSettings(SCIP *sourcescip, SCIP *targetscip)
Definition: scip_copy.c:2564
SCIP_RETCODE SCIPcopyLimits(SCIP *sourcescip, SCIP *targetscip)
Definition: scip_copy.c:3296
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:711
SCIP_RETCODE SCIPdigraphComputeUndirectedComponents(SCIP_DIGRAPH *digraph, int minsize, int *components, int *ncomponents)
Definition: misc.c:8092
void SCIPdigraphGetComponent(SCIP_DIGRAPH *digraph, int compidx, int **nodes, int *nnodes)
Definition: misc.c:8301
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:7665
SCIP_RETCODE SCIPdigraphSetSizes(SCIP_DIGRAPH *digraph, int *sizes)
Definition: misc.c:7547
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:7571
int SCIPdigraphGetNComponents(SCIP_DIGRAPH *digraph)
Definition: misc.c:8288
SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:643
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:734
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:349
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:317
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:508
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:390
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2082
int SCIPgetNImplVars(SCIP *scip)
Definition: scip_prob.c:2127
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1067
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2172
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition: scip_prob.c:3089
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2843
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3043
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
int SCIPgetNOrigVars(SCIP *scip)
Definition: scip_prob.c:2432
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3111
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3264
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3077
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:3697
SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3324
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
#define SCIPdebugMsg
Definition: scip_message.h:78
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
SCIP_RETCODE SCIPgetBoolParam(SCIP *scip, const char *name, SCIP_Bool *value)
Definition: scip_param.c:250
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:111
SCIP_Bool SCIPisParamFixed(SCIP *scip, const char *name)
Definition: scip_param.c:219
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_PARAM * SCIPgetParam(SCIP *scip, const char *name)
Definition: scip_param.c:234
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:545
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
Definition: scip_param.c:953
SCIP_RETCODE SCIPgetLongintParam(SCIP *scip, const char *name, SCIP_Longint *value)
Definition: scip_param.c:288
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:429
SCIP_RETCODE SCIPfixParam(SCIP *scip, const char *name)
Definition: scip_param.c:367
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:603
void SCIPpqueueFree(SCIP_PQUEUE **pqueue)
Definition: misc.c:1325
SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
Definition: misc.c:1397
int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
Definition: misc.c:1530
SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)))
Definition: misc.c:1298
void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
Definition: misc.c:1496
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4227
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4197
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:941
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:444
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4217
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4670
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4593
SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
Definition: scip_cons.c:2622
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8244
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8473
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8234
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8383
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8413
SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
Definition: scip_cons.c:2578
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8403
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:998
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8433
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8214
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8463
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8393
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8483
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:258
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1453
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip_mem.c:126
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip_mem.c:100
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPduplicateMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:76
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip_mem.h:80
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7510
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip_pricer.c:348
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
SCIP_RETCODE SCIPcheckSolOrig(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *feasible, SCIP_Bool printreason, SCIP_Bool completely)
Definition: scip_sol.c:3305
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2165
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:180
SCIP_Real SCIPsolGetOrigObj(SCIP_SOL *sol)
Definition: sol.c:2741
SCIP_RETCODE SCIPprintBestSol(SCIP *scip, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:2231
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:837
int SCIPgetNSols(SCIP *scip)
Definition: scip_sol.c:2066
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2804
SCIP_RETCODE SCIPcreateOrigSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:417
SCIP_RETCODE SCIPaddSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *stored)
Definition: scip_sol.c:2787
int SCIPsolGetIndex(SCIP_SOL *sol)
Definition: sol.c:2835
SCIP_RETCODE SCIPcheckSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *feasible)
Definition: scip_sol.c:3247
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1296
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1073
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1213
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1343
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition: scip_sol.c:1428
void SCIPsolSetHeur(SCIP_SOL *sol, SCIP_HEUR *heur)
Definition: sol.c:2849
SCIP_RETCODE SCIPtransformProb(SCIP *scip)
Definition: scip_solve.c:223
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip_solve.c:3350
SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
Definition: scip_solve.c:3436
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2502
void SCIPaddNNodes(SCIP *scip, SCIP_Longint nnodes)
SCIP_Real SCIPgetPrimalbound(SCIP *scip)
SCIP_RETCODE SCIPupdateCutoffbound(SCIP *scip, SCIP_Real cutoffbound)
SCIP_Real SCIPgetGap(SCIP *scip)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Real SCIPgetDualbound(SCIP *scip)
SCIP_RETCODE SCIPprintStatistics(SCIP *scip, FILE *file)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_RETCODE SCIPprintDisplayLine(SCIP *scip, FILE *file, SCIP_VERBLEVEL verblevel, SCIP_Bool endline)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5326
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17747
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3353
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18143
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17925
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5443
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17583
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18087
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17757
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17767
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17418
void SCIPvarMarkDeleteGlobalStructures(SCIP_VAR *var)
Definition: var.c:17675
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18133
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18077
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8399
SCIP_RETCODE SCIPgetActiveVars(SCIP *scip, SCIP_VAR **vars, int *nvars, int varssize, int *requiredsize)
Definition: scip_var.c:1830
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3295
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition: scip_var.c:8779
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8752
void SCIPsortIntPtr(int *intarray, void **ptrarray, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10880
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
public methods for managing constraints
public methods for primal heuristics
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for primal CIP solutions
public methods for branch and bound tree
public methods for problem variables
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for data structures
general public methods
public methods for primal heuristic plugins and divesets
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for variable pricer plugins
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public solving methods
public methods for querying solving statistics
public methods for timing
public methods for the branch-and-bound tree
public methods for SCIP variables
SCIP_VAR ** fixedsubvars
PROBLEM * problem
SCIP_Real lastdualbound
SCIP_SOL * workingsol
SCIP_VAR ** subvars
SCIP_STATUS laststatus
SCIP_Real fixedvarsobjsum
SCIP_Real lastprimalbound
SCIP_VAR ** vars
SCIP_VAR ** fixedvars
SCIP * subscip
int lastbestsolindex
SCIP_Bool solved
char * name
Definition: struct_cons.h:49
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
@ SCIP_VERBLEVEL_NORMAL
Definition: type_message.h:55
@ SCIP_VERBLEVEL_FULL
Definition: type_message.h:57
@ SCIP_PARAMSETTING_OFF
Definition: type_paramset.h:63
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_UNBOUNDED
Definition: type_result.h:47
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_DELAYNODE
Definition: type_result.h:59
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_PROBLEM
Definition: type_set.h:45
@ SCIP_STAGE_PRESOLVING
Definition: type_set.h:49
@ SCIP_STAGE_INIT
Definition: type_set.h:44
@ SCIP_STATUS_OPTIMAL
Definition: type_stat.h:61
@ SCIP_STATUS_TOTALNODELIMIT
Definition: type_stat.h:45
@ SCIP_STATUS_BESTSOLLIMIT
Definition: type_stat.h:57
@ SCIP_STATUS_SOLLIMIT
Definition: type_stat.h:56
@ SCIP_STATUS_UNBOUNDED
Definition: type_stat.h:63
@ SCIP_STATUS_UNKNOWN
Definition: type_stat.h:42
@ SCIP_STATUS_PRIMALLIMIT
Definition: type_stat.h:54
@ SCIP_STATUS_GAPLIMIT
Definition: type_stat.h:53
@ SCIP_STATUS_USERINTERRUPT
Definition: type_stat.h:43
@ SCIP_STATUS_TERMINATE
Definition: type_stat.h:65
@ SCIP_STATUS_INFORUNBD
Definition: type_stat.h:64
@ SCIP_STATUS_STALLNODELIMIT
Definition: type_stat.h:48
@ SCIP_STATUS_TIMELIMIT
Definition: type_stat.h:51
@ SCIP_STATUS_INFEASIBLE
Definition: type_stat.h:62
@ SCIP_STATUS_NODELIMIT
Definition: type_stat.h:44
@ SCIP_STATUS_DUALLIMIT
Definition: type_stat.h:55
@ SCIP_STATUS_MEMLIMIT
Definition: type_stat.h:52
@ SCIP_STATUS_RESTARTLIMIT
Definition: type_stat.h:60
enum SCIP_Status SCIP_STATUS
Definition: type_stat.h:67
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:63
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:62
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:97