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