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