SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_logicor.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-2026 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_logicor.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief Constraint handler for logic or constraints \f$1^T x \ge 1\f$
28 * (equivalent to set covering, but algorithms are suited for depth first search).
29 * @author Tobias Achterberg
30 * @author Michael Winkler
31 */
32
33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34
36#include "scip/cons_linear.h"
37#include "scip/cons_logicor.h"
38#include "scip/cons_setppc.h"
39#include "scip/presolve.h"
40#include "scip/pub_conflict.h"
41#include "scip/pub_cons.h"
42#include "scip/pub_event.h"
43#include "scip/pub_lp.h"
44#include "scip/pub_message.h"
45#include "scip/pub_misc.h"
46#include "scip/pub_misc_sort.h"
47#include "scip/pub_var.h"
48#include "scip/scip_conflict.h"
49#include "scip/scip_cons.h"
50#include "scip/scip_cut.h"
51#include "scip/scip_event.h"
52#include "scip/scip_general.h"
53#include "scip/scip_lp.h"
54#include "scip/scip_mem.h"
55#include "scip/scip_message.h"
56#include "scip/scip_nlp.h"
57#include "scip/scip_numerics.h"
58#include "scip/scip_param.h"
59#include "scip/scip_prob.h"
60#include "scip/scip_probing.h"
61#include "scip/scip_sol.h"
63#include "scip/scip_tree.h"
64#include "scip/scip_var.h"
65#include "scip/symmetry_graph.h"
67#include <string.h>
68
69
70#define CONSHDLR_NAME "logicor"
71#define CONSHDLR_DESC "logic or constraints"
72#define CONSHDLR_SEPAPRIORITY +10000 /**< priority of the constraint handler for separation */
73#define CONSHDLR_ENFOPRIORITY -2000000 /**< priority of the constraint handler for constraint enforcing */
74#define CONSHDLR_CHECKPRIORITY -2000000 /**< priority of the constraint handler for checking feasibility */
75#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
76#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
77#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
78 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
79#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
80#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
81#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
82#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
83
84#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
85#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
86
87#define LINCONSUPGD_PRIORITY +800000 /**< priority of the constraint handler for upgrading of linear constraints */
88
89#define EVENTHDLR_NAME "logicor"
90#define EVENTHDLR_DESC "event handler for logic or constraints"
91
92#define CONFLICTHDLR_NAME "logicor"
93#define CONFLICTHDLR_DESC "conflict handler creating logic or constraints"
94#define CONFLICTHDLR_PRIORITY LINCONSUPGD_PRIORITY
95
96#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
97#define DEFAULT_STRENGTHEN TRUE /**< should pairwise constraint comparison try to strengthen constraints by removing superflous non-zeros? */
98
99#define HASHSIZE_LOGICORCONS 500 /**< minimal size of hash table in logicor constraint tables */
100#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
101#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
102#define DEFAULT_NEGATEDCLIQUE TRUE /**< should negated clique information be used in presolving */
103#define DEFAULT_IMPLICATIONS TRUE /**< should we try to shrink the variables and derive global boundchanges by
104 * using cliques and implications */
105
106/* @todo make this a parameter setting */
107#if 1 /* @todo test which AGEINCREASE formula is better! */
108#define AGEINCREASE(n) (1.0 + 0.2 * (n))
109#else
110#define AGEINCREASE(n) (0.1 * (n))
111#endif
112
113
114/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
115
116/*
117 * Data structures
118 */
119
120/** constraint handler data */
121struct SCIP_ConshdlrData
122{
123 SCIP_EVENTHDLR* eventhdlr; /**< event handler for events on watched variables */
124 SCIP_CONSHDLR* conshdlrlinear; /**< pointer to linear constraint handler or NULL if not included */
125 SCIP_CONSHDLR* conshdlrsetppc; /**< pointer to setppc constraint handler or NULL if not included */
126 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
127 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in
128 * advance */
129 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
130 SCIP_Bool usenegatedclique; /**< should negated clique information be used in presolving */
131 SCIP_Bool useimplications; /**< should we try to shrink the variables and derive global boundchanges
132 * by using clique and implications */
133 SCIP_Bool usestrengthening; /**< should pairwise constraint comparison try to strengthen constraints by
134 * removing superflous non-zeros? */
135 int nlastcliquesneg; /**< number of cliques after last negated clique presolving round */
136 int nlastimplsneg; /**< number of implications after last negated clique presolving round */
137 int nlastcliquesshorten;/**< number of cliques after last shortening of constraints */
138 int nlastimplsshorten; /**< number of implications after last shortening of constraints */
139};
140
141/* @todo it might speed up exit-presolve to remember all positions for variables when catching the varfixed event, or we
142 * change catching and dropping the events like it is done in cons_setppc, which probably makes the code more
143 * clear
144 */
145
146/** logic or constraint data */
147struct SCIP_ConsData
148{
149 SCIP_ROW* row; /**< LP row, if constraint is already stored in LP row format */
150 SCIP_NLROW* nlrow; /**< NLP row, if constraint has been added to NLP relaxation */
151 SCIP_VAR** vars; /**< variables of the constraint */
152 int varssize; /**< size of vars array */
153 int nvars; /**< number of variables in the constraint */
154 int watchedvar1; /**< position of the first watched variable */
155 int watchedvar2; /**< position of the second watched variable */
156 int filterpos1; /**< event filter position of first watched variable */
157 int filterpos2; /**< event filter position of second watched variable */
158 unsigned int signature; /**< constraint signature which is need for pairwise comparison */
159 unsigned int presolved:1; /**< flag indicates if we have some fixed, aggregated or multi-aggregated
160 * variables
161 */
162 unsigned int impladded:1; /**< was the 2-variable logic or constraint already added as implication? */
163 unsigned int sorted:1; /**< are the constraint's variables sorted? */
164 unsigned int changed:1; /**< was constraint changed since last redundancy round in preprocessing? */
165 unsigned int merged:1; /**< are the constraint's equal/negated variables already merged? */
166 unsigned int existmultaggr:1; /**< does this constraint contain aggregations */
167 unsigned int validsignature:1; /**< is the signature valid */
168};
169
170
171/*
172 * Local methods
173 */
174
175/** installs rounding locks for the given variable in the given logic or constraint */
176static
178 SCIP* scip, /**< SCIP data structure */
179 SCIP_CONS* cons, /**< logic or constraint */
180 SCIP_VAR* var /**< variable of constraint entry */
181 )
182{
184
185 return SCIP_OKAY;
186}
187
188/** removes rounding locks for the given variable in the given logic or constraint */
189static
191 SCIP* scip, /**< SCIP data structure */
192 SCIP_CONS* cons, /**< logic or constraint */
193 SCIP_VAR* var /**< variable of constraint entry */
194 )
195{
197
198 return SCIP_OKAY;
199}
200
201/** creates constraint handler data for logic or constraint handler */
202static
204 SCIP* scip, /**< SCIP data structure */
205 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
206 SCIP_EVENTHDLR* eventhdlr /**< event handler */
207 )
208{
209 assert(scip != NULL);
210 assert(conshdlrdata != NULL);
211 assert(eventhdlr != NULL);
212
213 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
214
215 (*conshdlrdata)->nlastcliquesneg = 0;
216 (*conshdlrdata)->nlastimplsneg = 0;
217 (*conshdlrdata)->nlastcliquesshorten = 0;
218 (*conshdlrdata)->nlastimplsshorten = 0;
219
220 /* set event handler for catching events on watched variables */
221 (*conshdlrdata)->eventhdlr = eventhdlr;
222
223 return SCIP_OKAY;
224}
225
226/** frees constraint handler data for logic or constraint handler */
227static
229 SCIP* scip, /**< SCIP data structure */
230 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
231 )
232{
233 assert(conshdlrdata != NULL);
234 assert(*conshdlrdata != NULL);
235
236 SCIPfreeBlockMemory(scip, conshdlrdata);
237}
238
239/** ensures, that the vars array can store at least num entries */
240static
242 SCIP* scip, /**< SCIP data structure */
243 SCIP_CONSDATA* consdata, /**< logicor constraint data */
244 int num /**< minimum number of entries to store */
245 )
246{
247 assert(consdata != NULL);
248 assert(consdata->nvars <= consdata->varssize);
249
250 if( num > consdata->varssize )
251 {
252 int newsize;
253
254 newsize = SCIPcalcMemGrowSize(scip, num);
255 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
256 consdata->varssize = newsize;
257 }
258 assert(num <= consdata->varssize);
259
260 return SCIP_OKAY;
261}
262
263/** creates a logic or constraint data object */
264static
266 SCIP* scip, /**< SCIP data structure */
267 SCIP_CONSDATA** consdata, /**< pointer to store the logic or constraint data */
268 int nvars, /**< number of variables in the constraint */
269 SCIP_VAR** vars /**< variables of the constraint */
270 )
271{
272 int v;
273
274 assert(consdata != NULL);
275 assert(nvars == 0 || vars != NULL);
276
277 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
278
279 (*consdata)->row = NULL;
280 (*consdata)->nlrow = NULL;
281 if( nvars > 0 )
282 {
283 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
284 (*consdata)->varssize = nvars;
285 (*consdata)->nvars = nvars;
286 }
287 else
288 {
289 (*consdata)->vars = NULL;
290 (*consdata)->varssize = 0;
291 (*consdata)->nvars = 0;
292 }
293 (*consdata)->watchedvar1 = -1;
294 (*consdata)->watchedvar2 = -1;
295 (*consdata)->filterpos1 = -1;
296 (*consdata)->filterpos2 = -1;
297 (*consdata)->presolved = FALSE;
298 (*consdata)->impladded = FALSE;
299 (*consdata)->changed = TRUE;
300 (*consdata)->sorted = (nvars <= 1);
301 (*consdata)->merged = (nvars <= 1);
302 (*consdata)->existmultaggr = FALSE;
303 (*consdata)->validsignature = FALSE;
304
305 /* get transformed variables, if we are in the transformed problem */
307 {
308 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
309
310 /* check for multi-aggregations and capture variables */
311 for( v = 0; v < (*consdata)->nvars; v++ )
312 {
313 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
314 assert(var != NULL);
315 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
316 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
317 }
318 }
319 else
320 {
321 /* capture variables */
322 for( v = 0; v < (*consdata)->nvars; v++ )
323 {
324 assert((*consdata)->vars[v] != NULL);
325 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
326 }
327 }
328
329 return SCIP_OKAY;
330}
331
332/** frees a logic or constraint data */
333static
335 SCIP* scip, /**< SCIP data structure */
336 SCIP_CONSDATA** consdata /**< pointer to the logic or constraint */
337 )
338{
339 int v;
340
341 assert(consdata != NULL);
342 assert(*consdata != NULL);
343
344 /* release the row */
345 if( (*consdata)->row != NULL )
346 {
347 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
348 }
349
350 /* release the nlrow */
351 if( (*consdata)->nlrow != NULL )
352 {
353 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
354 }
355
356 /* release variables */
357 for( v = 0; v < (*consdata)->nvars; v++ )
358 {
359 assert((*consdata)->vars[v] != NULL);
360 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
361 }
362
363 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->varssize);
364 SCIPfreeBlockMemory(scip, consdata);
365
366 return SCIP_OKAY;
367}
368
369/** prints logic or constraint to file stream */
370static
372 SCIP* scip, /**< SCIP data structure */
373 SCIP_CONSDATA* consdata, /**< logic or constraint data */
374 FILE* file, /**< output file (or NULL for standard output) */
375 SCIP_Bool endline /**< should an endline be set? */
376 )
377{
378 assert(consdata != NULL);
379
380 /* print constraint type */
381 SCIPinfoMessage(scip, file, "logicor(");
382
383 /* print variable list */
384 SCIP_CALL( SCIPwriteVarsList(scip, file, consdata->vars, consdata->nvars, TRUE, ',') );
385
386 /* close bracket */
387 SCIPinfoMessage(scip, file, ")");
388
389 if( endline )
390 SCIPinfoMessage(scip, file, "\n");
391
392 return SCIP_OKAY;
393}
394
395/** stores the given variable numbers as watched variables, and updates the event processing */
396static
398 SCIP* scip, /**< SCIP data structure */
399 SCIP_CONS* cons, /**< logic or constraint */
400 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
401 int watchedvar1, /**< new first watched variable */
402 int watchedvar2 /**< new second watched variable */
403 )
404{
405 SCIP_CONSDATA* consdata;
406
407 consdata = SCIPconsGetData(cons);
408 assert(consdata != NULL);
409 assert(watchedvar1 == -1 || watchedvar1 != watchedvar2);
410 assert(watchedvar1 != -1 || watchedvar2 == -1);
411 assert(watchedvar1 == -1 || (0 <= watchedvar1 && watchedvar1 < consdata->nvars));
412 assert(watchedvar2 == -1 || (0 <= watchedvar2 && watchedvar2 < consdata->nvars));
413
414 /* if one watched variable is equal to the old other watched variable, just switch positions */
415 if( watchedvar1 == consdata->watchedvar2 || watchedvar2 == consdata->watchedvar1 )
416 {
417 int tmp;
418
419 tmp = consdata->watchedvar1;
420 consdata->watchedvar1 = consdata->watchedvar2;
421 consdata->watchedvar2 = tmp;
422 tmp = consdata->filterpos1;
423 consdata->filterpos1 = consdata->filterpos2;
424 consdata->filterpos2 = tmp;
425 }
426 assert(watchedvar1 == -1 || watchedvar1 != consdata->watchedvar2);
427 assert(watchedvar2 == -1 || watchedvar2 != consdata->watchedvar1);
428
429 /* drop events on old watched variables */
430 if( consdata->watchedvar1 != -1 && consdata->watchedvar1 != watchedvar1 )
431 {
432 assert(consdata->filterpos1 != -1);
433 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar1],
435 consdata->filterpos1) );
436 }
437 if( consdata->watchedvar2 != -1 && consdata->watchedvar2 != watchedvar2 )
438 {
439 assert(consdata->filterpos2 != -1);
440 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar2],
442 consdata->filterpos2) );
443 }
444
445 /* catch events on new watched variables */
446 if( watchedvar1 != -1 && watchedvar1 != consdata->watchedvar1 )
447 {
448 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[watchedvar1],
450 &consdata->filterpos1) );
451 }
452 if( watchedvar2 != -1 && watchedvar2 != consdata->watchedvar2 )
453 {
454 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[watchedvar2],
456 &consdata->filterpos2) );
457 }
458
459 /* set the new watched variables */
460 consdata->watchedvar1 = watchedvar1;
461 consdata->watchedvar2 = watchedvar2;
462
463 return SCIP_OKAY;
464}
465
466/** adds coefficient in logicor constraint */
467static
469 SCIP* scip, /**< SCIP data structure */
470 SCIP_CONS* cons, /**< logicor constraint */
471 SCIP_VAR* var /**< variable to add to the constraint */
472 )
473{
474 SCIP_CONSDATA* consdata;
475 SCIP_Bool transformed;
476
477 assert(var != NULL);
478
479 consdata = SCIPconsGetData(cons);
480 assert(consdata != NULL);
481
482 /* are we in the transformed problem? */
483 transformed = SCIPconsIsTransformed(cons);
484
485 /* always use transformed variables in transformed constraints */
486 if( transformed )
487 {
489
490 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
491 consdata->existmultaggr = TRUE;
492
493 consdata->presolved = FALSE;
494 }
495 assert(var != NULL);
496 assert(transformed == SCIPvarIsTransformed(var));
497
498 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars + 1) );
499 consdata->vars[consdata->nvars] = var;
500 SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[consdata->nvars]) );
501 consdata->nvars++;
502
503 /* we only catch this event in presolving stage */
505 {
506 SCIP_CONSHDLRDATA* conshdlrdata;
507 SCIP_CONSHDLR* conshdlr;
508
510 assert(conshdlr != NULL);
511 conshdlrdata = SCIPconshdlrGetData(conshdlr);
512 assert(conshdlrdata != NULL);
513
514 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
515 (SCIP_EVENTDATA*)cons, NULL) );
516 }
517
518 consdata->sorted = (consdata->nvars == 1);
519 consdata->changed = TRUE;
520 consdata->validsignature = FALSE;
521
522 /* install the rounding locks for the new variable */
523 SCIP_CALL( lockRounding(scip, cons, var) );
524
525 /* add the new coefficient to the LP row */
526 if( consdata->row != NULL )
527 {
528 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, 1.0) );
529 }
530
531 consdata->merged = FALSE;
532
533 return SCIP_OKAY;
534}
535
536/** deletes coefficient at given position from logic or constraint data */
537static
539 SCIP* scip, /**< SCIP data structure */
540 SCIP_CONS* cons, /**< logic or constraint */
541 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
542 int pos /**< position of coefficient to delete */
543 )
544{
545 SCIP_CONSDATA* consdata;
546
547 assert(eventhdlr != NULL);
548
549 consdata = SCIPconsGetData(cons);
550 assert(consdata != NULL);
551 assert(0 <= pos && pos < consdata->nvars);
552 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(consdata->vars[pos]));
553
554 /* remove the rounding locks of variable */
555 SCIP_CALL( unlockRounding(scip, cons, consdata->vars[pos]) );
556
557 /* we only catch this event in presolving stage, so we need to only drop it there */
559 {
560 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], SCIP_EVENTTYPE_VARFIXED, eventhdlr,
561 (SCIP_EVENTDATA*)cons, -1) );
562 }
563
564 if( SCIPconsIsTransformed(cons) )
565 {
566 /* if the position is watched, stop watching the position */
567 if( consdata->watchedvar1 == pos )
568 {
569 SCIP_CALL( switchWatchedvars(scip, cons, eventhdlr, consdata->watchedvar2, -1) );
570 }
571 if( consdata->watchedvar2 == pos )
572 {
573 SCIP_CALL( switchWatchedvars(scip, cons, eventhdlr, consdata->watchedvar1, -1) );
574 }
575 }
576 assert(pos != consdata->watchedvar1);
577 assert(pos != consdata->watchedvar2);
578
579 /* release variable */
580 SCIP_CALL( SCIPreleaseVar(scip, &consdata->vars[pos]) );
581
582 /* move the last variable to the free slot */
583 if( pos != consdata->nvars - 1 )
584 {
585 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
586 consdata->sorted = FALSE;
587 }
588 consdata->nvars--;
589
590 /* if the last variable (that moved) was watched, update the watched position */
591 if( consdata->watchedvar1 == consdata->nvars )
592 consdata->watchedvar1 = pos;
593 if( consdata->watchedvar2 == consdata->nvars )
594 consdata->watchedvar2 = pos;
595
596 consdata->changed = TRUE;
597 consdata->validsignature = FALSE;
598
600
601 return SCIP_OKAY;
602}
603
604/** in case a part (more than one variable) in the logic or constraint is independent of every else, we can perform dual
605 * reductions;
606 * - fix the variable with the smallest object coefficient to one if the constraint is not modifiable and all
607 * variable are independant
608 * - fix all independant variables with negative object coefficient to one
609 * - fix all remaining independant variables to zero
610 *
611 * also added the special case were exactly one variable is locked by this constraint and another variable without any
612 * uplocks has a better objective value than this single variable
613 * - here we fix the variable to 0.0 (if the objective contribution is non-negative)
614 *
615 * Moreover, if there exists a variable that is only locked by a constraint with two variables, one can aggregate variables.
616 *
617 * Note: the following dual reduction for logic or constraints is already performed by the presolver "dualfix"
618 * - if a variable in a set covering constraint is only locked by that constraint and has negative or zero
619 * objective coefficient than it can be fixed to one
620 */
621static
623 SCIP* scip, /**< SCIP data structure */
624 SCIP_CONS* cons, /**< setppc constraint */
625 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
626 int* nfixedvars, /**< pointer to count number of fixings */
627 int* ndelconss, /**< pointer to count number of deleted constraints */
628 int* nchgcoefs, /**< pointer to count number of changed/deleted coefficients */
629 int* naggrvars, /**< pointer to count number of variables aggregated */
630 SCIP_RESULT* result /**< pointer to store the result SCIP_SUCCESS, if presolving was performed */
631 )
632{
633 SCIP_CONSDATA* consdata;
634 SCIP_VAR** vars;
635 SCIP_VAR* var;
636 SCIP_VAR* activevar;
637 SCIP_Real bestobjval;
638 SCIP_Real bestobjvalnouplocks;
640 SCIP_Real fixval;
641 SCIP_Bool infeasible;
642 SCIP_Bool fixed;
643 SCIP_Bool negated;
644 int nfixables;
645 int nvars;
646 int idx;
647 int indepidx = -1;
648 int idxnouplocks;
649 int v;
650
651 assert(scip != NULL);
652 assert(cons != NULL);
653 assert(eventhdlr != NULL);
654 assert(nfixedvars != NULL);
655 assert(ndelconss != NULL);
656 assert(nchgcoefs != NULL);
657 assert(result != NULL);
658
659 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
660 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
661 * added to the problems have the check flag set to FALSE
662 */
663 if( !SCIPconsIsChecked(cons) )
664 return SCIP_OKAY;
665
667
668 consdata = SCIPconsGetData(cons);
669 assert(consdata != NULL);
670
671 nvars = consdata->nvars;
672
673 /* we don't want to consider small constraints (note that the constraints can be modifiable, so we can't delete this
674 * constraint)
675 */
676 if( nvars < 2 )
677 return SCIP_OKAY;
678
679 vars = consdata->vars;
680 idx = -1;
681 idxnouplocks = -1;
682 bestobjval = SCIP_INVALID;
683 bestobjvalnouplocks = SCIP_INVALID;
684
685 nfixables = 0;
686
687 /* check if we can apply the dual reduction; therefore count the number of variables where the logic or has the only
688 * locks on
689 */
690 for( v = nvars - 1; v >= 0; --v )
691 {
692 var = vars[v];
693 assert(var != NULL);
694
695 /* variables with varstatus not equal to SCIP_VARSTATUS_FIXED can also have fixed bounds, but were not removed yet */
696 if( SCIPvarGetUbGlobal(var) < 0.5 )
697 {
698#ifndef NDEBUG
699 SCIP_VAR* bestvar = NULL;
700#endif
701 if( idx == consdata->nvars - 1 )
702 {
703#ifndef NDEBUG
704 bestvar = consdata->vars[idx];
705#endif
706 idx = v;
707 }
708
709 if( idxnouplocks == consdata->nvars - 1 )
710 idxnouplocks = v;
711
712 if( indepidx == consdata->nvars - 1 )
713 indepidx = v;
714
715 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
716 ++(*nchgcoefs);
717
718 assert(bestvar == NULL || bestvar == consdata->vars[v]);
719
720 continue;
721 }
722 if( SCIPvarGetLbGlobal(var) > 0.5 )
723 {
724 /* remove constraint since it is redundant */
725 SCIP_CALL( SCIPdelCons(scip, cons) );
726 ++(*ndelconss);
727
728 return SCIP_OKAY;
729 }
730
731 /* remember best variable with no uplocks, this variable dominates all other with exactly one downlock */
734 {
736
737 /* check if the current variable has a smaller objective coefficient then the best one */
738 if( SCIPisLT(scip, objval, bestobjval) )
739 {
740 idxnouplocks = v;
741 bestobjvalnouplocks = objval;
742 }
743 }
744
745 /* in case an other constraints has also locks on that variable we cannot perform a dual reduction on these
746 * variables
747 */
750 continue;
751
752 ++nfixables;
753 negated = FALSE;
754
755 /* get the active variable */
758
759 if( negated )
761 else
763
764 /* check if the current variable has a smaller objective coefficient */
765 if( SCIPisLT(scip, objval, bestobjval) )
766 {
767 idx = v;
768 bestobjval = objval;
769 }
770
771 if ( objval >= 0.0 )
772 indepidx = v;
773 }
774
775 nvars = consdata->nvars;
776
777 /* In the special case of two variables, where one variable is independent and is minimized, we can aggregate variables:
778 * We have var1 + var2 >= 1 and var1 is independent with positive objective. Then var1 + var2 == 1 holds. */
779 if( nvars == 2 && indepidx >= 0 )
780 {
781 SCIP_Bool redundant;
782 SCIP_Bool aggregated;
783 int idx2;
784
785 idx2 = 1 - indepidx;
786 assert(0 <= idx2 && idx2 < 2);
787
788 SCIP_CALL( SCIPaggregateVars(scip, vars[indepidx], vars[idx2], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
789 assert(!infeasible);
790 assert(redundant);
791 assert(aggregated);
792 ++(*naggrvars);
793
794 /* remove constraint since it is now redundant */
795 SCIP_CALL( SCIPdelCons(scip, cons) );
796 ++(*ndelconss);
797
799
800 return SCIP_OKAY;
801 }
802
803 /* check if we have a single variable dominated by another */
804 if( nfixables == 1 && idxnouplocks >= 0 )
805 {
806 assert(bestobjvalnouplocks != SCIP_INVALID); /*lint !e777*/
807
808 for( v = nvars - 1; v >= 0; --v )
809 {
810 var = vars[v];
811 assert(var != NULL);
812
813 /* check if a variable only appearing in this constraint is dominated by another */
816 {
817 assert(idxnouplocks != v);
818
820
821 if( SCIPisGE(scip, objval, bestobjvalnouplocks) && !SCIPisNegative(scip, objval) )
822 {
823 SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
824 assert(!infeasible);
825 assert(fixed);
826
827 SCIPdebugMsg(scip, " -> dual fixing <%s> == 0.0\n", SCIPvarGetName(var));
828 ++(*nfixedvars);
829 }
830
831 break;
832 }
833 }
834 }
835
836 if( nfixables < 2 )
837 return SCIP_OKAY;
838
839 nvars = consdata->nvars;
840
841 assert(idx >= 0 && idx < nvars);
842 assert(bestobjval < SCIPinfinity(scip));
843
845
846 /* fix all redundant variables to their best bound */
847
848 /* first part of all variables */
849 for( v = 0; v < nvars; ++v )
850 {
851 var = vars[v];
852 assert(var != NULL);
853
854 /* in case an other constraints has also locks on that variable we cannot perform a dual reduction on these
855 * variables
856 */
859 continue;
860
861 if( v == idx )
862 continue;
863
864 activevar = var;
865 negated = FALSE;
866
867 /* get the active variable */
868 SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
869 assert(SCIPvarIsActive(activevar));
870
871 if( negated )
872 objval = -SCIPvarGetObj(activevar);
873 else
874 objval = SCIPvarGetObj(activevar);
875
876 if( objval > 0.0 )
877 fixval = 0.0;
878 else
879 fixval = 1.0;
880
881 SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeasible, &fixed) );
882 assert(!infeasible);
883 assert(fixed);
884
885 SCIPdebugMsg(scip, " -> dual fixing <%s> == %g\n", SCIPvarGetName(var), fixval);
886 ++(*nfixedvars);
887 }
888
889 /* if all variable have our appreciated number of locks and the constraint is not modifiable, or if the bestobjval is
890 * less than or equal to zero, we can fix the variable with the smallest objective coefficient to one and the
891 * constraint gets redundant
892 */
893 if( (nfixables == nvars && !SCIPconsIsModifiable(cons)) || bestobjval <= 0.0 )
894 {
895 SCIP_CALL( SCIPfixVar(scip, vars[idx], 1.0, &infeasible, &fixed) );
896 assert(!infeasible);
897 assert(fixed);
898
899 SCIPdebugMsg(scip, " -> fixed <%s> == 1.0\n", SCIPvarGetName(vars[idx]));
900 ++(*nfixedvars);
901
902 /* remove constraint since it is now redundant */
903 SCIP_CALL( SCIPdelCons(scip, cons) );
904 ++(*ndelconss);
905 }
906
907 return SCIP_OKAY;
908}
909
910/** deletes all zero-fixed variables, checks for variables fixed to one, replace all variables which are not active or
911 * not a negation of an active variable by their active or negation of an active counterpart
912 */
913static
915 SCIP* scip, /**< SCIP data structure */
916 SCIP_CONS* cons, /**< logic or constraint */
917 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
918 SCIP_Bool* redundant, /**< returns whether a variable fixed to one exists in the constraint */
919 int* nchgcoefs, /**< pointer to count number of changed/deleted coefficients */
920 int* naddconss, /**< pointer to count number of added constraints, or NULL indicating we
921 * can not resolve multi-aggregations
922 */
923 int* ndelconss /**< pointer to count number of deleted constraints, or NULL indicating we
924 * can not resolve multi-aggregations
925 */
926 )
927{
928 SCIP_CONSDATA* consdata;
929 SCIP_VAR* var;
930 int v;
931 SCIP_VAR** vars;
932 SCIP_Bool* negarray;
933 int nvars;
934
935 assert(eventhdlr != NULL);
936 assert(redundant != NULL);
937
938 consdata = SCIPconsGetData(cons);
939 assert(consdata != NULL);
940 assert(consdata->nvars == 0 || consdata->vars != NULL);
941
942 *redundant = FALSE;
943 v = 0;
944
945 /* all multi-aggregations should be resolved */
946 consdata->existmultaggr = FALSE;
947 consdata->presolved = TRUE;
948
949 /* remove zeros and mark constraint redundant when found one variable fixed to one */
950 while( v < consdata->nvars )
951 {
952 var = consdata->vars[v];
954
955 if( SCIPvarGetLbGlobal(var) > 0.5 )
956 {
958 *redundant = TRUE;
959
960 return SCIP_OKAY;
961 }
962 else if( SCIPvarGetUbGlobal(var) < 0.5 )
963 {
965 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
966 ++(*nchgcoefs);
967 }
968 else
969 ++v;
970 }
971
972 if( consdata->nvars == 0 )
973 return SCIP_OKAY;
974
975 nvars = consdata->nvars;
976
977 /* allocate temporary memory */
980
981 /* get active or negation of active variables */
982 SCIP_CALL( SCIPgetBinvarRepresentatives(scip, nvars, consdata->vars, vars, negarray) );
983
984 /* renew all variables, important that we do a backwards loop because deletion only affects rear items */
985 for( v = nvars - 1; v >= 0; --v )
986 {
987 var = vars[v];
988
989 /* resolve multi-aggregation */
991 {
992 SCIP_VAR** consvars;
993 SCIP_Real* consvals;
994 SCIP_Real constant = 0.0;
995 SCIP_Bool easycase;
996 int nconsvars;
997 int requiredsize;
998 int size = 1;
999 int v2;
1000
1001 nconsvars = 1;
1002 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 1) );
1003 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 1) );
1004 consvars[0] = var;
1005 consvals[0] = 1.0;
1006
1007 /* get active variables for new constraint */
1008 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) );
1009 /* if space was not enough we need to resize the buffers */
1010 if( requiredsize > size )
1011 {
1012 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1013 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1014 size = requiredsize;
1015
1016 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) );
1017 assert(requiredsize <= size);
1018 }
1019 assert(requiredsize == nconsvars);
1020
1021 easycase = FALSE;
1022
1023 if( SCIPisZero(scip, constant) )
1024 {
1025 /* add active representation */
1026 for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1027 {
1028 if( !SCIPvarIsBinary(consvars[v2]) )
1029 break;
1030
1031 if( !SCIPisEQ(scip, consvals[v2], 1.0) )
1032 break;
1033 }
1034
1035 if( v2 < 0 )
1036 easycase = TRUE;
1037 }
1038
1039 /* we can easily add the coefficients and still have a logicor constraint */
1040 if( easycase )
1041 {
1042 /* delete old (multi-aggregated) variable */
1043 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1044 ++(*nchgcoefs);
1045
1046 /* add active representation */
1047 for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1048 {
1049 assert(SCIPvarIsBinary(consvars[v2]));
1050 assert(SCIPvarIsActive(consvars[v2]) || (SCIPvarGetStatus(consvars[v2]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(consvars[v2]))));
1051
1052 SCIP_CALL( addCoef(scip, cons, consvars[v2]) );
1053 ++(*nchgcoefs);
1054 }
1055 }
1056 /* we need to degrade this logicor constraint to a linear constraint */
1057 else if( (ndelconss != NULL && naddconss != NULL) || SCIPconsIsAdded(cons) )
1058 {
1059 char name[SCIP_MAXSTRLEN];
1060 SCIP_CONS* newcons;
1061 SCIP_Real lhs;
1062 SCIP_Real rhs;
1063 int k;
1064
1065 /* it might happen that there is more than one multi-aggregated variable, so we need to get the whole probvar sum over all variables */
1066
1067 size = MAX(nconsvars, 1) + nvars - 1;
1068
1069 /* memory needed is at least old number of variables - 1 + number of variables in first multi-aggregation */
1070 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, size) );
1071 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, size) );
1072
1073 nconsvars = nvars;
1074
1075 /* add constraint variables to new linear variables */
1076 for( k = nvars - 1; k >= 0; --k )
1077 {
1078 consvars[k] = vars[k];
1079 consvals[k] = 1.0;
1080 }
1081
1082 constant = 0.0;
1083
1084 /* get active variables for new constraint */
1085 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) );
1086
1087 /* if space was not enough (we found another multi-aggregation), we need to resize the buffers */
1088 if( requiredsize > size )
1089 {
1090 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1091 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1092 size = requiredsize;
1093
1094 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize) );
1095 assert(requiredsize <= size);
1096 }
1097 assert(requiredsize == nconsvars);
1098
1099 lhs = 1.0 - constant;
1100 rhs = SCIPinfinity(scip);
1101
1102 /* create linear constraint */
1103 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
1104 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, nconsvars, consvars, consvals, lhs, rhs,
1105 SCIPconsIsInitial(cons),
1109
1110 /* add the downgraded constraint to the problem */
1111 SCIPdebugMsg(scip, "adding linear constraint: ");
1112 SCIPdebugPrintCons(scip, newcons, NULL);
1113 SCIP_CALL( SCIPaddCons(scip, newcons) );
1114 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1115
1116 /* free constraint arrays */
1117 SCIPfreeBufferArray(scip, &consvals);
1118 SCIPfreeBufferArray(scip, &consvars);
1119
1120 /* delete old constraint */
1121 SCIP_CALL( SCIPdelCons(scip, cons) );
1122 if( ndelconss != NULL && naddconss != NULL )
1123 {
1124 assert( naddconss != NULL ); /* for lint */
1125 ++(*ndelconss);
1126 ++(*naddconss);
1127 }
1128
1129 goto TERMINATE;
1130 }
1131 /* we need to degrade this logicor constraint to a linear constraint */
1132 else
1133 {
1134 if( var != consdata->vars[v] )
1135 {
1136 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1137 SCIP_CALL( addCoef(scip, cons, var) );
1138 }
1139
1140 SCIPwarningMessage(scip, "logicor constraint <%s> has a multi-aggregated variable, which was not resolved and therefore could lead to aborts\n", SCIPconsGetName(cons));
1141 }
1142
1143 SCIPfreeBufferArray(scip, &consvals);
1144 SCIPfreeBufferArray(scip, &consvars);
1145 }
1146 else if( var != consdata->vars[v] )
1147 {
1149
1150 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1151
1152 /* the binvar representative might be fixed:
1153 * - if fixed to 1, the constraint is redundant
1154 * - if fixed to 0, the representative does not need to be added to the constraint
1155 * - if not fixed, we add the representative to the constraint
1156 */
1157 if( SCIPvarGetLbGlobal(var) > 0.5 )
1158 {
1160 *redundant = TRUE;
1161
1162 goto TERMINATE;
1163 }
1164 else if( SCIPvarGetUbGlobal(var) < 0.5 )
1165 {
1167 ++(*nchgcoefs);
1168 }
1169 else
1170 {
1171 SCIP_CALL( addCoef(scip, cons, var) );
1172 }
1173 }
1174 }
1175
1176 SCIPdebugMsg(scip, "after fixings: ");
1177 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL, TRUE) ) );
1178
1179 TERMINATE:
1180 /* free temporary memory */
1181 SCIPfreeBufferArray(scip, &negarray);
1183
1184 consdata->presolved = TRUE;
1185
1186 return SCIP_OKAY;
1187}
1188
1189/** analyzes conflicting assignment on given constraint, and adds conflict constraint to problem */
1190static
1192 SCIP* scip, /**< SCIP data structure */
1193 SCIP_CONS* cons /**< logic or constraint that detected the conflict */
1194 )
1195{
1196 SCIP_CONSDATA* consdata;
1197 int v;
1198
1199 /* conflict analysis can only be applied in solving stage and if it is applicable */
1201 return SCIP_OKAY;
1202
1203 consdata = SCIPconsGetData(cons);
1204 assert(consdata != NULL);
1205
1206 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1208
1209 for( v = 0; v < consdata->nvars; ++v )
1210 {
1211 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
1212 }
1213
1214 /* analyze the conflict */
1216
1217 return SCIP_OKAY;
1218}
1219
1220/** disables or deletes the given constraint, depending on the current depth */
1221static
1223 SCIP* scip, /**< SCIP data structure */
1224 SCIP_CONS* cons /**< bound disjunction constraint to be disabled */
1225 )
1226{
1228
1229 /* in case the logic or constraint is satisfied in the depth where it is also valid, we can delete it */
1231 {
1232 SCIP_CALL( SCIPdelCons(scip, cons) );
1233 }
1234 else
1235 {
1236 SCIPdebugMsg(scip, "disabling constraint cons <%s> at depth %d\n", SCIPconsGetName(cons), SCIPgetDepth(scip));
1237 SCIP_CALL( SCIPdisableCons(scip, cons) );
1238 }
1239
1240 return SCIP_OKAY;
1241}
1242
1243/** find pairs of negated variables in constraint: constraint is redundant */
1244/** find sets of equal variables in constraint: multiple entries of variable can be replaced by single entry */
1245static
1247 SCIP* scip, /**< SCIP data structure */
1248 SCIP_CONS* cons, /**< logic or constraint */
1249 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1250 unsigned char** entries, /**< array to store whether two positions in constraints represent the same variable */
1251 int* nentries, /**< pointer for array size, if array will be to small it's corrected */
1252 SCIP_Bool* redundant, /**< returns whether a variable fixed to one exists in the constraint */
1253 int* nchgcoefs /**< pointer to count number of changed/deleted coefficients */
1254 )
1255{
1256 SCIP_CONSDATA* consdata;
1257 SCIP_VAR** vars;
1258 int nvars;
1259 SCIP_Bool* negarray;
1260 SCIP_VAR* var;
1261 int v;
1262 int pos;
1263#ifndef NDEBUG
1264 int nbinvars;
1265 int nintvars;
1266 int nimplvars;
1267#endif
1268
1269 assert(scip != NULL);
1270 assert(cons != NULL);
1271 assert(eventhdlr != NULL);
1272 assert(*entries != NULL);
1273 assert(nentries != NULL);
1274 assert(redundant != NULL);
1275 assert(nchgcoefs != NULL);
1276
1277 consdata = SCIPconsGetData(cons);
1278 assert(consdata != NULL);
1279
1280 nvars = consdata->nvars;
1281
1282 *redundant = FALSE;
1283
1284 if( consdata->merged )
1285 return SCIP_OKAY;
1286
1287 if( consdata->nvars <= 1 )
1288 {
1289 consdata->merged = TRUE;
1290 return SCIP_OKAY;
1291 }
1292
1293 assert(consdata->vars != NULL && nvars > 0);
1294
1295#ifndef NDEBUG
1296 nbinvars = SCIPgetNBinVars(scip);
1297 nintvars = SCIPgetNIntVars(scip);
1298 nimplvars = SCIPgetNImplVars(scip);
1299 assert(*nentries >= nbinvars + nintvars + nimplvars);
1300
1301 /* all variables should be active or negative active variables, otherwise something went wrong with applyFixings()
1302 * called before mergeMultiples()
1303 */
1304 assert(consdata->presolved);
1305#endif
1306
1307 /* allocate temporary memory */
1308 SCIP_CALL( SCIPallocBufferArray(scip, &negarray, nvars) );
1309
1310 vars = consdata->vars;
1311
1312 /* initialize entries array */
1313 for( v = nvars - 1; v >= 0; --v )
1314 {
1315 /* all variables should be active or negative active variables, otherwise something went wrong with applyFixings()
1316 * called before mergeMultiples()
1317 */
1320 negarray[v] = SCIPvarIsNegated(vars[v]);
1321 var = negarray[v] ? SCIPvarGetNegationVar(vars[v]) : vars[v];
1323
1324 pos = SCIPvarGetProbindex(var);
1325
1326 /* check variable type, either pure binary or an integer/implicit integer variable with 0/1 bounds */
1328 || (SCIPvarIsBinary(var) &&
1329 ((pos >= nbinvars && pos < nbinvars + nintvars && SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER
1331 (pos >= nbinvars + nintvars && pos < nbinvars + nintvars + nimplvars &&
1333
1334 /* var is not active yet */
1335 (*entries)[pos] = 0;
1336 }
1337
1338 /* check all vars for multiple entries, do necessary backwards loop because deletion only affect rear items */
1339 for( v = nvars - 1; v >= 0; --v )
1340 {
1341 var = negarray[v] ? SCIPvarGetNegationVar(vars[v]) : vars[v];
1343
1344 pos = SCIPvarGetProbindex(var);
1345
1346 /* if var occurs first time in constraint init entries array */
1347 if( (*entries)[pos] == 0 )
1348 (*entries)[pos] = negarray[v] ? 2 : 1;
1349 /* if var occurs second time in constraint, first time it was not negated */
1350 else if( (*entries)[pos] == 1 )
1351 {
1352 if( negarray[v] )
1353 {
1354 SCIPdebugMsg(scip, "logicor constraint <%s> redundant: variable <%s> and its negation are present\n",
1356
1357 *redundant = TRUE;
1358 goto TERMINATE;
1359 }
1360 else
1361 {
1362 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1363 ++(*nchgcoefs);
1364 }
1365 }
1366 /* if var occurs second time in constraint, first time it was negated */
1367 else
1368 {
1369 if( !negarray[v] )
1370 {
1371 SCIPdebugMsg(scip, "logicor constraint <%s> redundant: variable <%s> and its negation are present\n",
1373
1374 *redundant = TRUE;
1375 goto TERMINATE;
1376 }
1377 else
1378 {
1379 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1380 ++(*nchgcoefs);
1381 }
1382 }
1383 }
1384
1385 TERMINATE:
1386 /* free temporary memory */
1387 SCIPfreeBufferArray(scip, &negarray);
1388
1389 consdata->merged = TRUE;
1390
1391 return SCIP_OKAY;
1392}
1393
1394/** checks constraint for violation only looking at the watched variables, applies fixings if possible */
1395static
1397 SCIP* scip, /**< SCIP data structure */
1398 SCIP_CONS* cons, /**< logic or constraint to be processed */
1399 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1400 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1401 SCIP_Bool* reduceddom, /**< pointer to store TRUE, if a domain reduction was found */
1402 SCIP_Bool* addcut, /**< pointer to store whether this constraint must be added as a cut */
1403 SCIP_Bool* mustcheck /**< pointer to store whether this constraint must be checked for feasibility */
1404 )
1405{
1406 SCIP_CONSDATA* consdata;
1407 SCIP_VAR** vars;
1408 SCIP_Longint nbranchings1;
1409 SCIP_Longint nbranchings2;
1410 int nvars;
1411 int watchedvar1;
1412 int watchedvar2;
1413
1414 assert(cons != NULL);
1415 assert(SCIPconsGetHdlr(cons) != NULL);
1417 assert(cutoff != NULL);
1418 assert(reduceddom != NULL);
1419 assert(addcut != NULL);
1420 assert(mustcheck != NULL);
1421
1422 consdata = SCIPconsGetData(cons);
1423 assert(consdata != NULL);
1424 assert(consdata->watchedvar1 == -1 || consdata->watchedvar1 != consdata->watchedvar2);
1425
1426 *addcut = FALSE;
1427 *mustcheck = FALSE;
1428
1429 SCIPdebugMsg(scip, "processing watched variables of constraint <%s>\n", SCIPconsGetName(cons));
1430
1431 vars = consdata->vars;
1432 nvars = consdata->nvars;
1433 assert(nvars == 0 || vars != NULL);
1434
1435 /* check watched variables if they are fixed to one */
1436 if( consdata->watchedvar1 >= 0 && SCIPvarGetLbLocal(vars[consdata->watchedvar1]) > 0.5 )
1437 {
1438 /* the variable is fixed to one, making the constraint redundant -> disable the constraint */
1439 SCIPdebugMsg(scip, " -> disabling constraint <%s> (watchedvar1 fixed to 1.0)\n", SCIPconsGetName(cons));
1440 SCIP_CALL( disableCons(scip, cons) );
1441 return SCIP_OKAY;
1442 }
1443 if( consdata->watchedvar2 >= 0 && SCIPvarGetLbLocal(vars[consdata->watchedvar2]) > 0.5 )
1444 {
1445 /* the variable is fixed to one, making the constraint redundant -> disable the constraint */
1446 SCIPdebugMsg(scip, " -> disabling constraint <%s> (watchedvar2 fixed to 1.0)\n", SCIPconsGetName(cons));
1447 SCIP_CALL( disableCons(scip, cons) );
1448 return SCIP_OKAY;
1449 }
1450
1451 /* check if watched variables are still unfixed */
1452 watchedvar1 = -1;
1453 watchedvar2 = -1;
1454 nbranchings1 = SCIP_LONGINT_MAX;
1455 nbranchings2 = SCIP_LONGINT_MAX;
1456 if( consdata->watchedvar1 >= 0 && SCIPvarGetUbLocal(vars[consdata->watchedvar1]) > 0.5 )
1457 {
1458 watchedvar1 = consdata->watchedvar1;
1459 nbranchings1 = -1; /* prefer keeping the watched variable */
1460 }
1461 if( consdata->watchedvar2 >= 0 && SCIPvarGetUbLocal(vars[consdata->watchedvar2]) > 0.5 )
1462 {
1463 if( watchedvar1 == -1 )
1464 {
1465 watchedvar1 = consdata->watchedvar2;
1466 nbranchings1 = -1; /* prefer keeping the watched variable */
1467 }
1468 else
1469 {
1470 watchedvar2 = consdata->watchedvar2;
1471 nbranchings2 = -1; /* prefer keeping the watched variable */
1472 }
1473 }
1474 assert(watchedvar1 >= 0 || watchedvar2 == -1);
1475 assert(nbranchings1 <= nbranchings2);
1476
1477 /* search for new watched variables */
1478 if( watchedvar2 == -1 )
1479 {
1480 int v;
1481
1482 for( v = 0; v < nvars; ++v )
1483 {
1484 SCIP_Longint nbranchings;
1485
1486 /* don't process the watched variables again */
1487 if( v == consdata->watchedvar1 || v == consdata->watchedvar2 )
1488 continue;
1489
1490 /* check, if the variable is fixed */
1491 if( SCIPvarGetUbLocal(vars[v]) < 0.5 )
1492 continue;
1493
1494 /* check, if the literal is satisfied */
1495 if( SCIPvarGetLbLocal(vars[v]) > 0.5 )
1496 {
1497 assert(v != consdata->watchedvar1);
1498 assert(v != consdata->watchedvar2);
1499
1500 /* the variable is fixed to one, making the constraint redundant;
1501 * make sure, the feasible variable is watched and disable the constraint
1502 */
1503 SCIPdebugMsg(scip, " -> disabling constraint <%s> (variable <%s> fixed to 1.0)\n",
1505 if( consdata->watchedvar1 != -1 )
1506 {
1507 SCIP_CALL( switchWatchedvars(scip, cons, eventhdlr, consdata->watchedvar1, v) );
1508 }
1509 else
1510 {
1511 SCIP_CALL( switchWatchedvars(scip, cons, eventhdlr, v, consdata->watchedvar2) );
1512 }
1513 SCIP_CALL( disableCons(scip, cons) );
1514 return SCIP_OKAY;
1515 }
1516
1517 /* the variable is unfixed and can be used as watched variable */
1519 assert(nbranchings >= 0);
1520 if( nbranchings < nbranchings2 )
1521 {
1522 if( nbranchings < nbranchings1 )
1523 {
1524 watchedvar2 = watchedvar1;
1525 nbranchings2 = nbranchings1;
1526 watchedvar1 = v;
1527 nbranchings1 = nbranchings;
1528 }
1529 else
1530 {
1531 watchedvar2 = v;
1532 nbranchings2 = nbranchings;
1533 }
1534 }
1535 }
1536 }
1537 assert(nbranchings1 <= nbranchings2);
1538 assert(watchedvar1 >= 0 || watchedvar2 == -1);
1539
1540 if( watchedvar1 == -1 )
1541 {
1542 /* there is no unfixed variable left -> the constraint is infeasible
1543 * - a modifiable constraint must be added as a cut and further pricing must be performed in the LP solving loop
1544 * - an unmodifiable constraint is infeasible and the node can be cut off
1545 */
1546 assert(watchedvar2 == -1);
1547
1548 SCIPdebugMsg(scip, " -> constraint <%s> is infeasible\n", SCIPconsGetName(cons));
1549
1551 if( SCIPconsIsModifiable(cons) )
1552 *addcut = TRUE;
1553 else
1554 {
1555 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1556 SCIP_CALL( analyzeConflict(scip, cons) );
1557
1558 /* mark the node to be cut off */
1559 *cutoff = TRUE;
1560 }
1561 }
1562 else if( watchedvar2 == -1 )
1563 {
1564 /* there is only one unfixed variable:
1565 * - a modifiable constraint must be checked manually
1566 * - an unmodifiable constraint is feasible and can be disabled after the remaining variable is fixed to one
1567 */
1568 assert(0 <= watchedvar1 && watchedvar1 < nvars);
1569 assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(vars[watchedvar1]), 0.0));
1570 assert(SCIPisFeasEQ(scip, SCIPvarGetUbLocal(vars[watchedvar1]), 1.0));
1571 if( SCIPconsIsModifiable(cons) )
1572 *mustcheck = TRUE;
1573 else
1574 {
1575 SCIP_Bool infbdchg;
1576
1577 /* fixed remaining variable to one and disable constraint; make sure, the fixed-to-one variable is watched */
1578 SCIPdebugMsg(scip, " -> single-literal constraint <%s> (fix <%s> to 1.0) at depth %d\n",
1579 SCIPconsGetName(cons), SCIPvarGetName(vars[watchedvar1]), SCIPgetDepth(scip));
1580 SCIP_CALL( SCIPinferBinvarCons(scip, vars[watchedvar1], TRUE, cons, 0, &infbdchg, NULL) );
1581 assert(!infbdchg);
1583 if( watchedvar1 != consdata->watchedvar1 ) /* keep one of the watched variables */
1584 {
1585 SCIP_CALL( switchWatchedvars(scip, cons, eventhdlr, watchedvar1, consdata->watchedvar1) );
1586 }
1587 SCIP_CALL( disableCons(scip, cons) );
1588 *reduceddom = TRUE;
1589 }
1590 }
1591 else
1592 {
1593 SCIPdebugMsg(scip, " -> new watched variables <%s> and <%s> of constraint <%s> are still unfixed\n",
1594 SCIPvarGetName(vars[watchedvar1]), SCIPvarGetName(vars[watchedvar2]), SCIPconsGetName(cons));
1595
1596 /* switch to the new watched variables */
1597 SCIP_CALL( switchWatchedvars(scip, cons, eventhdlr, watchedvar1, watchedvar2) );
1598
1599 /* there are at least two unfixed variables -> the constraint must be checked manually */
1600 *mustcheck = TRUE;
1601
1602 /* disable propagation of constraint until a watched variable gets fixed */
1604
1605 /* increase aging counter */
1606 SCIP_CALL( SCIPaddConsAge(scip, cons, AGEINCREASE(consdata->nvars)) );
1607 }
1608
1609 return SCIP_OKAY;
1610}
1611
1612/** checks constraint for violation, returns TRUE iff constraint is feasible */
1613static
1615 SCIP* scip, /**< SCIP data structure */
1616 SCIP_CONS* cons, /**< logic or constraint to be checked */
1617 SCIP_SOL* sol /**< primal CIP solution */
1618 )
1619{
1620 SCIP_CONSDATA* consdata;
1621 SCIP_VAR** vars;
1622 SCIP_Real solval;
1623 SCIP_Real sum;
1624 int nvars;
1625 int v;
1626
1627 consdata = SCIPconsGetData(cons);
1628 assert(consdata != NULL);
1629
1630 vars = consdata->vars;
1631 nvars = consdata->nvars;
1632
1633 /* calculate the constraint's activity */
1634 sum = 0.0;
1635 for( v = 0; v < nvars && sum < 1.0; ++v )
1636 {
1638
1639 solval = SCIPgetSolVal(scip, sol, vars[v]);
1640 assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0));
1641
1642 sum += solval;
1643 }
1644
1645 /* calculate constraint violation and update it in solution */
1646 if( sol != NULL ){
1647 SCIP_Real absviol = 1.0 - sum;
1648 SCIP_Real relviol = SCIPrelDiff(1.0, sum);
1649 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
1650 }
1651
1652 return SCIPisFeasLT(scip, sum, 1.0);
1653}
1654
1655/** creates an LP row in a logic or constraint data object */
1656static
1658 SCIP* scip, /**< SCIP data structure */
1659 SCIP_CONS* cons /**< logic or constraint */
1660 )
1661{
1662 SCIP_CONSDATA* consdata;
1663
1664 consdata = SCIPconsGetData(cons);
1665 assert(consdata != NULL);
1666 assert(consdata->row == NULL);
1667
1668 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), 1.0, SCIPinfinity(scip),
1670
1671 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->row, consdata->nvars, consdata->vars, 1.0) );
1672
1673 return SCIP_OKAY;
1674}
1675
1676/** adds logicor constraint as row to the NLP, if not added yet */
1677static
1679 SCIP* scip, /**< SCIP data structure */
1680 SCIP_CONS* cons /**< logicor constraint */
1681 )
1682{
1683 SCIP_CONSDATA* consdata;
1684
1686
1687 /* skip deactivated, redundant, or local constraints (the NLP does not allow for local rows at the moment) */
1688 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
1689 return SCIP_OKAY;
1690
1691 consdata = SCIPconsGetData(cons);
1692 assert(consdata != NULL);
1693
1694 if( consdata->nlrow == NULL )
1695 {
1696 SCIP_Real* coefs;
1697 int i;
1698
1699 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, consdata->nvars) );
1700 for( i = 0; i < consdata->nvars; ++i )
1701 coefs[i] = 1.0;
1702
1703 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons),
1704 0.0, consdata->nvars, consdata->vars, coefs, NULL, 1.0, SCIPinfinity(scip), SCIP_EXPRCURV_LINEAR) );
1705 assert(consdata->nlrow != NULL);
1706
1707 SCIPfreeBufferArray(scip, &coefs);
1708 }
1709
1710 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
1711 {
1712 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
1713 }
1714
1715 return SCIP_OKAY;
1716}
1717
1718/** adds logic or constraint as cut to the LP */
1719static
1721 SCIP* scip, /**< SCIP data structure */
1722 SCIP_CONS* cons, /**< logic or constraint */
1723 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
1724 )
1725{
1726 SCIP_CONSDATA* consdata;
1727
1728 assert( cutoff != NULL );
1729 *cutoff = FALSE;
1730
1731 consdata = SCIPconsGetData(cons);
1732 assert(consdata != NULL);
1733
1734 if( consdata->row == NULL )
1735 {
1736 /* convert logic or constraint data into LP row */
1737 SCIP_CALL( createRow(scip, cons) );
1738 }
1739 assert(consdata->row != NULL);
1740
1741 /* insert LP row as cut */
1742 if( !SCIProwIsInLP(consdata->row) )
1743 {
1744 SCIPdebugMsg(scip, "adding constraint <%s> as cut to the LP\n", SCIPconsGetName(cons));
1745 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
1746 }
1747
1748 return SCIP_OKAY;
1749}
1750
1751/** checks constraint for violation, and adds it as a cut if possible */
1752static
1754 SCIP* scip, /**< SCIP data structure */
1755 SCIP_CONS* cons, /**< logic or constraint to be separated */
1756 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
1757 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1758 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1759 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
1760 SCIP_Bool* reduceddom /**< pointer to store TRUE, if a domain reduction was found */
1761 )
1762{
1763 SCIP_Bool addcut;
1764 SCIP_Bool mustcheck;
1765
1766 assert(cons != NULL);
1767 assert(SCIPconsGetHdlr(cons) != NULL);
1769 assert(cutoff != NULL);
1770 assert(separated != NULL);
1771 assert(reduceddom != NULL);
1772
1773 *cutoff = FALSE;
1774 SCIPdebugMsg(scip, "separating constraint <%s>\n", SCIPconsGetName(cons));
1775
1776 /* update and check the watched variables, if they were changed since last processing */
1777 if( sol == NULL && SCIPconsIsPropagationEnabled(cons) )
1778 {
1779 SCIP_CALL( processWatchedVars(scip, cons, eventhdlr, cutoff, reduceddom, &addcut, &mustcheck) );
1780 }
1781 else
1782 {
1783 addcut = FALSE;
1784 mustcheck = TRUE;
1785 }
1786
1787 if( mustcheck )
1788 {
1789 SCIP_CONSDATA* consdata;
1790
1791 assert(!addcut);
1792
1793 consdata = SCIPconsGetData(cons);
1794 assert(consdata != NULL);
1795
1796 /* variable's fixings didn't give us any information -> we have to check the constraint */
1797 if( sol == NULL && consdata->row != NULL )
1798 {
1799 /* skip constraints already in the LP */
1800 if( SCIProwIsInLP(consdata->row) )
1801 return SCIP_OKAY;
1802 else
1803 {
1804 SCIP_Real feasibility;
1805
1806 assert(!SCIProwIsInLP(consdata->row));
1807 feasibility = SCIPgetRowLPFeasibility(scip, consdata->row);
1808 addcut = SCIPisFeasNegative(scip, feasibility);
1809 }
1810 }
1811 else
1812 {
1813 addcut = isConsViolated(scip, cons, sol);
1814 }
1815 }
1816
1817 if( addcut )
1818 {
1819 /* insert LP row as cut */
1820 SCIP_CALL( addCut(scip, cons, cutoff) );
1822 *separated = TRUE;
1823 }
1824
1825 return SCIP_OKAY;
1826}
1827
1828/** enforces the pseudo solution on the given constraint */
1829static
1831 SCIP* scip, /**< SCIP data structure */
1832 SCIP_CONS* cons, /**< logic or constraint to be separated */
1833 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1834 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1835 SCIP_Bool* infeasible, /**< pointer to store TRUE, if the constraint was infeasible */
1836 SCIP_Bool* reduceddom, /**< pointer to store TRUE, if a domain reduction was found */
1837 SCIP_Bool* solvelp /**< pointer to store TRUE, if the LP has to be solved */
1838 )
1839{
1840 SCIP_Bool addcut;
1841 SCIP_Bool mustcheck;
1842
1844 assert(cons != NULL);
1845 assert(SCIPconsGetHdlr(cons) != NULL);
1847 assert(cutoff != NULL);
1848 assert(infeasible != NULL);
1849 assert(reduceddom != NULL);
1850 assert(solvelp != NULL);
1851
1852 /* update and check the watched variables, if they were changed since last processing */
1854 {
1855 SCIP_CALL( processWatchedVars(scip, cons, eventhdlr, cutoff, reduceddom, &addcut, &mustcheck) );
1856 }
1857 else
1858 {
1859 addcut = FALSE;
1860 mustcheck = TRUE;
1861 }
1862
1863 if( mustcheck )
1864 {
1865 assert(!addcut);
1866
1867 if( isConsViolated(scip, cons, NULL) )
1868 {
1869 /* constraint was infeasible -> reset age */
1871 *infeasible = TRUE;
1872 }
1873 }
1874 else if( addcut )
1875 {
1876 /* a cut must be added to the LP -> we have to solve the LP immediately */
1878 *solvelp = TRUE;
1879 }
1880
1881 return SCIP_OKAY;
1882}
1883
1884/** sorts logicor constraint's variables by non-decreasing variable index */
1885static
1887 SCIP_CONSDATA* consdata /**< linear constraint data */
1888 )
1889{
1890 assert(consdata != NULL);
1891
1892 if( !consdata->sorted )
1893 {
1894 if( consdata->nvars <= 1 )
1895 consdata->sorted = TRUE;
1896 else
1897 {
1898 SCIP_VAR* var1 = NULL;
1899 SCIP_VAR* var2 = NULL;
1900
1901 /* remember watch variables */
1902 if( consdata->watchedvar1 != -1 )
1903 {
1904 var1 = consdata->vars[consdata->watchedvar1];
1905 assert(var1 != NULL);
1906 consdata->watchedvar1 = -1;
1907 if( consdata->watchedvar2 != -1 )
1908 {
1909 var2 = consdata->vars[consdata->watchedvar2];
1910 assert(var2 != NULL);
1911 consdata->watchedvar2 = -1;
1912 }
1913 }
1914 assert(consdata->watchedvar1 == -1);
1915 assert(consdata->watchedvar2 == -1);
1916 assert(var1 != NULL || var2 == NULL);
1917
1918 /* sort variables after index */
1919 SCIPsortPtr((void**)consdata->vars, SCIPvarComp, consdata->nvars);
1920 consdata->sorted = TRUE;
1921
1922 /* correct watched variables */
1923 if( var1 != NULL )
1924 {
1925 int pos;
1926#ifndef NDEBUG
1927 SCIP_Bool found;
1928
1929 found = SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var1, consdata->nvars, &pos);
1930 assert(found);
1931#else
1932 (void) SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var1, consdata->nvars, &pos);
1933#endif
1934 assert(pos >= 0 && pos < consdata->nvars);
1935 consdata->watchedvar1 = pos;
1936
1937 if( var2 != NULL )
1938 {
1939#ifndef NDEBUG
1940 found = SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var2, consdata->nvars, &pos);
1941 assert(found);
1942#else
1943 (void) SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var2, consdata->nvars, &pos);
1944#endif
1945 assert(pos >= 0 && pos < consdata->nvars);
1946 consdata->watchedvar2 = pos;
1947 }
1948 }
1949 }
1950 }
1951
1952#ifdef SCIP_DEBUG
1953 /* check sorting */
1954 {
1955 int v;
1956
1957 for( v = consdata->nvars - 1; v > 0; --v )
1958 {
1959 assert(SCIPvarCompare(consdata->vars[v], consdata->vars[v - 1]) >= 0);
1960 }
1961 }
1962#endif
1963}
1964
1965/** gets the key of the given element */
1966static
1967SCIP_DECL_HASHGETKEY(hashGetKeyLogicorcons)
1968{ /*lint --e{715}*/
1969 /* the key is the element itself */
1970 return elem;
1971}
1972
1973/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */
1974static
1975SCIP_DECL_HASHKEYEQ(hashKeyEqLogicorcons)
1976{
1977 SCIP_CONSDATA* consdata1;
1978 SCIP_CONSDATA* consdata2;
1979 SCIP_Bool coefsequal;
1980 int i;
1981#ifndef NDEBUG
1982 SCIP* scip;
1983
1984 scip = (SCIP*)userptr;
1985 assert(scip != NULL);
1986#endif
1987
1988 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
1989 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
1990
1991 /* checks trivial case */
1992 if( consdata1->nvars != consdata2->nvars )
1993 return FALSE;
1994
1995 /* sorts the constraints */
1996 consdataSort(consdata1);
1997 consdataSort(consdata2);
1998 assert(consdata1->sorted);
1999 assert(consdata2->sorted);
2000
2001 coefsequal = TRUE;
2002
2003 for( i = 0; i < consdata1->nvars ; ++i )
2004 {
2005 /* tests if variables are equal */
2006 if( consdata1->vars[i] != consdata2->vars[i] )
2007 {
2008 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
2009 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
2010 coefsequal = FALSE;
2011 break;
2012 }
2013 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
2014 }
2015
2016 return coefsequal;
2017}
2018
2019/** returns the hash value of the key */
2020static
2021SCIP_DECL_HASHKEYVAL(hashKeyValLogicorcons)
2022{ /*lint --e{715}*/
2023 SCIP_CONSDATA* consdata;
2024 int minidx;
2025 int mididx;
2026 int maxidx;
2027
2028 consdata = SCIPconsGetData((SCIP_CONS*)key);
2029 assert(consdata != NULL);
2030 assert(consdata->sorted);
2031 assert(consdata->nvars > 0);
2032
2033 minidx = SCIPvarGetIndex(consdata->vars[0]);
2034 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
2035 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
2036 assert(minidx >= 0 && minidx <= maxidx);
2037
2038 return SCIPhashFour(consdata->nvars, minidx, mididx, maxidx);
2039}
2040
2041/** compares each constraint with all other constraints for a possible duplication and removes duplicates using a hash
2042 * table; also @see removeRedundantConssAndNonzeros()
2043 */
2044static
2046 SCIP* scip, /**< SCIP data structure */
2047 BMS_BLKMEM* blkmem, /**< block memory */
2048 SCIP_CONS** conss, /**< constraint set */
2049 int nconss, /**< number of constraints in constraint set */
2050 int* firstchange, /**< pointer to store first changed constraint */
2051 int* ndelconss /**< pointer to count number of deleted constraints */
2052 )
2053{
2054 SCIP_HASHTABLE* hashtable;
2055 int hashtablesize;
2056 int c;
2057
2058 assert(conss != NULL);
2059 assert(ndelconss != NULL);
2060
2061 /* create a hash table for the constraint set */
2062 hashtablesize = nconss;
2063 hashtablesize = MAX(hashtablesize, HASHSIZE_LOGICORCONS);
2064 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
2065 hashGetKeyLogicorcons, hashKeyEqLogicorcons, hashKeyValLogicorcons, (void*) scip) );
2066
2067 /* check all constraints in the given set for redundancy */
2068 for( c = 0; c < nconss; ++c )
2069 {
2070 SCIP_CONS* cons0;
2071 SCIP_CONS* cons1;
2072 SCIP_CONSDATA* consdata0;
2073
2074 cons0 = conss[c];
2075
2076 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
2077 continue;
2078
2079 consdata0 = SCIPconsGetData(cons0);
2080 /* sort the constraint */
2081 consdataSort(consdata0);
2082 assert(consdata0->sorted);
2083
2084 /* get constraint from current hash table with same variables as cons0 */
2085 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
2086
2087 if( cons1 != NULL )
2088 {
2089#ifndef NDEBUG
2090 SCIP_CONSDATA* consdata1;
2091#endif
2092
2093 assert(SCIPconsIsActive(cons1));
2095
2096#ifndef NDEBUG
2097 consdata1 = SCIPconsGetData(cons1);
2098#endif
2099 assert(consdata1 != NULL);
2100 assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars);
2101
2102 assert(consdata0->sorted && consdata1->sorted);
2103 assert(consdata0->vars[0] == consdata1->vars[0]);
2104
2105 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
2106 /* coverity[swapped_arguments] */
2107 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
2108
2109 /* delete consdel */
2110 SCIP_CALL( SCIPdelCons(scip, cons0) );
2111 (*ndelconss)++;
2112
2113 /* update the first changed constraint to begin the next aggregation round with */
2114 if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange )
2115 *firstchange = SCIPconsGetPos(cons1);
2116
2117 assert(SCIPconsIsActive(cons1));
2118 }
2119 else
2120 {
2121 /* no such constraint in current hash table: insert cons0 into hash table */
2122 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
2123 }
2124 }
2125
2126 /* free hash table */
2127 SCIPhashtableFree(&hashtable);
2128
2129 return SCIP_OKAY;
2130}
2131
2132/** removes the redundant second constraint and updates the flags of the first one */
2133static
2135 SCIP* scip, /**< SCIP data structure */
2136 SCIP_CONS* cons0, /**< constraint that should stay */
2137 SCIP_CONS* cons1, /**< constraint that should be deleted */
2138 int* ndelconss /**< pointer to count number of deleted constraints */
2139 )
2140{
2141 assert(ndelconss != NULL);
2142
2143 SCIPdebugMsg(scip, " -> removing logicor constraint <%s> which is redundant to <%s>\n",
2144 SCIPconsGetName(cons1), SCIPconsGetName(cons0));
2145 SCIPdebugPrintCons(scip, cons0, NULL);
2146 SCIPdebugPrintCons(scip, cons1, NULL);
2147
2148 /* update flags of cons0 */
2149 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
2150
2151 /* delete cons1 */
2152 SCIP_CALL( SCIPdelCons(scip, cons1) );
2153 (*ndelconss)++;
2154
2155 return SCIP_OKAY;
2156}
2157
2158
2159/** compute and return a signature for given variables */
2160static
2161unsigned int calcSignature(
2162 SCIP_VAR** vars, /**< variables to calculate the signature for */
2163 int nvars /**< number of variables to calculate the signature for */
2164 )
2165{
2166 unsigned int signature = 0;
2167 int v;
2168
2169 assert(vars != NULL);
2170 assert(nvars >= 1);
2171
2172 for( v = nvars - 1; v >= 0; --v )
2173 {
2174 signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
2175 }
2176
2177 return signature;
2178}
2179
2180/** compute the constraint signature which is used to detect constraints, that contain potentially the same set of
2181 * variables
2182 */
2183static
2185 SCIP_CONSDATA* consdata /**< logicor constraint data */
2186 )
2187{
2188 if( consdata->validsignature )
2189 return;
2190
2191 consdata->signature = calcSignature(consdata->vars, consdata->nvars);
2192 consdata->validsignature = TRUE;
2193}
2194
2195/** remove a constraint from the column representation */
2196static
2198 SCIP_CONS* cons, /**< logicor constraint */
2199 SCIP_HASHMAP* varstopos, /**< map for mapping variables to positions in the occurlist */
2200 SCIP_CONS*** occurlist, /**< column representation of logicor constraints */
2201 int* noccurlistentries, /**< arrray with number of constraints for each variable in the occurlist */
2202 int occurlistlength /**< number of columns in the occurlist */
2203 )
2204{
2205 SCIP_VAR** vars;
2206 SCIP_VAR* var;
2207 SCIP_CONSDATA* consdata;
2208 int nvars;
2209 int pos;
2210 int v;
2211 int l;
2212
2213 assert(cons != NULL);
2214 assert(SCIPconsIsActive(cons));
2215 assert(varstopos != NULL);
2216 assert(occurlist != NULL);
2217 assert(noccurlistentries != NULL);
2218
2219 consdata = SCIPconsGetData(cons);
2220 assert(consdata != NULL);
2221
2222 nvars = consdata->nvars;
2223 assert(nvars >= 1);
2224 vars = consdata->vars;
2225 assert(vars != NULL);
2226
2227 /* remove constraint from list */
2228 for( v = nvars - 1; v >= 0; --v )
2229 {
2230 var = vars[v];
2231
2232 assert(SCIPhashmapExists(varstopos, (void*) var));
2233
2234 pos = SCIPhashmapGetImageInt(varstopos, (void*)var);
2235 assert(0 < pos && pos <= occurlistlength);
2236
2237 --pos;
2238
2239 /* remove for each variable one corresponding entry */
2240 for( l = noccurlistentries[pos] - 1; l >= 0; --l )
2241 {
2242 if( occurlist[pos][l] == cons )
2243 {
2244 --noccurlistentries[pos];
2245 assert(noccurlistentries[pos] >= 0);
2246
2247 occurlist[pos][l] = occurlist[pos][noccurlistentries[pos]];
2248 break;
2249 }
2250 }
2251 assert(l >= 0);
2252 }
2253}
2254
2255/** determine shortest constraint list in column representation */
2256static
2258 SCIP_VAR** vars, /**< variables to find the shortestlist for */
2259 int nvars, /**< number of variables */
2260 SCIP_HASHMAP* varstopos, /**< map for mapping variables to positions in the occurlist */
2261 SCIP_CONS*** occurlist, /**< column representation of logicor constraints */
2262 int* noccurlistentries, /**< arrray with number of constraints for each variable in the occurlist */
2263 int occurlistlength, /**< number of columns in the occurlist */
2264 int* nentries, /**< pointer to store the number of entries in the shortest list */
2265 SCIP_CONS*** shortestlist /**< pointer to store smallest array with constraints */
2266 )
2267{
2268 SCIP_VAR* var;
2269 int pos;
2270 int v;
2271
2272 assert(vars != 0);
2273 assert(nvars >= 1);
2274 assert(varstopos != NULL);
2275 assert(occurlist != NULL);
2276 assert(noccurlistentries != NULL);
2277 assert(nentries != NULL);
2278 assert(shortestlist != NULL);
2279
2280 *nentries = INT_MAX;
2281 *shortestlist = NULL;
2282
2283 /* find the shortest list */
2284 for( v = nvars - 1; v >= 0; --v )
2285 {
2286 var = vars[v];
2287 assert(var != NULL);
2288
2289 /* it might be that a variable is not yet put into the occurlist, then this constraint cannot cover another */
2290 if( !SCIPhashmapExists(varstopos, (void*) var) )
2291 {
2292 *nentries = 0;
2293 return;
2294 }
2295
2296 pos = SCIPhashmapGetImageInt(varstopos, (void*)var);
2297 assert(0 < pos && pos <= occurlistlength);
2298
2299 --pos;
2300
2301 /* remember the shortest list */
2302 if( noccurlistentries[pos] < *nentries )
2303 {
2304 *nentries = noccurlistentries[pos];
2305 *shortestlist = occurlist[pos];
2306 }
2307 }
2308}
2309
2310/** run a pairwise comparison for detecting subset-constraints of other constraint while using a signature */
2311static
2313 SCIP* scip, /**< SCIP data structure */
2314 SCIP_CONS* cons, /**< logicor constraint to check if it covers another */
2315 SCIP_HASHMAP* varstopos, /**< map for mapping variables to positions in the occurlist */
2316 SCIP_CONS*** occurlist, /**< column representation of logicor constraints */
2317 int* noccurlistentries, /**< arrray with number of constraints for each variable in the occurlist */
2318 int occurlistlength, /**< number of columns in the occurlist */
2319 int* ndelconss /**< pointer to store the number of deleted constraints */
2320 )
2321{
2322 SCIP_CONS** shortestlist;
2323 SCIP_VAR** vars;
2324 SCIP_CONS* cons1;
2325 SCIP_VAR* var;
2326 SCIP_CONSDATA* consdata;
2327 int nentries;
2328 int c;
2329 int v;
2330
2331 assert(scip != NULL);
2332 assert(cons != NULL);
2333 assert(SCIPconsIsActive(cons));
2335 assert(varstopos != NULL);
2336 assert(occurlist != NULL);
2337 assert(noccurlistentries != NULL);
2338 assert(ndelconss != NULL);
2339
2340 consdata = SCIPconsGetData(cons);
2341 assert(consdata != NULL);
2342 assert(consdata->nvars > 1);
2343 assert(consdata->validsignature);
2344 assert(consdata->sorted);
2345
2346 vars = consdata->vars;
2347 assert(vars != NULL);
2348
2349 /* determine shortest column */
2350 findShortestOccurlist(vars, consdata->nvars, varstopos, occurlist, noccurlistentries, occurlistlength, &nentries, &shortestlist);
2351
2352 /* one variable which does not appear in the column representation anymore */
2353 if( nentries == 0 )
2354 return SCIP_OKAY;
2355
2356 assert(shortestlist != NULL);
2357 assert(0 < nentries);
2358
2359 /* check all constraints in the shortest list for coverage */
2360 for( c = nentries - 1; c >= 0; --c )
2361 {
2362 cons1 = shortestlist[c];
2363 assert(cons1 != NULL);
2365 assert(SCIPconsIsActive(cons1));
2366
2367 if( cons != cons1 )
2368 {
2369 SCIP_CONSDATA* consdata1 = SCIPconsGetData(cons1);
2370 assert(consdata1 != NULL);
2371 assert(consdata1->nvars >= consdata->nvars);
2372
2373 /* constraints with the same length cannot be covered and same constraints are removed in
2374 * detectRedundantConstraints()
2375 */
2376 if( consdata1->nvars == consdata->nvars )
2377 continue;
2378
2379 assert(consdata->validsignature);
2380 assert(consdata->sorted);
2381 assert(consdata1->validsignature);
2382 assert(consdata1->sorted);
2383
2384 if( (consdata->signature & (~consdata1->signature)) == 0 )
2385 {
2386 SCIP_VAR* var1;
2387 int v1;
2388
2389 v = 0;
2390 v1 = 0;
2391
2392 while( v < consdata->nvars && v1 < consdata1->nvars )
2393 {
2394 int comp;
2395
2396 var = vars[v];
2397 var1 = consdata1->vars[v1];
2398
2399 comp = SCIPvarCompare(var, var1);
2400
2401 if( comp == 0 )
2402 {
2403 ++v;
2404 ++v1;
2405 }
2406 else if( comp > 0 )
2407 ++v1;
2408 else
2409 break;
2410 }
2411
2412 /* cons1 is covered by cons */
2413 if( v == consdata->nvars )
2414 {
2415 /* remove cons1 from columns representation */
2416 removeConsFromOccurList(cons1, varstopos, occurlist, noccurlistentries, occurlistlength);
2417
2418 /* delete redundant constraint and update constraint flags if necessary */
2419 SCIP_CALL( removeRedundantCons(scip, cons, cons1, ndelconss) );
2420 }
2421 }
2422 }
2423 }
2424
2425 return SCIP_OKAY;
2426}
2427
2428/** compararer for sorting constraints after their number of variables */
2429static
2430SCIP_DECL_SORTPTRCOMP(conssLogicorComp)
2431{
2432 SCIP_CONSDATA* consdata1;
2433 SCIP_CONSDATA* consdata2;
2434
2435 assert(elem1 != NULL);
2436 assert(elem2 != NULL);
2437
2438 consdata1 = SCIPconsGetData((SCIP_CONS*) elem1);
2439 consdata2 = SCIPconsGetData((SCIP_CONS*) elem2);
2440
2441 assert(consdata1 != NULL);
2442 assert(consdata2 != NULL);
2443
2444 return consdata1->nvars - consdata2->nvars;
2445}
2446
2447/** add a constraint to the column representation */
2448static
2450 SCIP* scip, /**< SCIP data structure */
2451 SCIP_CONS* cons, /**< logicor constraint */
2452 SCIP_HASHMAP* varstopos, /**< map for mapping variables to positions in the occurlist */
2453 SCIP_CONS*** occurlist, /**< column representation of logicor constraints */
2454 int* noccurlistentries, /**< arrray with number of constraints for each variable in the occurlist */
2455 int* occurlistsizes, /**< array of sizes for each variable in the occurlist */
2456 int* occurlistlength, /**< number of columns in the occurlist */
2457 int occurlistsize /**< size of occurlist */
2458 )
2459{
2460 SCIP_VAR** vars;
2461 SCIP_VAR* var;
2462 SCIP_CONSDATA* consdata;
2463 int pos;
2464 int v;
2465
2466 assert(scip != NULL);
2467 assert(cons != NULL);
2468 assert(SCIPconsIsActive(cons));
2469 assert(varstopos != NULL);
2470 assert(occurlist != NULL);
2471 assert(noccurlistentries != NULL);
2472 assert(occurlistsizes != NULL);
2473 assert(occurlistlength != NULL);
2474 assert(*occurlistlength <= occurlistsize);
2475
2476 consdata = SCIPconsGetData(cons);
2477 assert(consdata != NULL);
2478 assert(consdata->nvars > 1);
2479
2480 vars = consdata->vars;
2481 assert(vars != NULL);
2482
2483 for( v = consdata->nvars - 1; v >= 0; --v )
2484 {
2485 var = vars[v];
2486 assert(var != NULL);
2488
2489 /* check if the variable is not yet put into the occurlist */
2490 if( !SCIPhashmapExists(varstopos, (void*) var) )
2491 {
2492 pos = *occurlistlength;
2493 assert(pos <= occurlistsize);
2494
2495 /* occurlist values need to be clear */
2496 assert(occurlist[pos] == NULL);
2497 assert(noccurlistentries[pos] == 0);
2498 assert(occurlistsizes[pos] == 0);
2499
2500 /* allocate memory */
2502 occurlistsizes[pos] = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) + 1;
2503 SCIP_CALL( SCIPallocBufferArray(scip, &(occurlist[pos]), occurlistsizes[pos]) ); /*lint !e866*/
2504
2505 /* put constraint in list of current variable */
2506 occurlist[pos][noccurlistentries[pos]] = cons;
2507 ++(noccurlistentries[pos]);
2508
2509 /* add new variable to map */
2510 SCIP_CALL( SCIPhashmapInsertInt(varstopos, var, pos + 1) );
2511
2512 ++(*occurlistlength);
2513 }
2514 else
2515 {
2516 pos = SCIPhashmapGetImageInt(varstopos, (void*)var);
2517 assert(0 < pos && pos <= *occurlistlength);
2518
2519 --pos;
2520
2521 assert(occurlist[pos] != NULL);
2522 assert(occurlistsizes[pos] > 0);
2523
2524 /* do we need to resize the array */
2525 if( noccurlistentries[pos] == occurlistsizes[pos] )
2526 {
2527 occurlistsizes[pos] = SCIPcalcMemGrowSize(scip, occurlistsizes[pos] + 1);
2528 assert(occurlistsizes[pos] > noccurlistentries[pos] && occurlistsizes[pos] < INT_MAX);
2529
2530 /* resize occurlist for current variable */
2531 SCIP_CALL( SCIPreallocBufferArray(scip, &(occurlist[pos]), occurlistsizes[pos]) ); /*lint !e866*/
2532 }
2533 assert(noccurlistentries[pos] < occurlistsizes[pos]);
2534
2535 /* put constraint in list of current variable */
2536 occurlist[pos][noccurlistentries[pos]] = cons;
2537 ++(noccurlistentries[pos]);
2538 }
2539 }
2540
2541 return SCIP_OKAY;
2542}
2543
2544/** run a pairwise comparison for the given variables against all constraits to detect redundant non-zeros in these
2545 * constraints
2546 */
2547static
2549 SCIP* scip, /**< SCIP data structure */
2550 SCIP_CONS* cons, /**< logicor constraint to check if it covers another */
2551 SCIP_VAR* artvar, /**< artificial negated variable of constraint */
2552 int artpos, /**< position to replace constraint variable with artvar */
2553 SCIP_HASHMAP* varstopos, /**< map for mapping variables to positions in the occurlist */
2554 SCIP_CONS*** occurlist, /**< column representation of logicor constraints */
2555 int* noccurlistentries, /**< number of constraints for each variable in the occurlist */
2556 int occurlistlength, /**< number of columns in the occurlist */
2557 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
2558 int* nchgcoefs, /**< pointer to store the number of deleted non-zeros */
2559 SCIP_Bool* deleted /**< pointer to store if cons will be deleted */
2560 )
2561{
2562 SCIP_CONS** shortestlist;
2563 SCIP_VAR** vars;
2564 SCIP_CONS* cons1;
2565 SCIP_VAR* oldvar;
2566 SCIP_VAR* var;
2567 SCIP_CONSDATA* consdata;
2568 unsigned int signature;
2569 int nentries;
2570 int nvars;
2571 int c;
2572 int v;
2573 int pos;
2574
2575 assert(scip != NULL);
2576 assert(cons != NULL);
2577 assert(artvar != NULL);
2578 assert(SCIPconsIsActive(cons));
2580 assert(varstopos != NULL);
2581 assert(SCIPhashmapExists(varstopos, (void*) artvar));
2582 assert(occurlist != NULL);
2583 assert(noccurlistentries != NULL);
2584 assert(nchgcoefs != NULL);
2585 assert(deleted != NULL);
2586
2587 consdata = SCIPconsGetData(cons);
2588 assert(consdata != NULL);
2589 assert(consdata->sorted);
2590
2591 nvars = consdata->nvars;
2592 assert(nvars > 1);
2593 assert(0 <= artpos && artpos < nvars);
2594
2595 vars = consdata->vars;
2596 assert(vars != NULL);
2597
2598 *deleted = FALSE;
2599
2600 /* temporary exchange the variable for finding the shortest list */
2601 oldvar = vars[artpos];
2602 assert(oldvar == SCIPvarGetNegatedVar(artvar));
2603 vars[artpos] = artvar;
2604
2605 /* determine shortest column */
2606 findShortestOccurlist(vars, nvars, varstopos, occurlist, noccurlistentries, occurlistlength, &nentries, &shortestlist);
2607
2608 /* correct exchanged variable with constraint variables */
2609 vars[artpos] = oldvar;
2610
2611 /* one variable which does not appear in the column representation anymore */
2612 if( nentries == 0 )
2613 return SCIP_OKAY;
2614
2615 assert(shortestlist != NULL);
2616 assert(0 < nentries);
2617
2618 /* temporary exchange the variable for calculating a valid signature */
2619 vars[artpos] = artvar;
2620 signature = calcSignature(vars, nvars);
2621
2622 /* correct exchanged variable with constraint variables */
2623 vars[artpos] = oldvar;
2624
2625 /* check all constraints in the shortest list for coverage */
2626 for( c = nentries - 1; c >= 0; --c )
2627 {
2628 cons1 = shortestlist[c];
2629 assert(cons1 != NULL);
2631
2632 if( !SCIPconsIsActive(cons1) )
2633 continue;
2634
2635 if( cons != cons1 )
2636 {
2637 SCIP_CONSDATA* consdata1 = SCIPconsGetData(cons1);
2638 assert(consdata1 != NULL);
2639
2640 /* constraints with the less variables cannot be covered */
2641 if( consdata1->nvars < nvars )
2642 continue;
2643
2644 pos = -1;
2645
2646 assert(consdata->sorted);
2647 assert(consdata->merged);
2648 assert(consdata1->validsignature);
2649 assert(consdata1->sorted);
2650 assert(consdata1->merged);
2651
2652 if( (signature & (~consdata1->signature)) == 0 )
2653 {
2654 SCIP_VAR* var1;
2655 int v1;
2656
2657 v = 0;
2658 v1 = 0;
2659
2660 while( v < nvars && v1 < consdata1->nvars )
2661 {
2662 int comp;
2663
2664 /* skip position of artificial variable */
2665 if( artpos == v )
2666 {
2667 ++v;
2668 continue;
2669 }
2670
2671 var1 = consdata1->vars[v1];
2672
2673 /* did we find the artificial variable in cons1 */
2674 if( artvar == var1 )
2675 {
2676 /* remember of possible redundant variable */
2677 assert(pos == -1);
2678 pos = v1;
2679
2680 ++v1;
2681 continue;
2682 }
2683
2684 var = vars[v];
2685 comp = SCIPvarCompare(var, var1);
2686
2687 /* check if the cons1 can still be covered */
2688 if( comp == 0 )
2689 {
2690 ++v;
2691 ++v1;
2692 }
2693 else if( comp > 0 )
2694 ++v1;
2695 else
2696 break;
2697 }
2698
2699 /* cons1 is might be covered by the changed constraints cons, meaning that we might remove the artvar from
2700 * cons1
2701 */
2702 if( v == nvars )
2703 {
2704 int l;
2705
2706 /* if the artificial variable was not yet found, search over the rear variables in constraint cons1 */
2707 if( pos == -1 )
2708 {
2709 while( v1 < consdata1->nvars )
2710 {
2711 if( artvar == consdata1->vars[v1] )
2712 {
2713 /* remember of possible redundant variable */
2714 pos = v1;
2715 break;
2716 }
2717 ++v1;
2718 }
2719 }
2720
2721 if( pos >= 0 )
2722 {
2723 int conspos;
2724
2725 assert(pos < consdata1->nvars);
2726 assert(artvar == consdata1->vars[pos]);
2727
2728 /* remove redudant entry in cons1 */
2729 SCIPdebugMsg(scip, "variable %s in logicor constraint <%s> is redundant and will be removed (used constraint %s)\n",
2730 SCIPvarGetName(artvar), SCIPconsGetName(cons1), SCIPconsGetName(cons));
2731 SCIPdebugPrintCons(scip, cons1, NULL);
2732 conspos = pos;
2733
2734 if( consdata1->nvars > nvars )
2735 {
2736 pos = SCIPhashmapGetImageInt(varstopos, (void*)artvar);
2737 assert(0 < pos && pos <= occurlistlength);
2738
2739 --pos;
2740
2741 /* remove corresponding entry in column representation */
2742 for( l = noccurlistentries[pos] - 1; l >= 0; --l )
2743 {
2744 if( occurlist[pos][l] == cons1 )
2745 {
2746 --noccurlistentries[pos];
2747 assert(noccurlistentries[pos] >= 0);
2748
2749 occurlist[pos][l] = occurlist[pos][noccurlistentries[pos]];
2750 break;
2751 }
2752 }
2753 assert(l >= 0);
2754 }
2755 else
2756 {
2757 assert(consdata1->nvars == nvars);
2758
2759 /* delete cons */
2760 SCIPdebugMsg(scip, "logicor constraint <%s> is redundant due to constraint <%s> after removing variable <%s>\n",
2761 SCIPconsGetName(cons), SCIPconsGetName(cons1), SCIPvarGetName(artvar));
2762
2763 /* remove cons from columns representation */
2764 removeConsFromOccurList(cons, varstopos, occurlist, noccurlistentries, occurlistlength);
2765
2766 /* update flags of cons1 */
2767 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) );
2768
2769 SCIP_CALL( SCIPdelCons(scip, cons) );
2770 *deleted = TRUE;
2771 }
2772
2773 /* remove variable */
2774 SCIP_CALL( delCoefPos(scip, cons1, eventhdlr, conspos) );
2775 ++(*nchgcoefs);
2776 consdataSort(consdata1);
2777 consdataCalcSignature(consdata1);
2778
2779 if( *deleted )
2780 return SCIP_OKAY;
2781 }
2782 }
2783 }
2784 }
2785 }
2786
2787 return SCIP_OKAY;
2788}
2789
2790/** find and remove redundant non-zero entries */
2791static
2793 SCIP* scip, /**< SCIP data structure */
2794 SCIP_CONS** conss, /**< sorted array of logicor constraint */
2795 int nconss, /**< number of sorted constraints */
2796 SCIP_HASHMAP* varstopos, /**< map for mapping variables to positions in the occurlist */
2797 SCIP_CONS*** occurlist, /**< column representation of logicor constraints */
2798 int* noccurlistentries, /**< number of constraints for each variable in the occurlist */
2799 int occurlistlength, /**< number of columns in the occurlist */
2800 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2801 int* ndelconss, /**< pointer to store the number of deleted constraints */
2802 int* nchgcoefs /**< pointer to store the number of remove coefficients */
2803 )
2804{
2805 SCIP_VAR** vars;
2806 SCIP_CONSDATA* consdata;
2807 SCIP_CONS* cons;
2808 SCIP_VAR* artvar;
2809 int nvars;
2810 int c;
2811 int v;
2812
2813 assert(scip != NULL);
2814 assert(conss != NULL || nconss == 0);
2815 assert(varstopos != NULL);
2816 assert(occurlist != NULL);
2817 assert(noccurlistentries != NULL);
2818 assert(eventhdlr != NULL);
2819 assert(ndelconss != NULL);
2820 assert(nchgcoefs != NULL);
2821
2822 if( nconss == 0 )
2823 return SCIP_OKAY;
2824
2825 assert(conss != NULL);
2826
2827 for( c = 0; c < nconss; ++c )
2828 {
2829 cons = conss[c];
2830 assert(cons != NULL);
2832
2833 if( !SCIPconsIsActive(cons) )
2834 continue;
2835
2836 consdata = SCIPconsGetData(cons);
2837 assert(consdata != NULL);
2838
2839 nvars = consdata->nvars;
2840 assert(nvars >= 1);
2841
2842 if( nvars == 1 )
2843 continue;
2844
2845 vars = consdata->vars;
2846 assert(vars != NULL);
2847
2848 for( v = nvars - 1; v >= 0; --v )
2849 {
2850 artvar = SCIPvarGetNegatedVar(vars[v]);
2851
2852 if( artvar != NULL && SCIPhashmapExists(varstopos, (void*) artvar) )
2853 {
2854 SCIP_Bool deleted;
2855
2856 /* detect and remove redundant non-zero entries */
2857 /* @todo: improve this algorithm by using the information that a constraint variables does not appaer in any
2858 * other constraint, which means that only this variable needs to be negated to check for redundant
2859 * non-zeros, therefor change also findShortestOccurlist() to return the corresponding
2860 * variable/position
2861 */
2862 SCIP_CALL( removeRedundantNonZeros(scip, cons, artvar, v, varstopos, occurlist, noccurlistentries,
2863 occurlistlength, eventhdlr, nchgcoefs, &deleted) );
2864
2865 if( deleted )
2866 {
2868 ++(*ndelconss);
2869 break;
2870 }
2871 else
2872 assert(SCIPconsIsActive(cons));
2873 }
2874 }
2875 }
2876
2877 return SCIP_OKAY;
2878}
2879
2880
2881/** prepares a constraint by removing fixings and merge it */
2882static
2884 SCIP* scip, /**< SCIP data structure */
2885 SCIP_CONS* cons, /**< logic or constraint */
2886 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2887 unsigned char** entries, /**< array to store whether two positions in constraints represent the same variable */
2888 int* nentries, /**< pointer for array size, if array will be to small it's corrected */
2889 SCIP_Bool* redundant, /**< returns whether a variable fixed to one exists in the constraint */
2890 int* nfixedvars, /**< pointer to count number of fixings */
2891 int* nchgcoefs, /**< pointer to count number of changed/deleted coefficients */
2892 int* ndelconss, /**< pointer to count number of deleted constraints */
2893 SCIP_Bool* cutoff /**< pointer to store, if cut off appeared */
2894 )
2895{
2896 SCIP_CONSDATA* consdata;
2897
2898 assert(scip != NULL);
2899 assert(cons != NULL);
2900 assert(!SCIPconsIsDeleted(cons));
2901 assert(eventhdlr != NULL);
2902 assert(*entries != NULL);
2903 assert(nentries != NULL);
2904 assert(redundant != NULL);
2905 assert(nfixedvars != NULL);
2906 assert(nchgcoefs != NULL);
2907 assert(ndelconss != NULL);
2908 assert(redundant != NULL);
2909
2910 consdata = SCIPconsGetData(cons);
2911 assert(consdata != NULL);
2912 assert(consdata->nvars > 0);
2913
2914 *redundant = FALSE;
2915
2916 /* remove old fixings */
2917 if( !consdata->presolved )
2918 {
2919 /* remove all variables that are fixed to zero, check redundancy due to fixed-to-one variable */
2920 SCIP_CALL( applyFixings(scip, cons, eventhdlr, redundant, nchgcoefs, NULL, NULL) );
2921 }
2922
2923 if( !*redundant )
2924 {
2925 /* merge constraint */
2926 SCIP_CALL( mergeMultiples(scip, cons, eventhdlr, entries, nentries, redundant, nchgcoefs) );
2927 }
2928
2929 if( *redundant )
2930 {
2931 SCIP_CALL( SCIPdelCons(scip, cons) );
2932 ++(*ndelconss);
2933
2934 return SCIP_OKAY;
2935 }
2936
2937 if( consdata->nvars == 0 )
2938 {
2939 *cutoff = TRUE;
2940 }
2941 else if( consdata->nvars == 1 )
2942 {
2943 SCIP_Bool infeasible;
2944 SCIP_Bool fixed;
2945
2946 SCIPdebugMsg(scip, " -> fix last remaining variable and delete constraint\n");
2947
2948 SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], 1.0, &infeasible, &fixed) );
2949 assert(!infeasible);
2950 assert(fixed);
2951 ++(*nfixedvars);
2952
2953 SCIP_CALL( SCIPdelCons(scip, cons) );
2954 ++(*ndelconss);
2955
2956 *redundant = TRUE;
2957 }
2958 consdata->presolved = TRUE;
2959
2960 return SCIP_OKAY;
2961}
2962
2963
2964/** find covered/subsumed constraints and redundant non-zero entries
2965 *
2966 * covered:
2967 * e.g.: c1: x1 + x2 + x3 >= 1
2968 * c2: x1 + x2 + x3 + x4 >= 1
2969 *
2970 * strengthen:
2971 * e.g.: c1: x1 + x2 + x3 >= 1
2972 * c2: x1 + x2 + ~x3 + x4 >= 1
2973 *
2974 * => c2: x1 + x2 + x4 >= 1
2975 *
2976 * @see "Effective Preprocessing in SAT through Variable and Clause Elimination" by Niklas En and Armin Biere
2977 */
2978static
2980 SCIP* scip, /**< SCIP data structure */
2981 SCIP_CONS** conss, /**< array of logicor constraints */
2982 int nconss, /**< number of logicor constraints */
2983 unsigned char** entries, /**< array to store whether two positions in constraints represent the same
2984 * variable */
2985 int* nentries, /**< pointer for array size, if array will be to small it's corrected */
2986 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2987 SCIP_Bool usestrengthening, /**< should we try to strengthen constraints by removing superflous
2988 * non-zeros? */
2989 int* firstchange, /**< pointer to store first changed constraint */
2990 int* nfixedvars, /**< pointer to count number of fixings */
2991 int* ndelconss, /**< pointer to store the number of deleted constraints */
2992 int* nchgcoefs, /**< pointer to store the number of deleted coefficients */
2993 SCIP_Bool* cutoff /**< pointer to store, if cut off appeared */
2994 )
2995{
2996 SCIP_CONS*** occurlist;
2997 SCIP_CONS** myconss;
2998 SCIP_HASHMAP* varstopos;
2999 SCIP_CONS* cons;
3000 SCIP_CONSDATA* consdata;
3001 int* noccurlistentries;
3002 int* occurlistsizes;
3003 SCIP_Bool redundant;
3004 SCIP_Bool conschanged;
3005 int lastnfixedvars;
3006 int nbinvars;
3007 int occurlistlength;
3008 int occurlistsize;
3009 int nmyconss;
3010 int nmaxvars;
3011 int c;
3012
3013 assert(scip != NULL);
3014 assert(conss != NULL || nconss == 0);
3015 assert(entries != NULL);
3016 assert(*entries != NULL);
3017 assert(nentries != NULL);
3018 assert(eventhdlr != NULL);
3019 assert(firstchange != NULL);
3020 assert(0 <= *firstchange);
3021 assert(nfixedvars != NULL);
3022 assert(ndelconss != NULL);
3023 assert(nchgcoefs != NULL);
3024
3025 if( *firstchange > nconss || nconss < 2 )
3026 return SCIP_OKAY;
3027
3028 SCIPdebugMsg(scip, "starting removeRedundantConssAndNonzeros(), pairwise comparison to detect covered logicor constraints\n");
3029
3030 /* copy constraints to re-order them */
3031 SCIP_CALL( SCIPduplicateBufferArray(scip, &myconss, conss, nconss) );
3032
3033 nmyconss = nconss;
3034 lastnfixedvars = -1;
3035 while( *nfixedvars != lastnfixedvars )
3036 {
3037 lastnfixedvars = *nfixedvars;
3038 for( c = nconss - 1; c >= 0; --c )
3039 {
3040 cons = myconss[c];
3041 assert(cons != NULL);
3042
3043 if( SCIPconsIsDeleted(cons) || SCIPconsIsModifiable(cons) )
3044 {
3045 myconss[c] = myconss[nmyconss - 1];
3046 --nmyconss;
3047
3048 continue;
3049 }
3050
3051 /* prepare constraint by removing fixings and merge it */
3052 SCIP_CALL( prepareCons(scip, cons, eventhdlr, entries, nentries, &redundant, nfixedvars, nchgcoefs, ndelconss, cutoff) );
3053
3054 if( redundant )
3055 {
3057 assert(!(*cutoff));
3058
3059 myconss[c] = myconss[nmyconss - 1];
3060 --nmyconss;
3061
3062 continue;
3063 }
3064
3065 if( *cutoff )
3066 {
3067 SCIPfreeBufferArray(scip, &myconss);
3068
3069 return SCIP_OKAY;
3070 }
3071
3072 consdata = SCIPconsGetData(cons);
3073
3074 /* sort the constraint */
3075 consdataSort(consdata);
3076
3077 assert(consdata->nvars >= 2);
3078 }
3079 }
3080
3081 SCIPsortPtr((void**)myconss, conssLogicorComp, nmyconss);
3082 assert(myconss[0] != NULL && myconss[nmyconss - 1] != NULL);
3083 assert(SCIPconsGetData(myconss[0]) != NULL && SCIPconsGetData(myconss[nmyconss - 1]) != NULL);
3084 assert(SCIPconsGetData(myconss[0])->nvars <= SCIPconsGetData(myconss[nmyconss - 1])->nvars);
3085
3086 /* we can stop if strengthening is disabled and all constraints have the same amount of variables */
3087 if( !usestrengthening && SCIPconsGetData(myconss[0])->nvars == SCIPconsGetData(myconss[nmyconss - 1])->nvars )
3088 {
3089 SCIPfreeBufferArray(scip, &myconss);
3090
3091 return SCIP_OKAY;
3092 }
3093
3094 /* @note: in the following we have at least number of nonzeros in logicor constraints + three times two the number of
3095 * binary variables memory consumption + a map for variables to positions, we need this to get a column base
3096 * representation
3097 */
3098
3099 /* get number of all possible(incl. implicit) binary variables and their negation */
3100 nbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
3101 occurlistsize = 2 * nbinvars;
3102
3103 /* allocate memory for the column representation for each variable */
3104 SCIP_CALL( SCIPallocBufferArray(scip, &occurlist, occurlistsize) );
3105 BMSclearMemoryArray(occurlist, occurlistsize);
3106 SCIP_CALL( SCIPallocBufferArray(scip, &noccurlistentries, occurlistsize) );
3107 BMSclearMemoryArray(noccurlistentries, occurlistsize);
3108 SCIP_CALL( SCIPallocBufferArray(scip, &occurlistsizes, occurlistsize) );
3109 BMSclearMemoryArray(occurlistsizes, occurlistsize);
3110
3111 /* create hashmap to map all occuring variables to a position in the list */
3112 SCIP_CALL( SCIPhashmapCreate(&varstopos, SCIPblkmem(scip), nmyconss) );
3113
3114 /* get maximal number of variables over all logicor constraints */
3115 c = nmyconss - 1;
3116 cons = myconss[c];
3117 assert(cons != NULL);
3118 assert(SCIPconsIsActive(cons));
3119 consdata = SCIPconsGetData(cons);
3120 assert(consdata != NULL);
3121 nmaxvars = consdata->nvars;
3122
3123 occurlistlength = 0;
3124 conschanged = FALSE;
3125
3126 /* determine all constraints with the maximal number of variables and add them to the column representation */
3127 do
3128 {
3129 /* calculate hash-signature */
3130 consdataCalcSignature(consdata);
3131 assert(consdata->validsignature);
3132 conschanged = conschanged || consdata->changed;
3133 consdata->changed = FALSE;
3134
3135 /* add constraint to column data structure */
3136 SCIP_CALL( addConsToOccurList(scip, cons, varstopos, occurlist, noccurlistentries, occurlistsizes, &occurlistlength, occurlistsize) );
3137
3138 --c;
3139 if( c < 0 )
3140 break;
3141
3142 cons = myconss[c];
3143 assert(cons != NULL);
3144 assert(SCIPconsIsActive(cons));
3145 consdata = SCIPconsGetData(cons);
3146 assert(consdata != NULL);
3147 }
3148 while( consdata->nvars == nmaxvars );
3149
3150 /* remove covered constraints and left over constraints to the column representation */
3151 while( c >= 0 )
3152 {
3153 cons = myconss[c];
3154 assert(cons != NULL);
3155 assert(SCIPconsIsActive(cons));
3156 consdata = SCIPconsGetData(cons);
3157 assert(consdata != NULL);
3158
3159 /* calculate hash-signature */
3160 consdataCalcSignature(consdata);
3161 assert(consdata->validsignature);
3162
3163 /* search for covered constraints */
3164 if( conschanged || consdata->changed )
3165 {
3166 /* detect covered constraints
3167 *
3168 * e.g.: c1: x1 + x2 + x3 >= 1
3169 * c2: x1 + x2 + x3 + x4 >= 1
3170 *
3171 * => delete c2
3172 */
3173 SCIP_CALL( removeRedundantConss(scip, cons, varstopos, occurlist, noccurlistentries, occurlistlength, ndelconss) );
3174 assert(SCIPconsIsActive(cons));
3175
3176 consdata->changed = FALSE;
3177 conschanged = TRUE;
3178 }
3179
3180 /* add constraint to column data structure */
3181 SCIP_CALL( addConsToOccurList(scip, cons, varstopos, occurlist, noccurlistentries, occurlistsizes, &occurlistlength, occurlistsize) );
3182
3183 --c;
3184 }
3185
3186 /* strengthen constraint while removing non-zeros
3187 *
3188 * e.g.: c1: x1 + x2 + x3 >= 1
3189 * c2: x1 + x2 + ~x3 + x4 >= 1
3190 *
3191 * => c2: x1 + x2 + x4 >= 1
3192 *
3193 * special case:
3194 *
3195 * e.g.: c1: x1 + x2 + x3 >= 1
3196 * c2: x1 + x2 + ~x3 >= 1
3197 *
3198 * => delete c1; c2: x1 + x2 >= 1
3199 *
3200 */
3201 SCIP_CALL( strengthenConss(scip, myconss, nmyconss, varstopos, occurlist, noccurlistentries, occurlistlength, eventhdlr, ndelconss, nchgcoefs) );
3202
3203 /* delete temporary memory in occurlist */
3204 for( --occurlistsize ; occurlistsize >= 0; --occurlistsize )
3205 {
3206 assert((occurlistsizes[occurlistsize] == 0) == (occurlist[occurlistsize] == NULL));
3207 SCIPfreeBufferArrayNull(scip, &(occurlist[occurlistsize]));
3208 }
3209
3210 /* delete temporary memory */
3211 SCIPhashmapFree(&varstopos);
3212 SCIPfreeBufferArray(scip, &occurlistsizes);
3213 SCIPfreeBufferArray(scip, &noccurlistentries);
3214 SCIPfreeBufferArray(scip, &occurlist);
3215 SCIPfreeBufferArray(scip, &myconss);
3216
3217 return SCIP_OKAY;
3218}
3219
3220#define MAX_CONSLENGTH 200
3221
3222/** try to tighten constraints by reducing the number of variables in the constraints using implications and cliques,
3223 * also derive fixations through them, @see SCIPshrinkDisjunctiveVarSet()
3224 */
3225static
3227 SCIP* scip, /**< SCIP data structure */
3228 SCIP_CONSHDLRDATA* conshdlrdata, /**< logic or constraint handler data */
3229 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
3230 SCIP_CONS** conss, /**< all constraints */
3231 int nconss, /**< number of constraints */
3232 unsigned char** entries, /**< array to store whether two positions in constraints represent the same
3233 * variable */
3234 int* nentries, /**< pointer for array size, if array will be to small it's corrected */
3235 int* nfixedvars, /**< pointer to count number of fixings */
3236 int* ndelconss, /**< pointer to count number of deleted constraints */
3237 int* nchgcoefs, /**< pointer to count number of changed/deleted coefficients */
3238 SCIP_Bool* cutoff /**< pointer to store, if cut off appeared */
3239 )
3240{
3241 SCIP_VAR** probvars;
3242 SCIP_VAR* var;
3243 SCIP_Real* bounds;
3244 SCIP_Bool* boundtypes;
3245 SCIP_Bool* redundants;
3246 int nbinprobvars;
3247 int nredvars;
3248 int c;
3249 int v;
3250
3251 assert(scip != NULL);
3252 assert(eventhdlr != NULL);
3253 assert(conss != NULL || nconss == 0);
3254 assert(entries != NULL);
3255 assert(*entries != NULL);
3256 assert(nentries != NULL);
3257 assert(nfixedvars != NULL);
3258 assert(ndelconss != NULL);
3259 assert(nchgcoefs != NULL);
3260
3261 if( nconss == 0 )
3262 return SCIP_OKAY;
3263
3264 assert(conss != NULL);
3265
3266 if( SCIPgetNCliques(scip) == conshdlrdata->nlastcliquesshorten
3267 && SCIPgetNImplications(scip) == conshdlrdata->nlastimplsshorten )
3268 return SCIP_OKAY;
3269
3270 conshdlrdata->nlastcliquesshorten = SCIPgetNCliques(scip);
3271 conshdlrdata->nlastimplsshorten = SCIPgetNImplications(scip);
3272
3273 nbinprobvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
3274
3275 /* allocate temporary memory */
3276 SCIP_CALL( SCIPallocBufferArray(scip, &probvars, nbinprobvars) );
3277 SCIP_CALL( SCIPallocBufferArray(scip, &bounds, nbinprobvars) );
3278 SCIP_CALL( SCIPallocBufferArray(scip, &boundtypes, nbinprobvars) );
3279 SCIP_CALL( SCIPallocCleanBufferArray(scip, &redundants, nbinprobvars) );
3280
3281 for( c = nconss - 1; c >= 0; --c )
3282 {
3283 SCIP_Bool redundant = FALSE;
3284 SCIP_CONS* cons = conss[c];
3285 SCIP_CONSDATA* consdata;
3286
3287 assert(cons != NULL);
3288
3289 if( SCIPconsIsDeleted(cons) )
3290 continue;
3291
3292 consdata = SCIPconsGetData(cons);
3293 assert(consdata != NULL);
3294
3295 /* prepare constraint by removing fixings and merge it; we invalidate the presolved flag, because the calls to
3296 * SCIPcleanupCliques() in this loop may have lead to fixed variables that are not yet removed */
3297 consdata->presolved = FALSE;
3298 SCIP_CALL( prepareCons(scip, cons, eventhdlr, entries, nentries, &redundant, nfixedvars, nchgcoefs, ndelconss, cutoff) );
3299
3300 if( redundant )
3301 {
3303 continue;
3304 }
3305
3306 if( *cutoff )
3307 goto TERMINATE;
3308
3309 assert(consdata->nvars >= 2);
3310
3311 /* do not try to shorten too long constraints */
3312 if( consdata->nvars > MAX_CONSLENGTH )
3313 continue;
3314
3315 /* form necessary data */
3316 for( v = consdata->nvars - 1; v >= 0; --v)
3317 {
3318 var = consdata->vars[v];
3319 assert(var != NULL);
3321
3322 if( SCIPvarIsActive(var) )
3323 {
3324 probvars[v] = var;
3325 bounds[v] = 1.0;
3326 boundtypes[v] = FALSE;
3327 }
3328 else
3329 {
3330 probvars[v] = SCIPvarGetNegationVar(var);
3331 bounds[v] = 0.0;
3332 boundtypes[v] = TRUE;
3333 }
3334 }
3335
3337
3338 if( *cutoff )
3339 goto TERMINATE;
3340
3341 /* use implications and cliques to derive global fixings and to shrink the number of variables in this constraints */
3342 SCIP_CALL( SCIPshrinkDisjunctiveVarSet(scip, probvars, bounds, boundtypes, redundants, consdata->nvars, &nredvars,
3343 nfixedvars, &redundant, cutoff, TRUE) );
3344
3345 if( *cutoff )
3346 {
3347 /* reset redundants array to FALSE */
3348 BMSclearMemoryArray(redundants, nbinprobvars);
3349 goto TERMINATE;
3350 }
3351
3352 /* remove redundant constraint */
3353 if( redundant )
3354 {
3355 SCIP_CALL( SCIPdelCons(scip, cons) );
3356 ++(*ndelconss);
3357
3358 /* reset redundants array to FALSE */
3359 BMSclearMemoryArray(redundants, consdata->nvars);
3360 continue;
3361 }
3362
3363 /* remove redundant variables */
3364 if( nredvars > 0 )
3365 {
3366 for( v = consdata->nvars - 1; v >= 0; --v )
3367 {
3368 if( redundants[v] )
3369 {
3370 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
3371
3372 /* reset entry to FALSE */
3373 redundants[v] = FALSE;
3374 }
3375 }
3376 *nchgcoefs += nredvars;
3377
3378 /* if only one variable is left over fix it */
3379 if( consdata->nvars == 1 )
3380 {
3381 SCIP_Bool infeasible;
3382 SCIP_Bool fixed;
3383
3384 SCIPdebugMsg(scip, " -> fix last remaining variable and delete constraint\n");
3385
3386 SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], 1.0, &infeasible, &fixed) );
3387 assert(!infeasible);
3388 assert(fixed);
3389 ++(*nfixedvars);
3390
3391 SCIP_CALL( SCIPdelCons(scip, cons) );
3392 ++(*ndelconss);
3393 }
3394 /* @todo might also upgrade a two variable constraint to a set-packing constraint */
3395 }
3396 }
3397
3398 /* invalidate the presolved flags, because the calls to SCIPcleanupCliques() may have lead to fixed variables that
3399 * are not yet removed */
3400 for( c = nconss - 1; c >= 0; --c )
3401 {
3402 SCIP_CONS* cons = conss[c];
3403 SCIP_CONSDATA* consdata;
3404
3405 assert(cons != NULL);
3406
3407 consdata = SCIPconsGetData(cons);
3408 assert(consdata != NULL);
3409
3410 consdata->presolved = FALSE;
3411 }
3412
3413 TERMINATE:
3414 /* free temporary memory */
3415 SCIPfreeCleanBufferArray(scip, &redundants);
3416 SCIPfreeBufferArray(scip, &boundtypes);
3417 SCIPfreeBufferArray(scip, &bounds);
3418 SCIPfreeBufferArray(scip, &probvars);
3419
3420 return SCIP_OKAY;
3421}
3422
3423#define MAXCOMPARISONS 1000000
3424
3425/** try to find a negated clique in a constraint which makes this constraint redundant but we need to keep the negated
3426 * clique information alive, so we create a corresponding set-packing constraint
3427 */
3428static
3430 SCIP* scip, /**< SCIP data structure */
3431 SCIP_CONSHDLR* conshdlr, /**< logicor constraint handler */
3432 SCIP_CONSHDLR* conshdlrsetppc, /**< setppc constraint handler, or NULL */
3433 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
3434 SCIP_CONS** conss, /**< all constraints */
3435 int nconss, /**< number of constraints */
3436 unsigned char** entries, /**< array to store whether two positions in constraints represent the same
3437 * variable */
3438 int* nentries, /**< pointer for array size, if array will be to small it's corrected */
3439 int* nfixedvars, /**< pointer to count number of fixings */
3440 int* ndelconss, /**< pointer to count number of deleted constraints */
3441 int* nupgdconss, /**< pointer to count number of upgraded constraints */
3442 int* nchgcoefs, /**< pointer to count number of changed/deleted coefficients */
3443 SCIP_Bool* cutoff /**< pointer to store, if cut off appeared */
3444 )
3445{
3446 SCIP_CONSHDLRDATA* conshdlrdata;
3447 SCIP_CONS* cons;
3448 SCIP_CONSDATA* consdata;
3449 SCIP_VAR** repvars;
3450 SCIP_Bool* negated;
3451 SCIP_VAR* var1;
3452 SCIP_Bool redundant;
3453 int c;
3454 int size;
3455 int maxcomppercons;
3456 int comppercons;
3457
3458 assert(scip != NULL);
3459 assert(conshdlr != NULL);
3460 assert(eventhdlr != NULL);
3461 assert(conss != NULL || nconss == 0);
3462 assert(entries != NULL);
3463 assert(*entries != NULL);
3464 assert(nentries != NULL);
3465 assert(nfixedvars != NULL);
3466 assert(ndelconss != NULL);
3467 assert(nupgdconss != NULL);
3468 assert(nchgcoefs != NULL);
3469 assert(cutoff != NULL);
3470
3471 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3472 assert(conshdlrdata != NULL);
3473
3474 if( nconss == 0 )
3475 return SCIP_OKAY;
3476
3477 if( SCIPgetNCliques(scip) == conshdlrdata->nlastcliquesneg && SCIPgetNImplications(scip) == conshdlrdata->nlastimplsneg )
3478 return SCIP_OKAY;
3479
3480 conshdlrdata->nlastcliquesneg = SCIPgetNCliques(scip);
3481 conshdlrdata->nlastimplsneg = SCIPgetNImplications(scip);
3482
3483 /* estimate the maximal number of variables in a logicor constraint */
3485 if( size <= 0 )
3486 return SCIP_OKAY;
3487
3488 /* temporary memory for active/negation of active variables */
3489 SCIP_CALL( SCIPallocBufferArray(scip, &repvars, size) );
3490 SCIP_CALL( SCIPallocBufferArray(scip, &negated, size) );
3491
3492 /* iterate over all constraints and try to find negated cliques in logicors */
3493 for( c = nconss - 1; c >= 0; --c )
3494 {
3495 int v;
3496
3497 assert(conss != NULL); /* for flexelint */
3498
3499 cons = conss[c];
3500 assert(cons != NULL);
3501
3502 if( !SCIPconsIsActive(cons) )
3503 continue;
3504
3505 /* prepare constraint by removing fixings and merge it */
3506 SCIP_CALL( prepareCons(scip, cons, eventhdlr, entries, nentries, &redundant, nfixedvars, nchgcoefs, ndelconss, cutoff) );
3507
3508 if( redundant )
3509 {
3511 continue;
3512 }
3513
3514 if( *cutoff )
3515 goto TERMINATE;
3516
3517 consdata = SCIPconsGetData(cons);
3518 assert(consdata != NULL);
3519 assert(consdata->nvars >= 2);
3520 assert(consdata->nvars <= size);
3521 assert(consdata->presolved);
3522
3523 if( SCIPconsIsModifiable(cons) && consdata->nvars == 2 )
3524 continue;
3525
3526 if( c % 100 == 0 && SCIPisStopped(scip) )
3527 break;
3528
3529 maxcomppercons = MAXCOMPARISONS / nconss;
3530 comppercons = 0;
3531
3532 BMScopyMemoryArray(repvars, consdata->vars, consdata->nvars);
3533
3534 /* all variables should be active or negative active variables, otherwise something went wrong with applyFixings()
3535 * called before mergeMultiples()
3536 */
3537 for( v = consdata->nvars - 1; v >= 0; --v )
3538 {
3540 negated[v] = SCIPvarIsNegated(repvars[v]);
3541 }
3542
3543 for( v = consdata->nvars - 1; v > 0; --v )
3544 {
3545 SCIP_Bool breakloop;
3546 SCIP_Bool neg1;
3547 int w;
3548
3549 var1 = repvars[v];
3550
3551 /* if there is no negated variable, there can't be a negated clique */
3552 if( SCIPvarGetNegatedVar(var1) == NULL )
3553 continue;
3554
3555 /* get active counterpart to check for common cliques */
3557 {
3558 var1 = SCIPvarGetNegatedVar(var1);
3559 neg1 = TRUE;
3560 }
3561 else
3562 neg1 = FALSE;
3563
3564 if( !SCIPvarIsActive(var1) )
3565 continue;
3566
3567 /* no cliques available */
3568 if( SCIPvarGetNCliques(var1, neg1) == 0 && SCIPvarGetNImpls(var1, neg1) == 0 )
3569 continue;
3570
3571 comppercons += (v - 1);
3572
3573 breakloop = FALSE;
3574
3575 for( w = v - 1; w >= 0; --w )
3576 {
3577 SCIP_VAR* var2;
3578 SCIP_Bool neg2;
3579
3580 var2 = repvars[w];
3581
3582 /* if there is no negated variable, there can't be a negated clique */
3583 if( SCIPvarGetNegatedVar(var2) == NULL )
3584 continue;
3585
3587 {
3588 var2 = SCIPvarGetNegatedVar(var2);
3589 neg2 = TRUE;
3590 }
3591 else
3592 neg2 = FALSE;
3593
3594 if( !SCIPvarIsActive(var2) )
3595 continue;
3596
3597 /* no cliques available */
3598 if( SCIPvarGetNCliques(var2, neg2) == 0 && SCIPvarGetNImpls(var2, neg2) == 0 )
3599 continue;
3600
3601 /* check if both active variable are the same */
3602 if( var1 == var2 )
3603 {
3604 if( neg1 != neg2 )
3605 {
3606 SCIPdebugMsg(scip, "logicor constraint <%s> is redundant, because variable <%s> and its negation <%s> exist\n",
3607 SCIPconsGetName(cons), SCIPvarGetName(var1), SCIPvarGetName(var2));
3608
3609 SCIP_CALL( SCIPdelCons(scip, cons) );
3610
3611 breakloop = TRUE;
3612 }
3613 else
3614 {
3615 #ifndef NDEBUG
3616 SCIP_VAR* lastvar = consdata->vars[consdata->nvars - 1];
3617 #endif
3618 SCIPdebugMsg(scip, "in logicor constraint <%s>, active variable of <%s> and active variable of <%s> are the same, removing the first\n",
3619 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v]), SCIPvarGetName(consdata->vars[w]));
3620
3621 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
3622
3623 if( v < consdata->nvars )
3624 {
3625 /* delCoefPos replaces the variable on position v with the last one, so w also need to correct the
3626 * negated array the same way, and because of deletion the number of variables is already decreased
3627 */
3628 assert(consdata->vars[v] == lastvar);
3629 negated[v] = negated[consdata->nvars];
3630 }
3631 ++(*nchgcoefs);
3632 }
3633 break;
3634 }
3635
3636 if( conshdlrsetppc != NULL && SCIPconsGetNUpgradeLocks(cons) == 0
3637 && SCIPvarsHaveCommonClique(var1, neg1, var2, neg2, TRUE) )
3638 {
3639 SCIP_CONS* newcons;
3640 SCIP_VAR* vars[2];
3641
3642 /* this negated clique information could be created out of this logicor constraint even if there are more
3643 * than two variables left (, for example by probing), we need to keep this information by creating a
3644 * setppc constraint instead
3645 */
3646
3647 /* get correct variables */
3648 if( !neg1 )
3649 vars[0] = SCIPvarGetNegatedVar(var1);
3650 else
3651 vars[0] = var1;
3652
3653 if( !neg2 )
3654 vars[1] = SCIPvarGetNegatedVar(var2);
3655 else
3656 vars[1] = var2;
3657
3663
3664 SCIPdebugPrintCons(scip, newcons, NULL);
3665 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
3666
3667 SCIPdebugMsg(scip, "logicor constraint <%s> is redundant due to negated clique information and will be replaced by a setppc constraint \n",
3668 SCIPconsGetName(cons));
3669 SCIPdebugMsg(scip, "variable <%s> and variable <%s> are in a negated clique\n", SCIPvarGetName(consdata->vars[v]), SCIPvarGetName(consdata->vars[w]));
3670
3671 SCIP_CALL( SCIPdelCons(scip, cons) );
3672 ++(*nupgdconss);
3673
3674 breakloop = TRUE;
3675 break;
3676 }
3677 }
3678 if( breakloop )
3679 break;
3680
3681 /* do not do to many comparisons */
3682 if( comppercons > maxcomppercons )
3683 break;
3684 }
3685 }
3686
3687 TERMINATE:
3688 /* free temporary memory */
3689 SCIPfreeBufferArray(scip, &negated);
3690 SCIPfreeBufferArray(scip, &repvars);
3691
3692 return SCIP_OKAY;
3693}
3694
3695/** handle all cases with less than three variables in a logicor constraint
3696 *
3697 * in case a constraint has zero variables left, we detected infeasibility
3698 * in case a constraint has one variables left, we will fix it to one
3699 * in case a constraint has two variables left, we will add the implication and upgrade it to a set-packing constraint
3700 */
3701static
3703 SCIP* scip, /**< SCIP data structure */
3704 SCIP_CONS* cons, /**< logic or constraint */
3705 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
3706 SCIP_CONSHDLR* conshdlrlinear, /**< linear constraint handler, or NULL */
3707 SCIP_CONSHDLR* conshdlrsetppc, /**< setppc constraint handler, or NULL */
3708 int* nfixedvars, /**< pointer to count number of fixings */
3709 int* nchgbds, /**< pointer to count number of tightened bounds */
3710 int* nchgcoefs, /**< pointer to count number of changed/deleted coefficients */
3711 int* ndelconss, /**< pointer to count number of deleted constraints */
3712 int* naddconss, /**< pointer to count number of added constraints */
3713 int* nupgdconss, /**< pointer to count number of upgraded constraints */
3714 SCIP_Bool* cutoff /**< pointer to store TRUE, if the node can be cut off */
3715 )
3716{
3717 SCIP_CONSDATA* consdata;
3718 SCIP_Bool infeasible;
3719 SCIP_Bool fixed;
3720
3721 assert(scip != NULL);
3722 assert(cons != NULL);
3723 assert(eventhdlr != NULL);
3724 assert(nfixedvars != NULL);
3725 assert(nchgbds != NULL);
3726 assert(nchgcoefs != NULL);
3727 assert(ndelconss != NULL);
3728 assert(naddconss != NULL);
3729 assert(nupgdconss != NULL);
3730 assert(cutoff != NULL);
3731
3732 *cutoff = FALSE;
3733
3734 if( SCIPconsIsModifiable(cons) )
3735 return SCIP_OKAY;
3736
3737 consdata = SCIPconsGetData(cons);
3738 assert(consdata != NULL);
3739
3740 /* if an unmodifiable logicor constraint has only two variables, we can add an implication and we will upgrade this
3741 * constraint to a set-packing constraint
3742 */
3743 if( consdata->nvars == 2 )
3744 {
3745 /* add implication if not yet done */
3746 if( !consdata->impladded )
3747 {
3748 SCIP_Bool implinfeasible;
3749 int nimplbdchgs;
3750 SCIP_Bool values[2];
3751
3752 values[0] = FALSE;
3753 values[1] = FALSE;
3754 /* a two-variable logicor constraint x + y >= 1 yields the implication x == 0 -> y == 1, and is represented
3755 * by the clique inequality ~x + ~y <= 1
3756 */
3757 SCIP_CALL( SCIPaddClique(scip, consdata->vars, values, consdata->nvars, FALSE, &implinfeasible, &nimplbdchgs) );
3758 *nchgbds += nimplbdchgs;
3759 if( implinfeasible )
3760 {
3761 *cutoff = TRUE;
3762 return SCIP_OKAY;
3763 }
3764
3765 /* adding the above implication could lead to fixings, which render the constraint redundant */
3766 if ( nimplbdchgs > 0 )
3767 {
3768 SCIP_Bool redundant;
3769
3770 /* remove all variables that are fixed to zero, check redundancy due to fixed-to-one variable */
3771 SCIP_CALL( applyFixings(scip, cons, eventhdlr, &redundant, nchgcoefs, naddconss, ndelconss) );
3772 assert(!SCIPconsIsDeleted(cons));
3773
3774 if( redundant )
3775 {
3776 SCIPdebugMsg(scip, "logic or constraint <%s> is redundant\n", SCIPconsGetName(cons));
3777
3778 SCIP_CALL( SCIPdelCons(scip, cons) );
3779 (*ndelconss)++;
3780
3781 return SCIP_OKAY;
3782 }
3783 }
3784 consdata->impladded = TRUE;
3785 }
3786
3787 /* still we have two variables left, we will upgrade this constraint */
3788 if( conshdlrsetppc != NULL && SCIPconsGetNUpgradeLocks(cons) == 0 && consdata->nvars == 2 )
3789 {
3790 SCIP_CONS* newcons;
3791 SCIP_VAR* vars[2];
3792
3793 /* get correct variables */
3794 SCIP_CALL( SCIPgetNegatedVar(scip, consdata->vars[0], &vars[0]) );
3795 SCIP_CALL( SCIPgetNegatedVar(scip, consdata->vars[1], &vars[1]) );
3796
3802
3803 SCIPdebugPrintCons(scip, newcons, NULL);
3804 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
3805
3806 SCIPdebugMsg(scip, "logicor constraint <%s> was upgraded to a set-packing constraint\n", SCIPconsGetName(cons));
3807
3808 SCIP_CALL( SCIPdelCons(scip, cons) );
3809 ++(*nupgdconss);
3810 }
3811 }
3812
3813 /* if unmodifiable constraint has no variables, it is infeasible,
3814 * if unmodifiable constraint has only one variable, this one can be fixed and the constraint deleted
3815 */
3816 if( consdata->nvars == 0 )
3817 {
3818 SCIPdebugMsg(scip, "logic or constraint <%s> is infeasible\n", SCIPconsGetName(cons));
3819
3820 *cutoff = TRUE;
3821 }
3822 else if( consdata->nvars == 1 )
3823 {
3824 SCIPdebugMsg(scip, "logic or constraint <%s> has only one variable not fixed to 0.0\n",
3825 SCIPconsGetName(cons));
3826
3827 assert(consdata->vars != NULL);
3828 assert(consdata->vars[0] != NULL);
3829
3830 if( SCIPvarGetStatus(consdata->vars[0]) != SCIP_VARSTATUS_MULTAGGR )
3831 {
3832 SCIPdebugMsg(scip, " -> fix variable and delete constraint\n");
3833
3834 SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], 1.0, &infeasible, &fixed) );
3835 if( infeasible )
3836 {
3837 SCIPdebugMsg(scip, " -> infeasible fixing\n");
3838
3839 *cutoff = TRUE;
3840 return SCIP_OKAY;
3841 }
3842 if( fixed )
3843 (*nfixedvars)++;
3844
3845 SCIP_CALL( SCIPdelCons(scip, cons) );
3846 (*ndelconss)++;
3847 }
3848 else if( conshdlrlinear != NULL )
3849 {
3850 SCIP_Real coef;
3851 SCIP_CONS* conslinear;
3852 char consname[SCIP_MAXSTRLEN];
3853
3854 SCIPdebugMsg(scip, " -> variable is multi-aggregated, convert to linear constraint <%s> == 1 \n",
3855 SCIPvarGetName(consdata->vars[0]));
3856
3857 coef = 1.0;
3858 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "fixmaggr_%s_%s", SCIPconsGetName(cons),SCIPvarGetName(consdata->vars[0]) );
3859 SCIP_CALL( SCIPcreateConsLinear(scip, &conslinear, consname, 1, consdata->vars, &coef, 1.0, 1.0,
3863 SCIPconsIsStickingAtNode(cons)) );
3864
3865 /* add the downgraded constraint to the problem */
3866 SCIP_CALL( SCIPaddCons(scip, conslinear) );
3867 SCIP_CALL( SCIPreleaseCons(scip, &conslinear) );
3868 SCIP_CALL( SCIPdelCons(scip, cons) );
3869
3870 (*ndelconss)++;
3871 (*naddconss)++;
3872 }
3873 }
3874
3875 return SCIP_OKAY;
3876}
3877
3878
3879/*
3880 * upgrading of linear constraints
3881 */
3882
3883/** creates and captures a normalized (with all coefficients +1) logic or constraint */
3884static
3886 SCIP* scip, /**< SCIP data structure */
3887 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3888 const char* name, /**< name of constraint */
3889 int nvars, /**< number of variables in the constraint */
3890 SCIP_VAR** vars, /**< array with variables of constraint entries */
3891 SCIP_Real* vals, /**< array with coefficients (+1.0 or -1.0) */
3892 int mult, /**< multiplier on the coefficients(+1 or -1) */
3893 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3894 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3895 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3896 * Usually set to TRUE. */
3897 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3898 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3899 SCIP_Bool check, /**< should the constraint be checked for feasibility?
3900 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3901 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3902 * Usually set to TRUE. */
3903 SCIP_Bool local, /**< is constraint only valid locally?
3904 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3905 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
3906 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
3907 * adds coefficients to this constraint. */
3908 SCIP_Bool dynamic, /**< is constraint subject to aging?
3909 * Usually set to FALSE. Set to TRUE for own cuts which
3910 * are separated as constraints. */
3911 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3912 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3913 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3914 * if it may be moved to a more global node?
3915 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3916 )
3917{
3918 SCIP_VAR** transvars;
3919 int v;
3920
3921 assert(nvars == 0 || vars != NULL);
3922 assert(nvars == 0 || vals != NULL);
3923 assert(mult == +1 || mult == -1);
3924
3925 /* get temporary memory */
3926 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
3927
3928 /* negate positive or negative variables */
3929 for( v = 0; v < nvars; ++v )
3930 {
3931 if( mult * vals[v] > 0.0 )
3932 transvars[v] = vars[v];
3933 else
3934 {
3935 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
3936 }
3937 assert(transvars[v] != NULL);
3938 }
3939
3940 /* create the constraint */
3941 SCIP_CALL( SCIPcreateConsLogicor(scip, cons, name, nvars, transvars,
3942 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3943
3944 /* free temporary memory */
3945 SCIPfreeBufferArray(scip, &transvars);
3946
3947 return SCIP_OKAY;
3948}
3949
3950static
3951SCIP_DECL_LINCONSUPGD(linconsUpgdLogicor)
3952{ /*lint --e{715}*/
3953 assert(upgdcons != NULL);
3954
3955 /* check, if linear constraint can be upgraded to logic or constraint
3956 * - logic or constraints consist only of binary variables with a
3957 * coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated):
3958 * lhs <= x1 + ... + xp - y1 - ... - yn <= rhs
3959 * - negating all variables y = (1-Y) with negative coefficients gives:
3960 * lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n
3961 * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives:
3962 * p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs
3963 * - logic or constraints have left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0
3964 * -> without negations: (lhs == 1 - n and rhs == +inf) or (lhs == -inf and rhs = p - 1)
3965 */
3966 if( nvars > 2 && nposbin + nnegbin + nposimplbin + nnegimplbin == nvars && ncoeffspone + ncoeffsnone == nvars
3967 && ((SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, rhs))
3968 || (SCIPisInfinity(scip, -lhs) && SCIPisEQ(scip, rhs, ncoeffspone - 1.0))) )
3969 {
3970 int mult;
3971
3972 SCIPdebugMsg(scip, "upgrading constraint <%s> to logic or constraint\n", SCIPconsGetName(cons));
3973
3974 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
3975 mult = SCIPisInfinity(scip, rhs) ? +1 : -1;
3976
3977 /* create the logic or constraint (an automatically upgraded constraint is always unmodifiable) */
3979 SCIP_CALL( createNormalizedLogicor(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult,
3984 }
3985
3986 return SCIP_OKAY;
3987}
3988
3989/** helper function to enforce constraints */
3990static
3992 SCIP* scip, /**< SCIP data structure */
3993 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3994 SCIP_CONS** conss, /**< constraints to process */
3995 int nconss, /**< number of constraints */
3996 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
3997 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
3998 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
3999 )
4000{
4001 SCIP_CONSHDLRDATA* conshdlrdata;
4003 SCIP_Bool separated;
4004 SCIP_Bool reduceddom;
4005 int c;
4006
4007 assert(conshdlr != NULL);
4008 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4009 assert(nconss == 0 || conss != NULL);
4010 assert(result != NULL);
4011
4012 SCIPdebugMsg(scip, "Enforcing %d logic or constraints for %s solution\n", nconss, sol == NULL ? "LP" : "relaxation");
4013
4015
4016 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4017 assert(conshdlrdata != NULL);
4018
4019 cutoff = FALSE;
4020 separated = FALSE;
4021 reduceddom = FALSE;
4022
4023 /* check all useful logic or constraints for feasibility */
4024 for( c = 0; c < nusefulconss && !cutoff && !reduceddom; ++c )
4025 {
4026 SCIP_CALL( separateCons(scip, conss[c], sol, conshdlrdata->eventhdlr, &cutoff, &separated, &reduceddom) );
4027 }
4028
4029 /* check all obsolete logic or constraints for feasibility */
4030 for( c = nusefulconss; c < nconss && !cutoff && !separated && !reduceddom; ++c )
4031 {
4032 SCIP_CALL( separateCons(scip, conss[c], sol, conshdlrdata->eventhdlr, &cutoff, &separated, &reduceddom) );
4033 }
4034
4035 /* return the correct result */
4036 if( cutoff )
4038 else if( separated )
4040 else if( reduceddom )
4042
4043 return SCIP_OKAY;
4044}
4045
4046/** adds symmetry information of constraint to a symmetry detection graph */
4047static
4049 SCIP* scip, /**< SCIP pointer */
4050 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
4051 SCIP_CONS* cons, /**< constraint */
4052 SYM_GRAPH* graph, /**< symmetry detection graph */
4053 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
4054 )
4055{
4056 SCIP_CONSDATA* consdata;
4057 SCIP_VAR** logicorvars;
4058 SCIP_VAR** vars;
4059 SCIP_Real* vals;
4060 SCIP_Real constant = 0.0;
4061 int nlocvars;
4062 int nvars;
4063 int i;
4064
4065 assert(scip != NULL);
4066 assert(cons != NULL);
4067 assert(graph != NULL);
4068 assert(success != NULL);
4069
4070 consdata = SCIPconsGetData(cons);
4071 assert(consdata != NULL);
4072
4073 /* get active variables of the constraint */
4075 nlocvars = SCIPgetNVarsLogicor(scip, cons);
4076
4079
4080 logicorvars = SCIPgetVarsLogicor(scip, cons);
4081 for( i = 0; i < consdata->nvars; ++i )
4082 {
4083 vars[i] = logicorvars[i];
4084 vals[i] = 1.0;
4085 }
4086
4087 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
4088
4090 cons, 1.0 - constant, SCIPinfinity(scip), success) );
4091
4092 SCIPfreeBufferArray(scip, &vals);
4094
4095 return SCIP_OKAY;
4096}
4097
4098/*
4099 * Callback methods of constraint handler
4100 */
4101
4102/** copy method for constraint handler plugins (called when SCIP copies plugins) */
4103static
4104SCIP_DECL_CONSHDLRCOPY(conshdlrCopyLogicor)
4105{ /*lint --e{715}*/
4106 assert(scip != NULL);
4107 assert(conshdlr != NULL);
4108 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4109
4110 /* call inclusion method of constraint handler */
4112
4113 *valid = TRUE;
4114
4115 return SCIP_OKAY;
4116}
4117
4118/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
4119static
4120SCIP_DECL_CONSFREE(consFreeLogicor)
4121{ /*lint --e{715}*/
4122 SCIP_CONSHDLRDATA* conshdlrdata;
4123
4124 assert(conshdlr != NULL);
4125 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4126 assert(scip != NULL);
4127
4128 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4129 assert(conshdlrdata != NULL);
4130
4131 /* free constraint handler data */
4132 conshdlrdataFree(scip, &conshdlrdata);
4133
4134 SCIPconshdlrSetData(conshdlr, NULL);
4135
4136 return SCIP_OKAY;
4137}
4138
4139
4140/** presolving initialization method of constraint handler (called when presolving is about to begin) */
4141static
4142SCIP_DECL_CONSINITPRE(consInitpreLogicor)
4143{ /*lint --e{715}*/
4144 SCIP_CONSHDLRDATA* conshdlrdata;
4145 SCIP_CONSDATA* consdata;
4146 int c;
4147 int v;
4148
4149 assert(conshdlr != NULL);
4150 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4151 assert(conshdlrdata != NULL);
4152
4153 conshdlrdata->nlastcliquesneg = 0;
4154 conshdlrdata->nlastimplsneg = 0;
4155 conshdlrdata->nlastcliquesshorten = 0;
4156 conshdlrdata->nlastimplsshorten = 0;
4157
4158 /* catch all variable event for deleted variables, which is only used in presolving */
4159 for( c = nconss - 1; c >= 0; --c )
4160 {
4161 consdata = SCIPconsGetData(conss[c]);
4162 assert(consdata != NULL);
4163
4164 for( v = consdata->nvars - 1; v >= 0; --v )
4165 {
4166 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
4167 (SCIP_EVENTDATA*)conss[c], NULL) );
4168 }
4169 }
4170
4171 return SCIP_OKAY;
4172}
4173
4174/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
4175static
4176SCIP_DECL_CONSEXITPRE(consExitpreLogicor)
4177{ /*lint --e{715}*/
4178 SCIP_CONSHDLRDATA* conshdlrdata;
4179 SCIP_CONSDATA* consdata;
4180 int nchgcoefs = 0;
4181 int c;
4182 int v;
4183
4184 assert(conshdlr != NULL);
4185 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4186 assert(conshdlrdata != NULL);
4187
4188 /* drop all variable event for deleted variables, which was only used in presolving */
4189 for( c = 0; c < nconss; ++c )
4190 {
4191 consdata = SCIPconsGetData(conss[c]);
4192 assert(consdata != NULL);
4193
4194 for( v = 0; v < consdata->nvars; ++v )
4195 {
4196 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
4197 (SCIP_EVENTDATA*)conss[c], -1) );
4198 }
4199
4200 if( !SCIPconsIsDeleted(conss[c]) && !consdata->presolved )
4201 {
4202 SCIP_Bool redundant;
4203
4204 /* we are not allowed to detect infeasibility in the exitpre stage */
4205 SCIP_CALL( applyFixings(scip, conss[c], conshdlrdata->eventhdlr, &redundant, &nchgcoefs, NULL, NULL) );
4206
4207 /* it may happen that a constraint still contains variables that are fixed to one; for example, this happens
4208 * when variable fixings have been detected in the last presolving round by some other plugins (see #2941)
4209 */
4210 if( redundant )
4211 {
4212 SCIPdebugMsg(scip, "logic or constraint <%s> is redundant (detected during EXITPRE)\n", SCIPconsGetName(conss[c]));
4213
4214 if( SCIPconsIsAdded(conss[c]) )
4215 {
4216 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
4217 }
4218 else
4219 {
4220 /* we set the presolved flag to FALSE since not all fixing are removed if redundancy is detected */
4221 consdata->presolved = FALSE;
4222 }
4223 }
4224 }
4225 }
4226
4227 return SCIP_OKAY;
4228}
4229
4230/** solving process initialization method of constraint handler */
4231static
4232SCIP_DECL_CONSINITSOL(consInitsolLogicor)
4233{ /*lint --e{715}*/
4234 /* add nlrow representation to NLP, if NLP had been constructed */
4236 {
4237 int c;
4238 for( c = 0; c < nconss; ++c )
4239 {
4240 SCIP_CALL( addNlrow(scip, conss[c]) );
4241 }
4242 }
4243
4244 return SCIP_OKAY;
4245}
4246
4247/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
4248static
4249SCIP_DECL_CONSEXITSOL(consExitsolLogicor)
4250{ /*lint --e{715}*/
4251 SCIP_CONSDATA* consdata;
4252 int c;
4253
4254 /* release the rows and nlrows of all constraints */
4255 for( c = 0; c < nconss; ++c )
4256 {
4257 consdata = SCIPconsGetData(conss[c]);
4258 assert(consdata != NULL);
4259
4260 if( consdata->row != NULL )
4261 {
4262 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
4263 }
4264
4265 if( consdata->nlrow != NULL )
4266 {
4267 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4268 }
4269 }
4270
4271 return SCIP_OKAY;
4272}
4273
4274
4275/** frees specific constraint data */
4276static
4277SCIP_DECL_CONSDELETE(consDeleteLogicor)
4278{ /*lint --e{715}*/
4279 assert(conshdlr != NULL);
4280 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4281 assert(consdata != NULL);
4282 assert(*consdata != NULL);
4283
4285 {
4286 SCIP_CONSHDLRDATA* conshdlrdata;
4287 int v;
4288
4289 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4290 assert(conshdlrdata != NULL);
4291
4292 for( v = (*consdata)->nvars - 1; v >= 0; --v )
4293 {
4294 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
4295 (SCIP_EVENTDATA*)cons, -1) );
4296 }
4297 }
4298
4299 /* free LP row and logic or constraint */
4300 SCIP_CALL( consdataFree(scip, consdata) );
4301
4302 return SCIP_OKAY;
4303}
4304
4305
4306/** transforms constraint data into data belonging to the transformed problem */
4307static
4308SCIP_DECL_CONSTRANS(consTransLogicor)
4309{ /*lint --e{715}*/
4310 SCIP_CONSDATA* sourcedata;
4311 SCIP_CONSDATA* targetdata;
4312
4313 /*debugMsg(scip, "Trans method of logic or constraints\n");*/
4314
4315 assert(conshdlr != NULL);
4316 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4318 assert(sourcecons != NULL);
4319 assert(targetcons != NULL);
4320
4321 sourcedata = SCIPconsGetData(sourcecons);
4322 assert(sourcedata != NULL);
4323 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
4324
4325 /* create constraint data for target constraint */
4326 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->nvars, sourcedata->vars) );
4327
4328 /* create target constraint */
4329 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
4330 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
4331 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
4332 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
4333 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
4334
4335 return SCIP_OKAY;
4336}
4337
4338
4339/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
4340static
4341SCIP_DECL_CONSINITLP(consInitlpLogicor)
4342{ /*lint --e{715}*/
4343 int c;
4344
4345 *infeasible = FALSE;
4346
4347 for( c = 0; c < nconss && !(*infeasible); ++c )
4348 {
4349 assert(SCIPconsIsInitial(conss[c]));
4350 SCIP_CALL( addCut(scip, conss[c], infeasible) );
4351 }
4352
4353 return SCIP_OKAY;
4354}
4355
4356
4357/** separation method of constraint handler for LP solutions */
4358static
4359SCIP_DECL_CONSSEPALP(consSepalpLogicor)
4360{ /*lint --e{715}*/
4361 SCIP_CONSHDLRDATA* conshdlrdata;
4363 SCIP_Bool separated;
4364 SCIP_Bool reduceddom;
4365 int c;
4366
4367 assert(conshdlr != NULL);
4368 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4369 assert(nconss == 0 || conss != NULL);
4370 assert(result != NULL);
4371
4372 SCIPdebugMsg(scip, "separating %d/%d logic or constraints\n", nusefulconss, nconss);
4373
4374 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4375 assert(conshdlrdata != NULL);
4376
4377 cutoff = FALSE;
4378 separated = FALSE;
4379 reduceddom = FALSE;
4380
4381 /* check all useful logic or constraints for feasibility */
4382 for( c = 0; c < nusefulconss && !cutoff; ++c )
4383 {
4384 SCIP_CALL( separateCons(scip, conss[c], NULL, conshdlrdata->eventhdlr, &cutoff, &separated, &reduceddom) );
4385 }
4386
4387 /* combine logic or constraints to get more cuts */
4388 /**@todo further cuts of logic or constraints */
4389
4390 /* return the correct result */
4391 if( cutoff )
4393 else if( reduceddom )
4395 else if( separated )
4397 else
4399
4400 return SCIP_OKAY;
4401}
4402
4403
4404/** separation method of constraint handler for arbitrary primal solutions */
4405static
4406SCIP_DECL_CONSSEPASOL(consSepasolLogicor)
4407{ /*lint --e{715}*/
4408 SCIP_CONSHDLRDATA* conshdlrdata;
4410 SCIP_Bool separated;
4411 SCIP_Bool reduceddom;
4412 int c;
4413
4414 assert(conshdlr != NULL);
4415 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4416 assert(nconss == 0 || conss != NULL);
4417 assert(result != NULL);
4418
4419 SCIPdebugMsg(scip, "separating %d/%d logic or constraints\n", nusefulconss, nconss);
4420
4421 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4422 assert(conshdlrdata != NULL);
4423
4424 cutoff = FALSE;
4425 separated = FALSE;
4426 reduceddom = FALSE;
4427
4428 /* check all useful logic or constraints for feasibility */
4429 for( c = 0; c < nusefulconss && !cutoff; ++c )
4430 {
4431 SCIP_CALL( separateCons(scip, conss[c], sol, conshdlrdata->eventhdlr, &cutoff, &separated, &reduceddom) );
4432 }
4433
4434 /* combine logic or constraints to get more cuts */
4435 /**@todo further cuts of logic or constraints */
4436
4437 /* return the correct result */
4438 if( cutoff )
4440 else if( reduceddom )
4442 else if( separated )
4444 else
4446
4447 return SCIP_OKAY;
4448}
4449
4450
4451/** constraint enforcing method of constraint handler for LP solutions */
4452static
4453SCIP_DECL_CONSENFOLP(consEnfolpLogicor)
4454{ /*lint --e{715}*/
4455 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
4456
4457 return SCIP_OKAY;
4458}
4459
4460
4461/** constraint enforcing method of constraint handler for relaxation solutions */
4462static
4463SCIP_DECL_CONSENFORELAX(consEnforelaxLogicor)
4464{ /*lint --e{715}*/
4465 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
4466
4467 return SCIP_OKAY;
4468}
4469
4470
4471/** constraint enforcing method of constraint handler for pseudo solutions */
4472static
4473SCIP_DECL_CONSENFOPS(consEnfopsLogicor)
4474{ /*lint --e{715}*/
4475 SCIP_CONSHDLRDATA* conshdlrdata;
4477 SCIP_Bool infeasible;
4478 SCIP_Bool reduceddom;
4479 SCIP_Bool solvelp;
4480 int c;
4481
4482 assert(conshdlr != NULL);
4483 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4484 assert(nconss == 0 || conss != NULL);
4485 assert(result != NULL);
4486
4487 SCIPdebugMsg(scip, "pseudo enforcing %d logic or constraints\n", nconss);
4488
4490
4491 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4492 assert(conshdlrdata != NULL);
4493
4494 cutoff = FALSE;
4495 infeasible = FALSE;
4496 reduceddom = FALSE;
4497 solvelp = FALSE;
4498
4499 /* check all logic or constraints for feasibility */
4500 for( c = 0; c < nconss && !cutoff && !reduceddom && !solvelp; ++c )
4501 {
4502 SCIP_CALL( enforcePseudo(scip, conss[c], conshdlrdata->eventhdlr, &cutoff, &infeasible, &reduceddom, &solvelp) );
4503 }
4504
4505 if( cutoff )
4507 else if( reduceddom )
4509 else if( solvelp )
4511 else if( infeasible )
4513
4514 return SCIP_OKAY;
4515}
4516
4517
4518/** feasibility check method of constraint handler for integral solutions */
4519static
4520SCIP_DECL_CONSCHECK(consCheckLogicor)
4521{ /*lint --e{715}*/
4522 SCIP_CONS* cons;
4523 SCIP_CONSDATA* consdata;
4524 int c;
4525
4526 assert(conshdlr != NULL);
4527 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4528 assert(nconss == 0 || conss != NULL);
4529 assert(result != NULL);
4530
4532
4533 /* check all logic or constraints for feasibility */
4534 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
4535 {
4536 cons = conss[c];
4537 consdata = SCIPconsGetData(cons);
4538 assert(consdata != NULL);
4539 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
4540 {
4541 if( isConsViolated(scip, cons, sol) )
4542 {
4543 /* constraint is violated */
4545
4546 if( printreason )
4547 {
4548#ifndef NDEBUG
4549 int v;
4550 for( v = 0; v < consdata->nvars; ++v )
4551 {
4552 assert( consdata->vars[v] != NULL);
4553 assert( SCIPvarIsBinary(consdata->vars[v]) );
4554 assert( SCIPisFeasLT(scip, SCIPgetSolVal(scip, sol, consdata->vars[v]), 1.0) );
4555 }
4556#endif
4557 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
4558 SCIPinfoMessage(scip, NULL, ";\n");
4559 SCIPinfoMessage(scip, NULL, "violation: all variables are set to zero\n");
4560 }
4561 }
4562 }
4563 }
4564
4565 return SCIP_OKAY;
4566}
4567
4568
4569/** domain propagation method of constraint handler */
4570static
4571SCIP_DECL_CONSPROP(consPropLogicor)
4572{ /*lint --e{715}*/
4573 SCIP_CONSHDLRDATA* conshdlrdata;
4575 SCIP_Bool reduceddom;
4576 SCIP_Bool addcut;
4577 SCIP_Bool mustcheck;
4578 int c;
4579#ifndef NDEBUG
4581#endif
4582
4583 assert(conshdlr != NULL);
4584 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4585 assert(nconss == 0 || conss != NULL);
4586 assert(result != NULL);
4587
4588 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4589 assert(conshdlrdata != NULL);
4590
4591 cutoff = FALSE;
4592 reduceddom = FALSE;
4593
4594 /* propagate all useful logic or constraints */
4595 for( c = 0; c < nusefulconss && !cutoff; ++c )
4596 {
4597 assert(inpresolve || !(SCIPconsGetData(conss[c])->existmultaggr));
4598
4599 SCIPdebugMsg(scip, " propagate constraint %s\n", SCIPconsGetName(conss[c]));
4600 SCIP_CALL( processWatchedVars(scip, conss[c], conshdlrdata->eventhdlr, &cutoff, &reduceddom, &addcut, &mustcheck) );
4601 }
4602
4603 /* return the correct result */
4604 if( cutoff )
4606 else if( reduceddom )
4608 else
4610
4611 return SCIP_OKAY; /*lint !e438*/
4612}
4613
4614/** presolving method of constraint handler */
4615static
4616SCIP_DECL_CONSPRESOL(consPresolLogicor)
4617{ /*lint --e{715}*/
4618 SCIP_CONSHDLRDATA* conshdlrdata;
4619 SCIP_CONS* cons;
4620 SCIP_CONSDATA* consdata;
4621 unsigned char* entries;
4622 SCIP_Bool redundant;
4623 int c;
4624 int firstchange;
4625 int nentries;
4626 int oldnfixedvars;
4627 int oldnchgbds;
4628 int oldndelconss;
4629 int oldnupgdconss;
4630 int oldnchgcoefs;
4631
4632 assert(conshdlr != NULL);
4633 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4634 assert(scip != NULL);
4635 assert(result != NULL);
4636
4638
4639 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4640 assert(conshdlrdata != NULL);
4641
4642 nentries = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
4643
4644 oldnfixedvars = *nfixedvars;
4645 oldnchgbds = *nchgbds;
4646 oldndelconss = *ndelconss;
4647 oldnupgdconss = *nupgdconss;
4648 oldnchgcoefs = *nchgcoefs;
4649
4650 firstchange = INT_MAX;
4651
4652 SCIP_CALL( SCIPallocBufferArray(scip, &entries, nentries) );
4653
4654 /* process constraints */
4655 for( c = 0; c < nconss && *result != SCIP_CUTOFF && !SCIPisStopped(scip); ++c )
4656 {
4657 cons = conss[c];
4658 assert(cons != NULL);
4659 consdata = SCIPconsGetData(cons);
4660 assert(consdata != NULL);
4661
4662 SCIPdebugMsg(scip, "presolving logic or constraint <%s>\n", SCIPconsGetName(cons));
4663
4664 /* force presolving the constraint in the initial round */
4665 if( nrounds == 0 )
4666 {
4668 }
4669
4670 redundant = FALSE;
4671 if( !consdata->presolved )
4672 {
4673 /* remove all variables that are fixed to zero, check redundancy due to fixed-to-one variable */
4674 SCIP_CALL( applyFixings(scip, cons, conshdlrdata->eventhdlr, &redundant, nchgcoefs, naddconss, ndelconss) );
4675 }
4676
4677 if( SCIPconsIsDeleted(cons) )
4678 continue;
4679
4680 /* find pairs of negated variables in constraint: constraint is redundant */
4681 /* find sets of equal variables in constraint: multiple entries of variable can be replaced by single entry */
4682 if( !redundant )
4683 {
4684 SCIP_CALL( mergeMultiples(scip, cons, conshdlrdata->eventhdlr, &entries, &nentries, &redundant, nchgcoefs) );
4685 }
4686
4687 if( redundant )
4688 {
4689 SCIPdebugMsg(scip, "logic or constraint <%s> is redundant\n", SCIPconsGetName(cons));
4690 SCIP_CALL( SCIPdelCons(scip, cons) );
4691 (*ndelconss)++;
4693 continue;
4694 }
4695 else if( !SCIPconsIsModifiable(cons) )
4696 {
4697 if( consdata->nvars <= 2 )
4698 {
4700
4701 /* handle all cases with less than three variables in a logicor constraint */
4702 SCIP_CALL( fixDeleteOrUpgradeCons(scip, cons, conshdlrdata->eventhdlr, conshdlrdata->conshdlrlinear,
4703 conshdlrdata->conshdlrsetppc, nfixedvars, nchgbds, nchgcoefs, ndelconss, naddconss, nupgdconss, &cutoff) );
4704
4705 if( cutoff )
4706 {
4708 goto TERMINATE;
4709 }
4710 else if( *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds || *nchgcoefs > oldnchgcoefs
4711 || *ndelconss > oldndelconss || *nupgdconss > oldnupgdconss )
4713
4714 if( SCIPconsIsDeleted(cons) )
4715 continue;
4716 }
4717 }
4718
4719 /* perform dual reductions */
4720 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) )
4721 {
4722 SCIP_CALL( dualPresolving(scip, cons, conshdlrdata->eventhdlr, nfixedvars, ndelconss, nchgcoefs, naggrvars, result) );
4723
4724 /* if dual reduction deleted the constraint we take the next */
4725 if( !SCIPconsIsActive(cons) )
4726 continue;
4727
4728 /* in dualpresolving we may have removed variables, so we need to take care of special cases */
4729 if( consdata->nvars <= 2 )
4730 {
4732
4733 /* handle all cases with less than three variables in a logicor constraint */
4734 SCIP_CALL( fixDeleteOrUpgradeCons(scip, cons, conshdlrdata->eventhdlr, conshdlrdata->conshdlrlinear,
4735 conshdlrdata->conshdlrsetppc, nfixedvars, nchgbds, nchgcoefs, ndelconss, naddconss, nupgdconss, &cutoff) );
4736
4737 if( cutoff )
4738 {
4740 goto TERMINATE;
4741 }
4742 else if( *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds || *nchgcoefs > oldnchgcoefs
4743 || *ndelconss > oldndelconss || *nupgdconss > oldnupgdconss )
4745
4746 if( SCIPconsIsDeleted(cons) )
4747 continue;
4748 }
4749 }
4750
4751 /* remember the first changed constraint to begin the next redundancy round with */
4752 if( firstchange == INT_MAX && consdata->changed )
4753 firstchange = c;
4754
4755 assert(consdata->nvars >= 2 || SCIPconsIsModifiable(cons));
4756 }
4757
4759
4760 /* fast preprocessing of pairs of logic or constraints, used for equal constraints */
4761 if( firstchange < nconss && conshdlrdata->presolusehashing )
4762 {
4763 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
4764 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, ndelconss) );
4765 }
4766
4767 /* preprocess pairs of logic or constraints and apply negated clique presolving */
4769 {
4771
4772 /* check constraints for redundancy */
4773 if( conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
4774 {
4775 SCIP_CALL( removeRedundantConssAndNonzeros(scip, conss, nconss, &entries, &nentries, conshdlrdata->eventhdlr,
4776 conshdlrdata->usestrengthening, &firstchange, nfixedvars, ndelconss, nchgcoefs, &cutoff) );
4777
4778 if( cutoff )
4779 {
4781 goto TERMINATE;
4782 }
4783 }
4784
4786 {
4787 /* try to tighten constraints by reducing the number of variables in the constraints using implications and
4788 * cliques, also derive fixations through them, @see SCIPshrinkDisjunctiveVarSet()
4789 */
4790 if( conshdlrdata->useimplications && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
4791 {
4792 SCIP_CALL( shortenConss(scip, conshdlrdata, conshdlrdata->eventhdlr, conss, nconss,
4793 &entries, &nentries, nfixedvars, ndelconss, nchgcoefs, &cutoff) );
4794
4795 if( cutoff )
4796 {
4798 goto TERMINATE;
4799 }
4800 }
4801
4802 /* check for redundant constraints due to negated clique information */
4803 if( conshdlrdata->usenegatedclique && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
4804 {
4805 SCIP_CALL( removeConstraintsDueToNegCliques(scip, conshdlr, conshdlrdata->conshdlrsetppc,
4806 conshdlrdata->eventhdlr, conss, nconss, &entries, &nentries, nfixedvars, ndelconss,
4807 nupgdconss, nchgcoefs, &cutoff) );
4808
4809 if( cutoff )
4810 {
4812 goto TERMINATE;
4813 }
4814 }
4815 }
4816 }
4817
4818 TERMINATE:
4819
4820 SCIPfreeBufferArray(scip, &entries);
4821
4822 return SCIP_OKAY;
4823}
4824
4825
4826/** propagation conflict resolving method of constraint handler */
4827static
4828SCIP_DECL_CONSRESPROP(consRespropLogicor)
4829{ /*lint --e{715}*/
4830 SCIP_CONSDATA* consdata;
4831#ifndef NDEBUG
4832 SCIP_Bool infervarfound;
4833#endif
4834 int v;
4835
4836 assert(conshdlr != NULL);
4837 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4838 assert(cons != NULL);
4839 assert(infervar != NULL);
4840 assert(result != NULL);
4841
4842 consdata = SCIPconsGetData(cons);
4843 assert(consdata != NULL);
4844
4845 SCIPdebugMsg(scip, "conflict resolving method of logic or constraint handler\n");
4846
4847 /* the only deductions are variables inferred to 1.0 on logic or constraints where all other variables
4848 * are assigned to zero
4849 */
4850 assert(SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5); /* the inference variable must be assigned to one */
4851
4852#ifndef NDEBUG
4853 infervarfound = FALSE;
4854#endif
4855 for( v = 0; v < consdata->nvars; ++v )
4856 {
4857 if( consdata->vars[v] != infervar )
4858 {
4859 /* the reason variable must have been assigned to zero */
4860 assert(SCIPgetVarUbAtIndex(scip, consdata->vars[v], bdchgidx, FALSE) < 0.5);
4861 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
4862 }
4863#ifndef NDEBUG
4864 else
4865 {
4866 assert(!infervarfound);
4867 infervarfound = TRUE;
4868 }
4869#endif
4870 }
4871 assert(infervarfound);
4872
4874
4875 return SCIP_OKAY;
4876}
4877
4878
4879/** variable rounding lock method of constraint handler */
4880static
4881SCIP_DECL_CONSLOCK(consLockLogicor)
4882{ /*lint --e{715}*/
4883 SCIP_CONSDATA* consdata;
4884 int i;
4885
4886 consdata = SCIPconsGetData(cons);
4887 assert(consdata != NULL);
4888
4889 /* lock every single coefficient */
4890 for( i = 0; i < consdata->nvars; ++i )
4891 {
4892 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlockspos, nlocksneg) );
4893 }
4894
4895 return SCIP_OKAY;
4896}
4897
4898
4899/** constraint activation notification method of constraint handler */
4900static
4901SCIP_DECL_CONSACTIVE(consActiveLogicor)
4902{ /*lint --e{715}*/
4903 SCIP_CONSHDLRDATA* conshdlrdata;
4904 SCIP_CONSDATA* consdata;
4905
4906 assert(conshdlr != NULL);
4907 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4908 assert(cons != NULL);
4910
4911 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4912 assert(conshdlrdata != NULL);
4913 consdata = SCIPconsGetData(cons);
4914 assert(consdata != NULL);
4915 assert(consdata->watchedvar1 == -1 || consdata->watchedvar1 != consdata->watchedvar2);
4916
4917 SCIPdebugMsg(scip, "activating information for logic or constraint <%s>\n", SCIPconsGetName(cons));
4918 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL, TRUE) ) );
4919
4920 /* catch events on watched variables */
4921 if( consdata->watchedvar1 != -1 )
4922 {
4923 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[consdata->watchedvar1],
4924 SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_LBRELAXED, conshdlrdata->eventhdlr, (SCIP_EVENTDATA*)cons,
4925 &consdata->filterpos1) );
4926 }
4927 if( consdata->watchedvar2 != -1 )
4928 {
4929 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[consdata->watchedvar2],
4930 SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_LBRELAXED, conshdlrdata->eventhdlr, (SCIP_EVENTDATA*)cons,
4931 &consdata->filterpos2) );
4932 }
4933
4935 {
4936 SCIP_CALL( addNlrow(scip, cons) );
4937 }
4938
4939 return SCIP_OKAY;
4940}
4941
4942
4943/** constraint deactivation notification method of constraint handler */
4944static
4945SCIP_DECL_CONSDEACTIVE(consDeactiveLogicor)
4946{ /*lint --e{715}*/
4947 SCIP_CONSHDLRDATA* conshdlrdata;
4948 SCIP_CONSDATA* consdata;
4949
4950 assert(conshdlr != NULL);
4951 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4952 assert(cons != NULL);
4954
4955 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4956 assert(conshdlrdata != NULL);
4957 consdata = SCIPconsGetData(cons);
4958 assert(consdata != NULL);
4959 assert(consdata->watchedvar1 == -1 || consdata->watchedvar1 != consdata->watchedvar2);
4960
4961 SCIPdebugMsg(scip, "deactivating information for logic or constraint <%s>\n", SCIPconsGetName(cons));
4962 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL, TRUE) ) );
4963
4964 /* drop events on watched variables */
4965 if( consdata->watchedvar1 != -1 )
4966 {
4967 assert(consdata->filterpos1 != -1);
4968 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar1],
4969 SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_LBRELAXED, conshdlrdata->eventhdlr, (SCIP_EVENTDATA*)cons,
4970 consdata->filterpos1) );
4971 consdata->watchedvar1 = -1;
4972 consdata->filterpos1 = -1;
4973 }
4974 if( consdata->watchedvar2 != -1 )
4975 {
4976 assert(consdata->filterpos2 != -1);
4977 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar2],
4978 SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_LBRELAXED, conshdlrdata->eventhdlr, (SCIP_EVENTDATA*)cons,
4979 consdata->filterpos2) );
4980 consdata->watchedvar2 = -1;
4981 consdata->filterpos2 = -1;
4982 }
4983
4984 /* remove row from NLP, if still in solving
4985 * if we are in exitsolve, the whole NLP will be freed anyway
4986 */
4987 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
4988 {
4989 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
4990 }
4991
4992 return SCIP_OKAY;
4993}
4994
4995
4996/** constraint display method of constraint handler */
4997static
4998SCIP_DECL_CONSPRINT(consPrintLogicor)
4999{ /*lint --e{715}*/
5000 assert( scip != NULL );
5001 assert( conshdlr != NULL );
5002 assert( cons != NULL );
5003
5005
5006 return SCIP_OKAY;
5007}
5008
5009/** constraint copying method of constraint handler */
5010static
5011SCIP_DECL_CONSCOPY(consCopyLogicor)
5012{ /*lint --e{715}*/
5013 SCIP_VAR** sourcevars;
5014 const char* consname;
5015 int nvars;
5016
5017 /* get variables and coefficients of the source constraint */
5018 sourcevars = SCIPgetVarsLogicor(sourcescip, sourcecons);
5019 nvars = SCIPgetNVarsLogicor(sourcescip, sourcecons);
5020
5021 if( name != NULL )
5022 consname = name;
5023 else
5024 consname = SCIPconsGetName(sourcecons);
5025
5026 /* copy the logic using the linear constraint copy method */
5027 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, NULL,
5028 1.0, SCIPinfinity(scip), varmap, consmap,
5029 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
5030 assert(cons != NULL);
5031
5032 return SCIP_OKAY;
5033}
5034
5035/** constraint parsing method of constraint handler */
5036static
5037SCIP_DECL_CONSPARSE(consParseLogicor)
5038{ /*lint --e{715}*/
5039 SCIP_VAR** vars;
5040 char* strcopy;
5041 char* endptr;
5042 char* startptr;
5043 int requiredsize;
5044 int varssize;
5045 int nvars;
5046
5047 SCIPdebugMsg(scip, "parse <%s> as logicor constraint\n", str);
5048
5049 *success = FALSE;
5050
5051 /* cutoff "logicor" from the constraint string */
5052 startptr = strchr((char*)str, '(');
5053
5054 if( startptr == NULL )
5055 {
5056 SCIPerrorMessage("missing starting character '(' parsing logicor\n");
5057 return SCIP_OKAY;
5058 }
5059
5060 /* skip '(' */
5061 ++startptr;
5062
5063 /* find end character ')' */
5064 endptr = strrchr(startptr, ')');
5065
5066 if( endptr == NULL )
5067 {
5068 SCIPerrorMessage("missing ending character ')' parsing logicor\n");
5069 return SCIP_OKAY;
5070 }
5071 assert(endptr >= startptr);
5072
5073 if( endptr > startptr )
5074 {
5075 /* copy string for parsing; note that SCIPskipSpace() in SCIPparseVarsList() requires that strcopy ends with '\0' */
5076 SCIP_CALL( SCIPduplicateBufferArray(scip, &strcopy, startptr, (int)(endptr-startptr+1)) );
5077 strcopy[endptr-startptr] = '\0';
5078 varssize = 100;
5079 nvars = 0;
5080
5081 /* allocate buffer array for variables */
5082 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
5083
5084 /* parse string */
5085 SCIP_CALL( SCIPparseVarsList(scip, strcopy, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
5086
5087 if( *success )
5088 {
5089 /* check if the size of the variable array was great enough */
5090 if( varssize < requiredsize )
5091 {
5092 /* reallocate memory */
5093 varssize = requiredsize;
5094 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
5095
5096 /* parse string again with the correct size of the variable array */
5097 SCIP_CALL( SCIPparseVarsList(scip, strcopy, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
5098 }
5099
5100 assert(*success);
5101 assert(varssize >= requiredsize);
5102
5103 /* create logicor constraint */
5105 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
5106 }
5107
5108 /* free buffers */
5110 SCIPfreeBufferArray(scip, &strcopy);
5111 }
5112 else
5113 {
5114 if( !modifiable )
5115 {
5116 SCIPerrorMessage("cannot create empty logicor constraint\n");
5117 return SCIP_OKAY;
5118 }
5119
5120 /* create empty logicor constraint */
5121 SCIP_CALL( SCIPcreateConsLogicor(scip, cons, name, 0, NULL,
5122 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
5123
5124 *success = TRUE;
5125 }
5126
5127 return SCIP_OKAY;
5128}
5129
5130/** constraint method of constraint handler which returns the variables (if possible) */
5131static
5132SCIP_DECL_CONSGETVARS(consGetVarsLogicor)
5133{ /*lint --e{715}*/
5134 SCIP_CONSDATA* consdata;
5135
5136 consdata = SCIPconsGetData(cons);
5137 assert(consdata != NULL);
5138
5139 if( varssize < consdata->nvars )
5140 (*success) = FALSE;
5141 else
5142 {
5143 assert(vars != NULL);
5144
5145 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
5146 (*success) = TRUE;
5147 }
5148
5149 return SCIP_OKAY;
5150}
5151
5152/** constraint method of constraint handler which returns the number of variables (if possible) */
5153static
5154SCIP_DECL_CONSGETNVARS(consGetNVarsLogicor)
5155{ /*lint --e{715}*/
5156 SCIP_CONSDATA* consdata;
5157
5158 consdata = SCIPconsGetData(cons);
5159 assert(consdata != NULL);
5160
5161 (*nvars) = consdata->nvars;
5162 (*success) = TRUE;
5163
5164 return SCIP_OKAY;
5165}
5166
5167/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
5168static
5169SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphLogicor)
5170{ /*lint --e{715}*/
5171 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
5172
5173 return SCIP_OKAY;
5174}
5175
5176/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
5177static
5178SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphLogicor)
5179{ /*lint --e{715}*/
5180 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
5181
5182 return SCIP_OKAY;
5183}
5184
5185/*
5186 * Callback methods of event handler
5187 */
5188
5189static
5190SCIP_DECL_EVENTEXEC(eventExecLogicor)
5191{ /*lint --e{715}*/
5192 assert(eventhdlr != NULL);
5193 assert(eventdata != NULL);
5194 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
5195 assert(event != NULL);
5196
5197 SCIPdebugMsg(scip, "exec method of event handler for logic or constraints\n");
5198
5200 {
5201 SCIPdebugMsg(scip, "enabling constraint cons <%s> at depth %d\n", SCIPconsGetName((SCIP_CONS*)eventdata), SCIPgetDepth(scip));
5202
5203 SCIP_CALL( SCIPenableCons(scip, (SCIP_CONS*)eventdata) );
5205 }
5206 else if( SCIPeventGetType(event) == SCIP_EVENTTYPE_UBTIGHTENED )
5207 {
5209 }
5210
5212 {
5213 SCIP_VAR* var = SCIPeventGetVar(event);
5214 SCIP_CONS* cons = (SCIP_CONS*)eventdata;
5215 SCIP_CONSDATA* consdata;
5216
5217 assert(cons != NULL);
5218 consdata = SCIPconsGetData(cons);
5219 assert(consdata != NULL);
5220
5221 /* we only catch this event in presolving stage */
5223 assert(var != NULL);
5224
5225 consdata->presolved = FALSE;
5226
5228 {
5229 if( SCIPconsIsActive(cons) )
5230 {
5231 if( SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 )
5232 consdata->merged = FALSE;
5233
5234 if( !consdata->existmultaggr )
5235 {
5237 consdata->existmultaggr = TRUE;
5238 }
5239 }
5240 }
5241 }
5242
5243 return SCIP_OKAY;
5244}
5245
5246
5247/*
5248 * Callback methods of conflict handler
5249 */
5250
5251/** conflict processing method of conflict handler (called when conflict was found) */
5252static
5253SCIP_DECL_CONFLICTEXEC(conflictExecLogicor)
5254{ /*lint --e{715}*/
5255 SCIP_VAR** vars;
5256 int i;
5257
5258 assert(conflicthdlr != NULL);
5259 assert(strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0);
5260 assert(bdchginfos != NULL || nbdchginfos == 0);
5261 assert(result != NULL);
5262
5264
5265 /* don't process already resolved conflicts */
5266 if( resolved )
5267 return SCIP_OKAY;
5268
5269 /* if the conflict consists of only two (binary) variables, it will be handled by the setppc conflict handler */
5270 if( nbdchginfos == 2 )
5271 return SCIP_OKAY;
5272
5274
5275 /* create array of variables in conflict constraint */
5276 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
5277 for( i = 0; i < nbdchginfos; ++i )
5278 {
5279 assert(bdchginfos != NULL); /* for flexelint */
5280 assert(bdchginfos[i] != NULL);
5281
5282 vars[i] = SCIPbdchginfoGetVar(bdchginfos[i]);
5283
5284 /* we can only treat binary variables */
5285 if( !SCIPvarIsBinary(vars[i]) )
5286 break;
5287
5288 /* if the variable is fixed to one in the conflict set, we have to use its negation */
5289 if( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 )
5290 {
5292 }
5293 }
5294
5295 if( i == nbdchginfos )
5296 {
5297 SCIP_CONS* cons;
5298 char consname[SCIP_MAXSTRLEN];
5299
5300 /* create a constraint out of the conflict set */
5302 SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, consname, nbdchginfos, vars,
5303 FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
5304
5305 /* add conflict to SCIP */
5306 SCIP_CALL( SCIPaddConflict(scip, node, &cons, validnode, conftype, cutoffinvolved) );
5307
5309 }
5310
5311 /* free temporary memory */
5313
5314 return SCIP_OKAY;
5315}
5316
5317
5318/*
5319 * constraint specific interface methods
5320 */
5321
5322/** creates the handler for logic or constraints and includes it in SCIP */
5324 SCIP* scip /**< SCIP data structure */
5325 )
5326{
5327 SCIP_CONSHDLRDATA* conshdlrdata;
5328 SCIP_CONSHDLR* conshdlr;
5329 SCIP_CONFLICTHDLR* conflicthdlr;
5330 SCIP_EVENTHDLR* eventhdlr;
5331
5332 /* create event handler for events on watched variables */
5334 eventExecLogicor, NULL) );
5335
5336 /* create conflict handler for logic or constraints */
5338 conflictExecLogicor, NULL) );
5339
5340 /* create constraint handler data */
5341 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
5342
5343 /* include constraint handler */
5346 consEnfolpLogicor, consEnfopsLogicor, consCheckLogicor, consLockLogicor,
5347 conshdlrdata) );
5348 assert(conshdlr != NULL);
5349
5350 /* set non-fundamental callbacks via specific setter functions */
5351 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveLogicor) );
5352 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyLogicor, consCopyLogicor) );
5353 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveLogicor) );
5354 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteLogicor) );
5355 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreLogicor) );
5356 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolLogicor) );
5357 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolLogicor) );
5358 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeLogicor) );
5359 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsLogicor) );
5360 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsLogicor) );
5361 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreLogicor) );
5362 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpLogicor) );
5363 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseLogicor) );
5365 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintLogicor) );
5368 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropLogicor) );
5369 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpLogicor, consSepasolLogicor, CONSHDLR_SEPAFREQ,
5371 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransLogicor) );
5372 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxLogicor) );
5373 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphLogicor) );
5374 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphLogicor) );
5375
5376 conshdlrdata->conshdlrlinear = SCIPfindConshdlr(scip, "linear");
5377 conshdlrdata->conshdlrsetppc = SCIPfindConshdlr(scip, "setppc");
5378
5379 if( conshdlrdata->conshdlrlinear != NULL )
5380 {
5381 /* include the linear constraint to logicor constraint upgrade in the linear constraint handler */
5383 }
5384
5385 /* logic or constraint handler parameters */
5387 "constraints/logicor/presolpairwise",
5388 "should pairwise constraint comparison be performed in presolving?",
5389 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
5391 "constraints/logicor/presolusehashing",
5392 "should hash table be used for detecting redundant constraints in advance",
5393 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
5395 "constraints/logicor/dualpresolving",
5396 "should dual presolving steps be performed?",
5397 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
5399 "constraints/logicor/negatedclique",
5400 "should negated clique information be used in presolving",
5401 &conshdlrdata->usenegatedclique, TRUE, DEFAULT_NEGATEDCLIQUE, NULL, NULL) );
5403 "constraints/logicor/implications",
5404 "should implications/cliques be used in presolving",
5405 &conshdlrdata->useimplications, TRUE, DEFAULT_IMPLICATIONS, NULL, NULL) );
5407 "constraints/logicor/strengthen",
5408 "should pairwise constraint comparison try to strengthen constraints by removing superflous non-zeros?",
5409 &conshdlrdata->usestrengthening, TRUE, DEFAULT_STRENGTHEN, NULL, NULL) );
5410
5411 return SCIP_OKAY;
5412}
5413
5414
5415/** creates and captures a logic or constraint
5416 *
5417 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
5418 */
5420 SCIP* scip, /**< SCIP data structure */
5421 SCIP_CONS** cons, /**< pointer to hold the created constraint */
5422 const char* name, /**< name of constraint */
5423 int nvars, /**< number of variables in the constraint */
5424 SCIP_VAR** vars, /**< array with variables of constraint entries */
5425 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
5426 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
5427 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
5428 * Usually set to TRUE. */
5429 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
5430 * TRUE for model constraints, FALSE for additional, redundant constraints. */
5431 SCIP_Bool check, /**< should the constraint be checked for feasibility?
5432 * TRUE for model constraints, FALSE for additional, redundant constraints. */
5433 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
5434 * Usually set to TRUE. */
5435 SCIP_Bool local, /**< is constraint only valid locally?
5436 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
5437 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
5438 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
5439 * adds coefficients to this constraint. */
5440 SCIP_Bool dynamic, /**< is constraint subject to aging?
5441 * Usually set to FALSE. Set to TRUE for own cuts which
5442 * are separated as constraints. */
5443 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
5444 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
5445 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
5446 * if it may be moved to a more global node?
5447 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
5448 )
5449{
5450 SCIP_CONSHDLR* conshdlr;
5451 SCIP_CONSDATA* consdata;
5452 int i;
5453
5454 assert(scip != NULL);
5455
5456 /* find the logicor constraint handler */
5457 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5458 if( conshdlr == NULL )
5459 {
5460 SCIPerrorMessage("logic or constraint handler not found\n");
5461 return SCIP_INVALIDCALL;
5462 }
5463
5464 /* check whether all variables are binary */
5465 assert(vars != NULL || nvars == 0);
5466 for( i = 0; i < nvars; ++i )
5467 {
5468 if( !SCIPvarIsBinary(vars[i]) )
5469 {
5470 SCIPerrorMessage("operand <%s> is not binary\n", SCIPvarGetName(vars[i]));
5471 return SCIP_INVALIDDATA;
5472 }
5473 }
5474
5475 /* create the constraint specific data */
5476 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars) );
5477
5478 /* create constraint */
5479 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
5480 local, modifiable, dynamic, removable, stickingatnode) );
5481
5483 {
5484 SCIP_CONSHDLRDATA* conshdlrdata;
5485 int v;
5486
5487 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5488 assert(conshdlrdata != NULL);
5489
5490 for( v = consdata->nvars - 1; v >= 0; --v )
5491 {
5492 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
5493 (SCIP_EVENTDATA*)(*cons), NULL) );
5494 }
5495 }
5496
5497 return SCIP_OKAY;
5498}
5499
5500/** creates and captures a logicor constraint
5501 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
5502 * method SCIPcreateConsLogicor(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
5503 *
5504 * @see SCIPcreateConsLogicor() for information about the basic constraint flag configuration
5505 *
5506 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
5507 */
5509 SCIP* scip, /**< SCIP data structure */
5510 SCIP_CONS** cons, /**< pointer to hold the created constraint */
5511 const char* name, /**< name of constraint */
5512 int nvars, /**< number of variables in the constraint */
5513 SCIP_VAR** vars /**< array with variables of constraint entries */
5514 )
5515{
5516 assert(scip != NULL);
5517
5520
5521 return SCIP_OKAY;
5522}
5523
5524/** adds coefficient in logic or constraint */
5526 SCIP* scip, /**< SCIP data structure */
5527 SCIP_CONS* cons, /**< logicor constraint */
5528 SCIP_VAR* var /**< variable to add to the constraint */
5529 )
5530{
5531 assert(var != NULL);
5532
5533 /*debugMsg(scip, "adding variable <%s> to logicor constraint <%s>\n",
5534 SCIPvarGetName(var), SCIPconsGetName(cons));*/
5535
5536 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5537 {
5538 SCIPerrorMessage("constraint is not a logic or constraint\n");
5539 return SCIP_INVALIDDATA;
5540 }
5541
5542 SCIP_CALL( addCoef(scip, cons, var) );
5543
5544 return SCIP_OKAY;
5545}
5546
5547/** gets number of variables in logic or constraint */
5549 SCIP* scip, /**< SCIP data structure */
5550 SCIP_CONS* cons /**< constraint data */
5551 )
5552{
5553 SCIP_CONSDATA* consdata;
5554
5555 assert(scip != NULL);
5556
5557 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5558 {
5559 SCIPerrorMessage("constraint is not a logic or constraint\n");
5560 SCIPABORT();
5561 return -1; /*lint !e527*/
5562 }
5563
5564 consdata = SCIPconsGetData(cons);
5565 assert(consdata != NULL);
5566
5567 return consdata->nvars;
5568}
5569
5570/** gets array of variables in logic or constraint */
5572 SCIP* scip, /**< SCIP data structure */
5573 SCIP_CONS* cons /**< constraint data */
5574 )
5575{
5576 SCIP_CONSDATA* consdata;
5577
5578 assert(scip != NULL);
5579
5580 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5581 {
5582 SCIPerrorMessage("constraint is not a logic or constraint\n");
5583 SCIPABORT();
5584 return NULL; /*lint !e527*/
5585 }
5586
5587 consdata = SCIPconsGetData(cons);
5588 assert(consdata != NULL);
5589
5590 return consdata->vars;
5591}
5592
5593/** gets the dual solution of the logic or constraint in the current LP */
5595 SCIP* scip, /**< SCIP data structure */
5596 SCIP_CONS* cons /**< constraint data */
5597 )
5598{
5599 SCIP_CONSDATA* consdata;
5600
5601 assert(scip != NULL);
5602
5603 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5604 {
5605 SCIPerrorMessage("constraint is not a logic or constraint\n");
5606 SCIPABORT();
5607 return SCIP_INVALID; /*lint !e527*/
5608 }
5609
5610 consdata = SCIPconsGetData(cons);
5611 assert(consdata != NULL);
5612
5613 if( consdata->row != NULL )
5614 return SCIProwGetDualsol(consdata->row);
5615 else
5616 return 0.0;
5617}
5618
5619/** gets the dual Farkas value of the logic or constraint in the current infeasible LP */
5621 SCIP* scip, /**< SCIP data structure */
5622 SCIP_CONS* cons /**< constraint data */
5623 )
5624{
5625 SCIP_CONSDATA* consdata;
5626
5627 assert(scip != NULL);
5628
5629 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5630 {
5631 SCIPerrorMessage("constraint is not a logic or constraint\n");
5632 SCIPABORT();
5633 return SCIP_INVALID; /*lint !e527*/
5634 }
5635
5636 consdata = SCIPconsGetData(cons);
5637 assert(consdata != NULL);
5638
5639 if( consdata->row != NULL )
5640 return SCIProwGetDualfarkas(consdata->row);
5641 else
5642 return 0.0;
5643}
5644
5645/** returns the linear relaxation of the given logic or constraint; may return NULL if no LP row was yet created;
5646 * the user must not modify the row!
5647 */
5649 SCIP* scip, /**< SCIP data structure */
5650 SCIP_CONS* cons /**< constraint data */
5651 )
5652{
5653 SCIP_CONSDATA* consdata;
5654
5655 assert(scip != NULL);
5656
5657 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5658 {
5659 SCIPerrorMessage("constraint is not a logic or constraint\n");
5660 SCIPABORT();
5661 return NULL; /*lint !e527*/
5662 }
5663
5664 consdata = SCIPconsGetData(cons);
5665 assert(consdata != NULL);
5666
5667 return consdata->row;
5668}
5669
5670/** creates and returns the row of the given logicor constraint */
5672 SCIP* scip, /**< SCIP data structure */
5673 SCIP_CONS* cons /**< constraint data */
5674 )
5675{
5676 SCIP_CONSDATA* consdata;
5677
5678 assert(scip != NULL);
5679
5680 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5681 {
5682 SCIPerrorMessage("constraint is not a logic or constraint\n");
5683 SCIPABORT();
5684 return SCIP_ERROR; /*lint !e527*/
5685 }
5686
5687 consdata = SCIPconsGetData(cons);
5688 assert(consdata != NULL);
5689 assert(consdata->row == NULL);
5690
5691 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), 1.0, SCIPinfinity(scip),
5693
5694 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->row, consdata->nvars, consdata->vars, 1.0) );
5695
5696 return SCIP_OKAY;
5697}
5698
5699/** cleans up (multi-)aggregations and fixings from logicor constraints */
5701 SCIP* scip, /**< SCIP data structure */
5702 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
5703 int* naddconss, /**< pointer to count number of added (linear) constraints */
5704 int* ndelconss, /**< pointer to count number of deleted (logicor) constraints */
5705 int* nchgcoefs /**< pointer to count number of changed coefficients */
5706 )
5707{
5708 SCIP_CONSHDLR* conshdlr;
5709 SCIP_EVENTHDLR* eventhdlr;
5710 SCIP_CONS** conss;
5711 unsigned char* entries;
5712 int nconss;
5713 int nentries;
5714 int i;
5715
5716 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5717 if( conshdlr == NULL )
5718 return SCIP_OKAY;
5719
5720 assert(naddconss != NULL);
5721 assert(ndelconss != NULL);
5722 assert(nchgcoefs != NULL);
5723
5724 eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr;
5725 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
5726 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
5727
5728 nentries = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5729 SCIP_CALL( SCIPallocBufferArray(scip, &entries, nentries) );
5730
5731 /* loop backwards since then deleted constraints do not interfere with the loop */
5732 for( i = nconss - 1; i >= 0; --i )
5733 {
5734 SCIP_CONS* cons;
5735 SCIP_Bool redundant;
5736
5737 cons = conss[i];
5738 redundant = FALSE;
5739
5740 SCIP_CALL( applyFixings(scip, cons, eventhdlr, &redundant, nchgcoefs, naddconss, ndelconss) );
5741
5742 if( SCIPconsIsDeleted(cons) )
5743 continue;
5744
5745 /* merge constraint */
5746 if( !redundant )
5747 {
5748 SCIP_CALL( mergeMultiples(scip, cons, eventhdlr, &entries, &nentries, &redundant, nchgcoefs) );
5749 }
5750
5751 if( redundant )
5752 {
5753 SCIP_CALL( SCIPdelCons(scip, cons) );
5754 ++(*ndelconss);
5755 }
5756 }
5757
5758 SCIPfreeBufferArray(scip, &entries);
5759
5760 return SCIP_OKAY;
5761}
#define EVENTHDLR_NAME
SCIP_VAR * w
#define EVENTHDLR_DESC
#define DEFAULT_DUALPRESOLVING
Definition cons_and.c:110
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:97
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:90
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:89
#define CONSHDLR_DESC
Definition cons_and.c:86
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:100
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:94
#define DEFAULT_PRESOLPAIRWISE
Definition cons_and.c:105
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:87
#define DEFAULT_PRESOLUSEHASHING
Definition cons_and.c:113
#define CONSHDLR_PROPFREQ
Definition cons_and.c:91
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:99
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:92
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:95
#define CONSHDLR_NAME
Definition cons_and.c:85
#define CONSHDLR_DELAYPROP
Definition cons_and.c:96
#define CONFLICTHDLR_PRIORITY
#define CONFLICTHDLR_NAME
#define CONFLICTHDLR_DESC
#define LINCONSUPGD_PRIORITY
#define DEFAULT_NEGATEDCLIQUE
Constraint handler for linear constraints in their most general form, .
static SCIP_Bool isConsViolated(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define MAXCOMPARISONS
#define DEFAULT_IMPLICATIONS
#define AGEINCREASE(n)
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
static SCIP_RETCODE addCut(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff)
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int pos)
static SCIP_RETCODE createRow(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE processWatchedVars(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, SCIP_Bool *reduceddom, SCIP_Bool *addcut, SCIP_Bool *mustcheck)
static SCIP_RETCODE analyzeConflict(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addConsToOccurList(SCIP *scip, SCIP_CONS *cons, SCIP_HASHMAP *varstopos, SCIP_CONS ***occurlist, int *noccurlistentries, int *occurlistsizes, int *occurlistlength, int occurlistsize)
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
static SCIP_RETCODE removeConstraintsDueToNegCliques(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLR *conshdlrsetppc, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS **conss, int nconss, unsigned char **entries, int *nentries, int *nfixedvars, int *ndelconss, int *nupgdconss, int *nchgcoefs, SCIP_Bool *cutoff)
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define DEFAULT_STRENGTHEN
#define MAX_CONSLENGTH
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS *cons, SCIP_HASHMAP *varstopos, SCIP_CONS ***occurlist, int *noccurlistentries, int occurlistlength, int *ndelconss)
static void findShortestOccurlist(SCIP_VAR **vars, int nvars, SCIP_HASHMAP *varstopos, SCIP_CONS ***occurlist, int *noccurlistentries, int occurlistlength, int *nentries, SCIP_CONS ***shortestlist)
static SCIP_RETCODE removeRedundantConssAndNonzeros(SCIP *scip, SCIP_CONS **conss, int nconss, unsigned char **entries, int *nentries, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool usestrengthening, int *firstchange, int *nfixedvars, int *ndelconss, int *nchgcoefs, SCIP_Bool *cutoff)
static SCIP_RETCODE prepareCons(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, unsigned char **entries, int *nentries, SCIP_Bool *redundant, int *nfixedvars, int *nchgcoefs, int *ndelconss, SCIP_Bool *cutoff)
static SCIP_RETCODE enforcePseudo(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, SCIP_Bool *infeasible, SCIP_Bool *reduceddom, SCIP_Bool *solvelp)
static SCIP_RETCODE createNormalizedLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, int mult, 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)
static SCIP_RETCODE dualPresolving(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int *nfixedvars, int *ndelconss, int *nchgcoefs, int *naggrvars, SCIP_RESULT *result)
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
static SCIP_RETCODE shortenConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS **conss, int nconss, unsigned char **entries, int *nentries, int *nfixedvars, int *ndelconss, int *nchgcoefs, SCIP_Bool *cutoff)
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_RETCODE switchWatchedvars(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int watchedvar1, int watchedvar2)
static SCIP_RETCODE fixDeleteOrUpgradeCons(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_CONSHDLR *conshdlrlinear, SCIP_CONSHDLR *conshdlrsetppc, int *nfixedvars, int *nchgbds, int *nchgcoefs, int *ndelconss, int *naddconss, int *nupgdconss, SCIP_Bool *cutoff)
#define HASHSIZE_LOGICORCONS
static unsigned int calcSignature(SCIP_VAR **vars, int nvars)
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, int *firstchange, int *ndelconss)
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, SCIP_Bool *separated, SCIP_Bool *reduceddom)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
static void consdataSort(SCIP_CONSDATA *consdata)
static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE strengthenConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_HASHMAP *varstopos, SCIP_CONS ***occurlist, int *noccurlistentries, int occurlistlength, SCIP_EVENTHDLR *eventhdlr, int *ndelconss, int *nchgcoefs)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, unsigned char **entries, int *nentries, SCIP_Bool *redundant, int *nchgcoefs)
static void removeConsFromOccurList(SCIP_CONS *cons, SCIP_HASHMAP *varstopos, SCIP_CONS ***occurlist, int *noccurlistentries, int occurlistlength)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, int nvars, SCIP_VAR **vars)
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *redundant, int *nchgcoefs, int *naddconss, int *ndelconss)
static SCIP_RETCODE disableCons(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE removeRedundantCons(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1, int *ndelconss)
static SCIP_RETCODE removeRedundantNonZeros(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *artvar, int artpos, SCIP_HASHMAP *varstopos, SCIP_CONS ***occurlist, int *noccurlistentries, int occurlistlength, SCIP_EVENTHDLR *eventhdlr, int *nchgcoefs, SCIP_Bool *deleted)
static SCIP_RETCODE consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file, SCIP_Bool endline)
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
Constraint handler for the set partitioning / packing / covering constraints .
#define NULL
Definition def.h:255
#define SCIP_MAXSTRLEN
Definition def.h:276
#define SCIP_Longint
Definition def.h:148
#define SCIP_INVALID
Definition def.h:185
#define SCIP_Bool
Definition def.h:98
#define SCIP_Real
Definition def.h:163
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
#define MAX(x, y)
Definition def.h:227
#define SCIP_LONGINT_FORMAT
Definition def.h:155
#define SCIPABORT()
Definition def.h:334
#define SCIP_LONGINT_MAX
Definition def.h:149
#define SCIP_CALL(x)
Definition def.h:362
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVarsLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetDualsolLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_ROW * SCIPgetRowLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, 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_RETCODE SCIPcleanupConssLogicor(SCIP *scip, SCIP_Bool onlychecked, int *naddconss, int *ndelconss, int *nchgcoefs)
SCIP_RETCODE SCIPcreateRowLogicor(SCIP *scip, SCIP_CONS *cons)
#define SCIP_DECL_LINCONSUPGD(x)
SCIP_RETCODE SCIPcopyConsLinear(SCIP *scip, SCIP_CONS **cons, SCIP *sourcescip, const char *name, int nvars, SCIP_VAR **sourcevars, SCIP_Real *sourcecoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, 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)
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, 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_VAR ** SCIPgetVarsLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsBasicLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, 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_Real SCIPgetDualfarkasLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddCoefLogicor(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_RETCODE SCIPincludeConshdlrLogicor(SCIP *scip)
SCIP_Bool SCIPisTransformed(SCIP *scip)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
int SCIPgetNIntVars(SCIP *scip)
Definition scip_prob.c:2340
SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
Definition scip_prob.c:3368
int SCIPgetNImplVars(SCIP *scip)
Definition scip_prob.c:2387
int SCIPgetNContVars(SCIP *scip)
Definition scip_prob.c:2569
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 SCIPgetNBinVars(SCIP *scip)
Definition scip_prob.c:2293
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3179
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition misc.c:2348
#define SCIPhashFour(a, b, c, d)
Definition pub_misc.h:573
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition misc.c:2298
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition misc.c:2596
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition misc.c:2535
SCIP_RETCODE SCIPaddConflict(SCIP *scip, SCIP_NODE *node, SCIP_CONS **cons, SCIP_NODE *validnode, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition scip_prob.c:3806
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition misc.c:11162
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
const char * SCIPconflicthdlrGetName(SCIP_CONFLICTHDLR *conflicthdlr)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_RETCODE SCIPincludeConflicthdlrBasic(SCIP *scip, SCIP_CONFLICTHDLR **conflicthdlrptr, const char *name, const char *desc, int priority, SCIP_DECL_CONFLICTEXEC((*conflictexec)), SCIP_CONFLICTHDLRDATA *conflicthdlrdata)
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4802
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4350
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:670
SCIP_CONS ** SCIPconshdlrGetCheckConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4759
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition scip_cons.c:235
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 SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
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 SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:924
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:444
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:693
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4816
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4739
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8423
int SCIPconsGetPos(SCIP_CONS *cons)
Definition cons.c:8403
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_RETCODE SCIPenableCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1837
SCIP_Bool SCIPconsIsPropagationEnabled(SCIP_CONS *cons)
Definition cons.c:8511
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition cons.c:8845
SCIP_RETCODE SCIPenableConsPropagation(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1951
int SCIPconsGetValidDepth(SCIP_CONS *cons)
Definition cons.c:8476
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8522
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8702
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8454
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:8612
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8632
SCIP_RETCODE SCIPdisableCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1871
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1812
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition cons.c:8822
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition scip_cons.c:1524
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8672
SCIP_RETCODE SCIPdisableConsPropagation(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1981
SCIP_RETCODE SCIPaddConsAge(SCIP *scip, SCIP_CONS *cons, SCIP_Real deltaage)
Definition scip_cons.c:1755
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:111
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition event.c:396
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1194
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:413
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1217
SCIP_Bool SCIPhasCurrentNodeLP(SCIP *scip)
Definition scip_lp.c:87
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition scip_mem.h:146
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition scip_mem.h:142
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#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 SCIPduplicateBufferArray(scip, ptr, source, num)
Definition scip_mem.h:132
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition scip_mem.h:111
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:424
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition scip_nlp.c:396
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition scip_nlp.c:110
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition scip_nlp.c:1058
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition nlp.c:1953
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition scip_nlp.c:954
SCIP_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPaddVarsToRowSameCoef(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real val)
Definition scip_lp.c:1718
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1398
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_Real SCIProwGetDualfarkas(SCIP_ROW *row)
Definition lp.c:17719
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1974
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17917
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition lp.c:17706
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1765
void SCIPupdateSolLPConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:469
int SCIPgetNImplications(SCIP *scip)
int SCIPgetNRuns(SCIP *scip)
SCIP_Longint SCIPgetNConflictConssApplied(SCIP *scip)
SCIP_RETCODE SCIPshrinkDisjunctiveVarSet(SCIP *scip, SCIP_VAR **vars, SCIP_Real *bounds, SCIP_Bool *boundtypes, SCIP_Bool *redundants, int nvars, int *nredvars, int *nglobalred, SCIP_Bool *setredundant, SCIP_Bool *glbinfeas, SCIP_Bool fullshortening)
Definition presolve.c:995
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 SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
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)
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition var.c:23869
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23643
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23479
SCIP_RETCODE SCIPaddClique(SCIP *scip, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition scip_var.c:8882
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition scip_var.c:2119
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24569
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23387
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4386
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition var.c:23499
SCIP_RETCODE SCIPvarGetAggregatedObj(SCIP_VAR *var, SCIP_Real *aggrobj)
Definition var.c:23945
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24269
SCIP_RETCODE SCIPgetBinvarRepresentatives(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **repvars, SCIP_Bool *negated)
Definition scip_var.c:2283
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:23431
SCIP_RETCODE SCIPparseVarsList(SCIP *scip, const char *str, SCIP_VAR **vars, int *nvars, int varssize, int *requiredsize, char **endptr, char delimiter, SCIP_Bool *success)
Definition scip_var.c:805
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition scip_var.c:10550
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23901
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition var.c:17551
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition var.c:23454
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24143
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23653
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5296
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23663
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23268
SCIP_VAR * SCIPbdchginfoGetVar(SCIP_BDCHGINFO *bdchginfo)
Definition var.c:24930
SCIP_RETCODE SCIPcleanupCliques(SCIP *scip, SCIP_Bool *infeasible)
Definition scip_var.c:9469
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize)
Definition scip_var.c:2378
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition scip_var.c:2166
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition var.c:24643
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24235
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition var.c:23444
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition var.c:23879
int SCIPgetNCliques(SCIP *scip)
Definition scip_var.c:9512
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24121
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17275
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition var.c:17643
SCIP_Longint SCIPvarGetNBranchingsCurrentRun(SCIP_VAR *var, SCIP_BRANCHDIR dir)
Definition var.c:21797
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7412
SCIP_RETCODE SCIPwriteVarsList(SCIP *scip, FILE *file, SCIP_VAR **vars, int nvars, SCIP_Bool type, char delimiter)
Definition scip_var.c:423
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition var.c:16808
SCIP_Real SCIPbdchginfoGetNewbound(SCIP_BDCHGINFO *bdchginfo)
Definition var.c:24920
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4328
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition scip_var.c:2078
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:1853
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition scip_var.c:10984
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
return SCIP_OKAY
int c
SCIP_Bool cutoff
SCIP_Real objval
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition memory.h:130
struct BMS_BlkMem BMS_BLKMEM
Definition memory.h:437
methods commonly used for presolving
public methods for conflict analysis handlers
public methods for managing constraints
public methods for managing events
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for problem variables
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for cuts and aggregation rows
public methods for event handler plugins and event handlers
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for nonlinear relaxation
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
structs for symmetry computations
methods for dealing with symmetry detection graphs
struct SCIP_Conflicthdlr SCIP_CONFLICTHDLR
#define SCIP_DECL_CONFLICTEXEC(x)
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:956
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:938
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:867
#define SCIP_DECL_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
struct SYM_Graph SYM_GRAPH
Definition type_cons.h:68
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSACTIVE(x)
Definition type_cons.h:691
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSDEACTIVE(x)
Definition type_cons.h:706
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:676
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:810
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:179
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition type_event.h:79
#define SCIP_EVENTTYPE_VARFIXED
Definition type_event.h:72
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_LBRELAXED
Definition type_event.h:78
@ SCIP_EXPRCURV_LINEAR
Definition type_expr.h:65
@ SCIP_BRANCHDIR_DOWNWARDS
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_SORTPTRCOMP(x)
Definition type_misc.h:189
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:195
#define SCIP_DECL_HASHGETKEY(x)
Definition type_misc.h:192
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:198
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
struct SCIP_NlRow SCIP_NLROW
Definition type_nlp.h:41
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_CONSADDED
Definition type_result.h:52
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SOLVELP
Definition type_result.h:55
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDDATA
@ SCIP_INVALIDCALL
@ SCIP_ERROR
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ SCIP_STAGE_INITPRESOLVE
Definition type_set.h:48
@ SCIP_STAGE_PRESOLVING
Definition type_set.h:49
@ SCIP_STAGE_INITSOLVE
Definition type_set.h:52
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
@ SCIP_STAGE_TRANSFORMING
Definition type_set.h:46
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
enum SYM_Symtype SYM_SYMTYPE
@ SYM_SYMTYPE_SIGNPERM
@ SYM_SYMTYPE_PERM
#define SCIP_PRESOLTIMING_MEDIUM
Definition type_timing.h:53
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition type_timing.h:54
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition type_var.h:57
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141