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-2025 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 INT_MAX /**< 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, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, &success) );
473#else
475 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, 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 if( SCIPvarIsImpliedIntegral(vars[cvars[v]]) )
1547 continue;
1548 /* check whether variable is of binary or integer type */
1549 if( SCIPvarGetType(vars[cvars[v]]) == SCIP_VARTYPE_BINARY )
1550 nbinvars++;
1551 else if( SCIPvarGetType(vars[cvars[v]]) == SCIP_VARTYPE_INTEGER )
1552 nintvars++;
1553 }
1554 ncontvars = ncvars - nintvars - nbinvars;
1555 /* TODO: come up with a more reasonable formula based on data.
1556 * This formula weights integer variables very strongly, but ignores the impact of continuous variables somewhat*/
1557 ndiscvars = (int)(nbinvars + conshdlrdata->intfactor * nintvars);
1558 compsize[c] = nbinvars + conshdlrdata->intfactor * nintvars + conshdlrdata->contfactor * ncontvars;
1559
1560 /* component fulfills the maxsize and maxcompweight requirement */
1561 if( ndiscvars <= conshdlrdata->maxintvars && compsize[c] <= conshdlrdata->maxcompweight )
1562 ++(*ncompsmaxsize);
1563
1564 /* component fulfills the minsize requirement */
1565 if( ncvars >= minsize )
1566 ++(*ncompsminsize);
1567 }
1568
1569 /* get permutation of component numbers such that the size of the components is increasing */
1570 SCIPsortRealInt(compsize, permu, ncomponents);
1571
1572 /* now, we need the reverse direction, i.e., for each component number, we store its new number
1573 * such that the components are sorted; for this, we abuse the conscomponent array
1574 */
1575 for( c = 0; c < ncomponents; ++c )
1576 conscomponent[permu[c]] = c;
1577
1578 /* for each variable, replace the old component number by the new one */
1579 for( c = 0; c < nvars; ++c )
1580 varcomponent[c] = conscomponent[varcomponent[c]];
1581
1582 SCIPfreeBufferArray(scip, &permu);
1583 SCIPfreeBufferArray(scip, &compsize);
1584
1585 /* do the mapping from calculated components per variable to corresponding
1586 * constraints and sort the component-arrays for faster finding the
1587 * actual variables and constraints belonging to one component
1588 */
1589 for( c = 0; c < nconss; c++ )
1590 conscomponent[c] = (firstvaridxpercons[c] == -1 ? -1 : varcomponent[firstvaridxpercons[c]]);
1591
1592 SCIPsortIntPtr(varcomponent, (void**)vars, nvars);
1593 SCIPsortIntPtr(conscomponent, (void**)conss, nconss);
1594
1595 return SCIP_OKAY;
1596}
1597
1598
1599
1600/** create PROBLEM structure for the current node and split it into components */
1601static
1603 SCIP* scip, /**< SCIP data structure */
1604 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1605 SCIP_Real fixedvarsobjsum, /**< objective contribution of all locally fixed variables */
1606 SCIP_VAR** sortedvars, /**< array of unfixed variables sorted by components */
1607 SCIP_CONS** sortedconss, /**< array of (checked) constraints sorted by components */
1608 int* compstartsvars, /**< start points of components in sortedvars array */
1609 int* compstartsconss, /**< start points of components in sortedconss array */
1610 int ncomponents, /**< number of components */
1611 PROBLEM** problem /**< pointer to store problem structure */
1612 )
1613{
1614 COMPONENT* component;
1615 SCIP_HASHMAP* consmap;
1616 SCIP_HASHMAP* varmap;
1617 SCIP_VAR** compvars;
1618 SCIP_CONS** compconss;
1619 SCIP_Bool success = TRUE;
1620 int nfixedvars = SCIPgetNVars(scip) - compstartsvars[ncomponents];
1621 int ncompconss;
1622 int comp;
1623
1624 /* init subproblem data structure */
1625 SCIP_CALL( initProblem(scip, problem, fixedvarsobjsum, ncomponents) );
1626 assert((*problem)->components != NULL);
1627
1628 /* hashmap mapping from original constraints to constraints in the sub-SCIPs (for performance reasons) */
1629 SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), compstartsconss[ncomponents]) );
1630
1631 /* loop over all components */
1632 for( comp = 0; comp < ncomponents; comp++ )
1633 {
1634 SCIP_CALL( initComponent(*problem) );
1635 assert((*problem)->ncomponents == comp+1);
1636
1637 component = &(*problem)->components[comp];
1638
1639 /* get component variables and store them in component structure */
1640 compvars = &(sortedvars[compstartsvars[comp]]);
1641 component->nvars = compstartsvars[comp + 1 ] - compstartsvars[comp];
1642 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &component->vars, compvars, component->nvars) );
1643 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &component->subvars, component->nvars) );
1644 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), component->nvars + nfixedvars) );
1645
1646 /* get component constraints */
1647 compconss = &(sortedconss[compstartsconss[comp]]);
1648 ncompconss = compstartsconss[comp + 1] - compstartsconss[comp];
1649
1650#ifdef DETAILED_OUTPUT
1651 /* print details about the component including its size */
1652 if( component->nvars > 1 && ncompconss > 1 )
1653 {
1654 int nbinvars = 0;
1655 int nintvars = 0;
1656 int ncontvars = 0;
1657 int i;
1658
1659 for( i = 0; i < component->nvars; ++i )
1660 {
1661 if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_BINARY )
1662 ++nbinvars;
1663 else if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_INTEGER )
1664 ++nintvars;
1665 else
1666 ++ncontvars;
1667 }
1668 SCIPdebugMsg(scip, "component %d at node %lld, depth %d (%d): %d vars (%d bin, %d int, %d cont), %d conss\n",
1669 comp, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), SCIPgetDepth(scip), SCIPgetDepth(scip) + conshdlrdata->subscipdepth,
1670 component->nvars, nbinvars, nintvars, ncontvars, ncompconss);
1671 }
1672#endif
1673 assert(ncompconss > 0 || component->nvars == 1);
1674
1675 SCIPdebugMsg(scip, "build sub-SCIP for component %d of problem <%s>: %d vars, %d conss\n",
1676 component->number, (*problem)->name, component->nvars, ncompconss);
1677
1678#ifndef NDEBUG
1679 {
1680 int i;
1681 for( i = 0; i < component->nvars; ++i )
1682 assert(SCIPvarIsActive(component->vars[i]));
1683 }
1684#endif
1685
1686 /* build subscip for component */
1687 SCIP_CALL( componentCreateSubscip(component, conshdlrdata, varmap, consmap, compconss, ncompconss, &success) );
1688
1689 if( success )
1690 {
1691 SCIP_CALL( componentSetupWorkingSol(component, varmap) );
1692
1693 /* add component to the priority queue of the problem structure */
1694 SCIP_CALL( SCIPpqueueInsert((*problem)->compqueue, component) );
1695 }
1696
1697 SCIPhashmapFree(&varmap);
1698
1699 if( !success )
1700 break;
1701 }
1702
1703 SCIPhashmapFree(&consmap);
1704
1705 if( !success )
1706 {
1707 /* free subproblem data structure since not all component could be copied */
1708 SCIP_CALL( freeProblem(problem) );
1709 }
1710
1711 return SCIP_OKAY;
1712}
1713
1714/** continue solving a problem */
1715static
1717 PROBLEM* problem, /**< problem structure */
1718 SCIP_RESULT* result /**< result pointer for the problem solve */
1719 )
1720{
1721 COMPONENT* component;
1722 SCIP_RESULT subscipresult;
1723
1724 assert(problem != NULL);
1725
1726 *result = SCIP_SUCCESS;
1727
1728 component = (COMPONENT*)SCIPpqueueRemove(problem->compqueue);
1729
1730 /* continue solving the component */
1731 SCIP_CALL( solveComponent(component, SCIPpqueueNElems(problem->compqueue) == 0, &subscipresult) );
1732
1733 /* if infeasibility or unboundedness was detected, return this */
1734 if( subscipresult == SCIP_CUTOFF || subscipresult == SCIP_UNBOUNDED )
1735 {
1736 *result = subscipresult;
1737 }
1738 /* the component was not solved to optimality, so we need to re-insert it in the components queue */
1739 else if( !component->solved )
1740 {
1741 SCIP_CALL( SCIPpqueueInsert(problem->compqueue, component) );
1742 *result = SCIP_DELAYNODE;
1743 }
1744 /* no unsolved components are left, so this problem has be completely evaluated and the node can be pruned */
1745 else if( SCIPpqueueNElems(problem->compqueue) == 0 )
1746 *result = SCIP_CUTOFF;
1747 /* there are some unsolved components left, so we delay this node */
1748 else
1749 *result = SCIP_DELAYNODE;
1750
1751 return SCIP_OKAY;
1752}
1753
1754/*
1755 * Local methods
1756 */
1757
1758/** loop over constraints, get active variables and fill directed graph */
1759static
1761 SCIP* scip, /**< SCIP data structure */
1762 SCIP_DIGRAPH* digraph, /**< directed graph */
1763 SCIP_CONS** conss, /**< constraints */
1764 int nconss, /**< number of constraints */
1765 int* unfixedvarpos, /**< mapping from variable problem index to unfixed var index */
1766 int nunfixedvars, /**< number of unfixed variables */
1767 int* firstvaridxpercons, /**< array to store for each constraint the index in the local vars array
1768 * of the first variable of the constraint */
1769 SCIP_Bool* success /**< flag indicating successful directed graph filling */
1770 )
1771{
1772 SCIP_VAR** consvars;
1773 int requiredsize;
1774 int nconsvars;
1775 int nvars;
1776 int idx1;
1777 int idx2;
1778 int c;
1779 int v;
1780
1781 assert(scip != NULL);
1782 assert(digraph != NULL);
1783 assert(conss != NULL);
1784 assert(firstvaridxpercons != NULL);
1785 assert(success != NULL);
1786
1787 *success = TRUE;
1788
1789 nconsvars = 0;
1790 requiredsize = 0;
1791 nvars = SCIPgetNVars(scip);
1792
1793 /* allocate buffer for storing active variables per constraint; size = nvars ensures that it will be big enough */
1794 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nvars) );
1795
1796 for( c = 0; c < nconss; ++c )
1797 {
1798 /* check for reached timelimit */
1799 if( (c % 1000 == 0) && SCIPisStopped(scip) )
1800 {
1801 *success = FALSE;
1802 break;
1803 }
1804
1805 /* get number of variables for this constraint */
1806 SCIP_CALL( SCIPgetConsNVars(scip, conss[c], &nconsvars, success) );
1807
1808 if( !(*success) )
1809 break;
1810
1811 /* reallocate consvars array, if needed */
1812 if( nconsvars > nvars )
1813 {
1814 nvars = nconsvars;
1815 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, nvars) );
1816 }
1817
1818#ifndef NDEBUG
1819 /* clearing variables array to check for consistency */
1820 if( nconsvars == nvars )
1821 {
1822 BMSclearMemoryArray(consvars, nconsvars);
1823 }
1824 else
1825 {
1826 assert(nconsvars < nvars);
1827 BMSclearMemoryArray(consvars, nconsvars + 1);
1828 }
1829#endif
1830
1831 /* get variables for this constraint */
1832 SCIP_CALL( SCIPgetConsVars(scip, conss[c], consvars, nvars, success) );
1833
1834 if( !(*success) )
1835 {
1836#ifndef NDEBUG
1837 /* it looks strange if returning the number of variables was successful but not returning the variables */
1838 SCIPwarningMessage(scip, "constraint <%s> returned number of variables but returning variables failed\n", SCIPconsGetName(conss[c]));
1839#endif
1840 break;
1841 }
1842
1843#ifndef NDEBUG
1844 /* check if returned variables are consistent with the number of variables that were returned */
1845 for( v = nconsvars - 1; v >= 0; --v )
1846 assert(consvars[v] != NULL);
1847 if( nconsvars < nvars )
1848 assert(consvars[nconsvars] == NULL);
1849#endif
1850
1851 /* transform given variables to active variables */
1852 SCIP_CALL( SCIPgetActiveVars(scip, consvars, &nconsvars, nvars, &requiredsize) );
1853 assert(requiredsize <= nvars);
1854
1855 firstvaridxpercons[c] = -1;
1856
1857 /* store the index of the first unfixed variable and add edges to the directed graph */
1858 if( nconsvars > 0 )
1859 {
1860 v = 0;
1861 idx1 = -1;
1862
1863 /* go through variables until the first unfixed one is reached (which has unfixedvarpos >= 0) */
1864 while( idx1 == -1 && v < nconsvars )
1865 {
1866 idx1 = SCIPvarGetProbindex(consvars[v]);
1867 assert(idx1 >= 0);
1868 idx1 = unfixedvarpos[idx1];
1869 assert(idx1 < nunfixedvars);
1870 ++v;
1871 }
1872
1873 if( idx1 >= 0 )
1874 {
1875 /* save index of the first variable for later component assignment */
1876 firstvaridxpercons[c] = idx1;
1877
1878 /* create sparse directed graph; sparse means to add only those edges necessary for component calculation,
1879 * i.e., add edges from the first variable to all others
1880 */
1881 for(; v < nconsvars; ++v )
1882 {
1883 idx2 = SCIPvarGetProbindex(consvars[v]);
1884 assert(idx2 >= 0);
1885 idx2 = unfixedvarpos[idx2];
1886 assert(idx2 < nunfixedvars);
1887
1888 /* variable is fixed */
1889 if( idx2 < 0 )
1890 continue;
1891
1892 /* we add only one directed edge, because the other direction is automatically added for component computation */
1893 SCIP_CALL( SCIPdigraphAddArc(digraph, idx1, idx2, NULL) );
1894 }
1895 }
1896 }
1897 }
1898
1899 SCIPfreeBufferArray(scip, &consvars);
1900
1901 return SCIP_OKAY;
1902}
1903
1904/** search for components in the problem */
1905static
1907 SCIP* scip, /**< SCIP main data structure */
1908 SCIP_CONSHDLRDATA* conshdlrdata, /**< the components constraint handler data */
1909 SCIP_Real* fixedvarsobjsum, /**< objective contribution of all locally fixed variables, or NULL if
1910 * fixed variables should not be disregarded */
1911 SCIP_VAR** sortedvars, /**< array to store variables sorted by components, should have enough size
1912 * for all variables */
1913 SCIP_CONS** sortedconss, /**< array to store (checked) constraints sorted by components, should have
1914 * enough size for all constraints */
1915 int* compstartsvars, /**< start points of components in sortedvars array */
1916 int* compstartsconss, /**< start points of components in sortedconss array */
1917 int* nsortedvars, /**< pointer to store the number of variables belonging to any component */
1918 int* nsortedconss, /**< pointer to store the number of (checked) constraints in components */
1919 int* ncomponents, /**< pointer to store the number of components */
1920 int* ncompsminsize, /**< pointer to store the number of components not exceeding the minimum size */
1921 int* ncompsmaxsize /**< pointer to store the number of components not exceeding the maximum size */
1922
1923 )
1924{
1925 SCIP_CONS** tmpconss;
1926 SCIP_VAR** vars;
1927 SCIP_Bool success;
1928 int ntmpconss;
1929 int nvars;
1930 int c;
1931
1932 assert(scip != NULL);
1933 assert(conshdlrdata != NULL);
1934 assert(sortedvars != NULL);
1935 assert(sortedconss != NULL);
1936 assert(compstartsvars != NULL);
1937 assert(compstartsconss != NULL);
1938 assert(nsortedvars != NULL);
1939 assert(nsortedconss != NULL);
1940 assert(ncomponents != NULL);
1941 assert(ncompsminsize != NULL);
1942 assert(ncompsmaxsize != NULL);
1943
1944 vars = SCIPgetVars(scip);
1945 nvars = SCIPgetNVars(scip);
1946
1947 if( fixedvarsobjsum != NULL )
1948 *fixedvarsobjsum = 0.0;
1949
1950 *ncomponents = 0;
1951 *ncompsminsize = 0;
1952 *ncompsmaxsize = 0;
1953
1954 /* collect checked constraints for component detection */
1955 ntmpconss = SCIPgetNConss(scip);
1956 tmpconss = SCIPgetConss(scip);
1957 (*nsortedconss) = 0;
1958 for( c = 0; c < ntmpconss; c++ )
1959 {
1960 sortedconss[(*nsortedconss)] = tmpconss[c];
1961 (*nsortedconss)++;
1962 }
1963
1964 if( nvars > 1 && *nsortedconss > 1 )
1965 {
1966 int* unfixedvarpos;
1967 int* firstvaridxpercons;
1968 int* varlocks;
1969 int nunfixedvars = 0;
1970 int v;
1971
1972 /* arrays for storing the first variable in each constraint (for later component assignment), the number of
1973 * variable locks, and the positions in the sortedvars array for all unfixed variables
1974 */
1975 SCIP_CALL( SCIPallocBufferArray(scip, &firstvaridxpercons, *nsortedconss) );
1976 SCIP_CALL( SCIPallocBufferArray(scip, &varlocks, nvars) );
1977 SCIP_CALL( SCIPallocBufferArray(scip, &unfixedvarpos, nvars) );
1978
1979 /* count number of varlocks for each variable (up + down locks) and multiply it by 2;
1980 * that value is used as an estimate of the number of arcs incident to the variable's node in the digraph
1981 * to be safe, we double this value
1982 */
1983 for( v = 0; v < nvars; ++v )
1984 {
1985 /* variable is not fixed or we do not want to disregard fixed variables */
1986 if( (fixedvarsobjsum == NULL) || SCIPisLT(scip, SCIPvarGetLbLocal(vars[v]), SCIPvarGetUbLocal(vars[v])) )
1987 {
1988 assert(nunfixedvars <= v);
1989 sortedvars[nunfixedvars] = vars[v];
1990 varlocks[nunfixedvars] = 4 * (SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL)
1992 unfixedvarpos[v] = nunfixedvars;
1993 ++nunfixedvars;
1994 }
1995 /* variable is fixed; update the objective sum of all fixed variables */
1996 else
1997 {
1998 unfixedvarpos[v] = -1;
1999 (*fixedvarsobjsum) += SCIPvarGetObj(vars[v]) * SCIPvarGetLbLocal(vars[v]);
2000 }
2001 }
2002 *nsortedvars = nunfixedvars;
2003
2004 if( nunfixedvars > 0 )
2005 {
2006 SCIP_DIGRAPH* digraph;
2007
2008 /* create and fill directed graph */
2009 SCIP_CALL( SCIPcreateDigraph(scip, &digraph, nunfixedvars) );
2010 SCIP_CALL( SCIPdigraphSetSizes(digraph, varlocks) );
2011 SCIP_CALL( fillDigraph(scip, digraph, sortedconss, *nsortedconss, unfixedvarpos, nunfixedvars, firstvaridxpercons, &success) );
2012
2013 if( success )
2014 {
2015 int* varcomponent;
2016 int* conscomponent;
2017
2018 SCIP_CALL( SCIPallocBufferArray(scip, &varcomponent, nunfixedvars) );
2019 SCIP_CALL( SCIPallocBufferArray(scip, &conscomponent, MAX(nunfixedvars,*nsortedconss)) );
2020
2021 /* compute independent components */
2022 SCIP_CALL( SCIPdigraphComputeUndirectedComponents(digraph, 1, varcomponent, ncomponents) );
2023
2024 if( *ncomponents > 1 )
2025 {
2026 int nconss = *nsortedconss;
2027 int i;
2028
2029 nvars = *nsortedvars;
2030
2032 "cons components found %d undirected components at node %lld, depth %d (%d)\n",
2033 *ncomponents, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), SCIPgetDepth(scip), SCIPgetDepth(scip) + conshdlrdata->subscipdepth);
2034
2035 /* sort components by size and sort variables and constraints by component number */
2036 SCIP_CALL( sortComponents(scip, conshdlrdata, digraph, sortedconss, sortedvars, varcomponent, conscomponent, nconss, *nsortedvars,
2037 firstvaridxpercons, ncompsminsize, ncompsmaxsize) );
2038
2039 /* determine start indices of components in sortedvars and sortedconss array */
2040 i = 0;
2041
2042 while( i < nconss && conscomponent[i] == -1 )
2043 ++i;
2044
2045 for( c = 0; c < *ncomponents + 1; ++c )
2046 {
2047 assert(i == nconss || conscomponent[i] >= c);
2048
2049 compstartsconss[c] = i;
2050
2051 while( i < nconss && conscomponent[i] == c )
2052 ++i;
2053 }
2054
2055 for( c = 0, i = 0; c < *ncomponents + 1; ++c )
2056 {
2057 assert(i == nvars || varcomponent[i] >= c);
2058
2059 compstartsvars[c] = i;
2060
2061 while( i < nvars && varcomponent[i] == c )
2062 ++i;
2063 }
2064
2065#ifndef NDEBUG
2066 for( c = 0; c < *ncomponents; ++c )
2067 {
2068 for( i = compstartsconss[c]; i < compstartsconss[c+1]; ++i )
2069 assert(conscomponent[i] == c);
2070 for( i = compstartsvars[c]; i < compstartsvars[c+1]; ++i )
2071 assert(varcomponent[i] == c);
2072 }
2073#endif
2074 }
2075
2076 SCIPfreeBufferArray(scip, &conscomponent);
2077 SCIPfreeBufferArray(scip, &varcomponent);
2078 }
2079
2080 SCIPdigraphFree(&digraph);
2081 }
2082
2083 SCIPfreeBufferArray(scip, &unfixedvarpos);
2084 SCIPfreeBufferArray(scip, &varlocks);
2085 SCIPfreeBufferArray(scip, &firstvaridxpercons);
2086 }
2087
2088 return SCIP_OKAY;
2089}
2090
2091
2092/*
2093 * Callback methods of constraint handler
2094 */
2095
2096/** copy method for constraint handler plugins (called when SCIP copies plugins) */
2097static
2098SCIP_DECL_CONSHDLRCOPY(conshdlrCopyComponents)
2099{ /*lint --e{715}*/
2100 assert(scip != NULL);
2101 assert(conshdlr != NULL);
2102 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2103
2104 /* call inclusion method of constraint handler */
2106
2107 *valid = TRUE;
2108
2109 return SCIP_OKAY;
2110}
2111
2112/** destructor of constraint handler to free user data (called when SCIP is exiting) */
2113static
2114SCIP_DECL_CONSFREE(conshdlrFreeComponents)
2115{ /*lint --e{715}*/
2116 SCIP_CONSHDLRDATA* conshdlrdata;
2117
2118 /* free constraint handler data */
2119 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2120 assert(conshdlrdata != NULL);
2121
2122 SCIPfreeBlockMemory(scip, &conshdlrdata);
2123 SCIPconshdlrSetData(conshdlr, NULL);
2124
2125 return SCIP_OKAY;
2126}
2127
2128/** domain propagation method of constraint handler */
2129static
2130SCIP_DECL_CONSPROP(consPropComponents)
2131{ /*lint --e{715}*/
2132 PROBLEM* problem;
2133 SCIP_CONSHDLRDATA* conshdlrdata;
2134 SCIP_Longint nodelimit;
2135
2136 assert(conshdlr != NULL);
2137 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2138 assert(result != NULL);
2139 assert(SCIPconshdlrGetNActiveConss(conshdlr) >= 0);
2140 assert(SCIPconshdlrGetNActiveConss(conshdlr) <= 1);
2141
2142 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2143 assert(conshdlrdata != NULL);
2144
2145 *result = SCIP_DIDNOTRUN;
2146
2147 /* do not try to detect independent components if the depth is too high */
2148 if( SCIPgetDepth(scip) + conshdlrdata->subscipdepth > conshdlrdata->maxdepth
2149 && SCIPconshdlrGetNActiveConss(conshdlr) == 0 )
2150 return SCIP_OKAY;
2151
2152 /* don't run in probing or in repropagation */
2154 return SCIP_OKAY;
2155
2156 /* do not run, if not all variables are explicitly known */
2157 if( SCIPgetNActivePricers(scip) > 0 )
2158 return SCIP_OKAY;
2159
2160 /* we do not want to run, if there are no variables left */
2161 if( SCIPgetNVars(scip) == 0 )
2162 return SCIP_OKAY;
2163
2164 /* check for a reached timelimit */
2165 if( SCIPisStopped(scip) )
2166 return SCIP_OKAY;
2167
2168 /* the components constraint handler does kind of dual reductions */
2170 return SCIP_OKAY;
2171
2172 problem = NULL;
2173 *result = SCIP_DIDNOTFIND;
2174
2175 /* the current node already has a components constraint storing a problem split into individual components */
2176 if( SCIPconshdlrGetNActiveConss(conshdlr) >= 1 )
2177 {
2178 assert(SCIPconshdlrGetNActiveConss(conshdlr) == 1);
2179
2180 problem = (PROBLEM*)SCIPconsGetData(SCIPconshdlrGetConss(conshdlr)[0]);
2181 }
2182 /* no components constraint at the current node, search for components */
2183 else
2184 {
2185 SCIP_Real fixedvarsobjsum;
2186 SCIP_VAR** sortedvars;
2187 SCIP_CONS** sortedconss;
2188 int* compstartsvars;
2189 int* compstartsconss;
2190 int nsortedvars;
2191 int nsortedconss;
2192 int ncomponents;
2193 int ncompsminsize;
2194 int ncompsmaxsize;
2195
2196 assert(SCIPconshdlrGetNActiveConss(conshdlr) == 0);
2197
2198 /* allocate memory for sorted components */
2201 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsvars, SCIPgetNVars(scip) + 1) );
2202 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsconss, SCIPgetNVars(scip) + 1) );
2203
2204 /* search for components */
2205 SCIP_CALL( findComponents(scip, conshdlrdata, &fixedvarsobjsum, sortedvars, sortedconss, compstartsvars,
2206 compstartsconss, &nsortedvars, &nsortedconss, &ncomponents, &ncompsminsize, &ncompsmaxsize) );
2207
2208 if( ncompsminsize > 1 )
2209 {
2210 SCIP_CONS* cons;
2211
2212 SCIPdebugMsg(scip, "found %d components (%d fulfilling the minsize requirement) at node %lld at depth %d (%d)\n",
2213 ncomponents, ncompsminsize, SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), SCIPgetDepth(scip),
2214 SCIPgetDepth(scip) + conshdlrdata->subscipdepth);
2215
2216 /* if there are components with size smaller than the limit, we merge them with the smallest component */
2217 if( ncomponents > ncompsminsize )
2218 {
2219 int minsize;
2220 int size;
2221 int c;
2222 int m = 0;
2223
2224 /* compute minimum size of components to solve individually */
2225 minsize = getMinsize(scip, conshdlrdata);
2226
2227 for( c = 0; c < ncomponents; ++c )
2228 {
2229 size = compstartsvars[c+1] - compstartsvars[c];
2230
2231 if( size >= minsize )
2232 {
2233 ++m;
2234 compstartsvars[m] = compstartsvars[c+1];
2235 compstartsconss[m] = compstartsconss[c+1];
2236 }
2237 /* the last component is too small */
2238 else if( c == ncomponents - 1 )
2239 {
2240 assert(m == ncompsminsize);
2241 compstartsvars[m] = compstartsvars[c+1];
2242 compstartsconss[m] = compstartsconss[c+1];
2243 }
2244 }
2245 assert(m == ncompsminsize);
2246 assert(compstartsvars[m] == nsortedvars);
2247 assert(compstartsconss[m] == nsortedconss);
2248
2249 ncomponents = m;
2250 }
2251
2252 SCIP_CALL( createAndSplitProblem(scip, conshdlrdata, fixedvarsobjsum, sortedvars, sortedconss, compstartsvars,
2253 compstartsconss, ncomponents, &problem) );
2254
2255 /* if the problem is not NULL, copying worked fine */
2256 if( problem != NULL )
2257 {
2258 SCIP_CALL( createConsComponents(scip, &cons, problem->name, problem) );
2260 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
2261 }
2262 }
2263
2264 SCIPfreeBufferArray(scip, &compstartsconss);
2265 SCIPfreeBufferArray(scip, &compstartsvars);
2266 SCIPfreeBufferArray(scip, &sortedconss);
2267 SCIPfreeBufferArray(scip, &sortedvars);
2268 }
2269
2270 /* (continue to) solve the problem
2271 *
2272 * If the problem was not solved to optimality yet, the result code is set to SCIP_DELAYNODE, so that after the
2273 * propagation is finished, the node is put back into the queue of open nodes and solving the components of the
2274 * problem will be continued when the node is focused and propagated the next time.
2275 * However, if we are at the root node, we continue solving the problem until it is solved or some limit is reached
2276 * since there are no other nodes to process and we want to avoid calling other propagation methods or heuristics
2277 * again and again
2278 */
2279 SCIP_CALL( SCIPgetLongintParam(scip, "limits/nodes", &nodelimit) );
2280 if( nodelimit == -1 )
2281 nodelimit = SCIP_LONGINT_MAX;
2282
2283 do
2284 {
2285 if( problem != NULL )
2286 {
2287 SCIP_CALL( solveProblem(problem, result) );
2288 }
2289 } while( *result == SCIP_DELAYNODE && SCIPgetDepth(scip) == 0 && !SCIPisStopped(scip) && SCIPgetNNodes(scip) < nodelimit);
2290
2291 return SCIP_OKAY;
2292}
2293
2294/** presolving method of constraint handler */
2295static
2296SCIP_DECL_CONSPRESOL(consPresolComponents)
2297{ /*lint --e{715}*/
2298 SCIP_CONSHDLRDATA* conshdlrdata;
2299 SCIP_VAR** sortedvars;
2300 SCIP_CONS** sortedconss;
2301 int* compstartsvars;
2302 int* compstartsconss;
2303 int nsortedvars;
2304 int nsortedconss;
2305 int ncomponents;
2306 int ncompsminsize;
2307 int ncompsmaxsize;
2308 int nvars;
2309
2310 assert(conshdlr != NULL);
2311 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2312 assert(result != NULL);
2313 assert(SCIPconshdlrGetNActiveConss(conshdlr) >= 0);
2314 assert(SCIPconshdlrGetNActiveConss(conshdlr) <= 1);
2315
2316 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2317 assert(conshdlrdata != NULL);
2318
2319 *result = SCIP_DIDNOTRUN;
2320
2322 return SCIP_OKAY;
2323
2324 /* do not run, if not all variables are explicitly known */
2325 if( SCIPgetNActivePricers(scip) > 0 )
2326 return SCIP_OKAY;
2327
2328 nvars = SCIPgetNVars(scip);
2329
2330 /* we do not want to run, if there are no variables left */
2331 if( nvars == 0 )
2332 return SCIP_OKAY;
2333
2334 /* only call the components presolving, if presolving would be stopped otherwise */
2336 return SCIP_OKAY;
2337
2338 /* the components constraint handler does kind of dual reductions */
2340 return SCIP_OKAY;
2341
2342 /* check for a reached timelimit */
2343 if( SCIPisStopped(scip) )
2344 return SCIP_OKAY;
2345
2346 *result = SCIP_DIDNOTFIND;
2347
2348 assert(SCIPconshdlrGetNActiveConss(conshdlr) == 0);
2349
2350 /* allocate memory for sorted components */
2353 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsvars, SCIPgetNVars(scip) + 1) );
2354 SCIP_CALL( SCIPallocBufferArray(scip, &compstartsconss, SCIPgetNVars(scip) + 1) );
2355
2356 /* search for components */
2357 SCIP_CALL( findComponents(scip, conshdlrdata, NULL, sortedvars, sortedconss, compstartsvars,
2358 compstartsconss, &nsortedvars, &nsortedconss, &ncomponents, &ncompsminsize, &ncompsmaxsize) );
2359
2360 if( ncompsmaxsize > 0 )
2361 {
2362 char name[SCIP_MAXSTRLEN];
2363 SCIP* subscip;
2364 SCIP_HASHMAP* consmap;
2365 SCIP_HASHMAP* varmap;
2366 SCIP_VAR** compvars;
2367 SCIP_VAR** subvars;
2368 SCIP_CONS** compconss;
2369 SCIP_Bool success;
2370 SCIP_Bool solved;
2371 int nsolved = 0;
2372 int ncompvars;
2373 int ncompconss;
2374 int comp;
2375
2376 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",
2378
2379 /* build subscip */
2380 SCIP_CALL( createSubscip(scip, conshdlrdata, &subscip) );
2381
2382 if( subscip == NULL )
2383 goto TERMINATE;
2384
2385 SCIP_CALL( SCIPsetBoolParam(subscip, "misc/usesmalltables", TRUE) );
2386 SCIP_CALL( SCIPsetIntParam(subscip, "constraints/" CONSHDLR_NAME "/propfreq", -1) );
2387
2388 /* hashmap mapping from original constraints to constraints in the sub-SCIPs (for performance reasons) */
2389 SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), nsortedconss) );
2390
2391 SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nsortedvars) );
2392
2393 /* loop over all components */
2394 for( comp = 0; comp < ncompsmaxsize && !SCIPisStopped(scip); comp++ )
2395 {
2396#ifdef WITH_DEBUG_SOLUTION
2397 if( SCIPgetStage(subscip) > SCIP_STAGE_INIT )
2398 {
2399 SCIP_CALL( SCIPfree(&subscip) );
2400 SCIP_CALL( createSubscip(scip, conshdlrdata, &subscip) );
2401 }
2402#endif
2403 /* get component variables */
2404 compvars = &(sortedvars[compstartsvars[comp]]);
2405 ncompvars = compstartsvars[comp + 1 ] - compstartsvars[comp];
2406
2407 /* get component constraints */
2408 compconss = &(sortedconss[compstartsconss[comp]]);
2409 ncompconss = compstartsconss[comp + 1] - compstartsconss[comp];
2410
2411 /* if we have an unlocked variable, let duality fixing do the job! */
2412 if( ncompconss == 0 )
2413 {
2414 assert(ncompvars == 1);
2415 continue;
2416 }
2417
2418 SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), ncompvars) );
2419#ifdef DETAILED_OUTPUT
2420 {
2421 int nbinvars = 0;
2422 int nintvars = 0;
2423 int ncontvars = 0;
2424 int i;
2425
2426 for( i = 0; i < ncompvars; ++i )
2427 {
2428 if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_BINARY )
2429 ++nbinvars;
2430 else if( SCIPvarGetType(compvars[i]) == SCIP_VARTYPE_INTEGER )
2431 ++nintvars;
2432 else
2433 ++ncontvars;
2434 }
2435 SCIPdebugMsg(scip, "solve component %d: %d vars (%d bin, %d int, %d cont), %d conss\n",
2436 comp, ncompvars, nbinvars, nintvars, ncontvars, ncompconss);
2437 }
2438#endif
2439#ifndef NDEBUG
2440 {
2441 int i;
2442 for( i = 0; i < ncompvars; ++i )
2443 assert(SCIPvarIsActive(compvars[i]));
2444 }
2445#endif
2446
2447 /* get name of the original problem and add "comp_nr" */
2448 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp_%d", SCIPgetProbName(scip), comp);
2449
2450 SCIP_CALL( copyToSubscip(scip, subscip, name, compvars, subvars,
2451 compconss, varmap, consmap, ncompvars, ncompconss, &success) );
2452
2453 if( !success )
2454 {
2455 SCIPhashmapFree(&varmap);
2456 continue;
2457 }
2458
2459 /* set up debug solution */
2460#ifdef WITH_DEBUG_SOLUTION
2462 {
2463 SCIP_SOL* debugsol;
2464 SCIP_Real val;
2465 int i;
2466
2467 SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
2468
2469 /* set solution values in the debug solution if it is available */
2470 if( debugsol != NULL )
2471 {
2472 SCIPdebugSolEnable(subscip);
2473
2474 for( i = 0; i < ncompvars; ++i )
2475 {
2476 if( subvars[i] != NULL )
2477 {
2478 SCIP_CALL( SCIPdebugGetSolVal(scip, compvars[i], &val) );
2479 SCIP_CALL( SCIPdebugAddSolVal(subscip, subvars[i], val) );
2480 }
2481 }
2482 }
2483 }
2484#endif
2485
2486 /* solve the subproblem and evaluate the result, i.e. apply fixings of variables and remove constraints */
2487 SCIP_CALL( solveAndEvalSubscip(scip, conshdlrdata, subscip, compvars, subvars, compconss,
2488 ncompvars, ncompconss, ndelconss, nfixedvars, nchgbds, result, &solved) );
2489
2490 /* free variable hash map */
2491 SCIPhashmapFree(&varmap);
2492
2493 if( solved )
2494 ++nsolved;
2495
2496 /* if the component is unbounded or infeasible, this holds for the complete problem as well */
2497 if( *result == SCIP_UNBOUNDED || *result == SCIP_CUTOFF )
2498 break;
2499 /* if there is only one component left, let's solve this in the main SCIP */
2500 else if( nsolved == ncomponents - 1 )
2501 break;
2502 }
2503
2504 SCIPfreeBufferArray(scip, &subvars);
2505 SCIPhashmapFree(&consmap);
2506
2507 SCIP_CALL( SCIPfree(&subscip) );
2508 }
2509
2510 TERMINATE:
2511 SCIPfreeBufferArray(scip, &compstartsconss);
2512 SCIPfreeBufferArray(scip, &compstartsvars);
2513 SCIPfreeBufferArray(scip, &sortedconss);
2514 SCIPfreeBufferArray(scip, &sortedvars);
2515
2516 return SCIP_OKAY;
2517}
2518
2519/** frees specific constraint data */
2520static
2521SCIP_DECL_CONSDELETE(consDeleteComponents)
2522{ /*lint --e{715}*/
2523 assert(conshdlr != NULL);
2524 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2525 assert(consdata != NULL);
2526 assert(*consdata != NULL);
2527
2528 SCIP_CALL( freeProblem((PROBLEM**) consdata) );
2529
2530 return SCIP_OKAY;
2531}
2532
2533/** constraint enforcing method of constraint handler for relaxation solutions */
2534static
2535SCIP_DECL_CONSENFORELAX(consEnforelaxComponents)
2536{ /*lint --e{715}*/
2537 assert(result != NULL);
2538
2539 /* no enforcement is performed, but the callback is needed for all constraint handlers with needscons = FALSE */
2540 *result = SCIP_FEASIBLE;
2541
2542 return SCIP_OKAY;
2543}
2544
2545/** variable rounding lock method of constraint handler */
2546static
2547SCIP_DECL_CONSLOCK(consLockComponents)
2548{ /*lint --e{715}*/
2549 return SCIP_OKAY;
2550}
2551
2552#ifndef NDEBUG
2553/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
2554static
2555SCIP_DECL_CONSINITSOL(consInitsolComponents)
2556{ /*lint --e{715}*/
2557 assert(nconss == 0);
2558
2559 return SCIP_OKAY;
2560}
2561#endif
2562
2563#define consEnfolpComponents NULL
2564#define consEnfopsComponents NULL
2565#define consCheckComponents NULL
2566
2567/** creates the components constraint handler and includes it in SCIP */
2569 SCIP* scip /**< SCIP data structure */
2570 )
2571{
2572 SCIP_CONSHDLRDATA* conshdlrdata;
2573 SCIP_CONSHDLR* conshdlr;
2574
2575 /* create components constraint data */
2576 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
2577 conshdlrdata->subscipdepth = 0;
2578
2579 /* include constraint handler */
2583 conshdlrdata) );
2584 assert(conshdlr != NULL);
2585
2586 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropComponents,
2588 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolComponents,
2590
2591 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, conshdlrFreeComponents) );
2592 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxComponents) );
2593#ifndef NDEBUG
2594 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolComponents) );
2595#endif
2596 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyComponents, NULL) );
2597 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteComponents) );
2598
2600 "constraints/" CONSHDLR_NAME "/maxdepth",
2601 "maximum depth of a node to run components detection (-1: disable component detection during solving)",
2602 &conshdlrdata->maxdepth, FALSE, DEFAULT_MAXDEPTH, -1, INT_MAX, NULL, NULL) );
2604 "constraints/" CONSHDLR_NAME "/maxintvars",
2605 "maximum number of integer (or binary) variables to solve a subproblem during presolving (-1: unlimited)",
2606 &conshdlrdata->maxintvars, TRUE, DEFAULT_MAXINTVARS, -1, INT_MAX, NULL, NULL) );
2608 "constraints/" CONSHDLR_NAME "/minsize",
2609 "minimum absolute size (in terms of variables) to solve a component individually during branch-and-bound",
2610 &conshdlrdata->minsize, TRUE, DEFAULT_MINSIZE, 0, INT_MAX, NULL, NULL) );
2612 "constraints/" CONSHDLR_NAME "/minrelsize",
2613 "minimum relative size (in terms of variables) to solve a component individually during branch-and-bound",
2614 &conshdlrdata->minrelsize, TRUE, DEFAULT_MINRELSIZE, 0.0, 1.0, NULL, NULL) );
2616 "constraints/" CONSHDLR_NAME "/nodelimit",
2617 "maximum number of nodes to be solved in subproblems during presolving",
2618 &conshdlrdata->nodelimit, FALSE, DEFAULT_NODELIMIT, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
2620 "constraints/" CONSHDLR_NAME "/maxcompweight",
2621 "the maximum weight of a component, in terms of the used factors",
2622 &conshdlrdata->maxcompweight, FALSE, DEFAULT_MAXCOMPWEIGHT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2624 "constraints/" CONSHDLR_NAME "/intfactor",
2625 "the weight of an integer variable compared to binary variables",
2626 &conshdlrdata->intfactor, FALSE, DEFAULT_INTFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2628 "constraints/" CONSHDLR_NAME "/contfactor",
2629 "the weight of a continuous variable compared to binary variables",
2630 &conshdlrdata->contfactor, FALSE, DEFAULT_CONTFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
2632 "constraints/" CONSHDLR_NAME "/feastolfactor",
2633 "factor to increase the feasibility tolerance of the main SCIP in all sub-SCIPs, default value 1.0",
2634 &conshdlrdata->feastolfactor, TRUE, DEFAULT_FEASTOLFACTOR, 0.0, 1000000.0, NULL, NULL) );
2635
2636 return SCIP_OKAY;
2637}
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:312
#define SCIPdebugSolEnable(scip)
Definition: debug.h:314
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:311
#define SCIPdebugSolIsEnabled(scip)
Definition: debug.h:316
#define SCIPdebugSolIsValidInSubtree(scip, isvalidinsubtree)
Definition: debug.h:313
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_INVALID
Definition: def.h:178
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define ABS(x)
Definition: def.h:216
#define SQR(x)
Definition: def.h:199
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIP_LONGINT_MAX
Definition: def.h:142
#define SCIP_CALL(x)
Definition: def.h:355
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 copyiisfinders, 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:276
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:1580
SCIP_RETCODE SCIPcopyProb(SCIP *sourcescip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, const char *name)
Definition: scip_copy.c:529
SCIP_RETCODE SCIPcopyParamSettings(SCIP *sourcescip, SCIP *targetscip)
Definition: scip_copy.c:2547
SCIP_RETCODE SCIPcopyLimits(SCIP *sourcescip, SCIP *targetscip)
Definition: scip_copy.c:3292
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:713
SCIP_RETCODE SCIPdigraphComputeUndirectedComponents(SCIP_DIGRAPH *digraph, int minsize, int *components, int *ncomponents)
Definition: misc.c:8165
void SCIPdigraphGetComponent(SCIP_DIGRAPH *digraph, int compidx, int **nodes, int *nnodes)
Definition: misc.c:8374
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:7739
SCIP_RETCODE SCIPdigraphSetSizes(SCIP_DIGRAPH *digraph, int *sizes)
Definition: misc.c:7621
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:7645
int SCIPdigraphGetNComponents(SCIP_DIGRAPH *digraph)
Definition: misc.c:8361
SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:668
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:402
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:370
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:562
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2340
int SCIPgetNImplVars(SCIP *scip)
Definition: scip_prob.c:2387
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1242
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2569
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition: scip_prob.c:3666
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3274
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3420
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3620
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
int SCIPgetNOrigVars(SCIP *scip)
Definition: scip_prob.c:2838
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2293
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3095
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3284
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3061
SCIP_RETCODE SCIPupdateLocalLowerbound(SCIP *scip, SCIP_Real newbound)
Definition: scip_prob.c:4289
SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3901
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:956
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:1324
SCIP_RETCODE SCIPpqueueInsert(SCIP_PQUEUE *pqueue, void *elem)
Definition: misc.c:1396
int SCIPpqueueNElems(SCIP_PQUEUE *pqueue)
Definition: misc.c:1529
SCIP_RETCODE SCIPpqueueCreate(SCIP_PQUEUE **pqueue, int initsize, SCIP_Real sizefac, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), SCIP_DECL_PQUEUEELEMCHGPOS((*elemchgpos)))
Definition: misc.c:1297
void * SCIPpqueueRemove(SCIP_PQUEUE *pqueue)
Definition: misc.c:1495
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4346
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:4316
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:940
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:4336
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4812
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4735
SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
Definition: scip_cons.c:2621
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8588
SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
Definition: scip_cons.c:2577
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8578
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:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8608
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8568
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:263
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1467
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
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#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:8483
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip_pricer.c:348
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_RETCODE SCIPcheckSolOrig(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *feasible, SCIP_Bool printreason, SCIP_Bool completely)
Definition: scip_sol.c:4380
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2981
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_Real SCIPsolGetOrigObj(SCIP_SOL *sol)
Definition: sol.c:4170
SCIP_RETCODE SCIPprintBestSol(SCIP *scip, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:3047
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
int SCIPgetNSols(SCIP *scip)
Definition: scip_sol.c:2882
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:4259
SCIP_RETCODE SCIPcreateOrigSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:831
SCIP_RETCODE SCIPaddSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool *stored)
Definition: scip_sol.c:3842
int SCIPsolGetIndex(SCIP_SOL *sol)
Definition: sol.c:4290
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:4312
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1892
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1571
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:2005
SCIP_Real SCIPretransformObj(SCIP *scip, SCIP_Real obj)
Definition: scip_sol.c:2132
void SCIPsolSetHeur(SCIP_SOL *sol, SCIP_HEUR *heur)
Definition: sol.c:4304
SCIP_RETCODE SCIPtransformProb(SCIP *scip)
Definition: scip_solve.c:232
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip_solve.c:3462
SCIP_RETCODE SCIPinterruptSolve(SCIP *scip)
Definition: scip_solve.c:3548
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2635
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:6401
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6651
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:23652
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
void SCIPvarMarkDeleteGlobalStructures(SCIP_VAR *var)
Definition: var.c:23570
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:10318
SCIP_RETCODE SCIPgetActiveVars(SCIP *scip, SCIP_VAR **vars, int *nvars, int varssize, int *requiredsize)
Definition: scip_var.c:2574
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4328
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition: scip_var.c:10998
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:10984
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:10827
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
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:60
@ SCIP_VERBLEVEL_FULL
Definition: type_message.h:62
@ 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:43
@ SCIP_STATUS_TOTALNODELIMIT
Definition: type_stat.h:50
@ SCIP_STATUS_BESTSOLLIMIT
Definition: type_stat.h:60
@ SCIP_STATUS_SOLLIMIT
Definition: type_stat.h:59
@ SCIP_STATUS_UNBOUNDED
Definition: type_stat.h:45
@ SCIP_STATUS_UNKNOWN
Definition: type_stat.h:42
@ SCIP_STATUS_PRIMALLIMIT
Definition: type_stat.h:57
@ SCIP_STATUS_GAPLIMIT
Definition: type_stat.h:56
@ SCIP_STATUS_USERINTERRUPT
Definition: type_stat.h:47
@ SCIP_STATUS_TERMINATE
Definition: type_stat.h:48
@ SCIP_STATUS_INFORUNBD
Definition: type_stat.h:46
@ SCIP_STATUS_STALLNODELIMIT
Definition: type_stat.h:52
@ SCIP_STATUS_TIMELIMIT
Definition: type_stat.h:54
@ SCIP_STATUS_INFEASIBLE
Definition: type_stat.h:44
@ SCIP_STATUS_NODELIMIT
Definition: type_stat.h:49
@ SCIP_STATUS_DUALLIMIT
Definition: type_stat.h:58
@ SCIP_STATUS_MEMLIMIT
Definition: type_stat.h:55
@ SCIP_STATUS_RESTARTLIMIT
Definition: type_stat.h:62
enum SCIP_Status SCIP_STATUS
Definition: type_stat.h:64
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:65
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:141