1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file concsolver_scip.c
17 * @ingroup PARALLEL
18 * @brief implementation of concurrent solver interface for SCIP
19 * @author Leona Gottwald
20 */
21
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23
24 #include "blockmemshell/memory.h"
25 #include "scip/boundstore.h"
26 #include "scip/concsolver.h"
27 #include "scip/concsolver_scip.h"
28 #include "scip/concurrent.h"
29 #include "scip/pub_event.h"
30 #include "scip/pub_heur.h"
31 #include "scip/pub_message.h"
32 #include "scip/pub_misc.h"
33 #include "scip/pub_paramset.h"
34 #include "scip/pub_sol.h"
35 #include "scip/pub_var.h"
36 #include "scip/scip_concurrent.h"
37 #include "scip/scip_copy.h"
38 #include "scip/scip_event.h"
39 #include "scip/scip_general.h"
40 #include "scip/scip_heur.h"
41 #include "scip/scip_mem.h"
42 #include "scip/scip_message.h"
43 #include "scip/scip_numerics.h"
44 #include "scip/scip_param.h"
45 #include "scip/scip_prob.h"
46 #include "scip/scip_sol.h"
47 #include "scip/scip_solve.h"
48 #include "scip/scip_solvingstats.h"
49 #include "scip/scip_timing.h"
50 #include "scip/syncstore.h"
51 #include <string.h>
52
53 /* event handler for synchronization */
54 #define EVENTHDLR_NAME "sync"
55 #define EVENTHDLR_DESC "event handler for synchronization of concurrent scip sovlers"
56
57 /*
58 * Data structures
59 */
60
61 /** event handler data */
62 struct SCIP_EventhdlrData
63 {
64 int filterpos;
65 };
66
67 /*
68 * Callback methods of event handler
69 */
70
71 /** destructor of event handler to free user data (called when SCIP is exiting) */
72 static
SCIP_DECL_EVENTFREE(eventFreeSync)73 SCIP_DECL_EVENTFREE(eventFreeSync)
74 { /*lint --e{715}*/
75 SCIP_EVENTHDLRDATA* eventhdlrdata;
76
77 assert(scip != NULL);
78 assert(eventhdlr != NULL);
79 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
80
81 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
82 assert(eventhdlrdata != NULL);
83
84 SCIPfreeBlockMemory(scip, &eventhdlrdata);
85
86 SCIPeventhdlrSetData(eventhdlr, NULL);
87
88 return SCIP_OKAY;
89 }
90
91 /** initialization method of event handler (called after problem was transformed) */
92 static
SCIP_DECL_EVENTINIT(eventInitSync)93 SCIP_DECL_EVENTINIT(eventInitSync)
94 { /*lint --e{715}*/
95 SCIP_EVENTHDLRDATA* eventhdlrdata;
96 SCIP_SYNCSTORE* syncstore;
97
98 assert(scip != NULL);
99 assert(eventhdlr != NULL);
100 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
101
102 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
103 assert(eventhdlrdata != NULL);
104
105 syncstore = SCIPgetSyncstore(scip);
106 assert(syncstore != NULL);
107
108 if( eventhdlrdata->filterpos < 0 && SCIPsyncstoreIsInitialized(syncstore) )
109 {
110 /* notify SCIP that your event handler wants to react on synchronization events */
111 SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SYNC, eventhdlr, NULL, &eventhdlrdata->filterpos) );
112 }
113
114 return SCIP_OKAY;
115 }
116
117 /** deinitialization method of event handler (called before transformed problem is freed) */
118 static
SCIP_DECL_EVENTEXIT(eventExitSync)119 SCIP_DECL_EVENTEXIT(eventExitSync)
120 { /*lint --e{715}*/
121 SCIP_EVENTHDLRDATA* eventhdlrdata;
122
123 assert(scip != NULL);
124 assert(eventhdlr != NULL);
125 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
126
127 eventhdlrdata = SCIPeventhdlrGetData(eventhdlr);
128 assert(eventhdlrdata != NULL);
129
130 /* notify SCIP that your event handler wants to drop the event type synchronization found */
131 if( eventhdlrdata->filterpos >= 0 )
132 {
133 SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SYNC, eventhdlr, NULL, eventhdlrdata->filterpos) );
134 eventhdlrdata->filterpos = -1;
135 }
136
137 return SCIP_OKAY;
138 }
139
140 /** execution method of event handler */
141 static
SCIP_DECL_EVENTEXEC(eventExecSync)142 SCIP_DECL_EVENTEXEC(eventExecSync)
143 { /*lint --e{715}*/
144 assert(eventhdlr != NULL);
145 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
146 assert(event != NULL);
147 assert(scip != NULL);
148
149 SCIP_CALL( SCIPsynchronize(scip) );
150
151 return SCIP_OKAY;
152 }
153
154
155 /** includes event handler for synchronization found */
156 static
includeEventHdlrSync(SCIP * scip)157 SCIP_RETCODE includeEventHdlrSync(
158 SCIP* scip /**< SCIP data structure */
159 )
160 {
161 SCIP_EVENTHDLR* eventhdlr;
162 SCIP_EVENTHDLRDATA* eventhdlrdata;
163
164 SCIP_CALL( SCIPallocBlockMemory(scip, &eventhdlrdata) );
165 eventhdlrdata->filterpos = -1;
166
167 /* create event handler for events on watched variables */
168 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecSync, eventhdlrdata) );
169 assert(eventhdlr != NULL);
170
171 SCIP_CALL( SCIPsetEventhdlrFree(scip, eventhdlr, eventFreeSync) );
172 SCIP_CALL( SCIPsetEventhdlrInit(scip, eventhdlr, eventInitSync) );
173 SCIP_CALL( SCIPsetEventhdlrExit(scip, eventhdlr, eventExitSync) );
174
175 return SCIP_OKAY;
176 }
177
178 /** data for a concurrent solver type */
179 struct SCIP_ConcSolverTypeData
180 {
181 SCIP_Bool loademphasis; /**< should emphasis settings be loaded when creating an instance of this concurrent solver */
182 SCIP_PARAMEMPHASIS emphasis; /**< parameter emphasis that will be loaded if loademphasis is true */
183 };
184
185 /** data for a concurrent solver */
186 struct SCIP_ConcSolverData
187 {
188 SCIP* solverscip; /**< the concurrent solvers private SCIP datastructure */
189 SCIP_VAR** vars; /**< array of variables in the order of the main SCIP's variable array */
190 int nvars; /**< number of variables in the above arrays */
191 };
192
193 /** Disable dual reductions that might cut off optimal solutions. Although they keep at least
194 * one optimal solution intact, communicating these bounds may cut off all optimal solutions,
195 * if different optimal solutions were kept in different concurrent solvers. */
196 static
disableConflictingDualReductions(SCIP * scip)197 SCIP_RETCODE disableConflictingDualReductions(
198 SCIP* scip /**< SCIP datastructure */
199 )
200 {
201 SCIP_Bool commvarbnds;
202
203 SCIP_CALL( SCIPgetBoolParam(scip, "concurrent/commvarbnds", &commvarbnds) );
204
205 if( !commvarbnds )
206 return SCIP_OKAY;
207
208 SCIP_CALL( SCIPsetBoolParam(scip, "misc/allowstrongdualreds", FALSE) );
209 return SCIP_OKAY;
210 }
211
212 /** sets the child selection rule based on the index of the concurrent solver */
213 static
setChildSelRule(SCIP_CONCSOLVER * concsolver)214 SCIP_RETCODE setChildSelRule(
215 SCIP_CONCSOLVER* concsolver /**< the concurrent solver */
216 )
217 {
218 SCIP_CONCSOLVERDATA* data;
219 static char childsel[] = { 'h', 'i', 'p', 'r', 'l', 'd', 'u' };
220
221 assert(concsolver != NULL);
222
223 data = SCIPconcsolverGetData(concsolver);
224 assert(data != NULL);
225
226 SCIP_CALL( SCIPsetCharParam(data->solverscip, "nodeselection/childsel", childsel[SCIPconcsolverGetIdx(concsolver) % 7]) );
227
228 return SCIP_OKAY;
229 }
230
231 /** initialize the concurrent SCIP solver, i.e. setup the copy of the problem and the
232 * mapping of the variables */
233 static
initConcsolver(SCIP * scip,SCIP_CONCSOLVER * concsolver)234 SCIP_RETCODE initConcsolver(
235 SCIP* scip, /**< the main SCIP instance */
236 SCIP_CONCSOLVER* concsolver /**< the concurrent solver to set up */
237 )
238 {
239 int i;
240 SCIP_VAR** vars;
241 SCIP_Bool valid;
242 SCIP_HASHMAP* varmapfw;
243 SCIP_CONCSOLVERDATA* data;
244 int* varperm;
245
246 assert(scip != NULL);
247 assert(concsolver != NULL);
248
249 data = SCIPconcsolverGetData(concsolver);
250 assert(data != NULL);
251
252 data->nvars = SCIPgetNVars(scip);
253 vars = SCIPgetVars(scip);
254
255 /* create the concurrent solver's SCIP instance and set up the problem */
256 SCIP_CALL( SCIPcreate(&data->solverscip) );
257 SCIP_CALL( SCIPhashmapCreate(&varmapfw, SCIPblkmem(data->solverscip), data->nvars) );
258 SCIP_CALL( SCIPcopy(scip, data->solverscip, varmapfw, NULL, SCIPconcsolverGetName(concsolver), TRUE, FALSE, FALSE,
259 FALSE, &valid) );
260 assert(valid);
261
262 /* allocate memory for the arrays to store the variable mapping */
263 SCIP_CALL( SCIPallocBlockMemoryArray(data->solverscip, &data->vars, data->nvars) );
264 SCIP_CALL( SCIPallocBufferArray(data->solverscip, &varperm, data->nvars) );
265
266 /* set up the arrays for the variable mapping */
267 for( i = 0; i < data->nvars; i++ )
268 {
269 SCIP_VAR* var;
270 var = (SCIP_VAR*) SCIPhashmapGetImage(varmapfw, vars[i]);
271 assert(var != NULL);
272 varperm[SCIPvarGetIndex(var)] = i;
273 data->vars[i] = var;
274 }
275
276 if( SCIPgetNSols(scip) != 0 )
277 {
278 SCIP_Bool stored;
279 SCIP_Real* solvals;
280 SCIP_SOL* sol = SCIPgetBestSol(scip);
281 SCIP_SOL* solversol;
282
283 SCIP_CALL( SCIPallocBufferArray(data->solverscip, &solvals, data->nvars) );
284
285 SCIP_CALL( SCIPgetSolVals(scip, sol, data->nvars, vars, solvals) );
286 SCIP_CALL( SCIPcreateSol(data->solverscip, &solversol, NULL) );
287 SCIP_CALL( SCIPsetSolVals(data->solverscip, solversol, data->nvars, data->vars, solvals) );
288
289 SCIPfreeBufferArray(data->solverscip, &solvals);
290
291 SCIP_CALL( SCIPaddSolFree(data->solverscip, &solversol, &stored) );
292
293 assert(stored);
294 }
295
296 /* create the concurrent data structure for the concurrent solver's SCIP */
297 /* this assert fails on check/instances/Orbitope/packorb_1-FullIns_3.cip
298 * assert(SCIPgetNOrigVars(data->solverscip) == data->nvars);
299 * also fails on check/instances/Orbitope/partorb_1-FullIns_3.cip
300 * TODO: test if this leads to any problems
301 */
302 SCIP_CALL( SCIPcreateConcurrent(data->solverscip, concsolver, varperm) );
303 SCIPfreeBufferArray(data->solverscip, &varperm);
304
305 /* free the hashmap */
306 SCIPhashmapFree(&varmapfw);
307
308 return SCIP_OKAY;
309 }
310
311 /** creates an instance of a concurrent SCIP solver */
312 static
SCIP_DECL_CONCSOLVERCREATEINST(concsolverScipCreateInstance)313 SCIP_DECL_CONCSOLVERCREATEINST(concsolverScipCreateInstance)
314 {
315 SCIP_CONCSOLVERDATA* data;
316 SCIP_CONCSOLVERTYPEDATA* typedata;
317 char* prefix;
318 char filename[SCIP_MAXSTRLEN];
319 SCIP_Bool changechildsel;
320
321 assert(scip != NULL);
322 assert(concsolvertype != NULL);
323 assert(concsolver != NULL);
324
325 typedata = SCIPconcsolverTypeGetData(concsolvertype);
326
327 SCIP_ALLOC( BMSallocMemory(&data) );
328 SCIPconcsolverSetData(concsolver, data);
329
330 SCIP_CALL( initConcsolver(scip, concsolver) );
331
332 /* check if emphasis setting should be loaded */
333 if( typedata->loademphasis )
334 {
335 SCIP_PARAM** params;
336 SCIP_PARAM** fixedparams;
337 int nparams;
338 int nfixedparams;
339 int i;
340
341 params = SCIPgetParams(data->solverscip);
342 nparams = SCIPgetNParams(data->solverscip);
343 SCIP_CALL( SCIPallocBufferArray(data->solverscip, &fixedparams, nparams) );
344 nfixedparams = 0;
345
346 /* fix certain parameters before loading emphasis to avoid setting them to default values */
347 for( i = 0; i < nparams; ++i )
348 {
349 const char* paramname;
350
351 paramname = SCIPparamGetName(params[i]);
352
353 if( strncmp(paramname, "limits/", 7) == 0 ||
354 strncmp(paramname, "numerics/", 9) == 0 ||
355 strncmp(paramname, "memory/", 7) == 0 ||
356 strncmp(paramname, "concurrent/sync/", 16) == 0 ||
357 strncmp(paramname, "heuristics/sync/", 16) == 0 ||
358 strncmp(paramname, "propagating/sync/", 17) == 0 )
359 {
360 fixedparams[nfixedparams++] = params[i];
361 SCIP_CALL( SCIPfixParam(data->solverscip, paramname) );
362 }
363 }
364
365 SCIP_CALL( SCIPsetEmphasis(data->solverscip, typedata->emphasis, TRUE) );
366
367 for( i = 0; i < nfixedparams; ++i )
368 SCIP_CALL( SCIPunfixParam(data->solverscip, SCIPparamGetName(fixedparams[i])) );
369
370 SCIPfreeBufferArray(data->solverscip, &fixedparams);
371 }
372
373 /* load settings file if it exists */
374 SCIP_CALL( SCIPgetStringParam(scip, "concurrent/paramsetprefix", &prefix) );
375 (void) SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s%s.set", prefix, SCIPconcsolverGetName(concsolver));
376
377 if( SCIPfileExists(filename) )
378 {
379 /* load settings file and print info message */
380 SCIPinfoMessage(scip, NULL, "reading parameter file <%s> for concurrent solver <%s>\n", filename, SCIPconcsolverGetName(concsolver));
381 SCIP_CALL( SCIPreadParams(data->solverscip, filename) );
382 }
383 else
384 {
385 /* print message about missing setting files only in verblevel full */
386 SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "skipping non existent parameter file <%s> for concurrent solver <%s>\n",
387 filename, SCIPconcsolverGetName(concsolver));
388 }
389
390 /* include eventhandler for synchronization */
391 SCIP_CALL( includeEventHdlrSync(data->solverscip) );
392
393 /* disable output for subscip */
394 SCIP_CALL( SCIPsetIntParam(data->solverscip, "display/verblevel", 0) );
395
396 /* use wall clock time in subscips */
397 SCIP_CALL( SCIPsetIntParam(data->solverscip, "timing/clocktype", (int)SCIP_CLOCKTYPE_WALL) );
398
399 /* don't catch ctrlc since already caught in main SCIP */
400 SCIP_CALL( SCIPsetBoolParam(data->solverscip, "misc/catchctrlc", FALSE) );
401
402 /* one solver can do all dual reductions and share them with the other solvers */
403 if( SCIPconcsolverGetIdx(concsolver) != 0 )
404 {
405 SCIP_CALL( disableConflictingDualReductions(data->solverscip) );
406 }
407
408 /* set different child selection rules if corresponding parameter is TRUE */
409 SCIP_CALL( SCIPgetBoolParam(scip, "concurrent/changechildsel", &changechildsel) );
410 if( changechildsel )
411 {
412 SCIP_CALL( setChildSelRule(concsolver) );
413 }
414
415 return SCIP_OKAY;
416 }
417
418 /** destroys an instance of a concurrent SCIP solver */
419 static
SCIP_DECL_CONCSOLVERDESTROYINST(concsolverScipDestroyInstance)420 SCIP_DECL_CONCSOLVERDESTROYINST(concsolverScipDestroyInstance)
421 {
422 SCIP_CONCSOLVERDATA* data;
423
424 assert(concsolver != NULL);
425
426 data = SCIPconcsolverGetData(concsolver);
427 assert(data != NULL);
428 assert(data->solverscip != NULL);
429
430 /* free the array with the variable mapping */
431 SCIPfreeBlockMemoryArray(data->solverscip, &data->vars, data->nvars);
432
433 /* free subscip */
434 SCIP_CALL( SCIPfree(&data->solverscip) );
435 BMSfreeMemory(&data);
436 SCIPconcsolverSetData(concsolver, NULL);
437
438 return SCIP_OKAY;
439 }
440
441 /** frees the data of a concurrent solver type */
442 static
SCIP_DECL_CONCSOLVERTYPEFREEDATA(concsolverTypeScipFreeData)443 SCIP_DECL_CONCSOLVERTYPEFREEDATA(concsolverTypeScipFreeData)
444 {
445 BMSfreeMemory(data);
446 }
447
448 /** initializes the random and permutation seeds with the given one
449 * and enables permutation of constraints and variables
450 */
451 static
SCIP_DECL_CONCSOLVERINITSEEDS(concsolverScipInitSeeds)452 SCIP_DECL_CONCSOLVERINITSEEDS(concsolverScipInitSeeds)
453 {
454 SCIP_CONCSOLVERDATA* data;
455
456 assert(concsolver != NULL);
457
458 data = SCIPconcsolverGetData(concsolver);
459 assert(data != NULL);
460
461 SCIPinfoMessage(data->solverscip, NULL, "initializing seeds to %d in concurrent solver '%s'\n", (int) seed, SCIPconcsolverGetName(concsolver));
462
463 SCIP_CALL( SCIPsetIntParam(data->solverscip, "randomization/randomseedshift", (int) seed) );
464 SCIP_CALL( SCIPsetIntParam(data->solverscip, "randomization/permutationseed", (int) seed) );
465 SCIP_CALL( SCIPsetBoolParam(data->solverscip, "randomization/permutevars", TRUE) );
466 SCIP_CALL( SCIPsetBoolParam(data->solverscip, "randomization/permuteconss", TRUE) );
467
468 return SCIP_OKAY;
469 }
470
471 /** installs the solving status of this concurrent solver and the solving statistics
472 * into the given SCIP instance
473 */
474 static
SCIP_DECL_CONCSOLVERCOPYSOLVINGDATA(concsolverGetSolvingData)475 SCIP_DECL_CONCSOLVERCOPYSOLVINGDATA(concsolverGetSolvingData)
476 {
477 SCIP_CONCSOLVERDATA* data;
478 SCIP_VAR** vars;
479 int nvars;
480 int nsols;
481 SCIP_SOL** sols;
482 SCIP_Real* solvals;
483 SCIP_HEUR* heur;
484 int i;
485
486 assert(concsolver != NULL);
487
488 data = SCIPconcsolverGetData(concsolver);
489 assert(data != NULL);
490 assert(data->solverscip != NULL);
491
492 assert(scip != NULL);
493 vars = SCIPgetVars(scip);
494 nvars = SCIPgetNVars(scip);
495
496 nsols = SCIPgetNSols(data->solverscip);
497 sols = SCIPgetSols(data->solverscip);
498
499 assert(nvars == data->nvars);
500
501 /* allocate buffer array used for translating the solution to the given SCIP */
502 SCIP_CALL( SCIPallocBufferArray(scip, &solvals, nvars) );
503
504 /* add the solutions to the given SCIP */
505 for( i = 0; i < nsols; ++i )
506 {
507 SCIP_SOL* sol;
508 SCIP_Bool stored;
509 SCIP_CALL( SCIPgetSolVals(data->solverscip, sols[i], nvars, data->vars, solvals) );
510
511 heur = SCIPsolGetHeur(sols[i]);
512
513 if( heur != NULL )
514 heur = SCIPfindHeur(scip, SCIPheurGetName(heur));
515
516 SCIP_CALL( SCIPcreateSol(scip, &sol, heur) );
517 SCIP_CALL( SCIPsetSolVals(scip, sol, nvars, vars, solvals) );
518
519 SCIP_CALL( SCIPcopySolStats(sols[i], sol) );
520
521 SCIP_CALL( SCIPaddSolFree(scip, &sol, &stored) );
522 }
523
524 /* free the buffer array */
525 SCIPfreeBufferArray(scip, &solvals);
526
527 /* copy solving statistics and status from the solver SCIP to the given SCIP */
528 SCIP_CALL( SCIPcopyConcurrentSolvingStats(data->solverscip, scip) );
529
530 return SCIP_OKAY;
531 }
532
533 /** start solving the problem until the solving reaches a limit, gets interrupted, or
534 * just finished successfully
535 */
536 static
SCIP_DECL_CONCSOLVEREXEC(concsolverScipExec)537 SCIP_DECL_CONCSOLVEREXEC(concsolverScipExec)
538 {
539 SCIP_CONCSOLVERDATA* data;
540
541 assert(concsolver != NULL);
542
543 data = SCIPconcsolverGetData(concsolver);
544 assert(data != NULL);
545
546 /* print info message that solving has started */
547 SCIPinfoMessage(data->solverscip, NULL, "starting solve in concurrent solver '%s'\n", SCIPconcsolverGetName(concsolver));
548
549 /* solve */
550 SCIP_CALL( SCIPsolve(data->solverscip) );
551
552 /* print info message with status */
553 SCIPinfoMessage(data->solverscip, NULL, "concurrent solver '%s' stopped with status ", SCIPconcsolverGetName(concsolver));
554 SCIP_CALL( SCIPprintStatus(data->solverscip, NULL) );
555 SCIPinfoMessage(data->solverscip, NULL, "\n");
556
557 /* set solving statistics */
558 *solvingtime = SCIPgetSolvingTime(data->solverscip);
559 *nlpiterations = SCIPgetNLPIterations(data->solverscip);
560 *nnodes = SCIPgetNNodes(data->solverscip);
561
562 return SCIP_OKAY;
563 }
564
565 /** stops the concurrent solver as soon as possible */
566 static
SCIP_DECL_CONCSOLVERSTOP(concsolverScipStop)567 SCIP_DECL_CONCSOLVERSTOP(concsolverScipStop)
568 {
569 SCIP_CONCSOLVERDATA* data;
570 assert(concsolver != NULL);
571
572 data = SCIPconcsolverGetData(concsolver);
573 assert(data != NULL);
574
575 SCIP_CALL( SCIPinterruptSolve(data->solverscip) );
576
577 return SCIP_OKAY;
578 }
579
580 /** writes new solutions and global boundchanges to the given synchronization data */
581 static
SCIP_DECL_CONCSOLVERSYNCWRITE(concsolverScipSyncWrite)582 SCIP_DECL_CONCSOLVERSYNCWRITE(concsolverScipSyncWrite)
583 {
584 int i;
585 int nsols;
586 SCIP_SOL** sols;
587 SCIP_CONCSOLVERDATA* data;
588 SCIP_BOUNDSTORE* boundstore;
589 int concsolverid;
590 SCIP_STATUS solverstatus;
591
592 data = SCIPconcsolverGetData(concsolver);
593 assert(data != NULL);
594 concsolverid = SCIPconcsolverGetIdx(concsolver);
595 solverstatus = SCIPgetStatus(data->solverscip);
596
597 SCIPsyncdataSetStatus(syncdata, solverstatus, concsolverid);
598 SCIPsyncdataSetLowerbound(syncdata, SCIPgetDualbound(data->solverscip));
599 SCIPsyncdataSetUpperbound(syncdata, SCIPgetPrimalbound(data->solverscip));
600
601 *nsolsshared = 0;
602
603 if( SCIPsyncdataGetStatus(syncdata) != SCIP_STATUS_UNKNOWN )
604 return SCIP_OKAY;
605
606 SCIPdebugMessage("syncing in concurrent solver %s\n", SCIPconcsolverGetName(concsolver));
607
608 /* consider at most maxcandsols many solutions, and since the solution array is sorted, we will cosider the best
609 * solutions
610 */
611 nsols = SCIPgetNSols(data->solverscip);
612 nsols = MIN(nsols, maxcandsols);
613 sols = SCIPgetSols(data->solverscip);
614
615 for( i = 0; i < nsols; ++i )
616 {
617 if( SCIPIsConcurrentSolNew(data->solverscip, sols[i]) )
618 {
619 SCIP_Real solobj;
620 SCIP_Real* solvals;
621
622 solobj = SCIPgetSolOrigObj(data->solverscip, sols[i]);
623
624 SCIPdebugMessage("adding sol in concurrent solver %s\n", SCIPconcsolverGetName(concsolver));
625 SCIPsyncdataGetSolutionBuffer(syncstore, syncdata, solobj, concsolverid, &solvals);
626
627 /* if syncstore has no place for this solution we can stop since the next solution will have
628 * a worse objective value and thus won't be accepted either
629 */
630 if( solvals == NULL )
631 break;
632
633 ++(*nsolsshared);
634 SCIP_CALL( SCIPgetSolVals(data->solverscip, sols[i], data->nvars, data->vars, solvals) );
635
636 /* if we have added the maximum number of solutions we can also stop */
637 if( *nsolsshared == maxsharedsols )
638 break;
639 }
640 }
641
642 boundstore = SCIPgetConcurrentGlobalBoundChanges(data->solverscip);
643
644 if( boundstore != NULL )
645 SCIP_CALL( SCIPsyncdataAddBoundChanges(syncstore, syncdata, boundstore) );
646
647 SCIPsyncdataAddMemTotal(syncdata, SCIPgetMemTotal(data->solverscip));
648
649 return SCIP_OKAY;
650 }
651
652 /** reads the solutions and bounds from the given synchronization data */
653 static
SCIP_DECL_CONCSOLVERSYNCREAD(concsolverScipSyncRead)654 SCIP_DECL_CONCSOLVERSYNCREAD(concsolverScipSyncRead)
655 { /*lint --e{715}*/
656 int i;
657 int nsols;
658 SCIP_Real** solvals;
659 SCIP_CONCSOLVERDATA* data;
660 SCIP_BOUNDSTORE* boundstore;
661 int* concsolverids;
662 int concsolverid;
663 int nbndchgs;
664
665 data = SCIPconcsolverGetData(concsolver);
666 assert(data != NULL);
667
668 concsolverid = SCIPconcsolverGetIdx(concsolver);
669
670 /* get solutions from synchronization data */
671 SCIPsyncdataGetSolutions(syncdata, &solvals, &concsolverids, &nsols);
672 *nsolsrecvd = 0;
673
674 for( i = 0; i < nsols; ++i )
675 {
676 SCIP_SOL* newsol;
677
678 /* do not add own solutions */
679 if( concsolverids[i] == concsolverid )
680 continue;
681
682 /* solution is from other solver so translate to this solvers variable space and add it to SCIP */
683 ++(*nsolsrecvd);
684 SCIP_CALL( SCIPcreateOrigSol(data->solverscip, &newsol, NULL) );
685
686 SCIP_CALL( SCIPsetSolVals(data->solverscip, newsol, data->nvars, data->vars, solvals[i]) );
687 SCIPdebugMessage("adding solution in concurrent solver %s\n", SCIPconcsolverGetName(concsolver));
688 SCIP_CALL( SCIPaddConcurrentSol(data->solverscip, newsol) );
689 }
690
691 /* get bound changes from the synchronization data and add it to this concurrent solvers SCIP */
692 *ntighterbnds = 0;
693 *ntighterintbnds = 0;
694 boundstore = SCIPsyncdataGetBoundChgs(syncdata);
695 nbndchgs = SCIPboundstoreGetNChgs(boundstore);
696
697 for( i = 0; i < nbndchgs; ++i )
698 {
699 SCIP_VAR* var;
700 SCIP_BOUNDTYPE boundtype;
701 SCIP_Real newbound;
702
703 var = data->vars[SCIPboundstoreGetChgVaridx(boundstore, i)];
704 boundtype = SCIPboundstoreGetChgType(boundstore, i);
705 newbound = SCIPboundstoreGetChgVal(boundstore, i);
706
707 SCIP_CALL( SCIPvarGetProbvarBound(&var, &newbound, &boundtype) );
708
709 /* cannot change bounds of multi-aggregated variables so dont pass this bound-change to the propagator */
710 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
711 return SCIP_OKAY;
712
713 /* if bound is not better than also don't pass this bound to the propagator and
714 * don't waste memory for storing this boundchange
715 */
716 if( boundtype == SCIP_BOUNDTYPE_LOWER && SCIPisGE(data->solverscip, SCIPvarGetLbGlobal(var), newbound) )
717 return SCIP_OKAY;
718
719 if( boundtype == SCIP_BOUNDTYPE_UPPER && SCIPisLE(data->solverscip, SCIPvarGetUbGlobal(var), newbound) )
720 return SCIP_OKAY;
721
722 /* bound is better so incremented counters for statistics and pass it to the sync propagator */
723 ++(*ntighterbnds);
724
725 if( SCIPvarGetType(var) <= SCIP_VARTYPE_INTEGER )
726 ++(*ntighterintbnds);
727
728 SCIP_CALL( SCIPaddConcurrentBndchg(data->solverscip, var, newbound, boundtype) );
729 }
730
731 return SCIP_OKAY;
732 }
733
734
735 /** creates the concurrent SCIP solver plugins and includes them in SCIP */
SCIPincludeConcurrentScipSolvers(SCIP * scip)736 SCIP_RETCODE SCIPincludeConcurrentScipSolvers(
737 SCIP* scip /**< SCIP datastructure */
738 )
739 {
740 SCIP_CONCSOLVERTYPEDATA* data;
741
742 assert(scip != NULL);
743
744 /* Include concurrent solvers for SCIP for all emphasis settings and without an emphasis setting.
745 * For the SCIP without an emphasis setting we set the default preferred priority to 1 and for the other types to 0
746 * so that the default concurent solve will use multiple SCIP's using settings as specified by the user in the main SCIP.
747 */
748 SCIP_CALL( SCIPallocMemory(scip, &data) );
749 data->loademphasis = FALSE;
750 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip", 1.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
751 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
752 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
753
754 SCIP_CALL( SCIPallocMemory(scip, &data) );
755 data->loademphasis = TRUE;
756 data->emphasis = SCIP_PARAMEMPHASIS_DEFAULT;
757 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip-default", 0.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
758 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
759 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
760
761 SCIP_CALL( SCIPallocMemory(scip, &data) );
762 data->loademphasis = TRUE;
763 data->emphasis = SCIP_PARAMEMPHASIS_CPSOLVER;
764 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip-cpsolver", 0.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
765 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
766 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
767
768 SCIP_CALL( SCIPallocMemory(scip, &data) );
769 data->loademphasis = TRUE;
770 data->emphasis = SCIP_PARAMEMPHASIS_EASYCIP;
771 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip-easycip", 0.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
772 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
773 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
774
775 SCIP_CALL( SCIPallocMemory(scip, &data) );
776 data->loademphasis = TRUE;
777 data->emphasis = SCIP_PARAMEMPHASIS_FEASIBILITY;
778 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip-feas", 0.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
779 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
780 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
781
782 SCIP_CALL( SCIPallocMemory(scip, &data) );
783 data->loademphasis = TRUE;
784 data->emphasis = SCIP_PARAMEMPHASIS_HARDLP;
785 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip-hardlp", 0.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
786 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
787 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
788
789 SCIP_CALL( SCIPallocMemory(scip, &data) );
790 data->loademphasis = TRUE;
791 data->emphasis = SCIP_PARAMEMPHASIS_OPTIMALITY;
792 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip-opti", 0.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
793 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
794 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
795
796 SCIP_CALL( SCIPallocMemory(scip, &data) );
797 data->loademphasis = TRUE;
798 data->emphasis = SCIP_PARAMEMPHASIS_COUNTER;
799 SCIP_CALL( SCIPincludeConcsolverType(scip, "scip-counter", 0.0, concsolverScipCreateInstance, concsolverScipDestroyInstance, concsolverScipInitSeeds,
800 concsolverScipExec, concsolverGetSolvingData, concsolverScipStop, concsolverScipSyncWrite,
801 concsolverScipSyncRead, concsolverTypeScipFreeData, data) );
802
803 return SCIP_OKAY;
804 }
805