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   heur_completesol.c
17   	 * @ingroup DEFPLUGINS_HEUR
18   	 * @brief  COMPLETESOL - primal heuristic trying to complete given partial solutions
19   	 * @author Jakob Witzig
20   	 */
21   	
22   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23   	
24   	#include "blockmemshell/memory.h"
25   	#include "scip/cons_linear.h"
26   	#include "scip/heur_completesol.h"
27   	#include "scip/pub_event.h"
28   	#include "scip/pub_heur.h"
29   	#include "scip/pub_message.h"
30   	#include "scip/pub_misc.h"
31   	#include "scip/pub_sol.h"
32   	#include "scip/pub_var.h"
33   	#include "scip/scip_branch.h"
34   	#include "scip/scip_cons.h"
35   	#include "scip/scip_copy.h"
36   	#include "scip/scip_event.h"
37   	#include "scip/scip_general.h"
38   	#include "scip/scip_heur.h"
39   	#include "scip/scip_mem.h"
40   	#include "scip/scip_message.h"
41   	#include "scip/scip_nlp.h"
42   	#include "scip/scip_nodesel.h"
43   	#include "scip/scip_numerics.h"
44   	#include "scip/scip_param.h"
45   	#include "scip/scip_prob.h"
46   	#include "scip/scip_probing.h"
47   	#include "scip/scip_sol.h"
48   	#include "scip/scip_solve.h"
49   	#include "scip/scip_solvingstats.h"
50   	#include "scip/scip_timing.h"
51   	#include "scip/scip_tree.h"
52   	#include "scip/scip_var.h"
53   	#include <string.h>
54   	
55   	#define HEUR_NAME             "completesol"
56   	#define HEUR_DESC             "primal heuristic trying to complete given partial solutions"
57   	#define HEUR_DISPCHAR         SCIP_HEURDISPCHAR_LNS
58   	#define HEUR_PRIORITY         0
59   	#define HEUR_FREQ             0
60   	#define HEUR_FREQOFS          0
61   	#define HEUR_MAXDEPTH         0
62   	#define HEUR_TIMING           SCIP_HEURTIMING_BEFOREPRESOL | SCIP_HEURTIMING_BEFORENODE
63   	#define HEUR_USESSUBSCIP      TRUE  /**< does the heuristic use a secondary SCIP instance? */
64   	
65   	/* default values for heuristic plugins */
66   	#define DEFAULT_MAXNODES      5000LL    /**< maximum number of nodes to regard in the subproblem */
67   	#define DEFAULT_MAXUNKRATE    0.85      /**< maximum percentage of unknown solution values */
68   	#define DEFAULT_ADDALLSOLS   FALSE      /**< should all subproblem solutions be added to the original SCIP? */
69   	#define DEFAULT_MINNODES      50LL      /**< minimum number of nodes to regard in the subproblem */
70   	#define DEFAULT_NODESOFS      500LL     /**< number of nodes added to the contingent of the total nodes */
71   	#define DEFAULT_NODESQUOT     0.1       /**< subproblem nodes in relation to nodes of the original problem */
72   	#define DEFAULT_LPLIMFAC      2.0       /**< factor by which the limit on the number of LP depends on the node limit */
73   	#define DEFAULT_OBJWEIGHT     1.0       /**< weight of the original objective function (1: only original objective) */
74   	#define DEFAULT_BOUNDWIDENING 0.1       /**< bound widening factor applied to continuous variables
75   	                                         *   (0: round bounds to next integer, 1: relax to global bounds)
76   	                                         */
77   	#define DEFAULT_MINIMPROVE    0.01      /**< factor by which the incumbent should be improved at least */
78   	#define DEFAULT_MINOBJWEIGHT 1e-3       /**< minimal weight for original objective function (zero could lead to infinite solutions) */
79   	#define DEFAULT_IGNORECONT  FALSE       /**< should solution values for continuous variables be ignored? */
80   	#define DEFAULT_BESTSOLS        5       /**< heuristic stops, if the given number of improving solutions were found (-1: no limit) */
81   	#define DEFAULT_MAXPROPROUNDS  10       /**< maximal number of iterations in propagation (-1: no limit) */
82   	#define DEFAULT_MAXLPITER      -1LL     /**< maximal number of LP iterations (-1: no limit) */
83   	#define DEFAULT_MAXCONTVARS    -1       /**< maximal number of continuous variables after presolving (-1: no limit) */
84   	#define DEFAULT_BEFOREPRESOL  TRUE      /**< should the heuristic run before presolving? */
85   	
86   	/* event handler properties */
87   	#define EVENTHDLR_NAME         "Completesol"
88   	#define EVENTHDLR_DESC         "LP event handler for " HEUR_NAME " heuristic"
89   	
90   	
91   	/** primal heuristic data */
92   	struct SCIP_HeurData
93   	{
94   	   SCIP_Longint          maxnodes;           /**< maximum number of nodes to regard in the subproblem */
95   	   SCIP_Longint          minnodes;           /**< minimum number of nodes to regard in the subproblem */
96   	   SCIP_Longint          nodesofs;           /**< number of nodes added to the contingent of the total nodes */
97   	   SCIP_Longint          maxlpiter;          /**< maximal number of LP iterations (-1: no limit) */
98   	   SCIP_Real             maxunknownrate;     /**< maximal rate of changed coefficients in the objective function */
99   	   SCIP_Real             nodesquot;          /**< subproblem nodes in relation to nodes of the original problem */
100  	   SCIP_Real             nodelimit;          /**< the nodelimit employed in the current sub-SCIP, for the event handler*/
101  	   SCIP_Real             lplimfac;           /**< factor by which the limit on the number of LP depends on the node limit */
102  	   SCIP_Real             objweight;          /**< weight of the original objective function (1: only original obj, 0: try to keep to given solution) */
103  	   SCIP_Real             boundwidening;      /**< bound widening factor applied to continuous variables
104  	                                              *   (0: fix variables to given solution values, 1: relax to global bounds)
105  	                                              */
106  	   SCIP_Real             minimprove;         /**< factor by which the incumbent should be improved at least */
107  	   SCIP_Bool             addallsols;         /**< should all subproblem solutions be added to the original SCIP? */
108  	   SCIP_Bool             ignorecont;         /**< should solution values for continuous variables be ignored? */
109  	   SCIP_Bool             beforepresol;       /**< should the heuristic run before presolving? */
110  	   int                   bestsols;           /**< heuristic stops, if the given number of improving solutions were found (-1: no limit) */
111  	   int                   maxcontvars;        /**< maximal number of continuous variables after presolving (-1: no limit) */
112  	   int                   maxproprounds;      /**< maximal number of iterations in propagation (-1: no limit) */
113  	};
114  	
115  	/* ---------------- Callback methods of event handler ---------------- */
116  	
117  	/* exec the event handler
118  	 *
119  	 * we interrupt the solution process
120  	 */
121  	static
122  	SCIP_DECL_EVENTEXEC(eventExecCompletesol)
123  	{
124  	   SCIP_HEURDATA* heurdata;
125  	
126  	   assert(eventhdlr != NULL);
127  	   assert(eventdata != NULL);
128  	   assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
129  	   assert(event != NULL);
130  	   assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_LPSOLVED);
131  	
132  	   heurdata = (SCIP_HEURDATA*)eventdata;
133  	   assert(heurdata != NULL);
134  	
135  	   /* interrupt solution process of sub-SCIP */
136  	   if( SCIPgetNLPs(scip) > heurdata->lplimfac * heurdata->nodelimit )
137  	   {
138  	      SCIPdebugMsg(scip, "interrupt after %" SCIP_LONGINT_FORMAT " LPs\n",SCIPgetNLPs(scip));
139  	      SCIP_CALL( SCIPinterruptSolve(scip) );
140  	   }
141  	
142  	   return SCIP_OKAY;
143  	}
144  	
145  	/** creates a subproblem by fixing a number of variables */
146  	static
147  	SCIP_RETCODE createSubproblem(
148  	   SCIP*                 scip,               /**< original SCIP data structure */
149  	   SCIP*                 subscip,            /**< SCIP data structure for the subproblem */
150  	   SCIP_HEURDATA*        heurdata,           /**< heuristic's private data structure */
151  	   SCIP_VAR**            subvars,            /**< the variables of the subproblem */
152  	   SCIP_SOL*             partialsol,         /**< partial solution */
153  	   SCIP_Bool*            tightened           /**< array to store for which variables we have found bound tightenings */
154  	   )
155  	{
156  	   SCIP_VAR** vars;
157  	   SCIP_CONS* objcons;
158  	   SCIP_Real epsobj;
159  	   SCIP_Real cutoff;
160  	   SCIP_Real upperbound;
161  	   char consobjname[SCIP_MAXSTRLEN];
162  	   int nvars;
163  	   int i;
164  	
165  	   assert(scip != NULL);
166  	   assert(subscip != NULL);
167  	   assert(subvars != NULL);
168  	   assert(heurdata != NULL);
169  	
170  	   /* if there is already a solution, add an objective cutoff */
171  	   if( SCIPgetNSols(scip) > 0 )
172  	   {
173  	      assert(!SCIPisInfinity(scip, SCIPgetUpperbound(scip)));
174  	
175  	      upperbound = SCIPgetUpperbound(scip) - SCIPsumepsilon(scip);
176  	
177  	      if( !SCIPisInfinity(scip, -1.0 * SCIPgetLowerbound(scip)) )
178  	         cutoff = (1 - heurdata->minimprove) * SCIPgetUpperbound(scip) + heurdata->minimprove * SCIPgetLowerbound(scip);
179  	      else
180  	      {
181  	         if( SCIPgetUpperbound(scip) >= 0 )
182  	            cutoff = (1 - heurdata->minimprove) * SCIPgetUpperbound(scip);
183  	         else
184  	            cutoff = (1 + heurdata->minimprove) * SCIPgetUpperbound(scip);
185  	      }
186  	      cutoff = MIN(upperbound, cutoff);
187  	      SCIPdebugMsg(scip, "set cutoff=%g for sub-SCIP\n", cutoff);
188  	   }
189  	   else
190  	      cutoff = SCIPinfinity(scip);
191  	
192  	   /* calculate objective coefficients for all potential epsilons */
193  	   if( SCIPisEQ(scip, heurdata->objweight, 1.0) )
194  	      return SCIP_OKAY;
195  	   else if( !SCIPisInfinity(scip, cutoff) )
196  	      epsobj = 1.0;
197  	   else
198  	   {
199  	      /* divide by objweight to avoid changing objective coefficient of original problem variables */
200  	      epsobj = (1.0 - heurdata->objweight)/heurdata->objweight;
201  	
202  	      /* scale with -1 if we have a maximization problem */
203  	      if( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE )
204  	         epsobj *= -1.0;
205  	   }
206  	
207  	   /* get active variables */
208  	   vars = SCIPgetVars(scip);
209  	   nvars = SCIPgetNVars(scip);
210  	
211  	   objcons = NULL;
212  	
213  	   /* add constraints to measure the distance to the given partial solution */
214  	   for( i = 0; i < nvars; i++ )
215  	   {
216  	      SCIP_Real solval;
217  	      int idx;
218  	
219  	      assert(SCIPvarIsActive(vars[i]));
220  	
221  	      if( subvars[i] == NULL )
222  	         continue;
223  	
224  	      /* add objective function as a constraint, if a primal bound exists */
225  	      if( SCIPisInfinity(scip, cutoff) )
226  	      {
227  	         /* create the constraints */
228  	         if( objcons == NULL )
229  	         {
230  	            SCIP_Real lhs;
231  	            SCIP_Real rhs;
232  	
233  	            if( SCIPgetObjsense(subscip) == SCIP_OBJSENSE_MINIMIZE )
234  	            {
235  	               lhs = -SCIPinfinity(subscip);
236  	               rhs = cutoff;
237  	            }
238  	            else
239  	            {
240  	               lhs = cutoff;
241  	               rhs = SCIPinfinity(subscip);
242  	            }
243  	
244  	            (void)SCIPsnprintf(consobjname, SCIP_MAXSTRLEN, "obj");
245  	            SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &objcons, consobjname, 0, NULL, NULL, lhs, rhs) );
246  	         }
247  	
248  	         /* add the variable to the constraints */
249  	         SCIP_CALL( SCIPaddCoefLinear(subscip, objcons, subvars[i], SCIPvarGetObj(subvars[i])) );
250  	
251  	         /* set objective coefficient to 0.0 */
252  	         SCIP_CALL( SCIPchgVarObj(subscip, subvars[i], 0.0) );
253  	      }
254  	
255  	      solval = SCIPgetSolVal(scip, partialsol, vars[i]);
256  	
257  	      /* skip variables with unknown solution value */
258  	      if( solval == SCIP_UNKNOWN ) /*lint !e777*/
259  	         continue;
260  	
261  	      idx = SCIPvarGetProbindex(vars[i]);
262  	      assert(idx >= 0);
263  	
264  	      /* skip variables where we already found some bound tightenings */
265  	      if( tightened[idx] == FALSE )
266  	      {
267  	         /* special case: vars[i] is binary; we do not add an extra variable, but we mimic the behavior we would get with it.
268  	          * E.g., if the solval is 0.3, setting the variable to 0 would give a cost of 0.3 * epsobj, setting it to 1 gives
269  	          * 0.7 * epsobj. Thus, 0.3 * epsobj can be treated as a constant in the objective function and the variable gets
270  	          * an objective coefficient of 0.4 * epsobj.
271  	          */
272  	         if( SCIPvarIsBinary(vars[i]) )
273  	         {
274  	            SCIP_Real frac = SCIPfeasFrac(scip, solval);
275  	            SCIP_Real objcoef;
276  	
277  	            frac = MIN(frac, 1-frac);
278  	            objcoef = (1 - 2*frac) * epsobj * (int)SCIPgetObjsense(scip);
279  	
280  	            if( solval > 0.5 )
281  	            {
282  	               SCIP_CALL( SCIPchgVarObj(scip, vars[i], -objcoef) );
283  	            }
284  	            else
285  	            {
286  	               SCIP_CALL( SCIPchgVarObj(scip, vars[i], objcoef) );
287  	            }
288  	         }
289  	         else
290  	         {
291  	            SCIP_CONS* conspos;
292  	            SCIP_CONS* consneg;
293  	            SCIP_VAR* eps;
294  	            char consnamepos[SCIP_MAXSTRLEN];
295  	            char consnameneg[SCIP_MAXSTRLEN];
296  	            char epsname[SCIP_MAXSTRLEN];
297  	
298  	            /* create two new variables */
299  	            (void)SCIPsnprintf(epsname, SCIP_MAXSTRLEN, "eps_%s", SCIPvarGetName(subvars[i]));
300  	
301  	            SCIP_CALL( SCIPcreateVarBasic(subscip, &eps, epsname, 0.0, SCIPinfinity(scip), epsobj, SCIP_VARTYPE_CONTINUOUS) );
302  	            SCIP_CALL( SCIPaddVar(subscip, eps) );
303  	
304  	            /* create two constraints */
305  	            (void)SCIPsnprintf(consnamepos, SCIP_MAXSTRLEN, "cons_%s_pos", SCIPvarGetName(subvars[i]));
306  	            (void)SCIPsnprintf(consnameneg, SCIP_MAXSTRLEN, "cons_%s_neq", SCIPvarGetName(subvars[i]));
307  	
308  	            /* x_{i} - s_{i} <= e_{i}   <==>   x_{i} - e_{i} <= s_{i} */
309  	            SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &conspos, consnamepos, 0, NULL, NULL, -SCIPinfinity(scip), solval) );
310  	            SCIP_CALL( SCIPaddCoefLinear(subscip, conspos, subvars[i], 1.0) );
311  	            SCIP_CALL( SCIPaddCoefLinear(subscip, conspos, eps, -1.0) );
312  	            SCIP_CALL( SCIPaddCons(subscip, conspos) );
313  	            SCIP_CALL( SCIPreleaseCons(subscip, &conspos) );
314  	
315  	            /* s_{i} - x_{i} <= e_{i}   <==>   e_{i} - x_{i} >= s_{i} */
316  	            SCIP_CALL( SCIPcreateConsBasicLinear(subscip, &consneg, consnameneg, 0, NULL, NULL, solval, SCIPinfinity(scip)) );
317  	            SCIP_CALL( SCIPaddCoefLinear(subscip, consneg, subvars[i], -1.0) );
318  	            SCIP_CALL( SCIPaddCoefLinear(subscip, consneg, eps, 1.0) );
319  	            SCIP_CALL( SCIPaddCons(subscip, consneg) );
320  	            SCIP_CALL( SCIPreleaseCons(subscip, &consneg) );
321  	
322  	            /* release the variables */
323  	            SCIP_CALL( SCIPreleaseVar(subscip, &eps) );
324  	         }
325  	      }
326  	   }
327  	
328  	   /* add and release the constraint representing the original objective function */
329  	   if( objcons != NULL )
330  	   {
331  	      SCIP_CALL( SCIPaddCons(subscip, objcons) );
332  	      SCIP_CALL( SCIPreleaseCons(subscip, &objcons) );
333  	   }
334  	
335  	   return SCIP_OKAY;
336  	}
337  	
338  	/** perform a probing bound change or fixes the variable */
339  	static
340  	SCIP_RETCODE chgProbingBound(
341  	   SCIP*                 scip,               /**< original SCIP data structure */
342  	   SCIP_VAR*             var,                /**< problem variable */
343  	   SCIP_Real             newval,             /**< new bound */
344  	   SCIP_BRANCHDIR        branchdir,          /**< bound change direction */
345  	   SCIP_Bool*            success             /**< pointer to store whether the bound could be tightened */
346  	   )
347  	{
348  	   SCIP_Real ub;
349  	   SCIP_Real lb;
350  	
351  	   assert(scip != NULL);
352  	   assert(var != NULL);
353  	
354  	   (*success) = FALSE;
355  	
356  	   ub = SCIPvarGetUbLocal(var);
357  	   lb = SCIPvarGetLbLocal(var);
358  	
359  	   switch (branchdir) {
360  	   case SCIP_BRANCHDIR_DOWNWARDS:
361  	      if( SCIPisLT(scip, newval, ub) && SCIPisGE(scip, newval, lb) )
362  	      {
363  	         SCIP_CALL( SCIPchgVarUbProbing(scip, var, newval) );
364  	         (*success) = TRUE;
365  	      }
366  	      break;
367  	   case SCIP_BRANCHDIR_UPWARDS:
368  	      if( SCIPisLE(scip, newval, ub) && SCIPisGT(scip, newval, lb) )
369  	      {
370  	         SCIP_CALL( SCIPchgVarLbProbing(scip, var, newval) );
371  	         (*success) = TRUE;
372  	      }
373  	      break;
374  	   case SCIP_BRANCHDIR_FIXED:
375  	      if( SCIPisLE(scip, newval, ub) && SCIPisGE(scip, newval, lb) )
376  	      {
377  	         SCIP_CALL( SCIPfixVarProbing(scip, var, newval) );
378  	         (*success) = TRUE;
379  	      }
380  	      break;
381  	   default:
382  	      return SCIP_INVALIDDATA;
383  	   }/*lint !e788*/
384  	
385  	   return SCIP_OKAY;
386  	}
387  	
388  	/** tries variables bound changes guided by the given solution */
389  	static
390  	SCIP_RETCODE tightenVariables(
391  	   SCIP*                 scip,               /**< original SCIP data structure */
392  	   SCIP_HEURDATA*        heurdata,           /**< heuristic's private data structure */
393  	   SCIP_VAR**            vars,               /**< problem variables */
394  	   int                   nvars,              /**< number of problem variables */
395  	   SCIP_SOL*             sol,                /**< solution to guide the bound changes */
396  	   SCIP_Bool*            tightened,          /**< array to store if variable bound could be tightened */
397  	   SCIP_Bool*            infeasible          /**< pointer to store whether subproblem is infeasible */
398  	   )
399  	{
400  	#ifndef NDEBUG
401  	   SCIP_Bool incontsection;
402  	#endif
403  	   SCIP_Bool abortearly;
404  	   SCIP_Bool cutoff;
405  	   SCIP_Bool probingsuccess;
406  	   SCIP_Longint ndomreds;
407  	   SCIP_Longint ndomredssum;
408  	   int nbndtightenings;
409  	   int v;
410  	
411  	   assert(scip != NULL);
412  	   assert(heurdata != NULL);
413  	   assert(vars != NULL);
414  	   assert(nvars >= 0);
415  	   assert(sol != NULL);
416  	   assert(tightened != NULL);
417  	
418  	   assert(SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_PARTIAL);
419  	
420  	   SCIPdebugMsg(scip, "> start probing along the solution values\n");
421  	
422  	   *infeasible = FALSE;
423  	   abortearly = FALSE;
424  	   nbndtightenings = 0;
425  	   ndomredssum = 0;
426  	#ifndef NDEBUG
427  	   incontsection = FALSE;
428  	#endif
429  	
430  	   /* there is at least one integral variable; open one probing node for all non-continuous variables */
431  	   if( nvars - SCIPgetNContVars(scip) > 0 )
432  	   {
433  	      SCIP_CALL( SCIPnewProbingNode(scip) );
434  	   }
435  	
436  	   for( v = 0; v < nvars && !abortearly; v++ )
437  	   {
438  	      SCIP_Real solval;
439  	
440  	      assert(SCIPvarIsActive(vars[v]));
441  	
442  	      cutoff = FALSE;
443  	      ndomreds = 0;
444  	
445  	#ifndef NDEBUG
446  	      incontsection |= (!SCIPvarIsIntegral(vars[v])); /*lint !e514*/
447  	      assert(!incontsection || !SCIPvarIsIntegral(vars[v]));
448  	#endif
449  	
450  	      /* return if we have found enough domain reductions tightenings */
451  	      if( ndomredssum > 0.3*nvars )
452  	         break;
453  	
454  	      solval = SCIPgetSolVal(scip, sol, vars[v]);
455  	
456  	      /* skip unknown variables */
457  	      if( solval == SCIP_UNKNOWN ) /*lint !e777*/
458  	         continue;
459  	      assert(!SCIPisInfinity(scip, solval) && !SCIPisInfinity(scip, -solval));
460  	
461  	      /* variable is binary or integer */
462  	      if( SCIPvarIsIntegral(vars[v]) )
463  	      {
464  	         /* the solution value is integral, try to fix them */
465  	         if( SCIPisIntegral(scip, solval) )
466  	         {
467  	            SCIP_CALL( chgProbingBound(scip, vars[v], solval, SCIP_BRANCHDIR_FIXED, &probingsuccess) );
468  	            tightened[SCIPvarGetProbindex(vars[v])] = TRUE;
469  	            ++nbndtightenings;
470  	
471  	#ifdef SCIP_MORE_DEBUG
472  	               SCIPdebugMsg(scip, "> fix variable <%s> = [%g,%g] to %g \n", SCIPvarGetName(vars[v]),
473  	                     SCIPvarGetLbGlobal(vars[v]), SCIPvarGetUbGlobal(vars[v]), solval);
474  	#endif
475  	         }
476  	         else
477  	         {
478  	            SCIP_Real ub = SCIPceil(scip, solval) + 1.0;
479  	            SCIP_Real lb = SCIPfloor(scip, solval) - 1.0;
480  	
481  	            /* try tightening of upper bound */
482  	            if( SCIPisLT(scip, ub, SCIPvarGetUbLocal(vars[v])) )
483  	            {
484  	               SCIP_CALL( chgProbingBound(scip, vars[v], solval, SCIP_BRANCHDIR_DOWNWARDS, &probingsuccess) );
485  	               tightened[SCIPvarGetProbindex(vars[v])] = TRUE;
486  	               ++nbndtightenings;
487  	
488  	#ifdef SCIP_MORE_DEBUG
489  	               SCIPdebugMsg(scip, "> tighten upper bound of variable <%s>: %g to %g\n", SCIPvarGetName(vars[v]),
490  	                     SCIPvarGetUbGlobal(vars[v]), ub);
491  	#endif
492  	            }
493  	
494  	            /* try tightening of lower bound */
495  	            if( SCIPisGT(scip, lb, SCIPvarGetLbLocal(vars[v])) )
496  	            {
497  	               SCIP_CALL( chgProbingBound(scip, vars[v], solval, SCIP_BRANCHDIR_UPWARDS, &probingsuccess) );
498  	               tightened[SCIPvarGetProbindex(vars[v])] = TRUE;
499  	               ++nbndtightenings;
500  	
501  	#ifdef SCIP_MORE_DEBUG
502  	               SCIPdebugMsg(scip, "> tighten lower bound of variable <%s>: %g to %g\n", SCIPvarGetName(vars[v]),
503  	                     SCIPvarGetLbGlobal(vars[v]), ub);
504  	#endif
505  	            }
506  	         }
507  	      }
508  	      /* variable is continuous */
509  	      else
510  	      {
511  	         /* fix to lb or ub */
512  	         if( SCIPisEQ(scip, solval, SCIPvarGetLbLocal(vars[v])) || SCIPisEQ(scip, solval, SCIPvarGetUbLocal(vars[v])) )
513  	         {
514  	            /* open a new probing node */
515  	            if( SCIPgetProbingDepth(scip) < SCIP_MAXTREEDEPTH-10 )
516  	            {
517  	               SCIP_CALL( SCIPnewProbingNode(scip) );
518  	
519  	               SCIP_CALL( chgProbingBound(scip, vars[v], solval, SCIP_BRANCHDIR_FIXED, &probingsuccess) );
520  	
521  	               /* skip propagation if the bound could not be changed, e.g., already tightened due to previous
522  	                * domain propagation
523  	                */
524  	               if( probingsuccess )
525  	               {
526  	                  SCIP_CALL( SCIPpropagateProbing(scip, heurdata->maxproprounds, &cutoff, &ndomreds) );
527  	               }
528  	
529  	               if( cutoff )
530  	               {
531  	                  ndomreds = 0;
532  	                  SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
533  	               }
534  	               else
535  	               {
536  	                  assert(SCIPvarGetProbindex(vars[v]) >= 0);
537  	                  tightened[SCIPvarGetProbindex(vars[v])] = TRUE;
538  	                  ++nbndtightenings;
539  	#ifdef SCIP_MORE_DEBUG
540  	                  SCIPdebugMsg(scip, "> fix variable <%s> = [%g,%g] to %g (ndomreds=%lld)\n", SCIPvarGetName(vars[v]),
541  	                        SCIPvarGetLbGlobal(vars[v]), SCIPvarGetUbGlobal(vars[v]), solval, ndomreds);
542  	#endif
543  	               }
544  	            }
545  	            else
546  	               /* abort probing */
547  	               abortearly = TRUE;
548  	         }
549  	         else
550  	         {
551  	            SCIP_Real offset;
552  	            SCIP_Real newub = SCIPvarGetUbGlobal(vars[v]);
553  	            SCIP_Real newlb = SCIPvarGetLbGlobal(vars[v]);
554  	
555  	            /* both bound are finite */
556  	            if( !SCIPisInfinity(scip, -newlb) && !SCIPisInfinity(scip, newub) )
557  	               offset = REALABS(heurdata->boundwidening * (newub-newlb));
558  	            else
559  	            {
560  	               offset = 0.0;
561  	
562  	               /* if exactly one bound is finite, widen bound w.r.t. solution value and finite bound */
563  	               if( !SCIPisInfinity(scip, -newlb) )
564  	                  offset = REALABS(heurdata->boundwidening * (solval-newlb));
565  	               else if( !SCIPisInfinity(scip, newub) )
566  	                  offset = REALABS(heurdata->boundwidening * (newub-solval));
567  	            }
568  	
569  	            /* update bounds */
570  	            newub = SCIPceil(scip, solval) + offset;
571  	            newlb = SCIPfloor(scip, solval) - offset;
572  	
573  	            /* try tightening of upper bound */
574  	            if( SCIPisLT(scip, newub, SCIPvarGetUbLocal(vars[v])) )
575  	            {
576  	               /* open a new probing node */
577  	               if( SCIPgetProbingDepth(scip) < SCIP_MAXTREEDEPTH-10 )
578  	               {
579  	                  SCIP_CALL( SCIPnewProbingNode(scip) );
580  	                  SCIP_CALL( chgProbingBound(scip, vars[v], newub, SCIP_BRANCHDIR_DOWNWARDS, &probingsuccess) );
581  	
582  	                  /* skip propagation if the bound could not be changed, e.g., already tightened due to previous
583  	                   * domain propagation
584  	                   */
585  	                  if( probingsuccess )
586  	                  {
587  	                     SCIP_CALL( SCIPpropagateProbing(scip, heurdata->maxproprounds, &cutoff, &ndomreds) );
588  	                  }
589  	
590  	                  if( cutoff )
591  	                  {
592  	                     ndomreds = 0;
593  	
594  	                     /* backtrack to last feasible probing node */
595  	                     SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
596  	
597  	                     /* we can tighten the lower bound by newub */
598  	                     SCIP_CALL( chgProbingBound(scip, vars[v], newub, SCIP_BRANCHDIR_UPWARDS, &probingsuccess) );
599  	
600  	                     /* propagate the new bound */
601  	                     SCIP_CALL( SCIPpropagateProbing(scip, heurdata->maxproprounds, &cutoff, &ndomreds) );
602  	
603  	                     /* there is no feasible solution w.r.t. the current bounds */
604  	                     if( cutoff )
605  	                     {
606  	                        SCIPdebugMsg(scip, "> subproblem is infeasible within the local bounds\n");
607  	                        *infeasible = TRUE;
608  	                        return SCIP_OKAY;
609  	                     }
610  	#ifdef SCIP_MORE_DEBUG
611  	                     SCIPdebugMsg(scip, "> tighten lower bound of variable <%s>: %g to %g\n",
612  	                           SCIPvarGetName(vars[v]), SCIPvarGetLbGlobal(vars[v]), newub);
613  	#endif
614  	                  }
615  	                  else
616  	                  {
617  	                     assert(SCIPvarGetProbindex(vars[v]) >= 0);
618  	                     tightened[SCIPvarGetProbindex(vars[v])] = TRUE;
619  	                     ++nbndtightenings;
620  	#ifdef SCIP_MORE_DEBUG
621  	                     SCIPdebugMsg(scip, "> tighten upper bound of variable <%s>: %g to %g (ndomreds=%lld)\n",
622  	                           SCIPvarGetName(vars[v]), SCIPvarGetUbGlobal(vars[v]), newub, ndomreds);
623  	#endif
624  	                  }
625  	               }
626  	               else
627  	                  /* abort probing */
628  	                  abortearly = TRUE;
629  	            }
630  	
631  	            /* try tightening of lower bound */
632  	            if( SCIPisGT(scip, newlb, SCIPvarGetLbLocal(vars[v])) )
633  	            {
634  	               /* open a new probing node */
635  	               if( SCIPgetProbingDepth(scip) < SCIP_MAXTREEDEPTH-10 )
636  	               {
637  	                  SCIP_CALL( SCIPnewProbingNode(scip) );
638  	                  SCIP_CALL( chgProbingBound(scip, vars[v], newlb, SCIP_BRANCHDIR_UPWARDS, &probingsuccess) );
639  	
640  	                  /* skip propagation if the bound could not be changed, e.g., already tightened due to previous
641  	                   * domain propagation
642  	                   */
643  	                  if( probingsuccess )
644  	                  {
645  	                     SCIP_CALL( SCIPpropagateProbing(scip, -1, &cutoff, &ndomreds) );
646  	                  }
647  	
648  	                  if( cutoff )
649  	                  {
650  	                     ndomreds = 0;
651  	
652  	                     /* backtrack to last feasible probing node */
653  	                     SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
654  	
655  	                     /* we can tighten the upper bound by newlb */
656  	                     SCIP_CALL( chgProbingBound(scip, vars[v], newlb, SCIP_BRANCHDIR_DOWNWARDS, &probingsuccess) );
657  	
658  	                     /* propagate the new bound */
659  	                     SCIP_CALL( SCIPpropagateProbing(scip, heurdata->maxproprounds, &cutoff, &ndomreds) );
660  	
661  	                     /* there is no feasible solution w.r.t. the current bounds */
662  	                     if( cutoff )
663  	                     {
664  	                        SCIPdebugMsg(scip, "> subproblem is infeasible within the local bounds\n");
665  	                        *infeasible = TRUE;
666  	                        return SCIP_OKAY;
667  	                     }
668  	#ifdef SCIP_MORE_DEBUG
669  	                     SCIPdebugMsg(scip, "> tighten upper bound of variable <%s>: %g to %g\n",
670  	                           SCIPvarGetName(vars[v]), SCIPvarGetUbGlobal(vars[v]), newlb);
671  	#endif
672  	                  }
673  	                  else
674  	                  {
675  	                     assert(SCIPvarGetProbindex(vars[v]) >= 0);
676  	                     tightened[SCIPvarGetProbindex(vars[v])] = TRUE;
677  	                     ++nbndtightenings;
678  	#ifdef SCIP_MORE_DEBUG
679  	                     SCIPdebugMsg(scip, "> tighten lower bound of variable <%s>: %g to %g (ndomreds=%lld)\n",
680  	                           SCIPvarGetName(vars[v]), SCIPvarGetLbGlobal(vars[v]), newlb, ndomreds);
681  	#endif
682  	                  }
683  	               }
684  	               else
685  	                  /* abort probing */
686  	                  abortearly = TRUE;
687  	            }
688  	         }
689  	      }
690  	
691  	      ndomredssum += ndomreds;
692  	   }
693  	
694  	   SCIPdebugMsg(scip, "> found %d bound tightenings and %lld induced domain reductions (abort=%u).\n", nbndtightenings,
695  	         ndomredssum, abortearly);
696  	
697  	   return SCIP_OKAY;
698  	}
699  	
700  	/* setup and solve the sub-SCIP */
701  	static
702  	SCIP_RETCODE setupAndSolve(
703  	   SCIP*                 scip,               /**< original SCIP data structure */
704  	   SCIP*                 subscip,            /**< sub-SCIP data structure */
705  	   SCIP_HEUR*            heur,               /**< heuristic data structure */
706  	   SCIP_HEURDATA*        heurdata,           /**< heuristic's private data structure */
707  	   SCIP_RESULT*          result,             /**< result data structure */
708  	   SCIP_Longint          nstallnodes,        /**< number of stalling nodes for the subproblem */
709  	   SCIP_SOL*             partialsol,         /**< partial solution */
710  	   SCIP_Bool*            tightened           /**< array to store whether a variable was already tightened */
711  	   )
712  	{
713  	   SCIP_HASHMAP* varmapf;
714  	   SCIP_VAR** vars;
715  	   SCIP_VAR** subvars = NULL;
716  	   SCIP_EVENTHDLR* eventhdlr;
717  	   int nvars;
718  	   int i;
719  	
720  	   SCIP_SOL** subsols;
721  	   int nsubsols;
722  	
723  	   SCIP_Bool valid;
724  	   SCIP_Bool success;
725  	   SCIP_RETCODE retcode;
726  	
727  	   assert(scip != NULL);
728  	   assert(subscip != NULL);
729  	   assert(heur != NULL);
730  	   assert(heurdata != NULL);
731  	   assert(result != NULL);
732  	   assert(partialsol != NULL);
733  	
734  	   vars = SCIPgetVars(scip);
735  	   nvars = SCIPgetNVars(scip);
736  	
737  	   /* create the variable mapping hash map */
738  	   SCIP_CALL( SCIPhashmapCreate(&varmapf, SCIPblkmem(subscip), nvars) );
739  	
740  	   eventhdlr = NULL;
741  	   valid = FALSE;
742  	
743  	   /* copy complete SCIP instance */
744  	   SCIP_CALL( SCIPcopyConsCompression(scip, subscip, varmapf, NULL, "completesol", NULL, NULL, 0, FALSE, FALSE, FALSE,
745  	         TRUE, &valid) );
746  	   SCIPdebugMsg(scip, "Copying the SCIP instance returned with valid=%u.\n", valid);
747  	
748  	   /* create event handler for LP events */
749  	   SCIP_CALL( SCIPincludeEventhdlrBasic(subscip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCompletesol, NULL) );
750  	   if( eventhdlr == NULL )
751  	   {
752  	      SCIPerrorMessage("event handler for " HEUR_NAME " heuristic not found.\n");
753  	      return SCIP_PLUGINNOTFOUND;
754  	   }
755  	
756  	   /* allocate memory to align the SCIP and the sub-SCIP variables */
757  	   SCIP_CALL( SCIPallocBufferArray(scip, &subvars, nvars) );
758  	
759  	   /* map all variables */
760  	   for( i = 0; i < nvars; i++ )
761  	     subvars[i] = (SCIP_VAR*) SCIPhashmapGetImage(varmapf, vars[i]);
762  	
763  	   /* free hash map */
764  	   SCIPhashmapFree(&varmapf);
765  	
766  	   /* create a new problem, which fixes variables with same value in bestsol and LP relaxation */
767  	   SCIP_CALL( createSubproblem(scip, subscip, heurdata, subvars, partialsol, tightened) );
768  	   SCIPdebugMsg(scip, "Completesol subproblem: %d vars, %d cons\n", SCIPgetNVars(subscip), SCIPgetNConss(subscip));
769  	
770  	   /* do not abort subproblem on CTRL-C */
771  	   SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
772  	
773  	#ifdef SCIP_DEBUG
774  	   /* for debugging, enable full output */
775  	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", SCIP_VERBLEVEL_FULL) );
776  	   SCIP_CALL( SCIPsetIntParam(subscip, "display/freq", -1) );
777  	#else
778  	   /* disable statistic timing inside sub SCIP and output to console */
779  	   SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", (int) SCIP_VERBLEVEL_NONE) );
780  	   SCIP_CALL( SCIPsetBoolParam(subscip, "timing/statistictiming", FALSE) );
781  	#endif
782  	
783  	   /* set limits for the subproblem */
784  	   SCIP_CALL( SCIPcopyLimits(scip, subscip) );
785  	   heurdata->nodelimit = heurdata->maxnodes;
786  	   SCIP_CALL( SCIPsetLongintParam(subscip, "limits/stallnodes", nstallnodes) );
787  	   SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", heurdata->maxnodes) );
788  	   SCIP_CALL( SCIPsetIntParam(subscip, "limits/bestsol", heurdata->bestsols) );
789  	
790  	   /* limit the number of LP iterations */
791  	   SCIP_CALL( SCIPsetLongintParam(subscip, "lp/iterlim", heurdata->maxlpiter) );
792  	   SCIP_CALL( SCIPsetLongintParam(subscip, "lp/rootiterlim", heurdata->maxlpiter) );
793  	
794  	   /* forbid recursive call of heuristics and separators solving sub-SCIPs */
795  	   SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
796  	
797  	   /* disable cutting plane separation */
798  	   SCIP_CALL( SCIPsetSeparating(subscip, SCIP_PARAMSETTING_OFF, TRUE) );
799  	
800  	   /* disable expensive presolving */
801  	   SCIP_CALL( SCIPsetPresolving(subscip, SCIP_PARAMSETTING_FAST, TRUE) );
802  	
803  	   /* use best estimate node selection */
804  	   if( SCIPfindNodesel(subscip, "estimate") != NULL && !SCIPisParamFixed(subscip, "nodeselection/estimate/stdpriority") )
805  	   {
806  	      SCIP_CALL( SCIPsetIntParam(subscip, "nodeselection/estimate/stdpriority", INT_MAX/4) );
807  	   }
808  	
809  	   /* use inference branching */
(7) Event example_checked: Example 5: "SCIPfindBranchrule(subscip, "inference")" has its value checked in "SCIPfindBranchrule(subscip, "inference") != NULL".
Also see events: [returned_null][example_assign][example_checked][example_checked][example_checked][example_checked][var_assigned][dereference]
810  	   if( SCIPfindBranchrule(subscip, "inference") != NULL && !SCIPisParamFixed(subscip, "branching/inference/priority") )
811  	   {
812  	      SCIP_CALL( SCIPsetIntParam(subscip, "branching/inference/priority", INT_MAX/4) );
813  	   }
814  	
815  	   /* disable conflict analysis */
816  	   if( !SCIPisParamFixed(subscip, "conflict/enable") )
817  	   {
818  	      SCIP_CALL( SCIPsetBoolParam(subscip, "conflict/enable", FALSE) );
819  	   }
820  	
821  	   /* speed up sub-SCIP by not checking dual LP feasibility */
822  	   SCIP_CALL( SCIPsetBoolParam(subscip, "lp/checkdualfeas", FALSE) );
823  	
824  	   SCIP_CALL( SCIPtransformProb(subscip) );
825  	   SCIP_CALL( SCIPcatchEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, NULL) );
826  	
827  	   /* solve the subproblem */
828  	   SCIPdebugMsg(scip, "solving subproblem: nstallnodes=%" SCIP_LONGINT_FORMAT ", maxnodes=%" SCIP_LONGINT_FORMAT "\n", nstallnodes, heurdata->maxnodes);
829  	
830  	   /* errors in solving the subproblem should not kill the overall solving process;
831  	    * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
832  	    */
833  	
834  	   retcode = SCIPpresolve(subscip);
835  	
836  	   /* errors in presolving the subproblem should not kill the overall solving process;
837  	    * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
838  	    */
839  	   if( retcode != SCIP_OKAY )
840  	   {
841  	      SCIPwarningMessage(scip, "Error while presolving subproblem in %s heuristic; sub-SCIP terminated with code <%d>\n", HEUR_NAME, retcode);
842  	
843  	      SCIPABORT(); /*lint --e{527}*/
844  	
845  	      goto TERMINATE;
846  	   }
847  	
848  	   if( SCIPgetStage(subscip) == SCIP_STAGE_PRESOLVED )
849  	   {
850  	      SCIPdebugMsg(scip, "presolved instance has bin=%d, int=%d, cont=%d variables\n",
851  	            SCIPgetNBinVars(subscip), SCIPgetNIntVars(subscip), SCIPgetNContVars(subscip));
852  	
853  	      /* check whether the presolved instance is small enough */
854  	      if( heurdata->maxcontvars >= 0 && SCIPgetNContVars(subscip) > heurdata->maxcontvars )
855  	      {
856  	         SCIPdebugMsg(scip, "presolved instance has too many continuous variables (maxcontvars: %d)\n", heurdata->maxcontvars);
857  	         goto TERMINATE;
858  	      }
859  	
860  	      /* set node limit of 1 if the presolved problem is an LP, otherwise we would start branching if an LP iteration
861  	       * limit was set by the user.
862  	       */
863  	      if( !SCIPisNLPEnabled(subscip) && SCIPgetNContVars(subscip) == SCIPgetNVars(subscip) )
864  	      {
865  	         SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", 1LL) );
866  	      }
867  	
868  	      retcode = SCIPsolve(subscip);
869  	
870  	      /* errors in solving the subproblem should not kill the overall solving process;
871  	       * hence, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
872  	       */
873  	      if( retcode != SCIP_OKAY )
874  	      {
875  	         SCIPwarningMessage(scip, "Error while solving subproblem in %s heuristic; sub-SCIP terminated with code <%d>\n", HEUR_NAME, retcode);
876  	
877  	         SCIPABORT(); /*lint --e{527}*/
878  	
879  	         goto TERMINATE;
880  	      }
881  	   }
882  	
883  	   SCIP_CALL( SCIPdropEvent(subscip, SCIP_EVENTTYPE_LPSOLVED, eventhdlr, (SCIP_EVENTDATA*) heurdata, -1) );
884  	
885  	   /* print solving statistics of subproblem if we are in SCIP's debug mode */
886  	   SCIPdebug( SCIP_CALL( SCIPprintStatistics(subscip, NULL) ) );
887  	
888  	   /* check, whether a solution was found;
889  	    * due to numerics, it might happen that not all solutions are feasible -> try all solutions until one was accepted
890  	    */
891  	   nsubsols = SCIPgetNSols(subscip);
892  	   subsols = SCIPgetSols(subscip);
893  	   success = FALSE;
894  	   for( i = 0; i < nsubsols && (!success || heurdata->addallsols); i++ )
895  	   {
896  	      SCIP_SOL* newsol;
897  	
898  	      /* create new solution, try to add to SCIP, and free it immediately */
899  	      SCIP_CALL( SCIPtranslateSubSol(scip, subscip, subsols[i], heur, subvars, &newsol) );
900  	      SCIP_CALL( SCIPtrySolFree(scip, &newsol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
901  	
902  	      if( success )
903  	         *result = SCIP_FOUNDSOL;
904  	   }
905  	
906  	   SCIPstatisticPrintf("%s statistic: fixed %6.3f integer variables, needed %6.1f seconds, %" SCIP_LONGINT_FORMAT " nodes, solution %10.4f found at node %" SCIP_LONGINT_FORMAT "\n",
907  	      HEUR_NAME, 0.0, SCIPgetSolvingTime(subscip), SCIPgetNNodes(subscip), success ? SCIPgetPrimalbound(scip) : SCIPinfinity(scip),
908  	      nsubsols > 0 ? SCIPsolGetNodenum(SCIPgetBestSol(subscip)) : -1 );
909  	
910  	   /* print message if the completion of a partial solution failed */
911  	   if( *result != SCIP_FOUNDSOL )
912  	   {
913  	      switch( SCIPgetStatus(subscip) )
914  	      {
915  	      case SCIP_STATUS_INFEASIBLE:
916  	         SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "completion of a partial solution failed (subproblem is infeasible)\n");
917  	         break;
918  	      case SCIP_STATUS_NODELIMIT:
919  	         SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "completion of a partial solution failed (node limit exceeded)\n");
920  	         break;
921  	      case SCIP_STATUS_TIMELIMIT:
922  	         SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "completion of a partial solution failed (time limit exceeded)\n");
923  	         break;
924  	      case SCIP_STATUS_MEMLIMIT:
925  	         SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "completion of a partial solution failed (memory limit exceeded)\n");
926  	         break;
927  	      default:
928  	         break;
929  	      } /*lint !e788*/
930  	   }
931  	
932  	TERMINATE:
933  	   SCIPfreeBufferArray(scip, &subvars);
934  	
935  	   return SCIP_OKAY;
936  	}
937  	
938  	/** main procedure of the completesol heuristic, creates and solves a sub-SCIP */
939  	static
940  	SCIP_RETCODE applyCompletesol(
941  	   SCIP*                 scip,               /**< original SCIP data structure */
942  	   SCIP_HEUR*            heur,               /**< heuristic data structure */
943  	   SCIP_HEURDATA*        heurdata,           /**< heuristic's private data structure */
944  	   SCIP_RESULT*          result,             /**< result data structure */
945  	   SCIP_Longint          nstallnodes,        /**< number of stalling nodes for the subproblem */
946  	   SCIP_SOL*             partialsol          /**< partial solution */
947  	   )
948  	{
949  	   SCIP* subscip;
950  	   SCIP_VAR** vars;
951  	   SCIP_Bool* tightened;
952  	   SCIP_Bool infeasible;
953  	   SCIP_Bool success;
954  	   SCIP_RETCODE retcode;
955  	   int nvars;
956  	
957  	   assert(scip != NULL);
958  	   assert(heur != NULL);
959  	   assert(heurdata != NULL);
960  	   assert(result != NULL);
961  	   assert(partialsol != NULL);
962  	
963  	   *result = SCIP_DIDNOTRUN;
964  	
965  	   SCIPdebugMsg(scip, "+---+ Start Completesol heuristic +---+\n");
966  	
967  	   /* check whether there is enough time and memory left */
968  	   SCIP_CALL( SCIPcheckCopyLimits(scip, &success) );
969  	
970  	   if( !success )
971  	      return SCIP_OKAY;
972  	
973  	   *result = SCIP_DIDNOTFIND;
974  	
975  	   /* get variable data */
976  	   vars = SCIPgetVars(scip);
977  	   nvars = SCIPgetNVars(scip);
978  	
979  	   /* get buffer memory and initialize it to FALSE */
980  	   SCIP_CALL( SCIPallocClearBufferArray(scip, &tightened, nvars) );
981  	
982  	   SCIP_CALL( SCIPstartProbing(scip) );
983  	
984  	   SCIP_CALL( tightenVariables(scip, heurdata, vars, nvars, partialsol, tightened, &infeasible) );
985  	
986  	   if( infeasible )
987  	   {
988  	      SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "completion of a partial solution failed (subproblem is infeasible)\n");
989  	      goto ENDPROBING;
990  	   }
991  	
992  	   /* initialize the subproblem */
993  	   SCIP_CALL( SCIPcreate(&subscip) );
994  	
995  	   retcode = setupAndSolve(scip, subscip, heur, heurdata, result, nstallnodes, partialsol, tightened);
996  	
997  	   /* free subproblem */
998  	   SCIP_CALL( SCIPfree(&subscip) );
999  	
1000 	   SCIP_CALL( retcode );
1001 	
1002 	  ENDPROBING:
1003 	   SCIPfreeBufferArray(scip, &tightened);
1004 	   SCIP_CALL( SCIPendProbing(scip) );
1005 	
1006 	   return SCIP_OKAY;
1007 	}
1008 	
1009 	
1010 	/*
1011 	 * Callback methods of primal heuristic
1012 	 */
1013 	
1014 	/** copy method for primal heuristic plugins (called when SCIP copies plugins) */
1015 	static
1016 	SCIP_DECL_HEURCOPY(heurCopyCompletesol)
1017 	{  /*lint --e{715}*/
1018 	   assert(scip != NULL);
1019 	   assert(heur != NULL);
1020 	   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1021 	
1022 	   /* call inclusion method of primal heuristic */
1023 	   SCIP_CALL( SCIPincludeHeurCompletesol(scip) );
1024 	
1025 	   return SCIP_OKAY;
1026 	}
1027 	
1028 	/** destructor of primal heuristic to free user data (called when SCIP is exiting) */
1029 	static
1030 	SCIP_DECL_HEURFREE(heurFreeCompletesol)
1031 	{  /*lint --e{715}*/
1032 	   SCIP_HEURDATA* heurdata;
1033 	
1034 	   assert(heur != NULL);
1035 	   assert(scip != NULL);
1036 	
1037 	   /* get heuristic data */
1038 	   heurdata = SCIPheurGetData(heur);
1039 	   assert(heurdata != NULL);
1040 	
1041 	   /* free heuristic data */
1042 	   SCIPfreeBlockMemory(scip, &heurdata);
1043 	   SCIPheurSetData(heur, NULL);
1044 	
1045 	   return SCIP_OKAY;
1046 	}
1047 	
1048 	/** execution method of primal heuristic */
1049 	static
1050 	SCIP_DECL_HEUREXEC(heurExecCompletesol)
1051 	{/*lint --e{715}*/
1052 	   SCIP_HEURDATA* heurdata;
1053 	   SCIP_VAR** vars;
1054 	   SCIP_SOL** partialsols;
1055 	   SCIP_Longint nstallnodes;
1056 	   int npartialsols;
1057 	   int nunknown;
1058 	   int nfracints;
1059 	   int nvars;
1060 	   int s;
1061 	   int v;
1062 	
1063 	   assert( heur != NULL );
1064 	   assert( scip != NULL );
1065 	   assert( result != NULL );
1066 	
1067 	   *result = SCIP_DELAYED;
1068 	
1069 	   /* do not call heuristic of node was already detected to be infeasible */
1070 	   if( nodeinfeasible )
1071 	      return SCIP_OKAY;
1072 	
1073 	   /* get heuristic data */
1074 	   heurdata = SCIPheurGetData(heur);
1075 	   assert( heurdata != NULL );
1076 	
1077 	   *result = SCIP_DIDNOTRUN;
1078 	
1079 	   if( SCIPisStopped(scip) )
1080 	      return SCIP_OKAY;
1081 	
1082 	   /* do not run after restart */
1083 	   if( SCIPgetNRuns(scip) > 1 )
1084 	      return SCIP_OKAY;
1085 	
1086 	   /* check whether we want to run before presolving */
1087 	   if( (heurtiming & SCIP_HEURTIMING_BEFOREPRESOL) && !heurdata->beforepresol )
1088 	      return SCIP_OKAY;
1089 	
1090 	   /* only run before root node */
1091 	   if( (heurtiming & SCIP_HEURTIMING_BEFORENODE)
1092 	      && (heurdata->beforepresol || SCIPgetCurrentNode(scip) != SCIPgetRootNode(scip)) )
1093 	      return SCIP_OKAY;
1094 	
1095 	   /* get variable data and return of no variables are left in the problem */
1096 	   vars = SCIPgetVars(scip);
1097 	   nvars = SCIPgetNVars(scip);
1098 	
1099 	   if( nvars == 0 )
1100 	      return SCIP_OKAY;
1101 	
1102 	   /* calculate the maximal number of branching nodes until heuristic is aborted */
1103 	   nstallnodes = (SCIP_Longint)(heurdata->nodesquot * SCIPgetNNodes(scip));
1104 	
1105 	   /* reward Completesol if it succeeded often */
1106 	   nstallnodes = (SCIP_Longint)(nstallnodes * 3.0 * (SCIPheurGetNBestSolsFound(heur)+1.0)/(SCIPheurGetNCalls(heur) + 1.0));
1107 	   nstallnodes -= 100 * SCIPheurGetNCalls(heur);  /* count the setup costs for the sub-SCIP as 100 nodes */
1108 	   nstallnodes += heurdata->nodesofs;
1109 	
1110 	   /* determine the node limit for the current process */
1111 	   nstallnodes = MIN(nstallnodes, heurdata->maxnodes);
1112 	
1113 	   /* check whether we have enough nodes left to call subproblem solving */
1114 	   if( nstallnodes < heurdata->minnodes )
1115 	   {
1116 	      SCIPdebugMsg(scip, "skipping Complete: nstallnodes=%" SCIP_LONGINT_FORMAT ", minnodes=%" SCIP_LONGINT_FORMAT "\n",
1117 	         nstallnodes, heurdata->minnodes);
1118 	      return SCIP_OKAY;
1119 	   }
1120 	
1121 	   /* check the number of variables with unknown value and continuous variables with fractional value */
1122 	   nfracints = 0;
1123 	
1124 	   /* get all partial sols */
1125 	   npartialsols = SCIPgetNPartialSols(scip);
1126 	   partialsols = SCIPgetPartialSols(scip);
1127 	
1128 	   /* loop over all partial solutions */
1129 	   for( s = 0; s < npartialsols; s++ )
1130 	   {
1131 	      SCIP_SOL* sol;
1132 	      SCIP_Real solval;
1133 	      SCIP_Real unknownrate;
1134 	
1135 	      sol = partialsols[s];
1136 	      assert(sol != NULL);
1137 	      assert(SCIPsolIsPartial(sol));
1138 	
1139 	      nunknown = 0;
1140 	      /* loop over all variables */
1141 	      for( v = 0; v < nvars; v++ )
1142 	      {
1143 	         assert(SCIPvarIsActive(vars[v]));
1144 	
1145 	         /* skip continuous variables if they should ignored */
1146 	         if( !SCIPvarIsIntegral(vars[v]) && heurdata->ignorecont )
1147 	            continue;
1148 	
1149 	         solval = SCIPgetSolVal(scip, sol, vars[v]);
1150 	
1151 	         /* we only want to count variables that are unfixed after the presolving */
1152 	         if( solval == SCIP_UNKNOWN ) /*lint !e777*/
1153 	            ++nunknown;
1154 	         else if( SCIPvarIsIntegral(vars[v]) && !SCIPisIntegral(scip, solval) )
1155 	            ++nfracints;
1156 	      }
1157 	
1158 	      if( heurdata->ignorecont )
1159 	         unknownrate = nunknown/((SCIP_Real)SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip));
1160 	      else
1161 	         unknownrate = nunknown/((SCIP_Real)nvars);
1162 	      SCIPdebugMsg(scip, "%d (rate %.4f) unknown solution values\n", nunknown, unknownrate);
1163 	
1164 	      /* run the heuristic, if not too many unknown variables exist */
1165 	      if( unknownrate > heurdata->maxunknownrate )
1166 	      {
1167 	         SCIPwarningMessage(scip, "ignore partial solution (%d) because unknown rate is too large (%g > %g)\n", s,
1168 	            unknownrate, heurdata->maxunknownrate);
1169 	         continue;
1170 	      }
1171 	
1172 	      /* all variables have a finite/known solution value all integer variables have an integral solution value,
1173 	       * and there are no continuous variables
1174 	       * in the sub-SCIP, all variables would be fixed, so create a new solution without solving a sub-SCIP
1175 	       */
1176 	      if( nunknown == 0 && nfracints == 0 && SCIPgetNContVars(scip) == 0 && SCIPgetNImplVars(scip) == 0 )
1177 	      {
1178 	         SCIP_SOL* newsol;
1179 	         SCIP_Bool stored;
1180 	
1181 	         assert(vars != NULL);
1182 	         assert(nvars >= 0);
1183 	
1184 	         SCIP_CALL( SCIPcreateSol(scip, &newsol, heur) );
1185 	
1186 	         for( v = 0; v < nvars; v++ )
1187 	         {
1188 	            solval = SCIPgetSolVal(scip, sol, vars[v]);
1189 	            assert(solval != SCIP_UNKNOWN); /*lint !e777*/
1190 	
1191 	            SCIP_CALL( SCIPsetSolVal(scip, newsol, vars[v], solval) );
1192 	         }
1193 	
1194 	         SCIP_CALL( SCIPtrySolFree(scip, &newsol, FALSE, FALSE, TRUE, TRUE, TRUE, &stored) );
1195 	         if( stored )
1196 	            *result = SCIP_FOUNDSOL;
1197 	      }
1198 	      else
1199 	      {
1200 	         /* run the heuristic */
1201 	         SCIP_CALL( applyCompletesol(scip, heur, heurdata, result, nstallnodes, sol) );
1202 	      }
1203 	   }
1204 	
1205 	   return SCIP_OKAY;
1206 	}
1207 	
1208 	
1209 	/*
1210 	 * primal heuristic specific interface methods
1211 	 */
1212 	
1213 	/** creates the completesol primal heuristic and includes it in SCIP */
1214 	SCIP_RETCODE SCIPincludeHeurCompletesol(
1215 	   SCIP*                 scip                /**< SCIP data structure */
1216 	   )
1217 	{
1218 	   SCIP_HEURDATA* heurdata;
1219 	   SCIP_HEUR* heur;
1220 	
1221 	   /* create completesol primal heuristic data */
1222 	   SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
1223 	   assert(heurdata != NULL);
1224 	
1225 	   /* include primal heuristic */
1226 	   SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
1227 	         HEUR_NAME, HEUR_DESC, HEUR_DISPCHAR, HEUR_PRIORITY, HEUR_FREQ, HEUR_FREQOFS,
1228 	         HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecCompletesol, heurdata) );
1229 	
1230 	   assert(heur != NULL);
1231 	
1232 	   /* set non fundamental callbacks via setter functions */
1233 	   SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyCompletesol) );
1234 	   SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeCompletesol) );
1235 	
1236 	   /* add completesol primal heuristic parameters */
1237 	
1238 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/maxnodes",
1239 	         "maximum number of nodes to regard in the subproblem",
1240 	         &heurdata->maxnodes, TRUE, DEFAULT_MAXNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1241 	
1242 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/minnodes",
1243 	         "minimum number of nodes required to start the subproblem",
1244 	         &heurdata->minnodes, TRUE, DEFAULT_MINNODES, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1245 	
1246 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/maxunknownrate",
1247 	         "maximal rate of unknown solution values",
1248 	         &heurdata->maxunknownrate, FALSE, DEFAULT_MAXUNKRATE, 0.0, 1.0, NULL, NULL) );
1249 	
1250 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/addallsols",
1251 	         "should all subproblem solutions be added to the original SCIP?",
1252 	         &heurdata->addallsols, TRUE, DEFAULT_ADDALLSOLS, NULL, NULL) );
1253 	
1254 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/nodesofs",
1255 	         "number of nodes added to the contingent of the total nodes",
1256 	         &heurdata->nodesofs, FALSE, DEFAULT_NODESOFS, 0LL, SCIP_LONGINT_MAX, NULL, NULL) );
1257 	
1258 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesquot",
1259 	         "contingent of sub problem nodes in relation to the number of nodes of the original problem",
1260 	         &heurdata->nodesquot, FALSE, DEFAULT_NODESQUOT, 0.0, 1.0, NULL, NULL) );
1261 	
1262 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/lplimfac",
1263 	         "factor by which the limit on the number of LP depends on the node limit",
1264 	         &heurdata->lplimfac, TRUE, DEFAULT_LPLIMFAC, 1.0, SCIP_REAL_MAX, NULL, NULL) );
1265 	
1266 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/objweight",
1267 	         "weight of the original objective function (1: only original objective)",
1268 	         &heurdata->objweight, TRUE, DEFAULT_OBJWEIGHT, DEFAULT_MINOBJWEIGHT, 1.0, NULL, NULL) );
1269 	
1270 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/boundwidening",
1271 	         "bound widening factor applied to continuous variables (0: fix variables to given solution values, 1: relax to global bounds)",
1272 	         &heurdata->boundwidening, TRUE, DEFAULT_BOUNDWIDENING, 0.0, 1.0, NULL, NULL) );
1273 	
1274 	   SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/minimprove",
1275 	         "factor by which the incumbent should be improved at least",
1276 	         &heurdata->minimprove, TRUE, DEFAULT_MINIMPROVE, 0.0, 1.0, NULL, NULL) );
1277 	
1278 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/ignorecont",
1279 	         "should number of continuous variables be ignored?",
1280 	         &heurdata->ignorecont, FALSE, DEFAULT_IGNORECONT, NULL, NULL) );
1281 	
1282 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/solutions",
1283 	         "heuristic stops, if the given number of improving solutions were found (-1: no limit)",
1284 	         &heurdata->bestsols, FALSE, DEFAULT_BESTSOLS, -1, INT_MAX, NULL, NULL) );
1285 	
1286 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxproprounds",
1287 	         "maximal number of iterations in propagation (-1: no limit)",
1288 	         &heurdata->maxproprounds, FALSE, DEFAULT_MAXPROPROUNDS, -1, INT_MAX, NULL, NULL) );
1289 	
1290 	   SCIP_CALL( SCIPaddBoolParam(scip, "heuristics/" HEUR_NAME "/beforepresol",
1291 	         "should the heuristic run before presolving?",
1292 	         &heurdata->beforepresol, FALSE, DEFAULT_BEFOREPRESOL, NULL, NULL) );
1293 	
1294 	   SCIP_CALL( SCIPaddLongintParam(scip, "heuristics/" HEUR_NAME "/maxlpiter",
1295 	         "maximal number of LP iterations (-1: no limit)",
1296 	         &heurdata->maxlpiter, FALSE, DEFAULT_MAXLPITER, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
1297 	
1298 	   SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxcontvars",
1299 	         "maximal number of continuous variables after presolving",
1300 	         &heurdata->maxcontvars, FALSE, DEFAULT_MAXCONTVARS, -1, INT_MAX, NULL, NULL) );
1301 	
1302 	   return SCIP_OKAY;
1303 	}
1304