1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /*                                                                           */
3 /*                  This file is part of the program and library             */
4 /*         SCIP --- Solving Constraint Integer Programs                      */
5 /*                                                                           */
6 /*    Copyright (C) 2002-2021 Konrad-Zuse-Zentrum                            */
7 /*                            fuer Informationstechnik Berlin                */
8 /*                                                                           */
9 /*  SCIP is distributed under the terms of the ZIB Academic License.         */
10 /*                                                                           */
11 /*  You should have received a copy of the ZIB Academic License              */
12 /*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13 /*                                                                           */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file   presol.c
17  * @ingroup OTHER_CFILES
18  * @brief  methods for presolvers
19  * @author Tobias Achterberg
20  * @author Timo Berthold
21  *
22  * @todo add maxrounds parameter for single timings, count number of runs of a presolver with given timing
23  */
24 
25 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26 
27 #include <assert.h>
28 #include <string.h>
29 
30 #include "scip/def.h"
31 #include "blockmemshell/memory.h"
32 #include "scip/set.h"
33 #include "scip/clock.h"
34 #include "scip/paramset.h"
35 #include "scip/scip.h"
36 #include "scip/pub_misc.h"
37 #include "scip/presol.h"
38 
39 #include "scip/struct_presol.h"
40 
41 
42 
43 /*
44  * presolver methods
45  */
46 
47 /** compares two presolvers w. r. to their priority */
SCIP_DECL_SORTPTRCOMP(SCIPpresolComp)48 SCIP_DECL_SORTPTRCOMP(SCIPpresolComp)
49 {  /*lint --e{715}*/
50    return ((SCIP_PRESOL*)elem2)->priority - ((SCIP_PRESOL*)elem1)->priority;
51 }
52 
53 /** comparison method for sorting presolvers w.r.t. to their name */
SCIP_DECL_SORTPTRCOMP(SCIPpresolCompName)54 SCIP_DECL_SORTPTRCOMP(SCIPpresolCompName)
55 {
56    return strcmp(SCIPpresolGetName((SCIP_PRESOL*)elem1), SCIPpresolGetName((SCIP_PRESOL*)elem2));
57 }
58 
59 /** method to call, when the priority of a presolver was changed */
60 static
SCIP_DECL_PARAMCHGD(paramChgdPresolPriority)61 SCIP_DECL_PARAMCHGD(paramChgdPresolPriority)
62 {  /*lint --e{715}*/
63    SCIP_PARAMDATA* paramdata;
64 
65    paramdata = SCIPparamGetData(param);
66    assert(paramdata != NULL);
67 
68    /* use SCIPsetPresolPriority() to mark the presols unsorted */
69    SCIP_CALL( SCIPsetPresolPriority(scip, (SCIP_PRESOL*)paramdata, SCIPparamGetInt(param)) ); /*lint !e740*/
70 
71    return SCIP_OKAY;
72 }
73 
74 /** copies the given presolver to a new scip */
SCIPpresolCopyInclude(SCIP_PRESOL * presol,SCIP_SET * set)75 SCIP_RETCODE SCIPpresolCopyInclude(
76    SCIP_PRESOL*          presol,             /**< presolver */
77    SCIP_SET*             set                 /**< SCIP_SET of SCIP to copy to */
78    )
79 {
80    assert(presol != NULL);
81    assert(set != NULL);
82    assert(set->scip != NULL);
83 
84    if( presol->presolcopy != NULL )
85    {
86       SCIPsetDebugMsg(set, "including presolver %s in subscip %p\n", SCIPpresolGetName(presol), (void*)set->scip);
87       SCIP_CALL( presol->presolcopy(set->scip, presol) );
88    }
89    return SCIP_OKAY;
90 }
91 
92 /** internal method for creating a presolver */
93 static
doPresolCreate(SCIP_PRESOL ** presol,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,const char * name,const char * desc,int priority,int maxrounds,SCIP_PRESOLTIMING timing,SCIP_DECL_PRESOLCOPY ((* presolcopy)),SCIP_DECL_PRESOLFREE ((* presolfree)),SCIP_DECL_PRESOLINIT ((* presolinit)),SCIP_DECL_PRESOLEXIT ((* presolexit)),SCIP_DECL_PRESOLINITPRE ((* presolinitpre)),SCIP_DECL_PRESOLEXITPRE ((* presolexitpre)),SCIP_DECL_PRESOLEXEC ((* presolexec)),SCIP_PRESOLDATA * presoldata)94 SCIP_RETCODE doPresolCreate(
95    SCIP_PRESOL**         presol,             /**< pointer to store presolver */
96    SCIP_SET*             set,                /**< global SCIP settings */
97    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
98    BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
99    const char*           name,               /**< name of presolver */
100    const char*           desc,               /**< description of presolver */
101    int                   priority,           /**< priority of the presolver (>= 0: before, < 0: after constraint handlers) */
102    int                   maxrounds,          /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
103    SCIP_PRESOLTIMING     timing,             /**< timing mask of the presolver */
104    SCIP_DECL_PRESOLCOPY  ((*presolcopy)),    /**< copy method of presolver or NULL if you don't want to copy your plugin into sub-SCIPs */
105    SCIP_DECL_PRESOLFREE  ((*presolfree)),    /**< destructor of presolver to free user data (called when SCIP is exiting) */
106    SCIP_DECL_PRESOLINIT  ((*presolinit)),    /**< initialization method of presolver (called after problem was transformed) */
107    SCIP_DECL_PRESOLEXIT  ((*presolexit)),    /**< deinitialization method of presolver (called before transformed problem is freed) */
108    SCIP_DECL_PRESOLINITPRE((*presolinitpre)),/**< presolving initialization method of presolver (called when presolving is about to begin) */
109    SCIP_DECL_PRESOLEXITPRE((*presolexitpre)),/**< presolving deinitialization method of presolver (called after presolving has been finished) */
110    SCIP_DECL_PRESOLEXEC  ((*presolexec)),    /**< execution method of presolver */
111    SCIP_PRESOLDATA*      presoldata          /**< presolver data */
112    )
113 {
114    char paramname[SCIP_MAXSTRLEN];
115    char paramdesc[SCIP_MAXSTRLEN];
116 
117    assert(presol != NULL);
118    assert(name != NULL);
119    assert(desc != NULL);
120 
121    /* the interface change from delay flags to timings cannot be recognized at compile time: Exit with an appropriate
122     * error message
123     */
124    if( timing < SCIP_PRESOLTIMING_NONE || timing > SCIP_PRESOLTIMING_MAX )
125    {
126       SCIPmessagePrintError("ERROR: 'PRESOLDELAY'-flag no longer available since SCIP 3.2, use an appropriate "
127          "'SCIP_PRESOLTIMING' for <%s> presolver instead.\n", name);
128 
129       return SCIP_PARAMETERWRONGVAL;
130    }
131 
132    SCIP_ALLOC( BMSallocMemory(presol) );
133    BMSclearMemory(*presol);
134 
135    SCIP_ALLOC( BMSduplicateMemoryArray(&(*presol)->name, name, strlen(name)+1) );
136    SCIP_ALLOC( BMSduplicateMemoryArray(&(*presol)->desc, desc, strlen(desc)+1) );
137    (*presol)->presolcopy = presolcopy;
138    (*presol)->presolfree = presolfree;
139    (*presol)->presolinit = presolinit;
140    (*presol)->presolexit = presolexit;
141    (*presol)->presolinitpre = presolinitpre;
142    (*presol)->presolexitpre = presolexitpre;
143    (*presol)->presolexec = presolexec;
144    (*presol)->presoldata = presoldata;
145    SCIP_CALL( SCIPclockCreate(&(*presol)->setuptime, SCIP_CLOCKTYPE_DEFAULT) );
146    SCIP_CALL( SCIPclockCreate(&(*presol)->presolclock, SCIP_CLOCKTYPE_DEFAULT) );
147    (*presol)->initialized = FALSE;
148 
149    /* add parameters */
150    (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "presolving/%s/priority", name);
151    (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of presolver <%s>", name);
152    SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
153          &(*presol)->priority, TRUE, priority, INT_MIN/4, INT_MAX/4,
154          paramChgdPresolPriority, (SCIP_PARAMDATA*)(*presol)) ); /*lint !e740*/
155 
156    (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "presolving/%s/maxrounds", name);
157    SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname,
158          "maximal number of presolving rounds the presolver participates in (-1: no limit)",
159          &(*presol)->maxrounds, FALSE, maxrounds, -1, INT_MAX, NULL, NULL) ); /*lint !e740*/
160 
161    (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "presolving/%s/timing", name);
162    (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "timing mask of presolver <%s> (%u:FAST, %u:MEDIUM, %u:EXHAUSTIVE, %u:FINAL)",
163       name, SCIP_PRESOLTIMING_FAST, SCIP_PRESOLTIMING_MEDIUM, SCIP_PRESOLTIMING_EXHAUSTIVE, SCIP_PRESOLTIMING_FINAL);
164    SCIP_CALL( SCIPsetAddIntParam(set, messagehdlr, blkmem, paramname, paramdesc,
165          (int*)&(*presol)->timing, TRUE, (int)timing, (int) SCIP_PRESOLTIMING_FAST, (int) SCIP_PRESOLTIMING_MAX, NULL, NULL) ); /*lint !e740*/
166 
167    return SCIP_OKAY;
168 }
169 
170 /** creates a presolver */
SCIPpresolCreate(SCIP_PRESOL ** presol,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,const char * name,const char * desc,int priority,int maxrounds,SCIP_PRESOLTIMING timing,SCIP_DECL_PRESOLCOPY ((* presolcopy)),SCIP_DECL_PRESOLFREE ((* presolfree)),SCIP_DECL_PRESOLINIT ((* presolinit)),SCIP_DECL_PRESOLEXIT ((* presolexit)),SCIP_DECL_PRESOLINITPRE ((* presolinitpre)),SCIP_DECL_PRESOLEXITPRE ((* presolexitpre)),SCIP_DECL_PRESOLEXEC ((* presolexec)),SCIP_PRESOLDATA * presoldata)171 SCIP_RETCODE SCIPpresolCreate(
172    SCIP_PRESOL**         presol,             /**< pointer to store presolver */
173    SCIP_SET*             set,                /**< global SCIP settings */
174    SCIP_MESSAGEHDLR*     messagehdlr,        /**< message handler */
175    BMS_BLKMEM*           blkmem,             /**< block memory for parameter settings */
176    const char*           name,               /**< name of presolver */
177    const char*           desc,               /**< description of presolver */
178    int                   priority,           /**< priority of the presolver (>= 0: before, < 0: after constraint handlers) */
179    int                   maxrounds,          /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
180    SCIP_PRESOLTIMING     timing,             /**< timing mask of the presolver */
181    SCIP_DECL_PRESOLCOPY  ((*presolcopy)),    /**< copy method of presolver or NULL if you don't want to copy your plugin into sub-SCIPs */
182    SCIP_DECL_PRESOLFREE  ((*presolfree)),    /**< destructor of presolver to free user data (called when SCIP is exiting) */
183    SCIP_DECL_PRESOLINIT  ((*presolinit)),    /**< initialization method of presolver (called after problem was transformed) */
184    SCIP_DECL_PRESOLEXIT  ((*presolexit)),    /**< deinitialization method of presolver (called before transformed problem is freed) */
185    SCIP_DECL_PRESOLINITPRE((*presolinitpre)),/**< presolving initialization method of presolver (called when presolving is about to begin) */
186    SCIP_DECL_PRESOLEXITPRE((*presolexitpre)),/**< presolving deinitialization method of presolver (called after presolving has been finished) */
187    SCIP_DECL_PRESOLEXEC  ((*presolexec)),    /**< execution method of presolver */
188    SCIP_PRESOLDATA*      presoldata          /**< presolver data */
189    )
190 {
191    assert(presol != NULL);
192    assert(name != NULL);
193    assert(desc != NULL);
194 
195    SCIP_CALL_FINALLY( doPresolCreate(presol, set, messagehdlr, blkmem, name, desc, priority, maxrounds, timing,
196       presolcopy, presolfree, presolinit, presolexit, presolinitpre, presolexitpre, presolexec, presoldata),
197       (void) SCIPpresolFree(presol, set) );
198 
199    return SCIP_OKAY;
200 }
201 
202 /** frees memory of presolver */
SCIPpresolFree(SCIP_PRESOL ** presol,SCIP_SET * set)203 SCIP_RETCODE SCIPpresolFree(
204    SCIP_PRESOL**         presol,             /**< pointer to presolver data structure */
205    SCIP_SET*             set                 /**< global SCIP settings */
206    )
207 {
208    assert(presol != NULL);
209    if( *presol == NULL )
210       return SCIP_OKAY;
211    assert(!(*presol)->initialized);
212    assert(set != NULL);
213 
214    /* call destructor of presolver */
215    if( (*presol)->presolfree != NULL )
216    {
217       SCIP_CALL( (*presol)->presolfree(set->scip, *presol) );
218    }
219 
220    SCIPclockFree(&(*presol)->presolclock);
221    SCIPclockFree(&(*presol)->setuptime);
222    BMSfreeMemoryArrayNull(&(*presol)->name);
223    BMSfreeMemoryArrayNull(&(*presol)->desc);
224    BMSfreeMemory(presol);
225 
226    return SCIP_OKAY;
227 }
228 
229 /** initializes presolver */
SCIPpresolInit(SCIP_PRESOL * presol,SCIP_SET * set)230 SCIP_RETCODE SCIPpresolInit(
231    SCIP_PRESOL*          presol,             /**< presolver */
232    SCIP_SET*             set                 /**< global SCIP settings */
233    )
234 {
235    assert(presol != NULL);
236    assert(set != NULL);
237 
238    if( presol->initialized )
239    {
240       SCIPerrorMessage("presolver <%s> already initialized\n", presol->name);
241       return SCIP_INVALIDCALL;
242    }
243 
244    if( set->misc_resetstat )
245    {
246       SCIPclockReset(presol->setuptime);
247       SCIPclockReset(presol->presolclock);
248 
249       presol->lastnfixedvars = 0;
250       presol->lastnaggrvars = 0;
251       presol->lastnchgvartypes = 0;
252       presol->lastnchgbds = 0;
253       presol->lastnaddholes = 0;
254       presol->lastndelconss = 0;
255       presol->lastnaddconss = 0;
256       presol->lastnupgdconss = 0;
257       presol->lastnchgcoefs = 0;
258       presol->lastnchgsides = 0;
259       presol->nfixedvars = 0;
260       presol->naggrvars = 0;
261       presol->nchgvartypes = 0;
262       presol->nchgbds = 0;
263       presol->naddholes = 0;
264       presol->ndelconss = 0;
265       presol->naddconss = 0;
266       presol->nupgdconss = 0;
267       presol->nchgcoefs = 0;
268       presol->nchgsides = 0;
269       presol->ncalls = 0;
270    }
271 
272    /* call initialization method of presolver */
273    if( presol->presolinit != NULL )
274    {
275       /* start timing */
276       SCIPclockStart(presol->setuptime, set);
277 
278       SCIP_CALL( presol->presolinit(set->scip, presol) );
279 
280       /* stop timing */
281       SCIPclockStop(presol->setuptime, set);
282    }
283    presol->initialized = TRUE;
284 
285    return SCIP_OKAY;
286 }
287 
288 /** deinitializes presolver */
SCIPpresolExit(SCIP_PRESOL * presol,SCIP_SET * set)289 SCIP_RETCODE SCIPpresolExit(
290    SCIP_PRESOL*          presol,             /**< presolver */
291    SCIP_SET*             set                 /**< global SCIP settings */
292    )
293 {
294    assert(presol != NULL);
295    assert(set != NULL);
296 
297    if( !presol->initialized )
298    {
299       SCIPerrorMessage("presolver <%s> not initialized\n", presol->name);
300       return SCIP_INVALIDCALL;
301    }
302 
303    /* call deinitialization method of presolver */
304    if( presol->presolexit != NULL )
305    {
306       /* start timing */
307       SCIPclockStart(presol->setuptime, set);
308 
309       SCIP_CALL( presol->presolexit(set->scip, presol) );
310 
311       /* stop timing */
312       SCIPclockStop(presol->setuptime, set);
313    }
314    presol->initialized = FALSE;
315 
316    return SCIP_OKAY;
317 }
318 
319 /** informs presolver that the presolving process is being started */
SCIPpresolInitpre(SCIP_PRESOL * presol,SCIP_SET * set)320 SCIP_RETCODE SCIPpresolInitpre(
321    SCIP_PRESOL*          presol,             /**< presolver */
322    SCIP_SET*             set                 /**< global SCIP settings */
323    )
324 {
325    assert(presol != NULL);
326    assert(set != NULL);
327 
328    presol->lastnfixedvars = 0;
329    presol->lastnaggrvars = 0;
330    presol->lastnchgvartypes = 0;
331    presol->lastnchgbds = 0;
332    presol->lastnaddholes = 0;
333    presol->lastndelconss = 0;
334    presol->lastnaddconss = 0;
335    presol->lastnupgdconss = 0;
336    presol->lastnchgcoefs = 0;
337    presol->lastnchgsides = 0;
338 
339    /* call presolving initialization method of presolver */
340    if( presol->presolinitpre != NULL )
341    {
342       /* start timing */
343       SCIPclockStart(presol->setuptime, set);
344 
345       SCIP_CALL( presol->presolinitpre(set->scip, presol) );
346 
347       /* stop timing */
348       SCIPclockStop(presol->setuptime, set);
349    }
350 
351    return SCIP_OKAY;
352 }
353 
354 /** informs presolver that the presolving process is finished */
SCIPpresolExitpre(SCIP_PRESOL * presol,SCIP_SET * set)355 SCIP_RETCODE SCIPpresolExitpre(
356    SCIP_PRESOL*          presol,             /**< presolver */
357    SCIP_SET*             set                 /**< global SCIP settings */
358    )
359 {
360    assert(presol != NULL);
361    assert(set != NULL);
362 
363    /* call presolving deinitialization method of presolver */
364    if( presol->presolexitpre != NULL )
365    {
366       /* start timing */
367       SCIPclockStart(presol->setuptime, set);
368 
369       SCIP_CALL( presol->presolexitpre(set->scip, presol) );
370 
371       /* stop timing */
372       SCIPclockStop(presol->setuptime, set);
373    }
374 
375    return SCIP_OKAY;
376 }
377 
378 /** executes presolver */
SCIPpresolExec(SCIP_PRESOL * presol,SCIP_SET * set,SCIP_PRESOLTIMING timing,int nrounds,int * nfixedvars,int * naggrvars,int * nchgvartypes,int * nchgbds,int * naddholes,int * ndelconss,int * naddconss,int * nupgdconss,int * nchgcoefs,int * nchgsides,SCIP_RESULT * result)379 SCIP_RETCODE SCIPpresolExec(
380    SCIP_PRESOL*          presol,             /**< presolver */
381    SCIP_SET*             set,                /**< global SCIP settings */
382    SCIP_PRESOLTIMING     timing,             /**< current presolving timing */
383    int                   nrounds,            /**< number of presolving rounds already done */
384    int*                  nfixedvars,         /**< pointer to total number of variables fixed of all presolvers */
385    int*                  naggrvars,          /**< pointer to total number of variables aggregated of all presolvers */
386    int*                  nchgvartypes,       /**< pointer to total number of variable type changes of all presolvers */
387    int*                  nchgbds,            /**< pointer to total number of variable bounds tightened of all presolvers */
388    int*                  naddholes,          /**< pointer to total number of domain holes added of all presolvers */
389    int*                  ndelconss,          /**< pointer to total number of deleted constraints of all presolvers */
390    int*                  naddconss,          /**< pointer to total number of added constraints of all presolvers */
391    int*                  nupgdconss,         /**< pointer to total number of upgraded constraints of all presolvers */
392    int*                  nchgcoefs,          /**< pointer to total number of changed coefficients of all presolvers */
393    int*                  nchgsides,          /**< pointer to total number of changed left/right hand sides of all presolvers */
394    SCIP_RESULT*          result              /**< pointer to store the result of the callback method */
395    )
396 {
397    int nnewfixedvars;
398    int nnewaggrvars;
399    int nnewchgvartypes;
400    int nnewchgbds;
401    int nnewaddholes;
402    int nnewdelconss;
403    int nnewaddconss;
404    int nnewupgdconss;
405    int nnewchgcoefs;
406    int nnewchgsides;
407 
408    assert(presol != NULL);
409    assert(presol->presolexec != NULL);
410    assert(set != NULL);
411    assert(nfixedvars != NULL);
412    assert(naggrvars != NULL);
413    assert(nchgvartypes != NULL);
414    assert(nchgbds != NULL);
415    assert(naddholes != NULL);
416    assert(ndelconss != NULL);
417    assert(naddconss != NULL);
418    assert(nupgdconss != NULL);
419    assert(nchgcoefs != NULL);
420    assert(nchgsides != NULL);
421    assert(result != NULL);
422 
423    *result = SCIP_DIDNOTRUN;
424 
425    /* check number of presolving rounds */
426    if( presol->maxrounds >= 0 && presol->ncalls >= presol->maxrounds )
427       return SCIP_OKAY;
428 
429    /* calculate the number of changes since last call */
430    nnewfixedvars = *nfixedvars - presol->lastnfixedvars;
431    nnewaggrvars = *naggrvars - presol->lastnaggrvars;
432    nnewchgvartypes = *nchgvartypes - presol->lastnchgvartypes;
433    nnewchgbds = *nchgbds - presol->lastnchgbds;
434    nnewaddholes = *naddholes - presol->lastnaddholes;
435    nnewdelconss = *ndelconss - presol->lastndelconss;
436    nnewaddconss = *naddconss - presol->lastnaddconss;
437    nnewupgdconss = *nupgdconss - presol->lastnupgdconss;
438    nnewchgcoefs = *nchgcoefs - presol->lastnchgcoefs;
439    nnewchgsides = *nchgsides - presol->lastnchgsides;
440 
441    /* remember the number of changes prior to the call of the presolver */
442    presol->lastnfixedvars = *nfixedvars;
443    presol->lastnaggrvars = *naggrvars;
444    presol->lastnchgvartypes = *nchgvartypes;
445    presol->lastnchgbds = *nchgbds;
446    presol->lastnaddholes = *naddholes;
447    presol->lastndelconss = *ndelconss;
448    presol->lastnaddconss = *naddconss;
449    presol->lastnupgdconss = *nupgdconss;
450    presol->lastnchgcoefs = *nchgcoefs;
451    presol->lastnchgsides = *nchgsides;
452 
453    /* check, if presolver should be called with the current timing */
454    if( timing & presol->timing )
455    {
456       SCIPsetDebugMsg(set, "calling presolver <%s> with timing %u\n", presol->name, timing);
457 
458       /* start timing */
459       SCIPclockStart(presol->presolclock, set);
460 
461       /* call external method */
462       SCIP_CALL( presol->presolexec(set->scip, presol, nrounds, timing,
463             nnewfixedvars, nnewaggrvars, nnewchgvartypes, nnewchgbds, nnewaddholes,
464             nnewdelconss, nnewaddconss, nnewupgdconss, nnewchgcoefs, nnewchgsides,
465             nfixedvars, naggrvars, nchgvartypes, nchgbds, naddholes,
466             ndelconss, naddconss, nupgdconss, nchgcoefs, nchgsides, result) );
467 
468       /* stop timing */
469       SCIPclockStop(presol->presolclock, set);
470 
471       /* add/count the new changes */
472       presol->nfixedvars += *nfixedvars - presol->lastnfixedvars;
473       presol->naggrvars += *naggrvars - presol->lastnaggrvars;
474       presol->nchgvartypes += *nchgvartypes - presol->lastnchgvartypes;
475       presol->nchgbds += *nchgbds - presol->lastnchgbds;
476       presol->naddholes += *naddholes - presol->lastnaddholes;
477       presol->ndelconss += *ndelconss - presol->lastndelconss;
478       presol->naddconss += *naddconss - presol->lastnaddconss;
479       presol->nupgdconss += *nupgdconss - presol->lastnupgdconss;
480       presol->nchgcoefs += *nchgcoefs - presol->lastnchgcoefs;
481       presol->nchgsides += *nchgsides - presol->lastnchgsides;
482 
483       /* check result code of callback method */
484       if( *result != SCIP_CUTOFF
485          && *result != SCIP_UNBOUNDED
486          && *result != SCIP_SUCCESS
487          && *result != SCIP_DIDNOTFIND
488          && *result != SCIP_DIDNOTRUN )
489       {
490          SCIPerrorMessage("presolver <%s> returned invalid result <%d>\n", presol->name, *result);
491          return SCIP_INVALIDRESULT;
492       }
493 
494       /* increase the number of calls, if the presolver tried to find reductions */
495       if( *result != SCIP_DIDNOTRUN )
496          ++(presol->ncalls);
497    }
498 
499    return SCIP_OKAY;
500 }
501 
502 /** gets user data of presolver */
SCIPpresolGetData(SCIP_PRESOL * presol)503 SCIP_PRESOLDATA* SCIPpresolGetData(
504    SCIP_PRESOL*          presol              /**< presolver */
505    )
506 {
507    assert(presol != NULL);
508 
509    return presol->presoldata;
510 }
511 
512 /** sets user data of presolver; user has to free old data in advance! */
SCIPpresolSetData(SCIP_PRESOL * presol,SCIP_PRESOLDATA * presoldata)513 void SCIPpresolSetData(
514    SCIP_PRESOL*          presol,             /**< presolver */
515    SCIP_PRESOLDATA*      presoldata          /**< new presolver user data */
516    )
517 {
518    assert(presol != NULL);
519 
520    presol->presoldata = presoldata;
521 }
522 
523 /** sets copy method of presolver */
SCIPpresolSetCopy(SCIP_PRESOL * presol,SCIP_DECL_PRESOLCOPY ((* presolcopy)))524 void SCIPpresolSetCopy(
525    SCIP_PRESOL*          presol,             /**< presolver */
526    SCIP_DECL_PRESOLCOPY  ((*presolcopy))     /**< copy method of presolver or NULL if you don't want to copy your plugin into sub-SCIPs */
527    )
528 {
529    assert(presol != NULL);
530 
531    presol->presolcopy = presolcopy;
532 }
533 
534 /** sets destructor method of presolver */
SCIPpresolSetFree(SCIP_PRESOL * presol,SCIP_DECL_PRESOLFREE ((* presolfree)))535 void SCIPpresolSetFree(
536    SCIP_PRESOL*          presol,             /**< presolver */
537    SCIP_DECL_PRESOLFREE  ((*presolfree))     /**< destructor of presolver */
538    )
539 {
540    assert(presol != NULL);
541 
542    presol->presolfree = presolfree;
543 }
544 
545 /** sets initialization method of presolver */
SCIPpresolSetInit(SCIP_PRESOL * presol,SCIP_DECL_PRESOLINIT ((* presolinit)))546 void SCIPpresolSetInit(
547    SCIP_PRESOL*          presol,             /**< presolver */
548    SCIP_DECL_PRESOLINIT  ((*presolinit))     /**< initialize presolver */
549    )
550 {
551    assert(presol != NULL);
552 
553    presol->presolinit = presolinit;
554 }
555 
556 /** sets deinitialization method of presolver */
SCIPpresolSetExit(SCIP_PRESOL * presol,SCIP_DECL_PRESOLEXIT ((* presolexit)))557 void SCIPpresolSetExit(
558    SCIP_PRESOL*          presol,             /**< presolver */
559    SCIP_DECL_PRESOLEXIT  ((*presolexit))     /**< deinitialize presolver */
560    )
561 {
562    assert(presol != NULL);
563 
564    presol->presolexit = presolexit;
565 }
566 
567 /** sets solving process initialization method of presolver */
SCIPpresolSetInitpre(SCIP_PRESOL * presol,SCIP_DECL_PRESOLINITPRE ((* presolinitpre)))568 void SCIPpresolSetInitpre(
569    SCIP_PRESOL*          presol,             /**< presolver */
570    SCIP_DECL_PRESOLINITPRE ((*presolinitpre))/**< solving process initialization method of presolver */
571    )
572 {
573    assert(presol != NULL);
574 
575    presol->presolinitpre = presolinitpre;
576 }
577 
578 /** sets solving process deinitialization method of presolver */
SCIPpresolSetExitpre(SCIP_PRESOL * presol,SCIP_DECL_PRESOLEXITPRE ((* presolexitpre)))579 void SCIPpresolSetExitpre(
580    SCIP_PRESOL*          presol,             /**< presolver */
581    SCIP_DECL_PRESOLEXITPRE ((*presolexitpre))/**< solving process deinitialization method of presolver */
582    )
583 {
584    assert(presol != NULL);
585 
586    presol->presolexitpre = presolexitpre;
587 }
588 
589 /** gets name of presolver */
SCIPpresolGetName(SCIP_PRESOL * presol)590 const char* SCIPpresolGetName(
591    SCIP_PRESOL*          presol              /**< presolver */
592    )
593 {
594    assert(presol != NULL);
595 
596    return presol->name;
597 }
598 
599 /** gets description of presolver */
SCIPpresolGetDesc(SCIP_PRESOL * presol)600 const char* SCIPpresolGetDesc(
601    SCIP_PRESOL*          presol              /**< presolver */
602    )
603 {
604    assert(presol != NULL);
605 
606    return presol->desc;
607 }
608 
609 /** gets priority of presolver */
SCIPpresolGetPriority(SCIP_PRESOL * presol)610 int SCIPpresolGetPriority(
611    SCIP_PRESOL*          presol              /**< presolver */
612    )
613 {
614    assert(presol != NULL);
615 
616    return presol->priority;
617 }
618 
619 /** gets round limit of presolver */
SCIPpresolGetMaxrounds(SCIP_PRESOL * presol)620 int SCIPpresolGetMaxrounds(
621    SCIP_PRESOL*          presol              /**< presolver */
622    )
623 {
624    assert(presol != NULL);
625 
626    return presol->maxrounds;
627 }
628 
629 /** sets priority of presolver */
SCIPpresolSetPriority(SCIP_PRESOL * presol,SCIP_SET * set,int priority)630 void SCIPpresolSetPriority(
631    SCIP_PRESOL*          presol,             /**< presolver */
632    SCIP_SET*             set,                /**< global SCIP settings */
633    int                   priority            /**< new priority of the presolver */
634    )
635 {
636    assert(presol != NULL);
637    assert(set != NULL);
638 
639    presol->priority = priority;
640    set->presolssorted = FALSE;
641 }
642 
643 /** gets the timing mask of the presolver */
SCIPpresolGetTiming(SCIP_PRESOL * presol)644 SCIP_PRESOLTIMING SCIPpresolGetTiming(
645    SCIP_PRESOL*          presol              /**< presolver */
646    )
647 {
648    assert(presol != NULL);
649 
650    return presol->timing;
651 }
652 
653 /** sets the timing mask of the presolver */
SCIPpresolSetTiming(SCIP_PRESOL * presol,SCIP_PRESOLTIMING timing)654 void SCIPpresolSetTiming(
655    SCIP_PRESOL*          presol,             /**< presolver */
656    SCIP_PRESOLTIMING     timing              /**< timing mask of the presolver */
657    )
658 {
659    assert(presol != NULL);
660 
661    presol->timing = timing;
662 }
663 
664 
665 /** is presolver initialized? */
SCIPpresolIsInitialized(SCIP_PRESOL * presol)666 SCIP_Bool SCIPpresolIsInitialized(
667    SCIP_PRESOL*          presol              /**< presolver */
668    )
669 {
670    assert(presol != NULL);
671 
672    return presol->initialized;
673 }
674 
675 /** enables or disables all clocks of \p presol, depending on the value of the flag */
SCIPpresolEnableOrDisableClocks(SCIP_PRESOL * presol,SCIP_Bool enable)676 void SCIPpresolEnableOrDisableClocks(
677    SCIP_PRESOL*          presol,             /**< the presolver for which all clocks should be enabled or disabled */
678    SCIP_Bool             enable              /**< should the clocks of the presolver be enabled? */
679    )
680 {
681    assert(presol != NULL);
682 
683    SCIPclockEnableOrDisable(presol->setuptime, enable);
684    SCIPclockEnableOrDisable(presol->presolclock, enable);
685 }
686 
687 /** gets time in seconds used in this presolver for setting up for next stages */
SCIPpresolGetSetupTime(SCIP_PRESOL * presol)688 SCIP_Real SCIPpresolGetSetupTime(
689    SCIP_PRESOL*          presol              /**< presolver */
690    )
691 {
692    assert(presol != NULL);
693 
694    return SCIPclockGetTime(presol->setuptime);
695 }
696 
697 /** gets time in seconds used in this presolver */
SCIPpresolGetTime(SCIP_PRESOL * presol)698 SCIP_Real SCIPpresolGetTime(
699    SCIP_PRESOL*          presol              /**< presolver */
700    )
701 {
702    assert(presol != NULL);
703 
704    return SCIPclockGetTime(presol->presolclock);
705 }
706 
707 /** gets number of variables fixed in presolver */
SCIPpresolGetNFixedVars(SCIP_PRESOL * presol)708 int SCIPpresolGetNFixedVars(
709    SCIP_PRESOL*          presol              /**< presolver */
710    )
711 {
712    assert(presol != NULL);
713 
714    return presol->nfixedvars;
715 }
716 
717 /** gets number of variables aggregated in presolver */
SCIPpresolGetNAggrVars(SCIP_PRESOL * presol)718 int SCIPpresolGetNAggrVars(
719    SCIP_PRESOL*          presol              /**< presolver */
720    )
721 {
722    assert(presol != NULL);
723 
724    return presol->naggrvars;
725 }
726 
727 /** gets number of variable types changed in presolver */
SCIPpresolGetNChgVarTypes(SCIP_PRESOL * presol)728 int SCIPpresolGetNChgVarTypes(
729    SCIP_PRESOL*          presol              /**< presolver */
730    )
731 {
732    assert(presol != NULL);
733 
734    return presol->nchgvartypes;
735 }
736 
737 /** gets number of bounds changed in presolver */
SCIPpresolGetNChgBds(SCIP_PRESOL * presol)738 int SCIPpresolGetNChgBds(
739    SCIP_PRESOL*          presol              /**< presolver */
740    )
741 {
742    assert(presol != NULL);
743 
744    return presol->nchgbds;
745 }
746 
747 /** gets number of holes added to domains of variables in presolver */
SCIPpresolGetNAddHoles(SCIP_PRESOL * presol)748 int SCIPpresolGetNAddHoles(
749    SCIP_PRESOL*          presol              /**< presolver */
750    )
751 {
752    assert(presol != NULL);
753 
754    return presol->naddholes;
755 }
756 
757 /** gets number of constraints deleted in presolver */
SCIPpresolGetNDelConss(SCIP_PRESOL * presol)758 int SCIPpresolGetNDelConss(
759    SCIP_PRESOL*          presol              /**< presolver */
760    )
761 {
762    assert(presol != NULL);
763 
764    return presol->ndelconss;
765 }
766 
767 /** gets number of constraints added in presolver */
SCIPpresolGetNAddConss(SCIP_PRESOL * presol)768 int SCIPpresolGetNAddConss(
769    SCIP_PRESOL*          presol              /**< presolver */
770    )
771 {
772    assert(presol != NULL);
773 
774    return presol->naddconss;
775 }
776 
777 /** gets number of constraints upgraded in presolver */
SCIPpresolGetNUpgdConss(SCIP_PRESOL * presol)778 int SCIPpresolGetNUpgdConss(
779    SCIP_PRESOL*          presol              /**< presolver */
780    )
781 {
782    assert(presol != NULL);
783 
784    return presol->nupgdconss;
785 }
786 
787 /** gets number of coefficients changed in presolver */
SCIPpresolGetNChgCoefs(SCIP_PRESOL * presol)788 int SCIPpresolGetNChgCoefs(
789    SCIP_PRESOL*          presol              /**< presolver */
790    )
791 {
792    assert(presol != NULL);
793 
794    return presol->nchgcoefs;
795 }
796 
797 /** gets number of constraint sides changed in presolver */
SCIPpresolGetNChgSides(SCIP_PRESOL * presol)798 int SCIPpresolGetNChgSides(
799    SCIP_PRESOL*          presol              /**< presolver */
800    )
801 {
802    assert(presol != NULL);
803 
804    return presol->nchgsides;
805 }
806 
807 /** gets number of times the presolver was called and tried to find reductions */
SCIPpresolGetNCalls(SCIP_PRESOL * presol)808 int SCIPpresolGetNCalls(
809    SCIP_PRESOL*          presol              /**< presolver */
810    )
811 {
812    assert(presol != NULL);
813 
814    return presol->ncalls;
815 }
816