Scippy

SCIP

Solving Constraint Integer Programs

heur_subnlp.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2024 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 heur_subnlp.c
26  * @ingroup DEFPLUGINS_HEUR
27  * @brief NLP local search primal heuristic using sub-SCIPs
28  * @author Stefan Vigerske
29  *
30  * @todo reconstruct sub-SCIP if problem has changed
31  */
32 
33 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
34 
35 #include "blockmemshell/memory.h"
36 #include "scip/nlpi_ipopt.h"
38 #include "scip/cons_setppc.h"
39 #include "scip/heur_subnlp.h"
40 #include "scip/pub_event.h"
41 #include "scip/pub_heur.h"
42 #include "scip/pub_message.h"
43 #include "scip/pub_misc.h"
44 #include "scip/pub_sol.h"
45 #include "scip/pub_var.h"
46 #include "scip/scip_branch.h"
47 #include "scip/scip_cons.h"
48 #include "scip/scip_copy.h"
49 #include "scip/scip_event.h"
50 #include "scip/scip_general.h"
51 #include "scip/scip_heur.h"
52 #include "scip/scip_lp.h"
53 #include "scip/scip_mem.h"
54 #include "scip/scip_message.h"
55 #include "scip/scip_nlp.h"
56 #include "scip/scip_nlpi.h"
57 #include "scip/scip_numerics.h"
58 #include "scip/scip_param.h"
59 #include "scip/scip_presol.h"
60 #include "scip/scip_pricer.h"
61 #include "scip/scip_prob.h"
62 #include "scip/scip_sol.h"
63 #include "scip/scip_solve.h"
64 #include "scip/scip_solvingstats.h"
65 #include "scip/scip_timing.h"
66 #include "scip/scip_var.h"
67 #include <string.h>
68 
69 #define HEUR_NAME "subnlp"
70 #define HEUR_DESC "primal heuristic that performs a local search in an NLP after fixing integer variables and presolving"
71 #define HEUR_DISPCHAR SCIP_HEURDISPCHAR_LNS
72 #define HEUR_PRIORITY -2000010
73 #define HEUR_FREQ 1
74 #define HEUR_FREQOFS 0
75 #define HEUR_MAXDEPTH -1
76 #define HEUR_TIMING SCIP_HEURTIMING_AFTERNODE
77 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? we set this to FALSE because we want this heuristic to also run within other heuristics */
78 
79 /*
80  * Data structures
81  */
82 
83 /** primal heuristic data */
84 struct SCIP_HeurData
85 {
86  SCIP* subscip; /**< copy of CIP where presolving and NLP solving is done */
87  SCIP_Bool triedsetupsubscip; /**< whether we have tried to setup a sub-SCIP */
88  SCIP_Bool subscipisvalid; /**< whether all constraints have been copied */
89  SCIP_Bool continuous; /**< whether problem was continuous when sub-SCIP was created */
90  int nseriousnlpierror; /**< number of consecutive serious NLP solver failures (memout, ...) */
91  SCIP_EVENTHDLR* eventhdlr; /**< event handler for global bound change events */
92 
93  int nvars; /**< number of active transformed variables in SCIP */
94  int nsubvars; /**< number of original variables in sub-SCIP */
95  SCIP_VAR** var_subscip2scip; /**< mapping variables in sub-SCIP to SCIP variables */
96  SCIP_VAR** var_scip2subscip; /**< mapping variables in SCIP to sub-SCIP variables */
97 
98  SCIP_SOL* startcand; /**< candidate for start point for heuristic */
99  SCIP_Real startcandviol; /**< violation of start point candidate w.r.t. constraint that reported this candidate */
100  SCIP_SOL* lastsol; /**< pointer to last found solution (or NULL if none), not captured, thus may be dangling */
101 
102  int nlpverblevel; /**< verbosity level of NLP solver */
103  SCIP_Real opttol; /**< optimality tolerance to use for NLP solves */
104  SCIP_Real feastolfactor; /**< factor on SCIP feasibility tolerance for NLP solves if resolving when NLP solution not feasible in CIP */
105  SCIP_Real feastol; /**< feasibility tolerance for NLP solves */
106  SCIP_Bool tighterfeastolfailed;/**< whether we tried to use a tighter feasibility tolerance but the NLP solution was still not accepted */
107  int maxpresolverounds; /**< limit on number of presolve rounds in sub-SCIP */
108  int presolveemphasis; /**< presolve emphasis in sub-SCIP */
109  SCIP_Bool setcutoff; /**< whether to set cutoff in sub-SCIP to current primal bound */
110  SCIP_Bool forbidfixings; /**< whether to add constraints that forbid specific fixations that turned out to be infeasible */
111  SCIP_Bool keepcopy; /**< whether to keep SCIP copy or to create new copy each time heuristic is applied */
112  SCIP_Real expectinfeas; /**< when to tell NLP solver that an infeasible NLP is not unexpected */
113 
114  SCIP_Longint iterused; /**< number of iterations used so far (+ number of heuristic runs + number of presolve runs in subscip) */
115  SCIP_Longint iterusedokay; /**< number of iterations used so far when NLP stopped with status okay */
116  SCIP_Longint iterusediterlim; /**< maximal number of iterations used when NLP stopped due to iteration limit */
117  int nnlpsolves; /**< number of NLP solves */
118  int nnlpsolvesokay; /**< number of NLP solves with status okay */
119  int nnlpsolvesiterlim; /**< number of NLP solves that hit an iteration limit */
120  int nnlpsolvesinfeas; /**< number of NLP solves with status okay and infeasible */
121  int nodesoffset; /**< number of nodes added to the actual number of nodes when computing itercontingent */
122  SCIP_Real nodesfactor; /**< factor to apply to number of nodes in SCIP to compute initial itercontingent */
123  SCIP_Real successrateexp; /**< exponent for power of success rate to be multiplied with itercontingent */
124  int iterinit; /**< number of iterations used for initial NLP solves */
125  int ninitsolves; /**< number of successful NLP solves until switching to iterlimit guess and using success rate */
126  int itermin; /**< minimal number of iterations for NLP solves */
127 };
128 
129 
130 /*
131  * Local methods
132  */
133 
134 /** indicates whether the heuristic should be running, i.e., whether we expect something nonlinear after fixing all discrete variables */
135 static
137  SCIP* scip, /**< SCIP data structure */
138  SCIP_Bool* runheur /**< buffer to store whether to run heuristic */
139  )
140 {
141  assert(scip != NULL);
142  assert(runheur != NULL);
143 
144  /* do not run heuristic if no NLP solver is available */
145  if( SCIPgetNNlpis(scip) <= 0 )
146  {
147  *runheur = FALSE;
148  return SCIP_OKAY;
149  }
150 
151  /* do not run heuristic if no NLP */
152  if( !SCIPisNLPConstructed(scip) )
153  {
154  *runheur = FALSE;
155  return SCIP_OKAY;
156  }
157 
158  /* do not run heuristic if no continuous nonlinear variables in NLP */
160 
161  return SCIP_OKAY;
162 }
163 
164 /** free sub-SCIP data structure */
165 static
167  SCIP* scip, /**< SCIP data structure */
168  SCIP_HEURDATA* heurdata /**< heuristic data structure */
169  )
170 {
171  SCIP_VAR** subvars;
172  int nsubvars;
173  int i;
174  SCIP_VAR* var;
175  SCIP_VAR* subvar;
176 
177  assert(scip != NULL);
178  assert(heurdata != NULL);
179 
180  assert(heurdata->subscip != NULL);
181 
182  SCIP_CALL( SCIPgetOrigVarsData(heurdata->subscip, &subvars, &nsubvars, NULL, NULL, NULL, NULL) );
183  assert(nsubvars == heurdata->nsubvars);
184 
185  /* drop global bound change events
186  * release variables in SCIP and sub-SCIP
187  */
188  for( i = 0; i < heurdata->nsubvars; ++i )
189  {
190  subvar = subvars[i];
191  assert(subvar != NULL);
192  assert(SCIPvarGetProbindex(subvar) == i);
193 
194  var = heurdata->var_subscip2scip[SCIPvarGetProbindex(subvar)];
195  assert(var != NULL);
196  assert(SCIPvarGetProbindex(var) <= heurdata->nvars);
197  assert(!SCIPvarIsActive(var) || heurdata->var_scip2subscip[SCIPvarGetProbindex(var)] == subvar);
198 
199  SCIP_CALL( SCIPdropVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, heurdata->eventhdlr, (SCIP_EVENTDATA*)heurdata, -1) );
200 
201  SCIP_CALL( SCIPreleaseVar(heurdata->subscip, &subvar) );
202  SCIP_CALL( SCIPreleaseVar(scip, &var) );
203  }
204 
205  /* free variable mappings subscip -> scip and scip -> subscip */
206  SCIPfreeBlockMemoryArray(scip, &heurdata->var_subscip2scip, heurdata->nsubvars);
207  SCIPfreeBlockMemoryArray(scip, &heurdata->var_scip2subscip, heurdata->nvars);
208  heurdata->nsubvars = 0;
209  heurdata->nvars = 0;
210 
211  /* free sub-SCIP */
212  SCIP_CALL( SCIPfree(&heurdata->subscip) );
213 
214  return SCIP_OKAY;
215 }
216 
217 /** creates copy of CIP from problem in SCIP */
218 static
220  SCIP* scip, /**< SCIP data structure */
221  SCIP_HEURDATA* heurdata /**< heuristic data structure */
222  )
223 {
224  int nvars;
225  SCIP_VAR** vars;
226  SCIP_VAR** subvars;
227  SCIP_VAR* var;
228  SCIP_VAR* subvar;
229  SCIP_Bool success;
230  char probname[SCIP_MAXSTRLEN];
231  int i;
232  SCIP_HASHMAP* varsmap;
233  SCIP_HASHMAP* conssmap;
234 
235  assert(heurdata != NULL);
236  assert(heurdata->subscip == NULL);
237 
238  heurdata->triedsetupsubscip = TRUE;
239 
240  /* initializing the subproblem */
241  SCIP_CALL( SCIPcreate(&heurdata->subscip) );
242 
243  /* create sub-SCIP copy of CIP */
244 
245  /* copy interesting plugins */
246  success = TRUE;
247  SCIP_CALL( SCIPcopyPlugins(scip, heurdata->subscip,
248  FALSE, /* readers */
249  FALSE, /* pricers */
250  TRUE, /* conshdlrs */
251  FALSE, /* conflicthdlrs */
252  TRUE, /* presolvers */
253  FALSE, /* relaxators */
254  FALSE, /* separators */
255  FALSE, /* cutselectors */
256  TRUE, /* propagators */
257  FALSE, /* heuristics */
258  TRUE, /* eventhandler */
259  TRUE, /* nodeselectors (SCIP gives an error if there is none) */
260  FALSE, /* branchrules */
261  TRUE, /* displays */
262  FALSE, /* tables */
263  FALSE, /* dialogs */
264  TRUE, /* expression handlers */
265  TRUE, /* nlpis */
266  TRUE, /* message handler */
267  &success) );
268  if( !success )
269  {
270  SCIPdebugMsg(scip, "failed to copy some plugins to sub-SCIP, continue anyway\n");
271  }
272 
273  /* check if we still have NLPI's in subscip */
274  if( SCIPgetNNlpis(heurdata->subscip) <= 0 )
275  {
276  SCIPdebugMsg(scip, "none of the NLPIs from main SCIP copied into sub-SCIP, give up heuristic.\n");
277  SCIP_CALL( SCIPfree(&heurdata->subscip) );
278 
279  return SCIP_OKAY;
280  }
281 
282  /* copy parameter settings */
283  SCIP_CALL( SCIPcopyParamSettings(scip, heurdata->subscip) );
284 
285  /* create problem in sub-SCIP */
286  /* get name of the original problem and add "subnlp" */
287  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subnlp", SCIPgetProbName(scip));
288  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
289  SCIP_CALL( SCIPhashmapCreate(&varsmap, SCIPblkmem(scip), nvars) );
290  SCIP_CALL( SCIPhashmapCreate(&conssmap, SCIPblkmem(scip), SCIPgetNConss(scip)) );
291  SCIP_CALL( SCIPcopyProb(scip, heurdata->subscip, varsmap, conssmap, TRUE, probname) );
292 
293  /* copy all variables */
294  SCIP_CALL( SCIPcopyVars(scip, heurdata->subscip, varsmap, conssmap, NULL, NULL, 0, TRUE) );
295 
296  /* copy as many constraints as possible */
297  SCIP_CALL( SCIPcopyConss(scip, heurdata->subscip, varsmap, conssmap, TRUE, FALSE, &heurdata->subscipisvalid) );
298  SCIPhashmapFree(&conssmap);
299  if( !heurdata->subscipisvalid )
300  {
301  SCIPdebugMsg(scip, "failed to copy some constraints to sub-SCIP, continue anyway\n");
302  }
303 
304  /* create arrays translating scip transformed vars to subscip original vars, and vice versa
305  * capture variables in SCIP and sub-SCIP
306  * catch global bound change events
307  */
308 
309  SCIP_CALL( SCIPgetVarsData(heurdata->subscip, &subvars, &heurdata->nsubvars, NULL, NULL, NULL, NULL) );
310 
311  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &heurdata->var_subscip2scip, heurdata->nsubvars) );
312 
313  heurdata->nvars = nvars;
314  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &heurdata->var_scip2subscip, heurdata->nvars) );
315 
316  /* we need to get all subscip variables, also those which are copies of fixed variables from the main scip
317  * therefore we iterate over the hashmap
318  */
319  for( i = 0; i < SCIPhashmapGetNEntries(varsmap); ++i )
320  {
321  SCIP_HASHMAPENTRY* entry;
322  entry = SCIPhashmapGetEntry(varsmap, i);
323  if( entry != NULL )
324  {
325  var = (SCIP_VAR*) SCIPhashmapEntryGetOrigin(entry);
326  subvar = (SCIP_VAR*) SCIPhashmapEntryGetImage(entry);
327  assert(subvar != NULL);
328  assert(SCIPvarGetProbindex(subvar) >= 0);
329  assert(SCIPvarGetProbindex(subvar) <= heurdata->nsubvars);
330 
331  if( SCIPvarIsActive(var) )
332  {
333  assert(SCIPvarGetProbindex(var) <= heurdata->nvars);
334  assert(heurdata->var_scip2subscip[SCIPvarGetProbindex(var)] == NULL); /* assert that we have no mapping for this var yet */
335  heurdata->var_scip2subscip[SCIPvarGetProbindex(var)] = subvar;
336  }
337 
338  assert(heurdata->var_subscip2scip[SCIPvarGetProbindex(subvar)] == NULL); /* assert that we have no mapping for this subvar yet */
339  heurdata->var_subscip2scip[SCIPvarGetProbindex(subvar)] = var;
340  }
341  }
342 
343  for( i = 0; i < heurdata->nsubvars; ++i )
344  {
345  subvar = SCIPgetVars(heurdata->subscip)[i];
346  assert(SCIPvarGetProbindex(subvar) == i);
347  var = heurdata->var_subscip2scip[i];
348 
349  SCIP_CALL( SCIPcaptureVar(scip, var) );
350  SCIP_CALL( SCIPcaptureVar(heurdata->subscip, subvar) );
351 
352  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetLbGlobal(subvar)));
353  assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), SCIPvarGetUbGlobal(subvar)));
354 
355  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_GBDCHANGED, heurdata->eventhdlr, (SCIP_EVENTDATA*)heurdata, NULL) );
356  }
357 
358 #ifndef NDEBUG
359  for( i = 0; i < heurdata->nvars; ++i )
360  {
361  assert(heurdata->var_scip2subscip[i] == NULL || (SCIP_VAR*)SCIPhashmapGetImage(varsmap, (void*)vars[i]) == heurdata->var_scip2subscip[i]);
362  }
363  for( i = 0; i < heurdata->nsubvars; ++i )
364  {
365  assert(heurdata->var_subscip2scip[i] != NULL);
366  assert((SCIP_VAR*)SCIPhashmapGetImage(varsmap, (void*)heurdata->var_subscip2scip[i]) == subvars[i]);
367  }
368 #endif
369 
370  /* do not need hashmap anymore */
371  SCIPhashmapFree(&varsmap);
372 
373  /* do not abort subproblem on CTRL-C */
374  SCIP_CALL( SCIPsetBoolParam(heurdata->subscip, "misc/catchctrlc", FALSE) );
375 
376  /* disable keeping solutions from one subscip solve for next solve (with usually different fixings) */
377  SCIP_CALL( SCIPsetIntParam(heurdata->subscip, "limits/maxorigsol", 0) );
378 
379 #ifdef SCIP_DEBUG
380  /* for debugging, enable SCIP output */
381  SCIP_CALL( SCIPsetIntParam(heurdata->subscip, "display/verblevel", 5) );
382 #else
383  /* disable output to console */
384  SCIP_CALL( SCIPsetIntParam(heurdata->subscip, "display/verblevel", 0) );
385 #endif
386 
387  /* reset some limits to default values, in case users changed them in main scip (SCIPcopy copies parameter values :-() */
388  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/absgap") );
389  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/bestsol") );
390  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/gap") );
391  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/restarts") );
392  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/solutions") );
393  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/time") );
394  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/totalnodes") );
395  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/primal") );
396  SCIP_CALL( SCIPresetParam(heurdata->subscip, "limits/dual") );
397 
398  /* we remember here which way (continuous or not) we went, in case all binary and integer vars get fixed in root */
399  heurdata->continuous = SCIPgetNBinVars(heurdata->subscip) == 0 && SCIPgetNIntVars(heurdata->subscip) == 0;
400  if( !heurdata->continuous )
401  {
402  /* set presolve maxrounds and emphasis; always disable components presolver
403  * heuristics and separators were not copied into subscip, so should not need to switch off
404  */
405  if( !SCIPisParamFixed(heurdata->subscip, "presolving/maxrounds") )
406  {
407  SCIP_CALL( SCIPsetIntParam(heurdata->subscip, "presolving/maxrounds", heurdata->maxpresolverounds) );
408  }
409  SCIP_CALL( SCIPsetPresolving(heurdata->subscip, (SCIP_PARAMSETTING)heurdata->presolveemphasis, TRUE) );
410  if( !SCIPisParamFixed(heurdata->subscip, "constraints/components/maxprerounds") )
411  {
412  SCIP_CALL( SCIPsetIntParam(heurdata->subscip, "constraints/components/maxprerounds", 0) );
413  }
414  }
415  else
416  {
417  /* for continuous problems, disable presolve and move subscip into a stage where it has a NLP
418  * the only reason why we don't solve the NLP in the main SCIP is that we want global variable bounds for the NLP
419  */
420  SCIP_RETCODE retcode;
421 
422  SCIP_CALL( SCIPtransformProb(heurdata->subscip) );
423 
424  SCIP_CALL( SCIPsetPresolving(heurdata->subscip, SCIP_PARAMSETTING_OFF, TRUE) );
425  SCIP_CALL( SCIPpresolve(heurdata->subscip) );
426 
427  if( SCIPgetStage(heurdata->subscip) != SCIP_STAGE_PRESOLVED || SCIPgetNVars(heurdata->subscip) == 0 )
428  {
429  /* presolve found problem infeasible, solved it, or stopped due to some limit
430  * all a bit strange, since problem should be the same as original, presolve was disabled, and we didn't set any limits
431  * we will give up and not run the heuristic
432  */
433  SCIP_CALL( freeSubSCIP(scip, heurdata) );
434  return SCIP_OKAY;
435  }
436 
437  /* do initial solve, i.e., "solve" root node with node limit 0 (should do scip.c::initSolve and then stop immediately in solve.c::SCIPsolveCIP) */
438  SCIP_CALL( SCIPsetLongintParam(heurdata->subscip, "limits/nodes", 0LL) );
439  retcode = SCIPsolve(heurdata->subscip);
440 
441  /* errors in solving the subproblem should not kill the overall solving process
442  * hence, the return code is caught and a warning is printed
443  */
444  if( retcode != SCIP_OKAY )
445  {
446  SCIPwarningMessage(scip, "Error while initializing subproblem in subnlp heuristic; sub-SCIP terminated with code <%d>\n", retcode);
447  SCIP_CALL( freeSubSCIP(scip, heurdata) );
448  return SCIP_OKAY;
449  }
450 
451  /* If we are in stage "solved" (strange) or have no NLP (also strange), then do not run heuristic, too */
452  if( SCIPgetStage(heurdata->subscip) == SCIP_STAGE_SOLVED || !SCIPisNLPConstructed(heurdata->subscip) )
453  {
454  SCIP_CALL( freeSubSCIP(scip, heurdata) );
455  return SCIP_OKAY;
456  }
457 
458  assert(SCIPgetStage(heurdata->subscip) == SCIP_STAGE_SOLVING);
459  assert(SCIPgetStatus(heurdata->subscip) == SCIP_STATUS_NODELIMIT);
460  assert(SCIPisNLPConstructed(heurdata->subscip));
461  }
462 
463  return SCIP_OKAY;
464 }
465 
466 /** process variable global bound change event */
467 static
468 SCIP_DECL_EVENTEXEC(processVarEvent)
469 {
470  SCIP_HEURDATA* heurdata;
471  SCIP_VAR* var;
472  SCIP_VAR* subvar;
473  int idx;
474 
475  assert(scip != NULL);
476  assert(event != NULL);
477  assert(eventdata != NULL);
478  assert(eventhdlr != NULL);
479 
480  heurdata = (SCIP_HEURDATA*)eventdata;
481  assert(heurdata != NULL);
482 
483  var = SCIPeventGetVar(event);
484  assert(var != NULL);
485 
486  idx = SCIPvarGetProbindex(var);
487  /* if event corresponds to an active variable, we can easily look up the corresponding subvar
488  * if it is an inactive variable that has been copied to the subproblem,
489  * then we need to check the subscip2scip mapping
490  * @todo we could do this faster if we keep the variables mapping from SCIPcopy around
491  */
492  if( idx >= 0 )
493  {
494  assert(idx < heurdata->nvars);
495 
496  subvar = heurdata->var_scip2subscip[idx];
497  }
498  else
499  {
500  for( idx = 0; idx < heurdata->nsubvars; ++idx )
501  {
502  if( heurdata->var_subscip2scip[idx] == var )
503  break;
504  }
505  assert(idx < heurdata->nsubvars);
506  subvar = SCIPgetVars(heurdata->subscip)[idx];
507  }
508  assert(subvar != NULL);
509 
511  {
512  SCIP_CALL( SCIPchgVarLbGlobal(heurdata->subscip, subvar, SCIPeventGetNewbound(event)) );
513  }
514 
516  {
517  SCIP_CALL( SCIPchgVarUbGlobal(heurdata->subscip, subvar, SCIPeventGetNewbound(event)) );
518  }
519 
520  return SCIP_OKAY;
521 }
522 
523 /* creates a SCIP_SOL in our SCIP space out of the solution from NLP solver in sub-SCIP */
524 static
526  SCIP* scip, /**< SCIP data structure */
527  SCIP_HEUR* heur, /**< heuristic data structure */
528  SCIP_SOL** sol, /**< buffer to store solution value; if pointing to NULL, then a new solution is created, otherwise values in the given one are overwritten */
529  SCIP_HEUR* authorheur /**< the heuristic which should be registered as author of the solution */
530  )
531 {
532  SCIP_HEURDATA* heurdata;
533  SCIP_VAR** vars;
534  int nvars;
535  SCIP_VAR* var;
536  SCIP_VAR* subvar;
537  SCIP_Real solval;
538  int i;
539 
540  assert(scip != NULL);
541  assert(heur != NULL);
542  assert(sol != NULL);
543 
544  heurdata = SCIPheurGetData(heur);
545  assert(heurdata != NULL);
546  assert(SCIPhasNLPSolution(heurdata->subscip));
547 
548  if( *sol == NULL )
549  {
550  SCIP_CALL( SCIPcreateSol(scip, sol, authorheur) );
551  }
552  else
553  {
554  SCIPsolSetHeur(*sol, authorheur);
555  }
556 
557  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
558 
559  assert(nvars >= heurdata->nvars);
560  for( i = 0; i < heurdata->nvars; ++i )
561  {
562  var = vars[i];
563  assert(var != NULL);
564  assert(SCIPvarIsActive(var)); /* SCIPgetVarsData should have given us only active vars */
565 
566  subvar = heurdata->var_scip2subscip[i];
567  if( subvar == NULL )
568  solval = MIN(MAX(0.0, SCIPvarGetLbLocal(var)), SCIPvarGetUbLocal(var)); /*lint !e666*/
569  else
570  solval = SCIPvarGetNLPSol(subvar);
571 
572  assert(solval != SCIP_INVALID); /*lint !e777*/
573  SCIP_CALL( SCIPsetSolVal(scip, *sol, var, solval) );
574  }
575 
576  for( ; i < nvars; ++i )
577  {
578  var = vars[i];
579  assert(var != NULL);
580  assert(SCIPvarIsActive(var)); /* SCIPgetVarsData should have given us only active vars */
581 
582  solval = MIN(MAX(0.0, SCIPvarGetLbLocal(var)), SCIPvarGetUbLocal(var)); /*lint !e666*/
583  SCIP_CALL( SCIPsetSolVal(scip, *sol, var, solval) );
584  }
585 
586  return SCIP_OKAY;
587 }
588 
589 /** creates SCIP solution from NLP and tries adding to SCIP or only checks feasibility */
590 static
592  SCIP* scip, /**< original SCIP data structure */
593  SCIP_HEUR* heur, /**< heuristic data structure */
594  SCIP_HEUR* authorheur, /**< the heuristic that should be the author of solution, if any */
595  SCIP_RESULT* result, /**< buffer to store result FOUNDSOL if a solution has been found and accepted */
596  SCIP_SOL* resultsol /**< a solution where to store found solution values, if any, or NULL if to try adding to SCIP */
597  )
598 {
599  SCIP_HEURDATA* heurdata;
600 
601  assert(scip != NULL);
602  assert(heur != NULL);
603  assert(result != NULL);
604 
605  heurdata = SCIPheurGetData(heur);
606  assert(heurdata != NULL);
607 
608  assert(SCIPhasNLPSolution(heurdata->subscip));
609 
610  if( resultsol == NULL )
611  {
612  /* resultsol NULL means we should try adding the sol to SCIP */
613  if( SCIPisLE(scip, SCIPgetNLPObjval(heurdata->subscip), SCIPgetUpperbound(scip)) )
614  {
615  /* solution is feasible and should improve upper bound, so try adding it to SCIP */
616  SCIP_SOL* sol;
617  SCIP_Bool stored;
618 
619  sol = NULL;
620  SCIP_CALL( createSolFromNLP(scip, heur, &sol, authorheur) );
621 
622  heurdata->lastsol = sol; /* remember just the pointer so we might recognize if this solution comes back as startingpoint */
623 #ifdef SCIP_DEBUG
624  /* print the infeasibilities to stdout */
625  SCIP_CALL( SCIPtrySolFree(scip, &sol, TRUE, TRUE, TRUE, FALSE, TRUE, &stored) );
626 #else
627  SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, TRUE, &stored) );
628 #endif
629 
630  if( stored )
631  {
632  /* SCIP stored solution (yippi!), so we are done */
633  if( heurdata->nlpverblevel >= 1 )
634  {
635  SCIPinfoMessage(scip, NULL, "SCIP stored solution from NLP solve\n");
636  }
637  else
638  {
639  SCIPdebugMsg(scip, "SCIP stored solution from NLP solve\n");
640  }
641 
642  *result = SCIP_FOUNDSOL;
643  }
644  else
645  {
646  if( heurdata->nlpverblevel >= 1 )
647  {
648  SCIPinfoMessage(scip, NULL, "solution reported by NLP solver not stored by SCIP\n");
649  }
650  else
651  {
652  SCIPdebugMsg(scip, "solution reported by NLP solver not stored by SCIP\n");
653  }
654  }
655  }
656  else if( heurdata->nlpverblevel >= 1 )
657  {
658  SCIPinfoMessage(scip, NULL, "subnlp solution objval %e is above the primal bound %e\n",
659  SCIPgetNLPObjval(heurdata->subscip), SCIPgetUpperbound(scip));
660  }
661  }
662  else
663  {
664  /* only create a solution and pass it back in resultsol, do not add to SCIP */
665  SCIP_Bool feasible;
666 
667  SCIP_CALL( createSolFromNLP(scip, heur, &resultsol, authorheur) );
668 
669  heurdata->lastsol = resultsol;
670 #ifdef SCIP_DEBUG
671  /* print the infeasibilities to stdout */
672  SCIP_CALL( SCIPcheckSol(scip, resultsol, TRUE, TRUE, TRUE, FALSE, TRUE, &feasible) );
673 #else
674  SCIP_CALL( SCIPcheckSol(scip, resultsol, FALSE, FALSE, TRUE, FALSE, TRUE, &feasible) );
675 #endif
676  if( feasible )
677  {
678  /* SCIP find solution feasible, so we are done */
679  if( heurdata->nlpverblevel >= 1 )
680  {
681  SCIPinfoMessage(scip, NULL, "solution reported by NLP solver feasible for SCIP\n");
682  }
683  else
684  {
685  SCIPdebugMsg(scip, "solution reported by NLP solver feasible for SCIP\n");
686  }
687  *result = SCIP_FOUNDSOL;
688  }
689  else
690  {
691  if( heurdata->nlpverblevel >= 1 )
692  {
693  SCIPinfoMessage(scip, NULL, "solution reported by NLP solver not feasible for SCIP\n");
694  }
695  else
696  {
697  SCIPdebugMsg(scip, "solution reported by NLP solver not feasible for SCIP\n");
698  }
699  }
700  }
701 
702  return SCIP_OKAY;
703 }
704 
705 /* creates a SCIP_SOL in our SCIP space out of the SCIP_SOL from a sub-SCIP */
706 static
708  SCIP* scip, /**< SCIP data structure */
709  SCIP_HEUR* heur, /**< heuristic data structure */
710  SCIP_SOL** sol, /**< buffer to store solution value; if pointing to NULL, then a new solution is created, otherwise values in the given one are overwritten */
711  SCIP_SOL* subsol, /**< solution of sub-SCIP */
712  SCIP_HEUR* authorheur /**< the heuristic which should be registered as author of the solution */
713  )
714 {
715  SCIP_HEURDATA* heurdata;
716  SCIP_VAR** vars;
717  int nvars;
718  SCIP_VAR* var;
719  SCIP_VAR* subvar;
720  SCIP_Real solval;
721  int i;
722 
723  assert(scip != NULL);
724  assert(heur != NULL);
725  assert(sol != NULL);
726  assert(subsol != NULL);
727 
728  heurdata = SCIPheurGetData(heur);
729  assert(heurdata != NULL);
730 
731  if( *sol == NULL )
732  {
733  SCIP_CALL( SCIPcreateSol(scip, sol, authorheur) );
734  }
735  else
736  {
737  SCIPsolSetHeur(*sol, authorheur);
738  }
739 
740  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
741 
742  assert(nvars >= heurdata->nvars);
743  for( i = 0; i < heurdata->nvars; ++i )
744  {
745  var = vars[i];
746  assert(var != NULL);
747  assert(SCIPvarIsActive(var));
748 
749  subvar = heurdata->var_scip2subscip[i];
750  if( subvar == NULL )
751  solval = MIN(MAX(0.0, SCIPvarGetLbLocal(var)), SCIPvarGetUbLocal(var)); /*lint !e666*/
752  else
753  solval = SCIPgetSolVal(heurdata->subscip, subsol, subvar);
754 
755  assert(solval != SCIP_INVALID); /*lint !e777*/
756  SCIP_CALL( SCIPsetSolVal(scip, *sol, var, solval) );
757  }
758 
759  for( ; i < nvars; ++i )
760  {
761  var = vars[i];
762  assert(var != NULL);
763  assert(SCIPvarIsActive(var));
764 
765  solval = MIN(MAX(0.0, SCIPvarGetLbLocal(var)), SCIPvarGetUbLocal(var)); /*lint !e666*/
766  SCIP_CALL( SCIPsetSolVal(scip, *sol, var, solval) );
767  }
768 
769  return SCIP_OKAY;
770 }
771 
772 /** finds an iteration limit */ /*lint --e{715}*/
773 static
775  SCIP* scip, /**< original SCIP data structure */
776  SCIP_HEURDATA* heurdata /**< heuristic data */
777  )
778 {
779  /* if we hit more often an iterlimit than we were successful (termstatus=okay), then allow for more iterations:
780  * take twice the maximal iterusage on solves that hit the iterlimit
781  */
782  if( heurdata->nnlpsolvesiterlim > heurdata->nnlpsolvesokay )
783  return MAX(heurdata->itermin, 2 * heurdata->iterusediterlim); /*lint !e712*/
784 
785  /* if we had sufficiently many successful solves, then take twice the average of previous iterusages on successful solves */
786  if( heurdata->nnlpsolvesokay >= heurdata->ninitsolves )
787  return MAX(heurdata->itermin, 2 * heurdata->iterusedokay / heurdata->nnlpsolvesokay); /*lint !e712*/
788 
789  /* if we had too few successful solves, then still ensure that we allow for at least iterinit iterations */
790  if( heurdata->nnlpsolvesokay > 0 )
791  return MAX3(heurdata->itermin, heurdata->iterinit, 2 * heurdata->iterusedokay / heurdata->nnlpsolvesokay); /*lint !e712*/
792 
793  /* if we had no successful solve so far and none that hit an iterlimit, e.g., we are at the first NLP solve, then use iterinit */
794  return MAX(heurdata->itermin, heurdata->iterinit);
795 }
796 
797 /** solves the subNLP specified in subscip */
798 static
800  SCIP* scip, /**< original SCIP data structure */
801  SCIP_HEUR* heur, /**< heuristic data structure */
802  SCIP_RESULT* result, /**< buffer to store result, DIDNOTFIND, FOUNDSOL, or CUTOFF */
803  SCIP_SOL* refpoint, /**< point to take fixation of discrete variables from, and startpoint for NLP solver; if NULL, then LP solution is used */
804  SCIP_SOL* resultsol /**< a solution where to store found solution values, if any, or NULL if to try adding to SCIP */
805  )
806 {
807  SCIP_HEURDATA* heurdata = SCIPheurGetData(heur);
808  SCIP_RETCODE retcode;
809  SCIP_Real* startpoint;
810  SCIP_VAR* var;
811  SCIP_VAR* subvar;
812  int i;
813  SCIP_HEUR* authorheur; /* the heuristic which will be the author of a solution, if found */
814  SCIP_Real timelimit;
815  SCIP_Bool expectinfeas;
816  SCIP_NLPSTATISTICS nlpstatistics;
817 
818  assert(scip != NULL);
819  assert(heur != NULL);
820  assert(heurdata != NULL);
821  assert(result != NULL);
822  assert(SCIPisTransformed(heurdata->subscip));
823 
824  /* get remaining SCIP solve time; if no time left, then stop */
825  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
826  if( !SCIPisInfinity(scip, timelimit) )
827  {
828  timelimit -= SCIPgetSolvingTime(scip);
829  if( timelimit <= 0.0 )
830  return SCIP_OKAY;
831  }
832  /* set timelimit for NLP solve and in case presolve is unexpectedly expensive */
833  SCIP_CALL( SCIPsetRealParam(heurdata->subscip, "limits/time", timelimit) );
834 
835  /* if the refpoint comes from a heuristic, then make it the author of a found solution,
836  * otherwise let the subNLP heuristic claim authorship
837  * TODO: I doubt that this has much effect; for the statistics, the number of solutions found by a heuristic
838  * seems to be computed as the increase in number of solutions before and after a heuristic is run
839  * check this and maybe change
840  */
841  if( refpoint == NULL || SCIPsolGetHeur(refpoint) == NULL )
842  authorheur = heur;
843  else
844  authorheur = SCIPsolGetHeur(refpoint);
845 
846  if( !heurdata->continuous )
847  {
848  /* presolve sub-SCIP
849  * set node limit to 1 so that presolve can go
850  */
851  SCIP_CALL( SCIPsetLongintParam(heurdata->subscip, "limits/nodes", 1LL) );
852  SCIP_CALL( SCIPpresolve(heurdata->subscip) );
853 
854  /* count one presolve round as on NLP iteration for now
855  * plus one extra for all the setup cost
856  * this is mainly to avoid that the primal heuristics runs all the time on instances that are solved in the subscip-presolve
857  */
858  heurdata->iterused += 1 + SCIPgetNPresolRounds(scip); /*lint !e776*/
859 
860  if( SCIPgetStage(heurdata->subscip) == SCIP_STAGE_SOLVED )
861  {
862  /* presolve probably found the subproblem infeasible */
863  SCIPdebugMsg(scip, "SCIP returned from presolve in stage solved with status %d and %d sols\n", SCIPgetStatus(heurdata->subscip), SCIPgetNSols(heurdata->subscip));
864  /* if presolve found subproblem infeasible, report this to caller by setting *result to cutoff */
865  if( SCIPgetStatus(heurdata->subscip) == SCIP_STATUS_INFEASIBLE )
866  *result = SCIP_CUTOFF;
867  }
868  else if( SCIPgetStage(heurdata->subscip) == SCIP_STAGE_PRESOLVING )
869  {
870  /* presolve was stopped because some still existing limit was hit (e.g., memory) */
871  SCIPdebugMsg(scip, "SCIP returned from presolve in stage presolving with status %d and %d sols\n", SCIPgetStatus(heurdata->subscip), SCIPgetNSols(heurdata->subscip));
872  /* if presolve found subproblem infeasible, report this to caller by setting *result to cutoff */
873  if( SCIPgetStatus(heurdata->subscip) == SCIP_STATUS_INFEASIBLE )
874  *result = SCIP_CUTOFF;
875  }
876  else
877  {
878  assert(SCIPgetStage(heurdata->subscip) == SCIP_STAGE_PRESOLVED);
879 
880  if( SCIPgetNVars(heurdata->subscip) > 0 )
881  {
882  /* do initial solve, i.e., "solve" root node with node limit 0 (should do scip.c::initSolve and then stop immediately in solve.c::SCIPsolveCIP) */
883  SCIP_CALL( SCIPsetLongintParam(heurdata->subscip, "limits/nodes", 0LL) );
884  retcode = SCIPsolve(heurdata->subscip);
885 
886  /* If no NLP was constructed, then there were no nonlinearities after presolve.
887  * So we increase the nodelimit to 1 and hope that SCIP will find some solution to this probably linear subproblem.
888  */
889  if( retcode == SCIP_OKAY && SCIPgetStage(heurdata->subscip) != SCIP_STAGE_SOLVED && !SCIPisNLPConstructed(heurdata->subscip) )
890  {
891  SCIP_CALL( SCIPsetLongintParam(heurdata->subscip, "limits/nodes", 1LL) );
892  retcode = SCIPsolve(heurdata->subscip);
893  }
894  }
895  else
896  {
897  /* If all variables were removed by presolve, but presolve did not end with status SOLVED,
898  * then we run solve, still with nodelimit=1, and hope to find some (maybe trivial) solution.
899  */
900  retcode = SCIPsolve(heurdata->subscip);
901  }
902 
903  /* errors in solving the subproblem should not kill the overall solving process
904  * hence, the return code is caught and a warning is printed
905  */
906  if( retcode != SCIP_OKAY )
907  {
908  SCIPwarningMessage(scip, "Error while solving subproblem in subnlp heuristic; sub-SCIP terminated with code <%d>\n", retcode);
909  return SCIP_OKAY;
910  }
911  }
912 
913  /* we should either have variables, or the problem was trivial, in which case it should have been presolved or solved */
914  assert(SCIPgetNVars(heurdata->subscip) > 0 || SCIPgetStage(heurdata->subscip) == SCIP_STAGE_PRESOLVING || SCIPgetStage(heurdata->subscip) == SCIP_STAGE_SOLVED);
915 
916  SCIPdebug( SCIP_CALL( SCIPprintStatistics(heurdata->subscip, NULL) ); )
917 
918  /* if sub-SCIP found solutions already, then pass them to main scip */
919  for( i = 0; i < SCIPgetNSols(heurdata->subscip); ++i )
920  {
921  if( resultsol == NULL )
922  {
923  SCIP_Bool stored;
924  SCIP_SOL* sol;
925 
926  sol = NULL;
927  SCIP_CALL( createSolFromSubScipSol(scip, heur, &sol, SCIPgetSols(heurdata->subscip)[i], authorheur) );
928 
929  heurdata->lastsol = sol; /* remember just the pointer so we might recognize if this solution comes back as startingpoint */
930  SCIP_CALL( SCIPtrySolFree(scip, &sol, FALSE, FALSE, TRUE, FALSE, TRUE, &stored) );
931  if( stored )
932  {
933  if( heurdata->nlpverblevel >= 1 )
934  {
935  SCIPinfoMessage(scip, NULL, "SCIP stored solution from sub-SCIP root node\n");
936  }
937  else
938  {
939  SCIPdebugMsg(scip, "SCIP stored solution from sub-SCIP root node\n");
940  }
941  *result = SCIP_FOUNDSOL;
942  break;
943  }
944  else
945  {
946  if( heurdata->nlpverblevel >= 1 )
947  {
948  SCIPinfoMessage(scip, NULL, "SCIP did not store sub-SCIP optimal solution\n");
949  }
950  else
951  {
952  SCIPdebugMsg(scip, "SCIP did not store sub-SCIP optimal solution\n");
953  }
954  }
955  }
956  else
957  {
958  SCIP_Bool feasible;
959 
960  SCIP_CALL( createSolFromSubScipSol(scip, heur, &resultsol, SCIPgetSols(heurdata->subscip)[i], authorheur) );
961 
962  heurdata->lastsol = resultsol;
963  SCIP_CALL( SCIPcheckSol(scip, resultsol, FALSE, FALSE, TRUE, FALSE, TRUE, &feasible) );
964  if( feasible )
965  {
966  if( heurdata->nlpverblevel >= 1 )
967  {
968  SCIPinfoMessage(scip, NULL, "SCIP solution from sub-SCIP root node is feasible\n");
969  }
970  else
971  {
972  SCIPdebugMsg(scip, "SCIP solution from sub-SCIP root node is feasible\n");
973  }
974  *result = SCIP_FOUNDSOL;
975  break;
976  }
977  else
978  {
979  if( heurdata->nlpverblevel >= 1 )
980  {
981  SCIPinfoMessage(scip, NULL, "SCIP solution from sub-SCIP root node is not feasible\n");
982  }
983  else
984  {
985  SCIPdebugMsg(scip, "SCIP solution from sub-SCIP root node is not feasible\n");
986  }
987  }
988  }
989  }
990 
991  /* if subscip is infeasible here, we signal this to the caller */
992  if( SCIPgetStatus(heurdata->subscip) == SCIP_STATUS_INFEASIBLE )
993  {
994  if( heurdata->nlpverblevel >= 1 )
995  {
996  SCIPinfoMessage(scip, NULL, "sub-SCIP detected infeasibility\n");
997  }
998  else
999  {
1000  SCIPdebugMsg(scip, "sub-SCIP detected infeasibility\n");
1001  }
1002 
1003  assert(SCIPgetStage(heurdata->subscip) == SCIP_STAGE_SOLVED);
1004  *result = SCIP_CUTOFF;
1005  return SCIP_OKAY;
1006  }
1007 
1008  /* if we stopped for some other reason, or there is no NLP, we also stop */
1009  if( SCIPgetStage(heurdata->subscip) <= SCIP_STAGE_PRESOLVED || SCIPgetStage(heurdata->subscip) == SCIP_STAGE_SOLVED || !SCIPisNLPConstructed(heurdata->subscip) )
1010  return SCIP_OKAY;
1011 
1012  /* in most cases, the status should be nodelimit
1013  * in some cases, if the sub-SCIP is very easy, it may report optimal, so we do not need invoke an NLP solver
1014  * if the presolve found the problem infeasible, then there is no use in solving an NLP
1015  * if the user interrupted or a timelimit was reached, then we should also stop here
1016  * unbounded is very unlikely to happen, in most cases, it should have been concluded in the main scip already
1017  */
1018  switch( SCIPgetStatus(heurdata->subscip) )
1019  {
1020  case SCIP_STATUS_NODELIMIT:
1021  break; /* this is the status that is most likely happening */
1024  case SCIP_STATUS_GAPLIMIT:
1025  case SCIP_STATUS_SOLLIMIT:
1027  /* these should not happen, but if one does, it's safe to return */
1028  SCIPABORT(); /*lint -fallthrough*/
1029  case SCIP_STATUS_OPTIMAL:
1032  case SCIP_STATUS_TIMELIMIT:
1033  case SCIP_STATUS_MEMLIMIT:
1034  case SCIP_STATUS_UNBOUNDED:
1035  case SCIP_STATUS_INFORUNBD:
1036  return SCIP_OKAY;
1037  default:
1038  SCIPerrorMessage("unexpected status of sub-SCIP: <%d>\n", SCIPgetStatus(heurdata->subscip));
1039  return SCIP_ERROR;
1040  } /*lint !e788*/
1041  }
1042  else
1043  {
1044  /* for continuous problem, createSubSCIP() should have put us into a state where we can invoke the NLP solver */
1045  assert(SCIPisNLPConstructed(heurdata->subscip));
1046  assert(SCIPgetStage(heurdata->subscip) == SCIP_STAGE_SOLVING);
1047  assert(SCIPgetStatus(heurdata->subscip) == SCIP_STATUS_NODELIMIT);
1048  }
1049 
1050  /* set starting values (=refpoint, if not NULL; otherwise LP solution (or pseudo solution)) */
1051  SCIP_CALL( SCIPallocBufferArray(scip, &startpoint, SCIPgetNNLPVars(heurdata->subscip)) );
1052 
1053  if( heurdata->nlpverblevel >= 3 )
1054  {
1055  SCIPinfoMessage(scip, NULL, "set NLP starting point\n");
1056  }
1057 
1058  for( i = 0; i < SCIPgetNNLPVars(heurdata->subscip); ++i )
1059  {
1060  SCIP_Real scalar;
1061  SCIP_Real constant;
1062 
1063  subvar = SCIPgetNLPVars(heurdata->subscip)[i];
1064 
1065  /* gets corresponding original variable */
1066  scalar = 1.0;
1067  constant = 0.0;
1068  SCIP_CALL( SCIPvarGetOrigvarSum(&subvar, &scalar, &constant) );
1069  if( subvar == NULL )
1070  {
1071  startpoint[i] = constant;
1072 
1073  if( heurdata->nlpverblevel >= 3 && !SCIPisZero(heurdata->subscip, startpoint[i]) )
1074  {
1075  SCIPinfoMessage(scip, NULL, "%s = %e\n", SCIPvarGetName(SCIPgetNLPVars(heurdata->subscip)[i]), startpoint[i]);
1076  }
1077 
1078  continue;
1079  }
1080 
1081  assert(SCIPvarGetProbindex(subvar) >= 0);
1082  assert(SCIPvarGetProbindex(subvar) < heurdata->nsubvars);
1083  var = heurdata->var_subscip2scip[SCIPvarGetProbindex(subvar)];
1084  if( var == NULL || REALABS(SCIPgetSolVal(scip, refpoint, var)) > 1.0e+12 )
1085  startpoint[i] = MIN(MAX(0.0, SCIPvarGetLbGlobal(subvar)), SCIPvarGetUbGlobal(subvar)); /*lint !e666*/
1086  else
1087  /* scalar*subvar+constant corresponds to nlpvar[i], so nlpvar[i] gets value scalar*varval+constant */
1088  startpoint[i] = scalar * SCIPgetSolVal(scip, refpoint, var) + constant;
1089 
1090  if( heurdata->nlpverblevel >= 3 && !SCIPisZero(heurdata->subscip, startpoint[i]) )
1091  {
1092  SCIPinfoMessage(scip, NULL, "%s = %e\n", SCIPvarGetName(SCIPgetNLPVars(heurdata->subscip)[i]), startpoint[i]);
1093  }
1094  }
1095  SCIP_CALL( SCIPsetNLPInitialGuess(heurdata->subscip, startpoint) );
1096 
1097  SCIPfreeBufferArray(scip, &startpoint);
1098 
1099  *result = SCIP_DIDNOTFIND;
1100 
1101  /* if we had many (fraction > expectinfeas) infeasible NLPs, then tell NLP solver to expect an infeasible problem */
1102  expectinfeas = FALSE;
1103  if( heurdata->expectinfeas == 0.0 ) /* to keep original behavior on default settings */
1104  expectinfeas = TRUE;
1105  else if( heurdata->nnlpsolvesokay > heurdata->ninitsolves && heurdata->nnlpsolvesinfeas > heurdata->expectinfeas * heurdata->nnlpsolvesokay )
1106  expectinfeas = TRUE;
1107 
1108  /* let the NLP solver do its magic */
1109  SCIPdebugMsg(scip, "start NLP solve with iteration limit %d\n", calcIterLimit(scip, heurdata));
1110  SCIP_CALL( SCIPsolveNLP(heurdata->subscip,
1111  .iterlimit = calcIterLimit(scip, heurdata),
1112  .opttol = heurdata->opttol,
1113  .feastol = heurdata->feastol,
1114  .verblevel = (unsigned short)heurdata->nlpverblevel,
1115  .expectinfeas = expectinfeas
1116  ) ); /*lint !e666*/
1117 
1118  SCIPdebugMsg(scip, "NLP solver returned with termination status %d and solution status %d, objective value is %g\n",
1119  SCIPgetNLPTermstat(heurdata->subscip), SCIPgetNLPSolstat(heurdata->subscip), SCIPgetNLPObjval(heurdata->subscip));
1120 
1121  /* add NLP solve statistics from subscip to main SCIP, so they show up in final statistics
1122  * for continuous problems, we also ask to reset statistics, since we do not retransform subSCIP in the next run (which would reset all stats)
1123  * (merging statistics once in exitsol is too late, since they may be printed before)
1124  */
1125  SCIPmergeNLPIStatistics(heurdata->subscip, scip, heurdata->continuous);
1126 
1127  if( SCIPgetNLPTermstat(heurdata->subscip) >= SCIP_NLPTERMSTAT_OUTOFMEMORY )
1128  {
1129  /* oops, something did not go well at all */
1130  if( heurdata->nlpverblevel >= 1 )
1131  {
1132  SCIPinfoMessage(scip, NULL, "NLP solver in subNLP heuristic for problem <%s> returned with bad termination status %d.\n",
1133  SCIPgetProbName(scip), SCIPgetNLPTermstat(heurdata->subscip));
1134  }
1135 
1136  ++(heurdata->nseriousnlpierror);
1138  "NLP solver in subNLP heuristic for problem <%s> returned with bad termination status %d. This was the %d%s successive time.\n",
1139  SCIPgetProbName(scip), SCIPgetNLPTermstat(heurdata->subscip), heurdata->nseriousnlpierror,
1140  heurdata->nseriousnlpierror == 1 ? "st" : heurdata->nseriousnlpierror == 2 ? "nd" : heurdata->nseriousnlpierror == 3 ? "rd" : "th");
1141  if( heurdata->nseriousnlpierror >= 5 )
1142  {
1143  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Will not run subNLP heuristic again for this run.\n");
1144  SCIP_CALL( freeSubSCIP(scip, heurdata) );
1145  }
1146  return SCIP_OKAY;
1147  }
1148  heurdata->nseriousnlpierror = 0;
1149 
1150  SCIP_CALL( SCIPgetNLPStatistics(heurdata->subscip, &nlpstatistics) );
1151 
1152  SCIPdebugMsg(scip, "NLP solver used %d iterations and %g seconds; violation cons %g, bounds %g\n",
1153  nlpstatistics.niterations, nlpstatistics.totaltime, nlpstatistics.consviol, nlpstatistics.boundviol);
1154 
1155  heurdata->iterused += nlpstatistics.niterations;
1156  ++heurdata->nnlpsolves;
1157  if( SCIPgetNLPTermstat(heurdata->subscip) == SCIP_NLPTERMSTAT_OKAY )
1158  {
1159  ++heurdata->nnlpsolvesokay;
1160  heurdata->iterusedokay += nlpstatistics.niterations;
1161 
1162  if( (SCIPgetNLPSolstat(heurdata->subscip) == SCIP_NLPSOLSTAT_GLOBINFEASIBLE) || (SCIPgetNLPSolstat(heurdata->subscip) == SCIP_NLPSOLSTAT_LOCINFEASIBLE) )
1163  ++heurdata->nnlpsolvesinfeas;
1164  }
1165  else if( SCIPgetNLPTermstat(heurdata->subscip) == SCIP_NLPTERMSTAT_ITERLIMIT )
1166  {
1167  ++heurdata->nnlpsolvesiterlim;
1168  heurdata->iterusediterlim = MAX(heurdata->iterusediterlim, nlpstatistics.niterations);
1169  }
1170 
1171  if( SCIPgetNLPSolstat(heurdata->subscip) > SCIP_NLPSOLSTAT_FEASIBLE )
1172  return SCIP_OKAY;
1173 
1174  /* create SCIP solution, check whether feasible, and try adding to SCIP (if resultsol==NULL) */
1175  SCIP_CALL( processNLPSol(scip, heur, authorheur, result, resultsol) );
1176 
1177  if( *result == SCIP_FOUNDSOL || !SCIPisLE(scip, SCIPgetNLPObjval(heurdata->subscip), SCIPgetUpperbound(scip)) )
1178  return SCIP_OKAY;
1179 
1180  /* if solution was not added to SCIP, then either
1181  * - the objective function value was not good enough,
1182  * - the NLP was missing some constraints of the original CIP, or
1183  * - the solution is feasible for the presolved CIP, but slightly infeasible for the unpresolved problem
1184  *
1185  * The first case we can check easily (see if() above).
1186  * For the last case, we try whether tightening the feasibility tolerance for the NLP solve may help.
1187  * If that doesn't help, we guess that we are in the second case and will not try a tighter feastol anymore.
1188  */
1189 
1190  /* if we tried with a tighter feastol before, but solution was still not accepted, then don't try again */
1191  if( heurdata->tighterfeastolfailed )
1192  return SCIP_OKAY;
1193 
1194  /* if resolve with tighter feastol is disabled, then don't do anything */
1195  if( heurdata->feastolfactor == 1.0 )
1196  return SCIP_OKAY;
1197 
1198  /* if we have already used a tighter feastol, then give up */
1199  if( heurdata->feastol < SCIPfeastol(scip) )
1200  return SCIP_OKAY;
1201 
1202  /* if original CIP is continuous, then we have not done any presolve, so it shouldn't have caused problems */
1203  if( heurdata->continuous )
1204  return SCIP_OKAY;
1205 
1206  /* if solution is NLP-feasible for a tightened tolerance already, then there is no use in resolving with that tighter feastol */
1207  if( MAX(nlpstatistics.consviol, nlpstatistics.boundviol) <= heurdata->feastolfactor * heurdata->feastol )
1208  return SCIP_OKAY;
1209 
1210  /* let the NLP solver redo its magic
1211  * as iterlimit, we use the number of iterations it took for the first solve, or itermin
1212  */
1213  SCIPdebugMsg(scip, "start NLP solve with iteration limit %d\n", calcIterLimit(scip, heurdata));
1214  SCIP_CALL( SCIPsolveNLP(heurdata->subscip,
1215  .iterlimit = MAX(heurdata->itermin, nlpstatistics.niterations),
1216  .opttol = heurdata->opttol,
1217  .feastol = heurdata->feastolfactor * heurdata->feastol,
1218  .verblevel = (unsigned short)heurdata->nlpverblevel,
1219  .warmstart = TRUE
1220  ) ); /*lint !e666*/
1221 
1222  SCIPdebugMsg(scip, "NLP solver returned with termination status %d and solution status %d, objective value is %g\n",
1223  SCIPgetNLPTermstat(heurdata->subscip), SCIPgetNLPSolstat(heurdata->subscip), SCIPgetNLPObjval(heurdata->subscip));
1224 
1225  /* add NLP solve statistics from subscip to main SCIP again, so they show up in final statistics */
1226  SCIPmergeNLPIStatistics(heurdata->subscip, scip, heurdata->continuous);
1227 
1228  /* some serious problem: just pretend it didn't happen */
1229  if( SCIPgetNLPTermstat(heurdata->subscip) >= SCIP_NLPTERMSTAT_OUTOFMEMORY )
1230  return SCIP_OKAY;
1231 
1232  SCIP_CALL( SCIPgetNLPStatistics(heurdata->subscip, &nlpstatistics) );
1233  SCIPdebugMsg(scip, "NLP solver used %d iterations and %g seconds; violation cons %g, bounds %g\n",
1234  nlpstatistics.niterations, nlpstatistics.totaltime, nlpstatistics.consviol, nlpstatistics.boundviol);
1235 
1236  /* we account only the extra iterations for this unusual NLP solve, but don't add anything else to our statistics (nnlpsolved, etc) */
1237  heurdata->iterused += nlpstatistics.niterations;
1238 
1239  /* if failed to get a feasible NLP solution now, then nothing to do */
1240  if( SCIPgetNLPSolstat(heurdata->subscip) > SCIP_NLPSOLSTAT_FEASIBLE )
1241  return SCIP_OKAY;
1242 
1243  SCIP_CALL( processNLPSol(scip, heur, authorheur, result, resultsol) );
1244 
1245  /* if successful, then use tighter feastol for all NLP solves from now on
1246  * if still not accepted, then don't try this again
1247  * (maybe the NLP is incomplete; we could give up on running this heur completely, but for now let the successrate factor in heurExec take care of running it less often)
1248  */
1249  if( *result == SCIP_FOUNDSOL )
1250  heurdata->feastol *= heurdata->feastolfactor;
1251  else
1252  heurdata->tighterfeastolfailed = TRUE;
1253 
1254  return SCIP_OKAY;
1255 }
1256 
1257 
1258 /** adds a set covering or bound disjunction constraint to the original problem */
1259 static
1261  SCIP* scip, /**< SCIP data structure */
1262  SCIP_HEURDATA* heurdata /**< heuristic data */
1263  )
1264 {
1265  SCIP_VAR** subvars;
1266  int nsubvars;
1267  int nsubbinvars;
1268  int nsubintvars;
1269  SCIP_VAR* var;
1270  SCIP_VAR* subvar;
1271  SCIP_CONS* cons;
1272  SCIP_VAR** consvars;
1273  int nconsvars;
1274  char name[SCIP_MAXSTRLEN];
1275  int i;
1276  SCIP_Real fixval;
1277 
1278  assert(scip != NULL);
1279 
1280  SCIP_CALL( SCIPgetOrigVarsData(heurdata->subscip, &subvars, &nsubvars, &nsubbinvars, &nsubintvars, NULL, NULL) );
1281  assert(nsubvars == heurdata->nsubvars);
1282 
1283  if( nsubbinvars == 0 && nsubintvars == 0 )
1284  {
1285  /* If we did not fix any discrete variables but found the "sub"CIP infeasible, then also the CIP is infeasible. */
1286  SCIPdebugMsg(scip, "heur_subnlp found subCIP infeasible after fixing no variables, something is strange here...\n");
1287  return SCIP_OKAY;
1288  }
1289 
1290  /* initialize */
1291  cons = NULL;
1292  consvars = NULL;
1293 
1294  /* create constraint name */
1295  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "subnlp_cutoff");
1296 
1297  /* if all discrete variables in the CIP are binary, then we create a set covering constraint
1298  * sum_{x_i fixed at 0} x_i + sum_{x_i fixed at 1} ~x_i >= 1
1299  */
1300  if( nsubintvars == 0 )
1301  {
1302  /* allocate memory for constraint variables */
1303  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nsubbinvars) );
1304 
1305  /* get fixations of discrete variables
1306  * to be sure, we take the values that were put into the subCIP before
1307  */
1308  nconsvars = 0;
1309  for( i = nsubbinvars - 1; i >= 0; --i )
1310  {
1311  subvar = subvars[i];
1312  assert(SCIPvarGetProbindex(subvar) == i);
1313 
1314  var = heurdata->var_subscip2scip[i];
1315  assert(var != NULL || SCIPisEQ(scip, SCIPvarGetLbGlobal(subvar), SCIPvarGetUbGlobal(subvar))); /* otherwise we should have exited in the variable fixation loop */
1316  if( var == NULL )
1317  continue;
1318 
1319  fixval = SCIPvarGetLbGlobal(subvar);
1320  assert(fixval == SCIPvarGetUbGlobal(subvar)); /* variable should be fixed in sub-SCIP */ /*lint !e777*/
1321  assert(fixval == 0.0 || fixval == 1.0); /* we have rounded values before fixing */
1322 
1323  if( fixval == 0.0 )
1324  {
1325  /* variable fixed at lower bound */
1326  consvars[nconsvars] = var;
1327  }
1328  else
1329  {
1330  SCIP_CALL( SCIPgetNegatedVar(scip, var, &consvars[nconsvars]) );
1331  }
1332 
1333  ++nconsvars;
1334  }
1335 
1336  /* create conflict constraint
1337  * In undercover, ConsLogicor is used, since then the inequality is not added to the LP.
1338  * However, I may want to use Setcover to avoid that the same fixing is computed by some LP based heuristic again.
1339  */
1340  SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, name, nconsvars, consvars,
1342  }
1343  else
1344  {
1345  /* if there are also integer variable, then create a bound disjunction constraint
1346  * x_1 >= fixval_1 + 1 || x_1 <= fixval_1 - 1 || x_2 >= fixval_2 + 1 || x_2 <= fixval_2 - 1 || ...
1347  */
1348  SCIP_BOUNDTYPE* boundtypes;
1349  SCIP_Real* bounds;
1350 
1351  /* allocate memory for constraint variables, boundtypes, and bounds
1352  * (there should be at most two literals for each integer variable)
1353  */
1354  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nsubbinvars + 2*nsubintvars) );
1355  SCIP_CALL( SCIPallocBufferArray(scip, &boundtypes, nsubbinvars + 2*nsubintvars) );
1356  SCIP_CALL( SCIPallocBufferArray(scip, &bounds, nsubbinvars + 2*nsubintvars) );
1357 
1358  /* get fixations of discrete variables
1359  * to be sure, we take the values that were put into the subCIP before
1360  */
1361  nconsvars = 0;
1362  for( i = nsubbinvars + nsubintvars - 1; i >= 0; --i )
1363  {
1364  subvar = subvars[i];
1365  assert(SCIPvarGetProbindex(subvar) == i);
1366 
1367  var = heurdata->var_subscip2scip[i];
1368  assert(var != NULL || SCIPisEQ(scip, SCIPvarGetLbGlobal(subvar), SCIPvarGetUbGlobal(subvar))); /* otherwise we should have exited in the variable fixation loop */
1369 
1370  if( var == NULL )
1371  continue;
1372 
1373  fixval = SCIPvarGetLbGlobal(subvar);
1374  assert(fixval == SCIPvarGetUbGlobal(subvar)); /* variable should be fixed in sub-SCIP */ /*lint !e777*/
1375  assert(SCIPceil(scip, fixval - 0.5) == fixval); /* we have rounded values before fixing */ /*lint !e777*/
1376  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY || SCIPvarGetLbGlobal(var) == fixval || SCIPvarGetUbGlobal(var) == fixval); /* for binaries, the fixval should be either 0.0 or 1.0 */ /*lint !e777*/
1377 
1378  if( SCIPvarGetLbGlobal(var) < fixval )
1379  {
1380  assert(nconsvars < nsubbinvars + 2*nsubintvars);
1381 
1382  /* literal x_i <= fixval-1 */
1383  boundtypes[nconsvars] = SCIP_BOUNDTYPE_UPPER;
1384  bounds[nconsvars] = fixval - 1.0;
1385  consvars[nconsvars] = var;
1386  ++nconsvars;
1387  }
1388 
1389  if( SCIPvarGetUbGlobal(var) > fixval )
1390  {
1391  assert(nconsvars < nsubbinvars + 2*nsubintvars);
1392 
1393  /* literal x_i >= fixval+1 */
1394  boundtypes[nconsvars] = SCIP_BOUNDTYPE_LOWER;
1395  bounds[nconsvars] = fixval + 1.0;
1396  consvars[nconsvars] = var;
1397  ++nconsvars;
1398  }
1399  }
1400 
1401  /* create conflict constraint */
1402  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, nconsvars, consvars, boundtypes, bounds,
1404 
1405  SCIPfreeBufferArray(scip, &bounds);
1406  SCIPfreeBufferArray(scip, &boundtypes);
1407  SCIPfreeBufferArray(scip, &consvars);
1408  }
1409 
1410  /* add and release constraint if created successfully */
1411  if( cons != NULL )
1412  {
1413  SCIPdebugMsg(scip, "adding constraint to forbid fixation in main problem\n");
1414  /* SCIPdebugPrintCons(scip, cons, NULL); */
1415  SCIP_CALL( SCIPaddCons(scip, cons) );
1416  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
1417  }
1418 
1419  /* free memory */
1420  SCIPfreeBufferArrayNull(scip, &consvars);
1421 
1422  return SCIP_OKAY;
1423 }
1424 
1425 
1426 /*
1427  * Callback methods of primal heuristic
1428  */
1429 
1430 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
1431 static
1432 SCIP_DECL_HEURCOPY(heurCopySubNlp)
1433 { /*lint --e{715}*/
1434  assert(scip != NULL);
1435  assert(heur != NULL);
1436  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1437 
1438  /* call inclusion method of primal heuristic */
1440 
1441  return SCIP_OKAY;
1442 }
1443 
1444 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
1445 static
1446 SCIP_DECL_HEURFREE(heurFreeSubNlp)
1447 {
1448  SCIP_HEURDATA* heurdata;
1449  assert(scip != NULL);
1450  assert(heur != NULL);
1451 
1452  heurdata = SCIPheurGetData(heur);
1453  assert(heurdata != NULL);
1454  assert(heurdata->subscip == NULL);
1455  assert(heurdata->var_subscip2scip == NULL);
1456  assert(heurdata->var_scip2subscip == NULL);
1457  assert(heurdata->startcand == NULL);
1458 
1459  SCIPfreeBlockMemory(scip, &heurdata);
1460 
1461  return SCIP_OKAY;
1462 }
1463 
1464 /** initialization method of primal heuristic (called after problem was transformed) */
1465 static
1466 SCIP_DECL_HEURINIT(heurInitSubNlp)
1467 { /*lint --e{715}*/
1468  SCIP_HEURDATA* heurdata;
1469 
1470  assert(scip != NULL);
1471  assert(heur != NULL);
1472 
1473  heurdata = SCIPheurGetData(heur);
1474  assert(heurdata != NULL);
1475  assert(heurdata->subscip == NULL);
1476 
1477  /* reset or initialize some flags and counters */
1478  heurdata->feastol = SCIPfeastol(scip);
1479  heurdata->tighterfeastolfailed = FALSE;
1480  heurdata->triedsetupsubscip = FALSE;
1481  heurdata->nseriousnlpierror = 0;
1482  heurdata->iterused = 0;
1483  heurdata->iterusedokay = 0;
1484  heurdata->iterusediterlim = 0;
1485  heurdata->nnlpsolves = 0;
1486  heurdata->nnlpsolvesokay = 0;
1487  heurdata->nnlpsolvesiterlim = 0;
1488  heurdata->nnlpsolvesinfeas = 0;
1489 
1490  return SCIP_OKAY;
1491 }
1492 
1493 /** solving process initialization method of primal heuristic (called when branch and bound process is about to begin) */
1494 static
1495 SCIP_DECL_HEURINITSOL(heurInitsolSubNlp)
1496 {
1497  assert(scip != NULL);
1498  assert(heur != NULL);
1499 
1500  /* if the heuristic is called at the root node, we want to be called directly after the initial root LP solve */
1501  if( SCIPheurGetFreqofs(heur) == 0 )
1503 
1504  return SCIP_OKAY;
1505 }
1506 
1507 /** solving process deinitialization method of primal heuristic (called before branch and bound process data is freed) */
1508 static
1509 SCIP_DECL_HEUREXITSOL(heurExitsolSubNlp)
1510 {
1511  SCIP_HEURDATA* heurdata;
1512  assert(scip != NULL);
1513  assert(heur != NULL);
1514 
1515  /* get heuristic's data */
1516  heurdata = SCIPheurGetData(heur);
1517  assert(heurdata != NULL);
1518 
1519  if( heurdata->subscip != NULL )
1520  {
1521  SCIP_CALL( freeSubSCIP(scip, heurdata) );
1522  heurdata->triedsetupsubscip = FALSE;
1523  }
1524 
1525  /* free start candidate */
1526  if( heurdata->startcand != NULL )
1527  {
1528  SCIP_CALL( SCIPfreeSol(scip, &heurdata->startcand) );
1529  }
1530 
1532 
1533  return SCIP_OKAY;
1534 }
1535 
1536 
1537 /** execution method of primal heuristic */
1538 static
1539 SCIP_DECL_HEUREXEC(heurExecSubNlp)
1540 { /*lint --e{666,715}*/
1541  SCIP_HEURDATA* heurdata;
1542  SCIP_Bool runheur;
1543  SCIP_Real itercontingent;
1544 
1545  assert(scip != NULL);
1546  assert(heur != NULL);
1547 
1548  /* obviously, we did not do anything yet */
1549  *result = SCIP_DIDNOTRUN;
1550 
1551  /* get heuristic's data */
1552  heurdata = SCIPheurGetData(heur);
1553  assert(heurdata != NULL);
1554 
1555  /* if triedsetupsubscip and keepcopy and subscip == NULL, then we tried to setup a subSCIP before, but failed due to some serious error
1556  * thus, we should do not need to try again
1557  *
1558  * otherwise, we continue and let SCIPapplyHeurSubNlp try to create subscip
1559  */
1560  if( heurdata->subscip == NULL && heurdata->keepcopy && heurdata->triedsetupsubscip )
1561  return SCIP_OKAY;
1562 
1563  /* before we run the heuristic for the first time, check whether we want to run the heuristic at all */
1564  if( SCIPheurGetNCalls(heur) == 0 )
1565  {
1566  SCIP_CALL( runHeuristic(scip, &runheur) );
1567  if( !runheur )
1568  return SCIP_OKAY;
1569  }
1570 
1571  if( heurdata->startcand == NULL )
1572  {
1573  /* if no start candidate is given, we consider the LP solution of the current node */
1574 
1575  /* however, if the node was already detected to be infeasible, then there is no point to look at its LP solution */
1576  if( nodeinfeasible )
1577  return SCIP_OKAY;
1578 
1579  /* at least if we are not called the first time, we call the heuristic only if an optimal LP solution is available
1580  * if we are called the first time and the LP is unbounded, then we are quite desperate and still give the NLP a try
1581  */
1583  {
1585  {
1586  *result = SCIP_DELAYED;
1587  SCIPdebugMsg(scip, "NLP heuristic delayed because no start candidate given and no LP solution available; LP status = %d\n", SCIPgetLPSolstat(scip));
1588  return SCIP_OKAY;
1589  }
1590  else
1591  {
1592  SCIPdebugMsg(scip, "LP is unbounded in root node, so we are quite desperate; run NLP heuristic and pray\n");
1593  }
1594  }
1595  else if( SCIPgetNLPBranchCands(scip) > 0 )
1596  {
1597  /* only call heuristic, if there are no fractional variables */
1598  *result = SCIP_DELAYED;
1599  SCIPdebugMsg(scip, "NLP heuristic delayed because no start candidate given and current LP solution is fractional\n");
1600  return SCIP_OKAY;
1601  }
1603  {
1604  /* only call heuristic, if there is still room for improvement in the current node */
1605  SCIPdebugMsg(scip, "NLP heuristic delayed because lower and upper bound coincide in current node\n");
1606  return SCIP_OKAY;
1607  }
1608  SCIPdebugMsg(scip, "using current LP solution as startcand\n");
1609  }
1610  else
1611  {
1612  SCIPdebugMsg(scip, "have startcand from heur %s\n", SCIPsolGetHeur(heurdata->startcand) ? SCIPheurGetName(SCIPsolGetHeur(heurdata->startcand)) : "NULL");
1613  }
1614 
1615  /* check if enough nodes have been processed so that we want to run the heuristic again */
1616 
1617  /* compute the contingent on number of iterations that the NLP solver is allowed to use
1618  * we make it depending on the current number of processed nodes
1619  */
1620  itercontingent = heurdata->nodesfactor * (SCIPgetNNodes(scip) + heurdata->nodesoffset);
1621  /* weight by previous success of heuristic if we have been running already
1622  * require at least ninitsolves many runs that didn't run into the NLP iterlimit
1623  * (so if we are still in the phase of finding a good iterlimit, do not consider success rate so far)
1624  */
1625  if( heurdata->successrateexp > 0.0 && SCIPheurGetNCalls(heur) - heurdata->nnlpsolvesiterlim >= heurdata->ninitsolves )
1626  itercontingent *= pow((SCIPheurGetNSolsFound(heur) + 1.0) / (SCIPheurGetNCalls(heur) + 1.0), heurdata->successrateexp);
1627  /* subtract the number of iterations used for all NLP solves so far */
1628  itercontingent -= heurdata->iterused;
1629 
1630  /* check whether the itercontingent is sufficient for the iteration limit we would use */
1631  if( itercontingent < calcIterLimit(scip, heurdata) )
1632  {
1633  /* not enough iterations left to start NLP solver */
1634  SCIPdebugMsg(scip, "skip NLP heuristic; contingent=%f; iterlimit=%d; success ratio=%g\n",
1635  itercontingent, calcIterLimit(scip, heurdata), pow((SCIPheurGetNSolsFound(heur) + 1.0) / (SCIPheurGetNCalls(heur) + 1.0), heurdata->successrateexp));
1636  return SCIP_OKAY;
1637  }
1638 
1639  /* so far we have not found any solution, but now we are willing to search for one */
1640  *result = SCIP_DIDNOTFIND;
1641 
1642  if( heurdata->nlpverblevel >= 1 )
1643  {
1644  SCIPinfoMessage(scip, NULL, "calling subnlp heuristic\n");
1645  }
1646 
1647  SCIP_CALL( SCIPapplyHeurSubNlp(scip, heur, result, heurdata->startcand, NULL) );
1648 
1649  /* SCIP does not like cutoff as return, so we say didnotfind, since we did not find a solution */
1650  if( *result == SCIP_CUTOFF )
1651  *result = SCIP_DIDNOTFIND;
1652 
1653  /* forget startcand */
1654  if( heurdata->startcand != NULL )
1655  {
1656  SCIP_CALL( SCIPfreeSol(scip, &heurdata->startcand) );
1657  }
1658 
1659  /* reset timing, if it was changed temporary (at the root node) */
1660  if( heurtiming != HEUR_TIMING )
1662 
1663  return SCIP_OKAY;
1664 }
1665 
1666 
1667 /*
1668  * primal heuristic specific interface methods
1669  */
1670 
1671 /** creates the NLP local search primal heuristic and includes it in SCIP */
1673  SCIP* scip /**< SCIP data structure */
1674  )
1675 {
1676  SCIP_HEURDATA* heurdata;
1677  SCIP_HEUR* heur;
1678 
1679  /* create Nlp primal heuristic data */
1680  SCIP_CALL( SCIPallocBlockMemory(scip, &heurdata) );
1681  BMSclearMemory(heurdata);
1682 
1683  /* include variable event handler */
1684  heurdata->eventhdlr = NULL;
1685  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &heurdata->eventhdlr, HEUR_NAME, "propagates a global bound change to the sub-SCIP",
1686  processVarEvent, NULL) );
1687  assert(heurdata->eventhdlr != NULL);
1688 
1689  /* include primal heuristic */
1690  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
1692  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecSubNlp, heurdata) );
1693 
1694  assert(heur != NULL);
1695 
1696  /* set non-NULL pointers to callback methods */
1697  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopySubNlp) );
1698  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeSubNlp) );
1699  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitSubNlp) );
1700  SCIP_CALL( SCIPsetHeurInitsol(scip, heur, heurInitsolSubNlp) );
1701  SCIP_CALL( SCIPsetHeurExitsol(scip, heur, heurExitsolSubNlp) );
1702 
1703  /* add Nlp primal heuristic parameters */
1704  SCIP_CALL( SCIPaddIntParam (scip, "heuristics/" HEUR_NAME "/nlpverblevel",
1705  "verbosity level of NLP solver",
1706  &heurdata->nlpverblevel, FALSE, 0, 0, USHRT_MAX, NULL, NULL) );
1707 
1708  SCIP_CALL( SCIPaddIntParam (scip, "heuristics/" HEUR_NAME "/nodesoffset",
1709  "number of nodes added to the current number of nodes when computing itercontingent (higher value runs heuristic more often in early search)",
1710  &heurdata->nodesoffset, FALSE, 1600, 0, INT_MAX, NULL, NULL) );
1711 
1712  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/nodesfactor",
1713  "factor on number of nodes in SCIP (plus nodesoffset) to compute itercontingent (higher value runs heuristics more frequently)",
1714  &heurdata->nodesfactor, FALSE, 0.3, 0.0, SCIPinfinity(scip), NULL, NULL) );
1715 
1716  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/successrateexp",
1717  "exponent for power of success rate to be multiplied with itercontingent (lower value decreases impact of success rate)",
1718  &heurdata->successrateexp, FALSE, 1.0, 0.0, DBL_MAX, NULL, NULL) );
1719 
1720  SCIP_CALL( SCIPaddIntParam (scip, "heuristics/" HEUR_NAME "/iterinit",
1721  "number of iterations used for initial NLP solves",
1722  &heurdata->iterinit, FALSE, 300, 0, INT_MAX, NULL, NULL) );
1723 
1724  SCIP_CALL( SCIPaddIntParam (scip, "heuristics/" HEUR_NAME "/ninitsolves",
1725  "number of successful NLP solves until switching to iterlimit guess and using success rate",
1726  &heurdata->ninitsolves, FALSE, 2, 0, INT_MAX, NULL, NULL) );
1727 
1728  SCIP_CALL( SCIPaddIntParam (scip, "heuristics/" HEUR_NAME "/itermin",
1729  "minimal number of iterations for NLP solves",
1730  &heurdata->itermin, FALSE, 20, 0, INT_MAX, NULL, NULL) );
1731 
1732  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/opttol",
1733  "absolute optimality tolerance to use for NLP solves",
1734  &heurdata->opttol, TRUE, SCIPdualfeastol(scip), 0.0, 1.0, NULL, NULL) );
1735 
1736  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/feastolfactor",
1737  "factor on SCIP feasibility tolerance for NLP solves if resolving when NLP solution not feasible in CIP",
1738  &heurdata->feastolfactor, FALSE, 0.1, 0.0, 1.0, NULL, NULL) );
1739 
1740  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/maxpresolverounds",
1741  "limit on number of presolve rounds in sub-SCIP (-1 for unlimited, 0 for no presolve)",
1742  &heurdata->maxpresolverounds, FALSE, -1, -1, INT_MAX, NULL, NULL) );
1743 
1744  SCIP_CALL( SCIPaddIntParam(scip, "heuristics/" HEUR_NAME "/presolveemphasis",
1745  "presolve emphasis in sub-SCIP (0: default, 1: aggressive, 2: fast, 3: off)",
1746  &heurdata->presolveemphasis, FALSE, (int)SCIP_PARAMSETTING_FAST, (int)SCIP_PARAMSETTING_DEFAULT, (int)SCIP_PARAMSETTING_OFF, NULL, NULL) );
1747 
1748  SCIP_CALL( SCIPaddBoolParam (scip, "heuristics/" HEUR_NAME "/setcutoff",
1749  "whether to set cutoff in sub-SCIP to current primal bound",
1750  &heurdata->setcutoff, FALSE, TRUE, NULL, NULL) );
1751 
1752  SCIP_CALL( SCIPaddBoolParam (scip, "heuristics/" HEUR_NAME "/forbidfixings",
1753  "whether to add constraints that forbid specific fixings that turned out to be infeasible",
1754  &heurdata->forbidfixings, FALSE, FALSE, NULL, NULL) );
1755 
1756  SCIP_CALL( SCIPaddBoolParam (scip, "heuristics/" HEUR_NAME "/keepcopy",
1757  "whether to keep SCIP copy or to create new copy each time heuristic is applied",
1758  &heurdata->keepcopy, TRUE, TRUE, NULL, NULL) );
1759 
1760  SCIP_CALL( SCIPaddRealParam(scip, "heuristics/" HEUR_NAME "/expectinfeas",
1761  "percentage of NLP solves with infeasible status required to tell NLP solver to expect an infeasible NLP",
1762  &heurdata->expectinfeas, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
1763 
1764  return SCIP_OKAY;
1765 }
1766 
1767 /** main procedure of the subNLP heuristic */
1769  SCIP* scip, /**< original SCIP data structure */
1770  SCIP_HEUR* heur, /**< heuristic data structure */
1771  SCIP_RESULT* result, /**< pointer to store result of: did not run, solution found, no solution found, or fixing is infeasible (cutoff) */
1772  SCIP_SOL* refpoint, /**< point to take fixation of discrete variables from, and startpoint for NLP solver; if NULL, then LP solution is used */
1773  SCIP_SOL* resultsol /**< a solution where to store found solution values, if any, or NULL if to try adding to SCIP */
1774  )
1775 {
1776  SCIP_HEURDATA* heurdata;
1777  SCIP_VAR* var;
1778  SCIP_VAR* subvar;
1779  int i;
1780  SCIP_Real cutoff = SCIPinfinity(scip);
1781 
1782  assert(scip != NULL);
1783  assert(heur != NULL);
1784 
1785  /* get heuristic's data */
1786  heurdata = SCIPheurGetData(heur);
1787  assert(heurdata != NULL);
1788 
1789  /* try to setup NLP if not tried before */
1790  if( heurdata->subscip == NULL && !heurdata->triedsetupsubscip )
1791  {
1792  SCIP_CALL( createSubSCIP(scip, heurdata) );
1793  }
1794 
1795  *result = SCIP_DIDNOTRUN;
1796 
1797  /* if subSCIP could not be created, then do not run */
1798  if( heurdata->subscip == NULL )
1799  return SCIP_OKAY;
1800 
1801  assert(heurdata->nsubvars > 0);
1802  assert(heurdata->var_subscip2scip != NULL);
1803 
1804  /* fix discrete variables in sub-SCIP */
1805  if( !heurdata->continuous )
1806  {
1807  SCIP_Real fixval;
1808  SCIP_VAR** subvars;
1809  int nsubvars;
1810  int nsubbinvars;
1811  int nsubintvars;
1812  SCIP_Bool infeas;
1813  SCIP_Bool tightened;
1814 
1815  /* transform sub-SCIP, so variable fixing are easily undone by free-transform */
1816  assert(!SCIPisTransformed(heurdata->subscip));
1817  SCIP_CALL( SCIPtransformProb(heurdata->subscip) );
1818 
1819  SCIP_CALL( SCIPgetOrigVarsData(heurdata->subscip, &subvars, &nsubvars, &nsubbinvars, &nsubintvars, NULL, NULL) );
1820  assert(nsubvars == heurdata->nsubvars);
1821 
1822  /* fix discrete variables to values in startpoint */
1823  for( i = nsubbinvars + nsubintvars - 1; i >= 0; --i )
1824  {
1825  subvar = subvars[i];
1826  assert(SCIPvarGetProbindex(subvar) == i);
1827 
1828  var = heurdata->var_subscip2scip[i];
1829  assert(var != NULL);
1830 
1831  /* at this point, variables in subscip and in our scip should have same bounds */
1832  assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(subvar), SCIPvarGetLbGlobal(var)));
1833  assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(subvar), SCIPvarGetUbGlobal(var)));
1834 
1835  fixval = SCIPgetSolVal(scip, refpoint, var);
1836 
1837  /* only run heuristic on integer feasible points (unless we are on an unbounded LP) */
1838  if( !SCIPisFeasIntegral(scip, fixval) )
1839  {
1840  if( refpoint != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
1841  {
1842  SCIPdebugMsg(scip, "skip NLP heuristic because start candidate not integer feasible: var <%s> has value %g\n", SCIPvarGetName(var), fixval);
1843  goto CLEANUP;
1844  }
1845  }
1846  /* if we do not really have a startpoint, then we should take care that we do not fix variables to very large values
1847  * thus, we set to 0.0 here and project on bounds below
1848  */
1849  if( REALABS(fixval) > 1E+10 && refpoint == NULL && SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
1850  fixval = 0.0;
1851 
1852  /* fixing variables to infinity causes problems, we should not have been passed such a solution as refpoint */
1853  assert(!SCIPisInfinity(scip, REALABS(fixval)));
1854 
1855  /* round fractional variables to the nearest integer */
1856  fixval = SCIPround(scip, fixval);
1857 
1858  /* adjust value to the global bounds of the corresponding SCIP variable */
1859  fixval = MAX(fixval, SCIPvarGetLbGlobal(var)); /*lint !e666*/
1860  fixval = MIN(fixval, SCIPvarGetUbGlobal(var)); /*lint !e666*/
1861 
1862  /* SCIPdebugMsg(scip, "fix variable <%s> to %g\n", SCIPvarGetName(var), fixval); */
1863  SCIP_CALL( SCIPtightenVarLb(heurdata->subscip, subvar, fixval, TRUE, &infeas, &tightened) );
1864  if( !infeas )
1865  {
1866  SCIP_CALL( SCIPtightenVarUb(heurdata->subscip, subvar, fixval, TRUE, &infeas, &tightened) );
1867  }
1868  if( infeas )
1869  {
1870  SCIPdebugMsg(scip, "skip NLP heuristic because start candidate not feasible: fixing var <%s> to value %g is infeasible\n", SCIPvarGetName(var), fixval);
1871  goto CLEANUP;
1872  }
1873  }
1874 
1875  /* if there is already a solution, possibly add an objective cutoff in sub-SCIP
1876  * we do this here only for problems with discrete variables, since the cutoff may be useful when presolving the subscip
1877  * for the NLP solver, a cutoff is useless at best
1878  */
1879  if( SCIPgetNSols(scip) > 0 && heurdata->setcutoff )
1880  {
1881  cutoff = SCIPgetUpperbound(scip);
1882  assert( !SCIPisInfinity(scip, cutoff) );
1883 
1884  SCIP_CALL( SCIPsetObjlimit(heurdata->subscip, cutoff) );
1885  SCIPdebugMsg(scip, "set objective limit %g\n", cutoff);
1886  }
1887  }
1888  else
1889  {
1890  /* for continuous problems, we should already be in the transformed stage */
1891  assert(SCIPisTransformed(heurdata->subscip));
1892  }
1893 
1894  /* solve the subNLP and try to add solution to SCIP */
1895  SCIP_CALL( solveSubNLP(scip, heur, result, refpoint, resultsol) );
1896 
1897  if( heurdata->subscip == NULL )
1898  {
1899  /* something horrible must have happened that we decided to give up completely on this heuristic */
1900  *result = SCIP_DIDNOTFIND;
1901  return SCIP_OKAY;
1902  }
1903 
1904  if( *result == SCIP_CUTOFF )
1905  {
1906  if( heurdata->subscipisvalid && SCIPgetNActivePricers(scip) == 0 )
1907  {
1908  /* if the subNLP is valid and turned out to be globally infeasible (i.e., proven by SCIP), then we forbid this fixation in the main problem */
1909  if( SCIPisInfinity(scip, cutoff) && heurdata->forbidfixings )
1910  {
1911  SCIP_CALL( forbidFixation(scip, heurdata) );
1912  }
1913  }
1914  else
1915  {
1916  /* if the subNLP turned out to be globally infeasible but we are not sure that we have a valid copy, we change to DIDNOTFIND */
1917  *result = SCIP_DIDNOTFIND;
1918  }
1919  }
1920 
1921  CLEANUP:
1922  if( !heurdata->continuous )
1923  {
1924  SCIP_CALL( SCIPfreeTransform(heurdata->subscip) );
1925  }
1926 
1927  /* if the heuristic was applied before solving has started, then destroy subSCIP, since EXITSOL may not be called
1928  * also if keepcopy is disabled, then destroy subSCIP
1929  */
1930  if( SCIPgetStage(scip) < SCIP_STAGE_SOLVING || !heurdata->keepcopy )
1931  {
1932  SCIP_CALL( freeSubSCIP(scip, heurdata) );
1933  heurdata->triedsetupsubscip = FALSE;
1934  }
1935 
1936  return SCIP_OKAY;
1937 }
1938 
1939 /** updates the starting point for the NLP heuristic
1940  *
1941  * Is called by a constraint handler that handles nonlinear constraints when a check on feasibility of a solution fails.
1942  */
1944  SCIP* scip, /**< SCIP data structure */
1945  SCIP_HEUR* heur, /**< NLP heuristic */
1946  SCIP_SOL* solcand, /**< solution candidate */
1947  SCIP_Real violation /**< constraint violation of solution candidate */
1948  )
1949 {
1950  SCIP_HEURDATA* heurdata;
1951 
1952  assert(scip != NULL);
1953  assert(heur != NULL);
1954  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
1955  assert(solcand != NULL);
1956  assert(SCIPisPositive(scip, violation));
1957 
1958  /* too early or the game is over already: no more interest in starting points */
1959  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
1960  return SCIP_OKAY;
1961 
1962  heurdata = SCIPheurGetData(heur);
1963  assert(heurdata != NULL);
1964 
1965  if( heurdata->subscip == NULL )
1966  {
1967  /* if we do not have a sub-SCIP, but tried to set one up before or will never create a subSCIP, then do not need a starting point */
1968  SCIP_Bool runheur;
1969  if( heurdata->triedsetupsubscip )
1970  return SCIP_OKAY;
1971  if( SCIPheurGetFreq(heur) < 0 )
1972  return SCIP_OKAY;
1973  SCIP_CALL( runHeuristic(scip, &runheur) );
1974  if( !runheur )
1975  return SCIP_OKAY;
1976  }
1977 
1978  /* if the solution is the one we created (last), then it is useless to use it as starting point again
1979  * (we cannot check SCIPsolGetHeur()==heur, as subnlp may not be registered as author of the solution)
1980  */
1981  if( heurdata->lastsol == solcand )
1982  return SCIP_OKAY;
1983 
1984  SCIPdebugMsg(scip, "consider solution candidate with violation %g and objective %g from %s\n",
1985  violation, SCIPgetSolTransObj(scip, solcand), SCIPsolGetHeur(solcand) ? SCIPheurGetName(SCIPsolGetHeur(solcand)) : "tree");
1986 
1987  /* if we have no point yet, or the new point has a lower constraint violation, or it has a better objective function value, then take the new point */
1988  if( heurdata->startcand == NULL || violation < heurdata->startcandviol ||
1989  SCIPisRelGT(scip, SCIPgetSolTransObj(scip, heurdata->startcand), SCIPgetSolTransObj(scip, solcand)) )
1990  {
1991  if( heurdata->startcand != NULL )
1992  {
1993  SCIP_CALL( SCIPfreeSol(scip, &heurdata->startcand) );
1994  }
1995  SCIP_CALL( SCIPcreateSolCopy(scip, &heurdata->startcand, solcand) );
1996  SCIP_CALL( SCIPunlinkSol(scip, heurdata->startcand) );
1997  heurdata->startcandviol = violation;
1998 
1999  /* remember which heuristic proposed the candidate */
2000  SCIPsolSetHeur(heurdata->startcand, SCIPgetSolHeur(scip, solcand));
2001  }
2002 
2003  return SCIP_OKAY;
2004 }
2005 
2006 /** gets startpoint candidate to be used in next call to NLP heuristic, or NULL if none */
2008  SCIP* scip, /**< original SCIP data structure */
2009  SCIP_HEUR* heur /**< heuristic data structure */
2010  )
2011 {
2012  SCIP_HEURDATA* heurdata;
2013 
2014  assert(scip != NULL);
2015  assert(heur != NULL);
2016  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
2017 
2018  heurdata = SCIPheurGetData(heur);
2019  assert(heurdata != NULL);
2020 
2021  return heurdata->startcand;
2022 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
SCIP_RETCODE SCIPsetHeurExitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEUREXITSOL((*heurexitsol)))
Definition: scip_heur.c:242
static SCIP_RETCODE solveSubNLP(SCIP *scip, SCIP_HEUR *heur, SCIP_RESULT *result, SCIP_SOL *refpoint, SCIP_SOL *resultsol)
Definition: heur_subnlp.c:799
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2082
#define SCIP_HEURTIMING_DURINGLPLOOP
Definition: type_timing.h:80
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3570
SCIP_RETCODE SCIPchgVarLbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4942
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
static SCIP_RETCODE createSubSCIP(SCIP *scip, SCIP_HEURDATA *heurdata)
Definition: heur_subnlp.c:219
#define NULL
Definition: def.h:267
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5202
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for SCIP parameter handling
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
public methods for memory management
static SCIP_DECL_HEURINIT(heurInitSubNlp)
Definition: heur_subnlp.c:1466
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_Real SCIPgetPrimalbound(SCIP *scip)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18079
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
#define SCIP_MAXSTRLEN
Definition: def.h:288
SCIP_RETCODE SCIPincludeHeurSubNlp(SCIP *scip)
Definition: heur_subnlp.c:1672
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18135
SCIP_RETCODE SCIPcreateConsSetcover(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9475
public solving methods
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:104
public methods for timing
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip_nlp.c:574
void * SCIPhashmapEntryGetOrigin(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3560
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1247
static SCIP_RETCODE createSolFromNLP(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL **sol, SCIP_HEUR *authorheur)
Definition: heur_subnlp.c:525
SCIP_Real SCIPdualfeastol(SCIP *scip)
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1866
SCIP_SOL ** SCIPgetSols(SCIP *scip)
Definition: scip_sol.c:2119
#define FALSE
Definition: def.h:94
public methods for presolving plugins
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3074
SCIP_RETCODE SCIPapplyHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_RESULT *result, SCIP_SOL *refpoint, SCIP_SOL *resultsol)
Definition: heur_subnlp.c:1768
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip_pricer.c:348
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
#define TRUE
Definition: def.h:93
#define SCIPdebug(x)
Definition: pub_message.h:93
#define HEUR_FREQ
Definition: heur_subnlp.c:73
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
SCIP_RETCODE SCIPsetPresolving(SCIP *scip, SCIP_PARAMSETTING paramsetting, SCIP_Bool quiet)
Definition: scip_param.c:953
int SCIPheurGetFreqofs(SCIP_HEUR *heur)
Definition: heur.c:1559
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17769
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:75
struct SCIP_HeurData SCIP_HEURDATA
Definition: type_heur.h:77
#define HEUR_FREQOFS
Definition: heur_subnlp.c:74
public methods for problem variables
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5319
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
SCIP_RETCODE SCIPincludeHeurBasic(SCIP *scip, SCIP_HEUR **heur, const char *name, const char *desc, char dispchar, int priority, int freq, int freqofs, int maxdepth, SCIP_HEURTIMING timingmask, SCIP_Bool usessubscip, SCIP_DECL_HEUREXEC((*heurexec)), SCIP_HEURDATA *heurdata)
Definition: scip_heur.c:117
SCIP_RETCODE SCIPgetOrigVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:2357
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3261
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:307
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:596
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:428
public methods for SCIP variables
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:603
SCIP_RETCODE SCIPcopyPlugins(SCIP *sourcescip, SCIP *targetscip, SCIP_Bool copyreaders, SCIP_Bool copypricers, SCIP_Bool copyconshdlrs, SCIP_Bool copyconflicthdlrs, SCIP_Bool copypresolvers, SCIP_Bool copyrelaxators, SCIP_Bool copyseparators, SCIP_Bool copycutselectors, SCIP_Bool copypropagators, SCIP_Bool copyheuristics, SCIP_Bool copyeventhdlrs, SCIP_Bool copynodeselectors, SCIP_Bool copybranchrules, SCIP_Bool copydisplays, SCIP_Bool copydialogs, SCIP_Bool copytables, SCIP_Bool copyexprhdlrs, SCIP_Bool copynlpis, SCIP_Bool passmessagehdlr, SCIP_Bool *valid)
Definition: scip_copy.c:275
static SCIP_RETCODE createSolFromSubScipSol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL **sol, SCIP_SOL *subsol, SCIP_HEUR *authorheur)
Definition: heur_subnlp.c:707
static SCIP_DECL_HEUREXITSOL(heurExitsolSubNlp)
Definition: heur_subnlp.c:1509
static SCIP_DECL_HEURINITSOL(heurInitsolSubNlp)
Definition: heur_subnlp.c:1495
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
SCIP_RETCODE SCIPchgVarUbGlobal(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:5031
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPcopyParamSettings(SCIP *sourcescip, SCIP *targetscip)
Definition: scip_copy.c:2564
SCIP_RETCODE SCIPprintStatistics(SCIP *scip, FILE *file)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
SCIP_SOL * SCIPgetStartCandidateHeurSubNlp(SCIP *scip, SCIP_HEUR *heur)
Definition: heur_subnlp.c:2007
public methods for numerical tolerances
SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
enum SCIP_ParamSetting SCIP_PARAMSETTING
Definition: type_paramset.h:65
static SCIP_DECL_HEUREXEC(heurExecSubNlp)
Definition: heur_subnlp.c:1539
public methods for querying solving statistics
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1067
int SCIPgetNNlpis(SCIP *scip)
Definition: scip_nlpi.c:200
#define HEUR_DESC
Definition: heur_subnlp.c:70
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18089
public methods for NLPI solver interfaces
int SCIPgetNNLPVars(SCIP *scip)
Definition: scip_nlp.c:201
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1242
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:474
SCIP_NLPTERMSTAT SCIPgetNLPTermstat(SCIP *scip)
Definition: scip_nlp.c:596
SCIP_RETCODE SCIPsetHeurInitsol(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINITSOL((*heurinitsol)))
Definition: scip_heur.c:226
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2498
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1453
#define SCIPerrorMessage
Definition: pub_message.h:64
SCIP_Bool SCIPisParamFixed(SCIP *scip, const char *name)
Definition: scip_param.c:219
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition: misc.c:3541
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition: misc.c:3549
SCIP_RETCODE SCIPsetHeurFree(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURFREE((*heurfree)))
Definition: scip_heur.c:178
#define HEUR_DISPCHAR
Definition: heur_subnlp.c:71
public methods for event handler plugins and event handlers
SCIP_RETCODE SCIPhasNLPContinuousNonlinearity(SCIP *scip, SCIP_Bool *result)
Definition: scip_nlp.c:125
static SCIP_RETCODE forbidFixation(SCIP *scip, SCIP_HEURDATA *heurdata)
Definition: heur_subnlp.c:1260
SCIP_RETCODE SCIPcopyVars(SCIP *sourcescip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_VAR **fixedvars, SCIP_Real *fixedvals, int nfixedvars, SCIP_Bool global)
Definition: scip_copy.c:1178
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:429
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:498
SCIP_RETCODE SCIPpresolve(SCIP *scip)
Definition: scip_solve.c:2328
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
#define MAX3(x, y, z)
Definition: def.h:247
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE freeSubSCIP(SCIP *scip, SCIP_HEURDATA *heurdata)
Definition: heur_subnlp.c:166
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17420
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3108
SCIP_Real totaltime
Definition: type_nlpi.h:200
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2804
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1347
SCIP_RETCODE SCIPsetNLPInitialGuess(SCIP *scip, SCIP_Real *initialguess)
Definition: scip_nlp.c:474
#define REALABS(x)
Definition: def.h:197
int SCIPheurGetFreq(SCIP_HEUR *heur)
Definition: heur.c:1538
SCIP_Real SCIPgetLocalDualbound(SCIP *scip)
Definition: scip_prob.c:3566
public methods for problem copies
public methods for primal CIP solutions
#define SCIP_CALL(x)
Definition: def.h:380
#define HEUR_TIMING
Definition: heur_subnlp.c:76
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
SCIP_Longint SCIPheurGetNCalls(SCIP_HEUR *heur)
Definition: heur.c:1579
public methods for primal heuristic plugins and divesets
#define HEUR_PRIORITY
Definition: heur_subnlp.c:72
public methods for constraint handler plugins and constraints
Ipopt NLP interface.
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1077
public data structures and miscellaneous methods
SCIP_RETCODE SCIPfreeTransform(SCIP *scip)
Definition: scip_solve.c:3344
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1053
SCIP_RETCODE SCIPcheckSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *feasible)
Definition: scip_sol.c:3251
#define SCIP_Bool
Definition: def.h:91
SCIP_RETCODE SCIPgetNLPStatistics(SCIP *scip, SCIP_NLPSTATISTICS *statistics)
Definition: scip_nlp.c:621
static SCIP_DECL_HEURFREE(heurFreeSubNlp)
Definition: heur_subnlp.c:1446
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:168
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1030
SCIP_RETCODE SCIPsetObjlimit(SCIP *scip, SCIP_Real objlimit)
Definition: scip_prob.c:1422
SCIP_Real boundviol
Definition: type_nlpi.h:204
SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
Definition: var.c:18466
#define HEUR_MAXDEPTH
Definition: heur_subnlp.c:75
SCIP_RETCODE SCIPcopyConss(SCIP *sourcescip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool enablepricing, SCIP_Bool *valid)
Definition: scip_copy.c:1730
void SCIPsolSetHeur(SCIP_SOL *sol, SCIP_HEUR *heur)
Definition: sol.c:2849
SCIP_RETCODE SCIPtrySolFree(SCIP *scip, SCIP_SOL **sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
Definition: scip_sol.c:3050
#define MIN(x, y)
Definition: def.h:243
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:841
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
int SCIPgetNSols(SCIP *scip)
Definition: scip_sol.c:2070
#define HEUR_USESSUBSCIP
Definition: heur_subnlp.c:77
int SCIPgetNPresolRounds(SCIP *scip)
Definition: scip_presol.c:288
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE runHeuristic(SCIP *scip, SCIP_Bool *runheur)
Definition: heur_subnlp.c:136
#define BMSclearMemory(ptr)
Definition: memory.h:129
#define SCIP_EVENTTYPE_GBDCHANGED
Definition: type_event.h:120
SCIP_RETCODE SCIPvarGetOrigvarSum(SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: var.c:12775
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
public methods for the LP relaxation, rows and columns
public methods for variable pricer plugins
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
public methods for nonlinear relaxation
SCIP_Real consviol
Definition: type_nlpi.h:203
SCIP_Bool SCIPhasNLPSolution(SCIP *scip)
Definition: scip_nlp.c:671
public methods for branching rule plugins and branching
SCIP_RETCODE SCIPcopyProb(SCIP *sourcescip, SCIP *targetscip, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, const char *name)
Definition: scip_copy.c:527
public methods for managing events
general public methods
#define MAX(x, y)
Definition: def.h:239
public methods for solutions
static SCIP_DECL_HEURCOPY(heurCopySubNlp)
Definition: heur_subnlp.c:1432
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3042
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
public methods for message output
NLP local search primal heuristic using sub-SCIPs.
SCIP_RETCODE SCIPsetHeurInit(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURINIT((*heurinit)))
Definition: scip_heur.c:194
#define HEUR_NAME
Definition: heur_subnlp.c:69
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
SCIP_HEUR * SCIPgetSolHeur(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1540
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1213
#define SCIP_Real
Definition: def.h:173
public methods for message handling
void SCIPheurSetTimingmask(SCIP_HEUR *heur, SCIP_HEURTIMING timingmask)
Definition: heur.c:1493
#define SCIP_INVALID
Definition: def.h:193
#define SCIP_Longint
Definition: def.h:158
SCIP_Longint SCIPheurGetNSolsFound(SCIP_HEUR *heur)
Definition: heur.c:1589
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1046
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17585
SCIP_RETCODE SCIPtransformProb(SCIP *scip)
Definition: scip_solve.c:222
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetNLPObjval(SCIP *scip)
Definition: scip_nlp.c:645
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPmergeNLPIStatistics(SCIP *sourcescip, SCIP *targetscip, SCIP_Bool reset)
Definition: scip_copy.c:1330
static SCIP_RETCODE processNLPSol(SCIP *scip, SCIP_HEUR *heur, SCIP_HEUR *authorheur, SCIP_RESULT *result, SCIP_SOL *resultsol)
Definition: heur_subnlp.c:591
SCIP_RETCODE SCIPsetHeurCopy(SCIP *scip, SCIP_HEUR *heur, SCIP_DECL_HEURCOPY((*heurcopy)))
Definition: scip_heur.c:162
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18145
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:1943
SCIP_Real SCIPgetUpperbound(SCIP *scip)
public methods for primal heuristics
static SCIP_DECL_EVENTEXEC(processVarEvent)
Definition: heur_subnlp.c:468
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:76
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_HEURDATA * SCIPheurGetData(SCIP_HEUR *heur)
Definition: heur.c:1364
constraint handler for bound disjunction constraints
#define SCIPsolveNLP(...)
Definition: scip_nlp.h:361
SCIP_RETCODE SCIPresetParam(SCIP *scip, const char *name)
Definition: scip_param.c:835
SCIP_Longint SCIPgetNNodes(SCIP *scip)
#define SCIPABORT()
Definition: def.h:352
public methods for global and local (sub)problems
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
static int calcIterLimit(SCIP *scip, SCIP_HEURDATA *heurdata)
Definition: heur_subnlp.c:774
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:545
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:1526
SCIP_VAR ** SCIPgetNLPVars(SCIP *scip)
Definition: scip_nlp.c:179
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17749
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:339
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:184
memory allocation routines