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   sepa_rapidlearning.c
26   	 * @ingroup DEFPLUGINS_SEPA
27   	 * @brief  rapidlearning separator
28   	 * @author Timo Berthold
29   	 * @author Jakob Witzig
30   	 */
31   	
32   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33   	
34   	#include <assert.h>
35   	#ifndef NDEBUG
36   	#include <string.h>
37   	#endif
38   	
39   	#include "scip/sepa_rapidlearning.h"
40   	#include "scip/scipdefplugins.h"
41   	#include "scip/heuristics.h"
42   	#include "scip/pub_var.h"
43   	
44   	#define SEPA_NAME              "rapidlearning"
45   	#define SEPA_DESC               "rapid learning heuristic and separator"
46   	#define SEPA_PRIORITY          -1200000
47   	#define SEPA_FREQ                     5
48   	#define SEPA_MAXBOUNDDIST           1.0
49   	#define SEPA_USESSUBSCIP           TRUE /**< does the separator use a secondary SCIP instance? */
50   	#define SEPA_DELAY                FALSE /**< should separation method be delayed, if other separators found cuts? */
51   	
52   	#define DEFAULT_APPLYCONFLICTS     TRUE /**< should the found conflicts be applied in the original SCIP? */
53   	#define DEFAULT_APPLYBDCHGS        TRUE /**< should the found global bound deductions be applied in the original SCIP?
54   	                                         *   apply only if conflicts and incumbent solution will be copied too
55   	                                         */
56   	#define DEFAULT_APPLYINFERVALS     TRUE /**< should the inference values be used as initialization in the original SCIP? */
57   	#define DEFAULT_REDUCEDINFER      FALSE /**< should the inference values only be used when rapid learning found other reductions? */
58   	#define DEFAULT_APPLYPRIMALSOL     TRUE /**< should the incumbent solution be copied to the original SCIP? */
59   	#define DEFAULT_APPLYSOLVED        TRUE /**< should a solved status be copied to the original SCIP? */
60   	
61   	#define DEFAULT_CHECKEXEC          TRUE /**< check whether rapid learning should be executed */
62   	#define DEFAULT_CHECKDEGANERACY    TRUE /**< should local LP degeneracy be checked? */
63   	#define DEFAULT_CHECKDUALBOUND    FALSE /**< should the progress on the dual bound be checked? */
64   	#define DEFAULT_CHECKLEAVES       FALSE /**< should the ratio of leaves proven to be infeasible and exceeding the
65   	                                         *   cutoff bound be checked? */
66   	#define DEFAULT_CHECKOBJ          FALSE /**< should the local objection function be checked? */
67   	#define DEFAULT_CHECKNSOLS         TRUE /**< should the number of solutions found so far be checked? */
68   	#define DEFAULT_MINDEGENERACY       0.7 /**< minimal degeneracy threshold to allow local rapid learning */
69   	#define DEFAULT_MININFLPRATIO      10.0 /**< minimal threshold of inf/obj leaves to allow local rapid learning */
70   	#define DEFAULT_MINVARCONSRATIO     2.0 /**< minimal ratio of unfixed variables in relation to basis size to
71   	                                         *   allow local rapid learning */
72   	#define DEFAULT_NWAITINGNODES      100L /**< number of nodes that should be processed before rapid learning is
73   	                                         *   executed locally based on the progress of the dualbound */
74   	
75   	#define DEFAULT_MAXNVARS          10000 /**< maximum problem size (variables) for which rapid learning will be called */
76   	#define DEFAULT_MAXNCONSS         10000 /**< maximum problem size (constraints) for which rapid learning will be called */
77   	#define DEFAULT_MAXCALLS            100 /**< maximum number of overall calls */
78   	
79   	#define DEFAULT_MINNODES            500 /**< minimum number of nodes considered in rapid learning run */
80   	#define DEFAULT_MAXNODES           5000 /**< maximum number of nodes considered in rapid learning run */
81   	
82   	#define DEFAULT_CONTVARS          FALSE /**< should rapid learning be applied when there are continuous variables? */
83   	#define DEFAULT_CONTVARSQUOT        0.3 /**< maximal portion of continuous variables to apply rapid learning */
84   	#define DEFAULT_LPITERQUOT          0.2 /**< maximal fraction of LP iterations compared to node LP iterations */
85   	#define DEFAULT_COPYCUTS           TRUE /**< should all active cuts from the cutpool of the
86   	                                         *   original scip be copied to constraints of the subscip */
87   	
88   	
89   	/*
90   	 * Data structures
91   	 */
92   	
93   	/** separator data */
94   	struct SCIP_SepaData
95   	{
96   	   SCIP_Real             lpiterquot;         /**< maximal fraction of LP iterations compared to node LP iterations */
97   	   SCIP_Real             mindegeneracy;      /**< minimal degeneracy threshold to allow local rapid learning */
98   	   SCIP_Real             mininflpratio;      /**< minimal threshold of inf/obj leaves to allow local rapid learning */
99   	   SCIP_Real             minvarconsratio;    /**< minimal ratio of unfixed variables in relation to basis size to
100  	                                              *   allow local rapid learning */
101  	   int                   maxnvars;           /**< maximum problem size (variables) for which rapid learning will be called */
102  	   int                   maxnconss;          /**< maximum problem size (constraints) for which rapid learning will be called */
103  	   int                   maxcalls;           /**< maximum number of overall calls */
104  	   int                   minnodes;           /**< minimum number of nodes considered in rapid learning run */
105  	   int                   maxnodes;           /**< maximum number of nodes considered in rapid learning run */
106  	   SCIP_Longint          nwaitingnodes;      /**< number of nodes that should be processed before rapid learning is executed locally
107  	                                              *   based on the progress of the dualbound */
108  	   SCIP_Bool             applybdchgs;        /**< should the found global bound deductions be applied in the original SCIP? */
109  	   SCIP_Bool             applyconflicts;     /**< should the found conflicts be applied in the original SCIP? */
110  	   SCIP_Bool             applyinfervals;     /**< should the inference values be used as initialization in the original SCIP? */
111  	   SCIP_Bool             applyprimalsol;     /**< should the incumbent solution be copied to the original SCIP? */
112  	   SCIP_Bool             applysolved;        /**< should a solved status ba copied to the original SCIP? */
113  	   SCIP_Bool             checkdegeneracy;    /**< should local LP degeneracy be checked? */
114  	   SCIP_Bool             checkdualbound;     /**< should the progress on the dual bound be checked? */
115  	   SCIP_Bool             checkleaves;        /**< should the ratio of leaves proven to be infeasible and exceeding the
116  	                                              *   cutoff bound be checked? */
117  	   SCIP_Bool             checkexec;          /**< check whether rapid learning should be executed */
118  	   SCIP_Bool             checkobj;           /**< should the (local) objective function be checked? */
119  	   SCIP_Bool             checknsols;         /**< should number if solutions found so far be checked? */
120  	   SCIP_Bool             contvars;           /**< should rapid learning be applied when there are continuous variables? */
121  	   SCIP_Real             contvarsquot;       /**< maximal portion of continuous variables to apply rapid learning */
122  	   SCIP_Bool             copycuts;           /**< should all active cuts from cutpool be copied to constraints in
123  	                                              *   subproblem? */
124  	   SCIP_Bool             reducedinfer;       /**< should the inference values only be used when rapid learning found other reductions? */
125  	};
126  	
127  	/*
128  	 * Callback methods of separator
129  	 */
130  	
131  	/** copy method for separator plugins (called when SCIP copies plugins) */
132  	static
133  	SCIP_DECL_SEPACOPY(sepaCopyRapidlearning)
134  	{  /*lint --e{715}*/
135  	   assert(scip != NULL);
136  	   assert(sepa != NULL);
137  	   assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
138  	
139  	   /* call inclusion method of constraint handler */
140  	   SCIP_CALL( SCIPincludeSepaRapidlearning(scip) );
141  	
142  	   return SCIP_OKAY;
143  	}
144  	
145  	/** destructor of separator to free user data (called when SCIP is exiting) */
146  	static
147  	SCIP_DECL_SEPAFREE(sepaFreeRapidlearning)
148  	{  /*lint --e{715}*/
149  	   SCIP_SEPADATA* sepadata;
150  	
151  	   assert(sepa != NULL);
152  	   assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
153  	   assert(scip != NULL);
154  	
155  	   /* free separator data */
156  	   sepadata = SCIPsepaGetData(sepa);
157  	   assert(sepadata != NULL);
158  	   SCIPfreeBlockMemory(scip, &sepadata);
159  	   SCIPsepaSetData(sepa, NULL);
160  	
161  	   return SCIP_OKAY;
162  	}
163  	
164  	
165  	/** setup and solve sub-SCIP */
166  	static
167  	SCIP_RETCODE setupAndSolveSubscipRapidlearning(
168  	   SCIP*                 scip,               /**< SCIP data structure */
169  	   SCIP*                 subscip,            /**< subSCIP data structure */
170  	   SCIP_SEPADATA*        sepadata,           /**< separator data */
171  	   int                   randseed,           /**< global seed shift used in the sub-SCIP */
172  	   SCIP_Bool             global,             /**< should rapid learning run on the global problem? */
173  	   SCIP_RESULT*          result              /**< result pointer */
174  	   )
175  	{
176  	   SCIP_VAR** vars;                          /* original problem's variables */
177  	   SCIP_VAR** subvars;                       /* subproblem's variables */
178  	   SCIP_HASHMAP* varmapfw;                   /* mapping of SCIP variables to sub-SCIP variables */
179  	   SCIP_HASHMAP* varmapbw = NULL;            /* mapping of sub-SCIP variables to SCIP variables */
180  	
181  	   SCIP_CONSHDLR** conshdlrs = NULL;         /* array of constraint handler's that might that might obtain conflicts */
182  	   int* oldnconss = NULL;                    /* number of constraints without rapid learning conflicts */
183  	
184  	   SCIP_Longint nodelimit;                   /* node limit for the subproblem */
185  	
186  	   int nconshdlrs;                           /* size of conshdlr and oldnconss array */
187  	   int nvars;                                /* number of variables */
188  	   int nbinvars;
189  	   int nintvars;
190  	   int nimplvars;
191  	   int implstart;
192  	   int implend;
193  	   int restartnum;                           /* maximal number of conflicts that should be created */
194  	   int i;                                    /* counter */
195  	
196  	   SCIP_Bool success;                        /* was problem creation / copying constraint successful? */
197  	
198  	   SCIP_Bool cutoff;                         /* detected infeasibility */
199  	   int nconflicts;                           /* statistic: number of conflicts applied */
200  	   int nbdchgs;                              /* statistic: number of bound changes applied */
201  	
202  	   SCIP_Bool soladded = FALSE;               /* statistic: was a new incumbent found? */
203  	   SCIP_Bool dualboundchg;                   /* statistic: was a new dual bound found? */
204  	   SCIP_Bool disabledualreductions;          /* TRUE, if dual reductions in sub-SCIP are not valid for original SCIP,
205  	                                              * e.g., because a constraint could not be copied or a primal solution
206  	                                              * could not be copied back */
207  	   int initseed;
208  	   int seedshift;
209  	   SCIP_Bool valid;
210  	
211  	#ifdef SCIP_DEBUG
212  	   int n1startinfers = 0;                    /* statistic: number of one side infer values */
213  	   int n2startinfers = 0;                    /* statistic: number of both side infer values */
214  	#endif
215  	
216  	   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, &nimplvars, NULL) );
217  	
218  	   /* initializing the subproblem */
219  	   SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
220  	   SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(subscip), nvars) );
221  	   valid = FALSE;
222  	
223  	   /* copy the subproblem */
224  	   SCIP_CALL( SCIPcopyConsCompression(scip, subscip, varmapfw, NULL, "rapid", NULL, NULL, 0, global, FALSE, FALSE, TRUE, &valid) );
225  	
226  	   if( sepadata->copycuts )
227  	   {
228  	      /* copies all active cuts from cutpool of sourcescip to linear constraints in targetscip */
229  	      SCIP_CALL( SCIPcopyCuts(scip, subscip, varmapfw, NULL, global, NULL) );
230  	   }
231  	
232  	   /* fill subvars array in the order of the variables of the main SCIP */
233  	   for( i = 0; i < nvars; i++ )
234  	   {
235  	      subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]);
236  	   }
237  	   SCIPhashmapFree(&varmapfw);
238  	
239  	   /* change implicit integer variables to integer type */
240  	   implstart = nbinvars + nintvars;
241  	   implend = nbinvars + nintvars + nimplvars;
242  	   for( i = implstart; i < implend; i++ )
243  	   {
244  	      SCIP_Bool infeasible;
245  	
246  	      if( subvars[i] == NULL )
247  	         continue;
248  	
249  	      assert(SCIPvarGetType(subvars[i]) == SCIP_VARTYPE_IMPLINT);
250  	      SCIP_CALL( SCIPchgVarType(subscip, subvars[i], SCIP_VARTYPE_INTEGER, &infeasible) );
251  	      assert(!infeasible);
252  	   }
253  	
254  	   /* This avoids dual presolving.
255  	    *
256  	    * If the copy is not valid, it should be a relaxation of the problem (constraints might have failed to be copied,
257  	    * but no variables should be missing because we stop earlier anyway if pricers are present).
258  	    * By disabling dual presolving, conflicts and bound changes found in a relaxation are still valid for the original problem.
259  	    */
260  	   if( ! valid )
261  	   {
262  	      SCIP_CALL( SCIPsetBoolParam(subscip, "misc/allowweakdualreds", FALSE) );
263  	      SCIP_CALL( SCIPsetBoolParam(subscip, "misc/allowstrongdualreds", FALSE) );
264  	   }
265  	
266  	   SCIPdebugMsg(scip, "Copying SCIP was%s valid.\n", valid ? "" : " not");
267  	
268  	   /* mimic an FD solver: DFS, no LP solving, 1-FUIP instead of all-FUIP, ... */
269  	   if( SCIPisParamFixed(subscip, "lp/solvefreq") )
270  	   {
271  	      SCIPwarningMessage(scip, "unfixing parameter lp/solvefreq in subscip of rapidlearning\n");
272  	      SCIP_CALL( SCIPunfixParam(subscip, "lp/solvefreq") );
273  	   }
274  	   if( SCIPisParamFixed(subscip, "nodeselection/dfs/stdpriority") )
275  	   {
276  	      SCIPwarningMessage(scip, "unfixing parameter nodeselection/dfs/stdpriority in subscip of rapidlearning\n");
277  	      SCIP_CALL( SCIPunfixParam(subscip, "nodeselection/dfs/stdpriority") );
278  	   }
279  	   SCIP_CALL( SCIPsetEmphasis(subscip, SCIP_PARAMEMPHASIS_CPSOLVER, TRUE) );
280  	
281  	   /* turn off pseudo objective propagation */
282  	   if( !SCIPisParamFixed(subscip, "propagating/pseudoobj/freq") )
283  	   {
284  	      SCIP_CALL( SCIPsetIntParam(subscip, "propagating/pseudoobj/freq", -1) );
285  	   }
286  	
287  	   /* use classic inference branching */
288  	   if( !SCIPisParamFixed(subscip, "branching/inference/useweightedsum") )
289  	   {
290  	      SCIP_CALL( SCIPsetBoolParam(subscip, "branching/inference/useweightedsum", FALSE) );
291  	   }
292  	
293  	   /* only create short conflicts */
294  	   if( !SCIPisParamFixed(subscip, "conflict/maxvarsfac") )
295  	   {
296  	      SCIP_CALL( SCIPsetRealParam(subscip, "conflict/maxvarsfac", 0.05) );
297  	   }
298  	
299  	   /* set node limit for the subproblem based on the number of LP iterations per node,
300  	    * which are a determistic measure for the node processing time.
301  	    *
302  	    * Note: We scale by number of LPs + 1 because the counter is increased after solving the LP.
303  	    */
304  	   nodelimit = SCIPgetNLPIterations(scip) / (SCIPgetNLPs(scip) + 1);
305  	   nodelimit = MAX(sepadata->minnodes, nodelimit);
306  	   nodelimit = MIN(sepadata->maxnodes, nodelimit);
307  	
308  	   /* change global random seed */
309  	   assert(randseed >= 0);
310  	   SCIP_CALL( SCIPgetIntParam(scip, "randomization/randomseedshift", &seedshift) );
311  	
312  	   initseed = ((randseed + seedshift) % INT_MAX);
313  	   SCIP_CALL( SCIPsetIntParam(subscip, "randomization/randomseedshift", initseed) );
314  	
315  	   restartnum = 1000;
316  	
317  	 #ifdef SCIP_DEBUG
318  	   /* for debugging, enable full output */
319  	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 5) );
320  	   SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", -1) );
321  	 #else
322  	   /* disable statistic timing inside sub SCIP and output to console */
323  	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
324  	   SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) );
325  	 #endif
326  	
327  	   /* set limits for the subproblem */
328  	   SCIP_CALL( SCIPcopyLimits(scip, subscip) );
329  	   SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit/5) );
330  	   SCIP_CALL( SCIPsetIntParam(subscip, "limits/restarts", 0) );
331  	   SCIP_CALL( SCIPsetIntParam(subscip, "conflict/restartnum", restartnum) );
332  	
333  	   /* forbid recursive call of heuristics and separators solving subMIPs */
334  	   SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
335  	
336  	   /* disable cutting plane separation */
337  	   SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) );
338  	
339  	   /* disable expensive presolving */
340  	   SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) );
341  	
342  	   /* do not abort subproblem on CTRL-C */
343  	   SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
344  	
345  	   /* add an objective cutoff */
346  	   SCIP_CALL( SCIPsetObjlimit(subscip, SCIPgetUpperbound(scip)) );
347  	
348  	   /* create the variable mapping hash map */
349  	   SCIP_CALL( SCIPhashmapCreate(&varmapbw, SCIPblkmem(scip), nvars) );
350  	
351  	   /* store reversing mapping of variables */
352  	   SCIP_CALL( SCIPtransformProb(subscip) );
353  	   for( i = 0; i < nvars; ++i)
354  	   {
355  	      if( subvars[i] != NULL )
356  	      {
357  	         SCIP_CALL( SCIPhashmapInsert(varmapbw, SCIPvarGetTransVar(subvars[i]), vars[i]) );
358  	      }
359  	   }
360  	
361  	   /* allocate memory for constraints storage. Each constraint that will be created from now on will be a conflict.
362  	    * Therefore, we need to remember oldnconss to get the conflicts from the FD search.
363  	    */
364  	   nconshdlrs = 4;
365  	   SCIP_CALL( SCIPallocBufferArray(scip, &conshdlrs, nconshdlrs) );
366  	   SCIP_CALL( SCIPallocBufferArray(scip, &oldnconss, nconshdlrs) );
367  	
368  	   /* store number of constraints before rapid learning search */
369  	   conshdlrs[0] = SCIPfindConshdlr(subscip, "setppc");
370  	   conshdlrs[1] = SCIPfindConshdlr(subscip, "logicor");
371  	   conshdlrs[2] = SCIPfindConshdlr(subscip, "linear");
372  	   conshdlrs[3] = SCIPfindConshdlr(subscip, "bounddisjunction");
373  	
374  	   /* redundant constraints might be eliminated in presolving */
375  	   SCIP_CALL( SCIPpresolve(subscip) );
376  	
377  	   for( i = 0; i < nconshdlrs; ++i)
378  	   {
379  	      if( conshdlrs[i] != NULL )
380  	         oldnconss[i] = SCIPconshdlrGetNConss(conshdlrs[i]);
381  	   }
382  	
383  	   /* solve the subproblem, abort after errors in debug mode */
384  	   SCIP_CALL_ABORT( SCIPsolve(subscip) );
385  	
386  	   /* if problem was already solved do not increase limits to run again */
387  	   if( SCIPgetStage(subscip) == SCIP_STAGE_SOLVED )
388  	   {
389  	      SCIPdebugMsg(scip, "Subscip was completely solved, status %d.\n", SCIPgetStatus(subscip));
390  	   }
391  	   /* abort solving, if limit of applied conflicts is reached */
392  	   else if( SCIPgetNConflictConssApplied(subscip) >= restartnum )
393  	   {
394  	      SCIPdebugMsg(scip, "finish after %" SCIP_LONGINT_FORMAT " successful conflict calls.\n", SCIPgetNConflictConssApplied(subscip));
395  	   }
396  	   /* if the first 20% of the solution process were successful, proceed */
397  	   else if( (sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 && SCIPisFeasLT(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) )
398  	      || (sepadata->applybdchgs && SCIPgetNRootboundChgs(subscip) > 0 )
399  	      || (sepadata->applyconflicts && SCIPgetNConflictConssApplied(subscip) > 0) )
400  	   {
401  	      SCIPdebugMsg(scip, "proceed solving after the first 20%% of the solution process, since:\n");
402  	
403  	      if( SCIPgetNSols(subscip) > 0 && SCIPisFeasLE(scip, SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip) ) )
404  	      {
405  	         SCIPdebugMsg(scip, "   - there was a better solution (%f < %f)\n",SCIPgetUpperbound(subscip), SCIPgetUpperbound(scip));
406  	      }
407  	      if( SCIPgetNRootboundChgs(subscip) > 0 )
408  	      {
409  	         SCIPdebugMsg(scip, "   - there were %d changed variables bounds\n", SCIPgetNRootboundChgs(subscip) );
410  	      }
411  	      if( SCIPgetNConflictConssFound(subscip) > 0 )
412  	      {
413  	         SCIPdebugMsg(scip, "   - there were %" SCIP_LONGINT_FORMAT " conflict constraints created\n", SCIPgetNConflictConssApplied(subscip));
414  	      }
415  	
416  	      /* set node limit to 100% */
417  	      SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", nodelimit) );
418  	
419  	      /* solve the subproblem, abort after errors in debug mode */
420  	      SCIP_CALL_ABORT( SCIPsolve(subscip) );
421  	   }
422  	   else
423  	   {
424  	      SCIPdebugMsg(scip, "do not proceed solving after the first 20%% of the solution process.\n");
425  	   }
426  	
427  	 #ifdef SCIP_DEBUG
428  	   SCIP_CALL( SCIPprintStatistics(subscip, NULL) );
429  	 #endif
430  	
431  	   if( SCIPallowStrongDualReds(scip) )
432  	      disabledualreductions = FALSE;
433  	   else
434  	      disabledualreductions = TRUE;
435  	
436  	   /* check, whether a solution was found */
437  	   if( sepadata->applyprimalsol && SCIPgetNSols(subscip) > 0 )
438  	   {
439  	      SCIP_SOL** subsols;
440  	      int nsubsols;
441  	
442  	      /* check, whether a solution was found;
443  	       * due to numerics, it might happen that not all solutions are feasible -> try all solutions until was declared to be feasible
444  	       */
445  	      nsubsols = SCIPgetNSols(subscip);
446  	      subsols = SCIPgetSols(subscip);
447  	      soladded = FALSE;
448  	
449  	      /* try adding solution from subSCIP to SCIP, until finding one that is accepted */
450  	      for( i = 0; i < nsubsols && !soladded; ++i )
451  	      {
452  	         SCIP_SOL* newsol;
453  	
454  	         SCIP_CALL( SCIPtranslateSubSol(scip, subscip, subsols[i], NULL, subvars, &newsol) );
455  	         SCIP_CALL( SCIPtrySolFree(scip, &newsol, FALSE, FALSE, TRUE, TRUE, TRUE, &soladded) );
456  	      }
457  	      if( !soladded || !SCIPisEQ(scip, SCIPgetSolOrigObj(subscip, subsols[i-1]), SCIPgetSolOrigObj(subscip, subsols[0])) )
458  	         disabledualreductions = TRUE;
459  	   }
460  	
461  	   /* if the sub problem was solved completely, we update the dual bound */
462  	   dualboundchg = FALSE;
463  	   if( sepadata->applysolved && !disabledualreductions
464  	      && (SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL || SCIPgetStatus(subscip) == SCIP_STATUS_INFEASIBLE) )
465  	   {
466  	      /* we need to multiply the dualbound with the scaling factor and add the offset,
467  	       * because this information has been disregarded in the sub-SCIP
468  	       */
469  	      SCIPdebugMsg(scip, "Update old dualbound %g to new dualbound %g.\n",
470  	         SCIPgetDualbound(scip), SCIPretransformObj(scip, SCIPgetDualbound(subscip)));
471  	
472  	      SCIP_CALL( SCIPupdateLocalDualbound(scip, SCIPretransformObj(scip, SCIPgetDualbound(subscip))) );
473  	      dualboundchg = TRUE;
474  	   }
475  	
476  	   /* check, whether conflicts were created */
477  	   nconflicts = 0;
478  	   if( sepadata->applyconflicts && !disabledualreductions && SCIPgetNConflictConssApplied(subscip) > 0 )
479  	   {
480  	      SCIP_HASHMAP* consmap;
481  	      int hashtablesize;
482  	      int nmaxconfs;
483  	
484  	      assert(SCIPgetNConflictConssApplied(subscip) < (SCIP_Longint) INT_MAX);
485  	      hashtablesize = (int) SCIPgetNConflictConssApplied(subscip);
486  	      assert(hashtablesize < INT_MAX/5);
487  	
488  	      /* create the variable mapping hash map */
489  	      SCIP_CALL( SCIPhashmapCreate(&consmap, SCIPblkmem(scip), hashtablesize) );
490  	
491  	      SCIP_CALL( SCIPgetIntParam(scip, "conflict/maxconss", &nmaxconfs) );
492  	      if( global )
493  	         nmaxconfs *= 20;
494  	
495  	      /* loop over all constraint handlers that might contain conflict constraints
496  	       * @todo select promising constraints and not greedy
497  	       */
498  	      for( i = 0; i < nconshdlrs && nconflicts < nmaxconfs; ++i)
499  	      {
500  	         /* copy constraints that have been created in FD run */
501  	         if( conshdlrs[i] != NULL && SCIPconshdlrGetNConss(conshdlrs[i]) > oldnconss[i] )
502  	         {
503  	            SCIP_CONS** conss;
504  	            int c;
505  	            int nconss;
506  	
507  	            nconss = SCIPconshdlrGetNConss(conshdlrs[i]);
508  	            conss = SCIPconshdlrGetConss(conshdlrs[i]);
509  	
510  	            /* loop over all constraints that have been added in sub-SCIP run, these are the conflicts */
511  	            for( c = oldnconss[i]; c < nconss && nconflicts < nmaxconfs; ++c)
512  	            {
513  	               SCIP_CONS* cons;
514  	               SCIP_CONS* conscopy;
515  	
516  	               cons = conss[c];
517  	               assert(cons != NULL);
518  	
519  	               success = FALSE;
520  	
521  	               /* @todo assert that flags are as they should be for conflicts */
522  	               SCIP_CALL( SCIPgetConsCopy(subscip, scip, cons, &conscopy, conshdlrs[i], varmapbw, consmap, NULL,
523  	                     SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
524  	                     SCIPconsIsPropagated(cons), !global, FALSE, SCIPconsIsDynamic(cons),
525  	                     SCIPconsIsRemovable(cons), FALSE, TRUE, &success) );
526  	
527  	               if( success )
528  	               {
529  	                  nconflicts++;
530  	
531  	                  SCIP_CALL( SCIPaddConflict(scip, global ? NULL : SCIPgetCurrentNode(scip), conscopy, NULL,
532  	                     SCIP_CONFTYPE_UNKNOWN, FALSE) );
533  	               }
534  	               else
535  	               {
536  	                  SCIPdebugMsg(scip, "failed to copy conflict constraint %s back to original SCIP\n", SCIPconsGetName(cons));
537  	               }
538  	            }
539  	         }
540  	      }
541  	      SCIPhashmapFree(&consmap);
542  	   }
543  	
544  	   /* check, whether tighter (global) bounds were detected */
545  	   cutoff = FALSE;
546  	   nbdchgs = 0;
547  	   if( sepadata->applybdchgs && !disabledualreductions )
548  	   {
549  	      for( i = 0; i < nvars; ++i )
550  	      {
551  	         SCIP_Bool tightened;
552  	
553  	         if( subvars[i] == NULL )
554  	            continue;
555  	
556  	         assert(SCIPisLE(scip, SCIPvarGetLbGlobal(vars[i]), SCIPvarGetLbGlobal(subvars[i])));
557  	         assert(SCIPisLE(scip, SCIPvarGetLbGlobal(subvars[i]), SCIPvarGetUbGlobal(subvars[i])));
558  	         assert(SCIPisLE(scip, SCIPvarGetUbGlobal(subvars[i]), SCIPvarGetUbGlobal(vars[i])));
559  	
560  	         /* update the bounds of the original SCIP, if a better bound was proven in the sub-SCIP */
561  	         if( global )
562  	         {
563  	#ifndef NDEBUG
564  	            assert(SCIPgetEffectiveRootDepth(scip) == SCIPgetDepth(scip));
565  	#else
566  	            if( SCIPgetEffectiveRootDepth(scip) < SCIPgetDepth(scip) )
567  	               return SCIP_INVALIDCALL;
568  	#endif
569  	            tightened = FALSE;
570  	
571  	            SCIP_CALL( SCIPtightenVarUbGlobal(scip, vars[i], SCIPvarGetUbGlobal(subvars[i]), FALSE, &cutoff, &tightened) );
572  	
573  	            if( cutoff )
574  	               break;
575  	
576  	            if( tightened )
577  	               nbdchgs++;
578  	
579  	            tightened = FALSE;
580  	
581  	            SCIP_CALL( SCIPtightenVarLbGlobal(scip, vars[i], SCIPvarGetLbGlobal(subvars[i]), FALSE, &cutoff, &tightened) );
582  	
583  	            if( cutoff )
584  	               break;
585  	
586  	            if( tightened )
587  	               nbdchgs++;
588  	         }
589  	         else
590  	         {
591  	            tightened = FALSE;
592  	
593  	            SCIP_CALL( SCIPtightenVarUb(scip, vars[i], SCIPvarGetUbGlobal(subvars[i]), FALSE, &cutoff, &tightened) );
594  	
595  	            if( cutoff )
596  	               break;
597  	
598  	            if( tightened )
599  	               nbdchgs++;
600  	
601  	            tightened = FALSE;
602  	
603  	            SCIP_CALL( SCIPtightenVarLb(scip, vars[i], SCIPvarGetLbGlobal(subvars[i]), FALSE, &cutoff, &tightened) );
604  	
605  	            if( cutoff )
606  	               break;
607  	
608  	            if( tightened )
609  	               nbdchgs++;
610  	         }
611  	      }
612  	   }
613  	
614  	   /* install start values for inference branching */
615  	   /* @todo use different nbranching counters for pseudo cost and inference values and update inference values in the tree */
616  	   if( sepadata->applyinfervals && global && (!sepadata->reducedinfer || soladded || nbdchgs + nconflicts > 0) )
617  	   {
618  	      for( i = 0; i < nvars; ++i )
619  	      {
620  	         SCIP_Real downinfer;
621  	         SCIP_Real upinfer;
622  	         SCIP_Real downvsids;
623  	         SCIP_Real upvsids;
624  	         SCIP_Real downconflen;
625  	         SCIP_Real upconflen;
626  	
627  	         if( subvars[i] == NULL )
628  	            continue;
629  	
630  	         /* copy downwards branching statistics */
631  	         downvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS);
632  	         downconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS);
633  	         downinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_DOWNWARDS);
634  	
635  	         /* copy upwards branching statistics */
636  	         upvsids = SCIPgetVarVSIDS(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS);
637  	         upconflen = SCIPgetVarAvgConflictlength(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS);
638  	         upinfer = SCIPgetVarAvgInferences(subscip, subvars[i], SCIP_BRANCHDIR_UPWARDS);
639  	
640  	#ifdef SCIP_DEBUG
641  	         /* memorize statistics */
642  	         if( downinfer+downconflen+downvsids > 0.0 || upinfer+upconflen+upvsids != 0 )
643  	            n1startinfers++;
644  	
645  	         if( downinfer+downconflen+downvsids > 0.0 && upinfer+upconflen+upvsids != 0 )
646  	            n2startinfers++;
647  	#endif
648  	
649  	         SCIP_CALL( SCIPinitVarBranchStats(scip, vars[i], 0.0, 0.0, downvsids, upvsids, downconflen, upconflen, downinfer, upinfer, 0.0, 0.0) );
650  	      }
651  	   }
652  	
653  	#ifdef SCIP_DEBUG
654  	   if( cutoff )
655  	   {
656  	      SCIPdebugMsg(scip, "Rapidlearning detected %s infeasibility.\n", global ? "global" : "local");
657  	   }
658  	
659  	   SCIPdebugMsg(scip, "Rapidlearning added %d %s conflicts, changed %d bounds, %s primal solution, %s dual bound improvement.\n",
660  	      nconflicts, global ? "global" : "local", nbdchgs, soladded ? "found" : "no",  dualboundchg ? "found" : "no");
661  	
662  	   SCIPdebugMsg(scip, "YYY Infervalues initialized on one side: %5.2f %% of variables, %5.2f %% on both sides\n",
663  	      100.0 * n1startinfers/(SCIP_Real)nvars, 100.0 * n2startinfers/(SCIP_Real)nvars);
664  	#endif
665  	
666  	   /* change result pointer */
667  	   if( cutoff )
668  	      *result = SCIP_CUTOFF;
669  	   else if( nconflicts > 0 || dualboundchg )
670  	      *result = SCIP_CONSADDED;
671  	   else if( nbdchgs > 0 )
672  	      *result = SCIP_REDUCEDDOM;
673  	
674  	   /* free local data */
675  	   assert(oldnconss != NULL);
676  	   assert(conshdlrs != NULL);
677  	   assert(varmapbw != NULL);
678  	   SCIPfreeBufferArray(scip, &oldnconss);
679  	   SCIPfreeBufferArray(scip, &conshdlrs);
680  	   SCIPhashmapFree(&varmapbw);
681  	
682  	   /* free subproblem */
683  	   SCIPfreeBufferArray(scip, &subvars);
684  	
685  	   return SCIP_OKAY;
686  	}
687  	
688  	/** returns whether rapid learning is allowed to run locally */
689  	static
690  	SCIP_RETCODE checkExec(
691  	   SCIP*                 scip,               /**< SCIP data structure */
692  	   SCIP_SEPADATA*        sepadata,           /**< separator's private data */
693  	   SCIP_Bool*            run                 /**< pointer to store whether rapid learning is allowed to run */
694  	   )
695  	{
696  	   assert(scip != NULL);
697  	   assert(sepadata != NULL);
698  	
699  	   *run = FALSE;
700  	
701  	   /* return TRUE if local exec should not be checked */
702  	   if( !sepadata->checkexec )
703  	   {
704  	      *run = TRUE;
705  	   }
706  	
707  	   /* problem has zero objective function, i.e., it is a pure feasibility problem */
708  	   if( !(*run) && sepadata->checkobj && SCIPgetNObjVars(scip) == 0 )
709  	   {
710  	         SCIPdebugMsg(scip, "-> allow local rapid learning due to global zero objective\n");
711  	
712  	         *run = TRUE;
713  	   }
714  	
715  	   /* check whether a solution was found */
716  	   if( !(*run) && sepadata->checknsols && SCIPgetNSolsFound(scip) == 0 )
717  	   {
718  	      SCIPdebugMsg(scip, "-> allow local rapid learning due to no solution found so far\n");
719  	
720  	      *run = TRUE;
721  	   }
722  	
723  	   /* check whether the dual bound has not changed since the root node */
724  	   if( !(*run) && sepadata->checkdualbound && sepadata->nwaitingnodes < SCIPgetNNodes(scip) )
725  	   {
726  	      SCIP_Real rootdualbound;
727  	      SCIP_Real locdualbound;
728  	
729  	      rootdualbound = SCIPgetLowerboundRoot(scip);
730  	      locdualbound = SCIPgetLocalLowerbound(scip);
731  	
732  	      if( SCIPisEQ(scip, rootdualbound, locdualbound) )
733  	      {
734  	         SCIPdebugMsg(scip, "-> allow local rapid learning due to equal dualbound\n");
735  	
736  	         *run = TRUE;
737  	      }
738  	   }
739  	
740  	   /* check leaf nodes */
741  	   if( !(*run) && sepadata->checkleaves )
742  	   {
743  	      SCIP_Real ratio = (SCIPgetNInfeasibleLeaves(scip) + 1.0) / (SCIPgetNObjlimLeaves(scip) + 1.0);
744  	
745  	      if( SCIPisLE(scip, sepadata->mininflpratio, ratio) )
746  	      {
747  	         SCIPdebugMsg(scip, "-> allow local rapid learning due to inf/obj leaves ratio\n");
748  	
749  	         *run = TRUE;
750  	      }
751  	   }
752  	
753  	   /* check whether all undecided integer variables have zero objective coefficient */
754  	   if( !(*run) && sepadata->checkobj )
755  	   {
756  	      SCIP_Bool allzero;
757  	      SCIP_VAR** vars;
758  	      int ndiscvars;
759  	      int i;
760  	
761  	      allzero = TRUE;
762  	      vars = SCIPgetVars(scip);
763  	      ndiscvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip);
764  	
765  	      for( i = 0; i < ndiscvars; i++ )
766  	      {
767  	         assert(SCIPvarIsIntegral(vars[i]));
768  	
769  	         /* skip locally fixed variables */
770  	         if( SCIPisEQ(scip, SCIPvarGetLbLocal(vars[i]), SCIPvarGetUbLocal(vars[i])) )
771  	            continue;
772  	
773  	         if( !SCIPisZero(scip, SCIPvarGetObj(vars[i])) )
774  	         {
775  	            allzero = FALSE;
776  	            break;
777  	         }
778  	      }
779  	
780  	      if( allzero )
781  	      {
782  	         SCIPdebugMsg(scip, "-> allow local rapid learning due to local zero objective\n");
783  	
784  	         *run = TRUE;
785  	      }
786  	   }
787  	
788  	   /* check degeneracy */
789  	   if( !(*run) && sepadata->checkdegeneracy )
790  	   {
791  	      SCIP_Real degeneracy;
792  	      SCIP_Real varconsratio;
793  	
794  	      SCIP_CALL( SCIPgetLPDualDegeneracy(scip, &degeneracy, &varconsratio) );
795  	
796  	      SCIPdebugMsg(scip, "degeneracy: %.2f ratio: %.2f\n", degeneracy, varconsratio);
797  	
798  	      if( degeneracy >= sepadata->mindegeneracy || varconsratio >= sepadata->minvarconsratio )
799  	      {
800  	         SCIPdebugMsg(scip, "-> allow local rapid learning due to degeneracy\n");
801  	
802  	         *run = TRUE;
803  	      }
804  	   }
805  	
806  	   return SCIP_OKAY;
807  	}
808  	
809  	/** LP solution separation method of separator */
810  	static
811  	SCIP_DECL_SEPAEXECLP(sepaExeclpRapidlearning)
812  	{/*lint --e{715}*/
813  	   SCIP_VAR** vars;
814  	   SCIP* subscip;
815  	   SCIP_SEPADATA* sepadata;
816  	   SCIP_Bool global;
817  	   SCIP_Bool run;
818  	   SCIP_Bool success;
819  	   SCIP_RETCODE retcode;
820  	   int ndiscvars;
821  	   int i;
822  	
823  	   assert(sepa != NULL);
824  	   assert(scip != NULL);
825  	   assert(result != NULL);
826  	
827  	   *result = SCIP_DIDNOTRUN;
828  	
829  	   ndiscvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip);
830  	
831  	   /* only run when still not fixed binary variables exists */
832  	   if( ndiscvars == 0 )
833  	      return SCIP_OKAY;
834  	
835  	   /* get separator's data */
836  	   sepadata = SCIPsepaGetData(sepa);
837  	   assert(sepadata != NULL);
838  	
839  	   /* call separator at most maxcalls times */
840  	   if( SCIPsepaGetNCalls(sepa) >= sepadata->maxcalls )
841  	      return SCIP_OKAY;
842  	
843  	   /* only run for integer programs */
844  	   if( !sepadata->contvars && ndiscvars != SCIPgetNVars(scip) )
845  	      return SCIP_OKAY;
846  	
847  	   /* only run if there are few enough continuous variables */
848  	   if( sepadata->contvars && SCIPgetNContVars(scip) > sepadata->contvarsquot * SCIPgetNVars(scip) )
849  	      return SCIP_OKAY;
850  	
851  	   /* do not run if pricers are present */
852  	   if( SCIPgetNActivePricers(scip) > 0 )
853  	      return SCIP_OKAY;
854  	
855  	   /* if the separator should be exclusive to the root node, this prevents multiple calls due to restarts */
856  	   if( SCIPsepaGetFreq(sepa) == 0 && SCIPsepaGetNCalls(sepa) > 0 )
857  	      return SCIP_OKAY;
858  	
859  	   /* call separator at most once per node */
860  	   if( SCIPsepaGetNCallsAtNode(sepa) > 0 )
861  	      return SCIP_OKAY;
862  	
863  	   /* the information deduced from rapid learning is globally valid only if we are at the root node; thus we can't use
864  	    * the depth argument of the callback
865  	    */
866  	   global = (SCIPgetDepth(scip) <= SCIPgetEffectiveRootDepth(scip));
867  	
868  	   /* check if rapid learning should be applied locally */
869  	   SCIP_CALL( checkExec(scip, sepadata, &run) );
870  	
871  	   /* @todo check whether we want to run at the root node again, e.g., inf/obj ratio is large enough */
872  	   if( !run )
873  	      return SCIP_OKAY;
874  	
875  	   /* do not call rapid learning, if the problem is too big */
876  	   if( SCIPgetNVars(scip) > sepadata->maxnvars || SCIPgetNConss(scip) > sepadata->maxnconss )
877  	      return SCIP_OKAY;
878  	
879  	   if( SCIPisStopped(scip) )
880  	      return SCIP_OKAY;
881  	
882  	   /* check whether there is enough time and memory left */
883  	   SCIP_CALL( SCIPcheckCopyLimits(scip, &success) );
884  	
885  	   if( !success)
886  	      return SCIP_OKAY;
887  	
888  	   /* skip rapid learning when the sub-SCIP would contain an integer variable with an infinite bound in direction of the
889  	    * objective function; this might lead to very bad branching decisions when enforcing a pseudo solution (#1439)
890  	    */
891  	   vars = SCIPgetVars(scip);
892  	   for( i = SCIPgetNBinVars(scip); i < ndiscvars; i++ )
893  	   {
894  	      SCIP_Real lb = SCIPvarGetLbLocal(vars[i]);
895  	      SCIP_Real ub = SCIPvarGetUbLocal(vars[i]);
896  	      SCIP_Real obj = SCIPvarGetObj(vars[i]);
897  	
898  	      if( (SCIPisNegative(scip, obj) && SCIPisInfinity(scip, ub))
899  	         || (SCIPisPositive(scip, obj) && SCIPisInfinity(scip, -lb)) )
900  	      {
901  	         SCIPdebugMsg(scip, "unbounded integer variable %s (in [%g,%g]) with objective %g -> skip rapid learning\n",
902  	            SCIPvarGetName(vars[i]), lb, ub, obj);
903  	         return SCIP_OKAY;
904  	      }
905  	   }
906  	
907  	   *result = SCIP_DIDNOTFIND;
908  	
909  	   SCIP_CALL( SCIPcreate(&subscip) );
910  	
911  	   retcode = setupAndSolveSubscipRapidlearning(scip, subscip, sepadata, (int)SCIPsepaGetNCalls(sepa)+1, global, result);
912  	
913  	   SCIP_CALL( SCIPfree(&subscip) );
914  	
915  	   return retcode;
916  	}
917  	
918  	
919  	/*
920  	 * separator specific interface methods
921  	 */
922  	
923  	/** creates the rapidlearning separator and includes it in SCIP */
924  	SCIP_RETCODE SCIPincludeSepaRapidlearning(
925  	   SCIP*                 scip                /**< SCIP data structure */
926  	   )
927  	{
928  	   SCIP_SEPADATA* sepadata;
929  	   SCIP_SEPA* sepa;
930  	
931  	   /* create rapidlearning separator data */
932  	   SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
933  	
934  	   /* include separator */
935  	   SCIP_CALL( SCIPincludeSepaBasic(scip, &sepa, SEPA_NAME, SEPA_DESC, SEPA_PRIORITY, SEPA_FREQ, SEPA_MAXBOUNDDIST,
936  	         SEPA_USESSUBSCIP, SEPA_DELAY,
937  	         sepaExeclpRapidlearning, NULL,
938  	         sepadata) );
939  	
940  	   assert(sepa != NULL);
941  	
942  	   /* set non-NULL pointers to callback methods */
943  	   SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyRapidlearning) );
944  	   SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeRapidlearning) );
945  	
946  	   /* add rapidlearning separator parameters */
947  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/applyconflicts",
948  	         "should the found conflicts be applied in the original SCIP?",
949  	         &sepadata->applyconflicts, TRUE, DEFAULT_APPLYCONFLICTS, NULL, NULL) );
950  	
951  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/applybdchgs",
952  	         "should the found global bound deductions be applied in the original SCIP?",
953  	         &sepadata->applybdchgs, TRUE, DEFAULT_APPLYBDCHGS, NULL, NULL) );
954  	
955  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/applyinfervals",
956  	         "should the inference values be used as initialization in the original SCIP?",
957  	         &sepadata->applyinfervals, TRUE, DEFAULT_APPLYINFERVALS, NULL, NULL) );
958  	
959  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/reducedinfer",
960  	         "should the inference values only be used when " SEPA_NAME " found other reductions?",
961  	         &sepadata->reducedinfer, TRUE, DEFAULT_REDUCEDINFER, NULL, NULL) );
962  	
963  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/applyprimalsol",
964  	         "should the incumbent solution be copied to the original SCIP?",
965  	         &sepadata->applyprimalsol, TRUE, DEFAULT_APPLYPRIMALSOL, NULL, NULL) );
966  	
967  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/applysolved",
968  	         "should a solved status be copied to the original SCIP?",
969  	         &sepadata->applysolved, TRUE, DEFAULT_APPLYSOLVED, NULL, NULL) );
970  	
971  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/checkdegeneracy",
972  	         "should local LP degeneracy be checked?",
973  	         &sepadata->checkdegeneracy, TRUE, DEFAULT_CHECKDEGANERACY, NULL, NULL) );
974  	
975  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/checkdualbound",
976  	         "should the progress on the dual bound be checked?",
977  	         &sepadata->checkdualbound, TRUE, DEFAULT_CHECKDUALBOUND, NULL, NULL) );
978  	
979  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/checkleaves",
980  	         "should the ratio of leaves proven to be infeasible and exceeding the cutoff bound be checked?",
981  	         &sepadata->checkleaves, TRUE, DEFAULT_CHECKLEAVES, NULL, NULL) );
982  	
983  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/checkexec",
984  	         "check whether rapid learning should be executed",
985  	         &sepadata->checkexec, TRUE, DEFAULT_CHECKEXEC, NULL, NULL) );
986  	
987  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/checkobj",
988  	         "should the (local) objective function be checked?",
989  	         &sepadata->checkobj, TRUE, DEFAULT_CHECKOBJ, NULL, NULL) );
990  	
991  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/checknsols",
992  	         "should the number of solutions found so far be checked?",
993  	         &sepadata->checknsols, TRUE, DEFAULT_CHECKNSOLS, NULL, NULL) );
994  	
995  	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/contvars",
996  	         "should rapid learning be applied when there are continuous variables?",
997  	         &sepadata->contvars, TRUE, DEFAULT_CONTVARS, NULL, NULL) );
998  	
999  	   SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/contvarsquot",
1000 	         "maximal portion of continuous variables to apply rapid learning",
1001 	         &sepadata->contvarsquot, TRUE, DEFAULT_CONTVARSQUOT, 0.0, 1.0, NULL, NULL) );
1002 	
1003 	   SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/lpiterquot",
1004 	         "maximal fraction of LP iterations compared to node LP iterations",
1005 	         &sepadata->lpiterquot, TRUE, DEFAULT_LPITERQUOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1006 	
1007 	   SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/mindegeneracy",
1008 	         "minimal degeneracy threshold to allow local rapid learning",
1009 	         &sepadata->mindegeneracy, TRUE, DEFAULT_MINDEGENERACY, 0.0, 1.0, NULL, NULL) );
1010 	
1011 	   SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/mininflpratio",
1012 	         "minimal threshold of inf/obj leaves to allow local rapid learning",
1013 	         &sepadata->mininflpratio, TRUE, DEFAULT_MININFLPRATIO, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1014 	
1015 	   SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/minvarconsratio",
1016 	         "minimal ratio of unfixed variables in relation to basis size to allow local rapid learning",
1017 	         &sepadata->minvarconsratio, TRUE, DEFAULT_MINVARCONSRATIO, 1.0, SCIP_REAL_MAX, NULL, NULL) );
1018 	
1019 	   SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxnvars",
1020 	         "maximum problem size (variables) for which rapid learning will be called",
1021 	         &sepadata->maxnvars, TRUE, DEFAULT_MAXNVARS, 0, INT_MAX, NULL, NULL) );
1022 	
1023 	   SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxnconss",
1024 	         "maximum problem size (constraints) for which rapid learning will be called",
1025 	         &sepadata->maxnconss, TRUE, DEFAULT_MAXNCONSS, 0, INT_MAX, NULL, NULL) );
1026 	
1027 	   SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxcalls",
1028 	         "maximum number of overall calls",
1029 	         &sepadata->maxcalls, TRUE, DEFAULT_MAXCALLS, 0, INT_MAX, NULL, NULL) );
1030 	
1031 	   SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxnodes",
1032 	         "maximum number of nodes considered in rapid learning run",
1033 	         &sepadata->maxnodes, TRUE, DEFAULT_MAXNODES, 0, INT_MAX, NULL, NULL) );
1034 	
1035 	   SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/minnodes",
1036 	         "minimum number of nodes considered in rapid learning run",
1037 	         &sepadata->minnodes, TRUE, DEFAULT_MINNODES, 0, INT_MAX, NULL, NULL) );
1038 	
1039 	   SCIP_CALL( SCIPaddLongintParam(scip, "separating/" SEPA_NAME "/nwaitingnodes",
1040 	         "number of nodes that should be processed before rapid learning is executed locally based on the progress of the dualbound",
1041 	         &sepadata->nwaitingnodes, TRUE, DEFAULT_NWAITINGNODES, 0L, SCIP_LONGINT_MAX, NULL, NULL) );
1042 	
1043 	   SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/copycuts",
1044 	         "should all active cuts from cutpool be copied to constraints in subproblem?",
1045 	         &sepadata->copycuts, TRUE, DEFAULT_COPYCUTS, NULL, NULL) );
1046 	
1047 	   return SCIP_OKAY;
1048 	}
1049