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.c
17 * @ingroup OTHER_CFILES
18 * @brief methods for concurrent solvers
19 * @author Leona Gottwald
20 */
21
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23
24 #include <assert.h>
25 #include <string.h>
26
27 #include "scip/concsolver.h"
28 #include "scip/set.h"
29 #include "scip/scip.h"
30 #include "scip/concurrent.h"
31
32 #include "scip/struct_concsolver.h"
33 #include "scip/struct_stat.h"
34 #include "scip/struct_scip.h"
35 #include "blockmemshell/memory.h"
36 #include "scip/syncstore.h"
37 #include "scip/boundstore.h"
38 #include "scip/clock.h"
39
40
41 /** internal method for creating a concurrent solver type */
42 static
doConcsolverTypeCreate(SCIP_CONCSOLVERTYPE ** concsolvertype,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,const char * name,SCIP_Real prefpriodefault,SCIP_DECL_CONCSOLVERCREATEINST ((* concsolvercreateinst)),SCIP_DECL_CONCSOLVERDESTROYINST ((* concsolverdestroyinst)),SCIP_DECL_CONCSOLVERINITSEEDS ((* concsolverinitseeds)),SCIP_DECL_CONCSOLVEREXEC ((* concsolverexec)),SCIP_DECL_CONCSOLVERCOPYSOLVINGDATA ((* concsolvercopysolvdata)),SCIP_DECL_CONCSOLVERSTOP ((* concsolverstop)),SCIP_DECL_CONCSOLVERSYNCWRITE ((* concsolversyncwrite)),SCIP_DECL_CONCSOLVERSYNCREAD ((* concsolversyncread)),SCIP_DECL_CONCSOLVERTYPEFREEDATA ((* concsolvertypefreedata)),SCIP_CONCSOLVERTYPEDATA * data)43 SCIP_RETCODE doConcsolverTypeCreate(
44 SCIP_CONCSOLVERTYPE** concsolvertype, /**< pointer to concurrent solver data structure */
45 SCIP_SET* set, /**< global SCIP settings */
46 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
47 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */
48 const char* name, /**< name of concurrent solver */
49 SCIP_Real prefpriodefault, /**< the default preferred priority of this concurrent solver type */
50 SCIP_DECL_CONCSOLVERCREATEINST ((*concsolvercreateinst)),/**< data copy method of concurrent solver */
51 SCIP_DECL_CONCSOLVERDESTROYINST ((*concsolverdestroyinst)),/**< data copy method of concurrent solver */
52 SCIP_DECL_CONCSOLVERINITSEEDS ((*concsolverinitseeds)),/**< initialize random seeds of concurrent solver */
53 SCIP_DECL_CONCSOLVEREXEC ((*concsolverexec)),/**< execution method of concurrent solver */
54 SCIP_DECL_CONCSOLVERCOPYSOLVINGDATA ((*concsolvercopysolvdata)),/**< method to copy solving data */
55 SCIP_DECL_CONCSOLVERSTOP ((*concsolverstop)),/**< terminate solving in concurrent solver */
56 SCIP_DECL_CONCSOLVERSYNCWRITE ((*concsolversyncwrite)),/**< synchronization method of concurrent solver */
57 SCIP_DECL_CONCSOLVERSYNCREAD ((*concsolversyncread)),/**< synchronization method of concurrent solver */
58 SCIP_DECL_CONCSOLVERTYPEFREEDATA ((*concsolvertypefreedata)),/**< method to free data of concurrent solver type */
59 SCIP_CONCSOLVERTYPEDATA* data /**< the concurent solver type's data */
60 )
61 {
62 char paramname[SCIP_MAXSTRLEN];
63 char paramdesc[SCIP_MAXSTRLEN];
64
65 assert(concsolvertype != NULL);
66 assert(name != NULL);
67 assert(prefpriodefault >= 0.0 && prefpriodefault <= 1.0);
68
69 assert(concsolvercreateinst != NULL);
70 assert(concsolverdestroyinst != NULL);
71 assert(concsolverexec != NULL);
72 assert(concsolvercopysolvdata != NULL);
73 assert(concsolverstop != NULL);
74 assert(concsolversyncwrite != NULL);
75 assert(concsolversyncread != NULL);
76
77 SCIP_ALLOC( BMSallocMemory(concsolvertype) );
78 BMSclearMemory(*concsolvertype);
79
80 SCIP_ALLOC( BMSduplicateMemoryArray(&(*concsolvertype)->name, name, strlen(name) + 1) );
81
82 (*concsolvertype)->data = data;
83 (*concsolvertype)->ninstances = 0;
84 (*concsolvertype)->concsolvercreateinst = concsolvercreateinst;
85 (*concsolvertype)->concsolverdestroyinst = concsolverdestroyinst;
86 (*concsolvertype)->concsolverinitseeds = concsolverinitseeds;
87 (*concsolvertype)->concsolverexec = concsolverexec;
88 (*concsolvertype)->concsolvercopysolvdata = concsolvercopysolvdata;
89 (*concsolvertype)->concsolverstop = concsolverstop;
90 (*concsolvertype)->concsolversyncwrite = concsolversyncwrite;
91 (*concsolvertype)->concsolversyncread = concsolversyncread;
92 (*concsolvertype)->concsolvertypefreedata = concsolvertypefreedata;
93
94 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "concurrent/%s/prefprio", name);
95 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "the preferred number concurrent solvers of type <%s> with respect to the number of threads", name);
96 SCIP_CALL( SCIPsetAddRealParam(set, messagehdlr, blkmem, paramname, paramdesc,
97 &(*concsolvertype)->prefprio, FALSE, prefpriodefault, 0.0, 1.0,
98 NULL, NULL) ); /*lint !e740*/
99
100 return SCIP_OKAY;
101 }
102
103 /** creates a concurrent solver type */
SCIPconcsolverTypeCreate(SCIP_CONCSOLVERTYPE ** concsolvertype,SCIP_SET * set,SCIP_MESSAGEHDLR * messagehdlr,BMS_BLKMEM * blkmem,const char * name,SCIP_Real prefpriodefault,SCIP_DECL_CONCSOLVERCREATEINST ((* concsolvercreateinst)),SCIP_DECL_CONCSOLVERDESTROYINST ((* concsolverdestroyinst)),SCIP_DECL_CONCSOLVERINITSEEDS ((* concsolverinitseeds)),SCIP_DECL_CONCSOLVEREXEC ((* concsolverexec)),SCIP_DECL_CONCSOLVERCOPYSOLVINGDATA ((* concsolvercopysolvdata)),SCIP_DECL_CONCSOLVERSTOP ((* concsolverstop)),SCIP_DECL_CONCSOLVERSYNCWRITE ((* concsolversyncwrite)),SCIP_DECL_CONCSOLVERSYNCREAD ((* concsolversyncread)),SCIP_DECL_CONCSOLVERTYPEFREEDATA ((* concsolvertypefreedata)),SCIP_CONCSOLVERTYPEDATA * data)104 SCIP_RETCODE SCIPconcsolverTypeCreate(
105 SCIP_CONCSOLVERTYPE** concsolvertype, /**< pointer to concurrent solver data structure */
106 SCIP_SET* set, /**< global SCIP settings */
107 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
108 BMS_BLKMEM* blkmem, /**< block memory for parameter settings */
109 const char* name, /**< name of concurrent solver */
110 SCIP_Real prefpriodefault, /**< the default preferred priority of this concurrent solver type */
111 SCIP_DECL_CONCSOLVERCREATEINST ((*concsolvercreateinst)),/**< data copy method of concurrent solver */
112 SCIP_DECL_CONCSOLVERDESTROYINST ((*concsolverdestroyinst)),/**< data copy method of concurrent solver */
113 SCIP_DECL_CONCSOLVERINITSEEDS ((*concsolverinitseeds)),/**< initialize random seeds of concurrent solver */
114 SCIP_DECL_CONCSOLVEREXEC ((*concsolverexec)),/**< execution method of concurrent solver */
115 SCIP_DECL_CONCSOLVERCOPYSOLVINGDATA ((*concsolvercopysolvdata)),/**< method to copy solving data */
116 SCIP_DECL_CONCSOLVERSTOP ((*concsolverstop)),/**< terminate solving in concurrent solver */
117 SCIP_DECL_CONCSOLVERSYNCWRITE ((*concsolversyncwrite)),/**< synchronization method of concurrent solver */
118 SCIP_DECL_CONCSOLVERSYNCREAD ((*concsolversyncread)),/**< synchronization method of concurrent solver */
119 SCIP_DECL_CONCSOLVERTYPEFREEDATA ((*concsolvertypefreedata)),/**< method to free data of concurrent solver type */
120 SCIP_CONCSOLVERTYPEDATA* data /**< the concurent solver type's data */
121 )
122 {
123 assert(concsolvertype != NULL);
124 assert(name != NULL);
125 assert(prefpriodefault >= 0.0 && prefpriodefault <= 1.0);
126
127 assert(concsolvercreateinst != NULL);
128 assert(concsolverdestroyinst != NULL);
129 assert(concsolverexec != NULL);
130 assert(concsolvercopysolvdata != NULL);
131 assert(concsolverstop != NULL);
132 assert(concsolversyncwrite != NULL);
133 assert(concsolversyncread != NULL);
134
135 SCIP_CALL_FINALLY( doConcsolverTypeCreate(concsolvertype, set, messagehdlr, blkmem,
136 name, prefpriodefault, concsolvercreateinst, concsolverdestroyinst, concsolverinitseeds, concsolverexec,
137 concsolvercopysolvdata, concsolverstop, concsolversyncwrite, concsolversyncread, concsolvertypefreedata, data),
138 SCIPconcsolverTypeFree(concsolvertype) );
139
140 return SCIP_OKAY;
141 }
142
143 /** frees all memory of a concurrent solver type */
SCIPconcsolverTypeFree(SCIP_CONCSOLVERTYPE ** concsolvertype)144 void SCIPconcsolverTypeFree(
145 SCIP_CONCSOLVERTYPE** concsolvertype /**< pointer to concurrent solver data structure */
146 )
147 {
148 assert(concsolvertype != NULL);
149 if( *concsolvertype == NULL )
150 return;
151
152 if( (*concsolvertype)->concsolvertypefreedata != NULL )
153 (*concsolvertype)->concsolvertypefreedata(&(*concsolvertype)->data);
154
155 BMSfreeMemoryArrayNull(&(*concsolvertype)->name);
156 BMSfreeMemory(concsolvertype);
157 }
158
159 /** gets the data of a concurrent solver type */
SCIPconcsolverTypeGetData(SCIP_CONCSOLVERTYPE * concsolvertype)160 SCIP_CONCSOLVERTYPEDATA* SCIPconcsolverTypeGetData(
161 SCIP_CONCSOLVERTYPE* concsolvertype /**< concurrent solver type */
162 )
163 {
164 assert(concsolvertype != NULL);
165
166 return concsolvertype->data;
167 }
168
169 /** sets the data of a concurrent solver type */
SCIPconcsolverTypeSetData(SCIP_CONCSOLVERTYPE * concsolvertype,SCIP_CONCSOLVERTYPEDATA * data)170 void SCIPconcsolverTypeSetData(
171 SCIP_CONCSOLVERTYPE* concsolvertype, /**< concurrent solver type */
172 SCIP_CONCSOLVERTYPEDATA* data /**< the concurrent solver's data */
173 )
174 {
175 assert(concsolvertype != NULL);
176
177 concsolvertype->data = data;
178 }
179
180 /** gets the name of a concurrent solver type */
SCIPconcsolverTypeGetName(SCIP_CONCSOLVERTYPE * concsolvertype)181 char* SCIPconcsolverTypeGetName(
182 SCIP_CONCSOLVERTYPE* concsolvertype /**< concurrent solver type */
183 )
184 {
185 assert(concsolvertype != NULL);
186
187 return concsolvertype->name;
188 }
189
190 /** gets the preferred priority from a concurrent solver type */
SCIPconcsolverTypeGetPrefPrio(SCIP_CONCSOLVERTYPE * concsolvertype)191 SCIP_Real SCIPconcsolverTypeGetPrefPrio(
192 SCIP_CONCSOLVERTYPE* concsolvertype /**< concurrent solver type */
193 )
194 {
195 assert(concsolvertype != NULL);
196
197 return concsolvertype->prefprio;
198 }
199
200 /** creates an instance of the given concurrent solver type */
SCIPconcsolverCreateInstance(SCIP_SET * set,SCIP_CONCSOLVERTYPE * concsolvertype,SCIP_CONCSOLVER ** concsolver)201 SCIP_RETCODE SCIPconcsolverCreateInstance(
202 SCIP_SET* set, /**< global SCIP settings */
203 SCIP_CONCSOLVERTYPE* concsolvertype, /**< concurrent solver type to create */
204 SCIP_CONCSOLVER** concsolver /**< pointer to return concurrent solver instance */
205 )
206 {
207 char instancename[SCIP_MAXSTRLEN];
208
209 ++concsolvertype->ninstances;
210 (void) SCIPsnprintf(instancename, SCIP_MAXSTRLEN, "%s-%i", concsolvertype->name, concsolvertype->ninstances);
211
212 SCIP_ALLOC( BMSallocMemory(concsolver) );
213 SCIP_ALLOC( BMSduplicateMemoryArray(&(*concsolver)->name, instancename, strlen(instancename) + 1) );
214
215 (*concsolver)->type = concsolvertype;
216
217 /* initialize counters for statistics */
218 (*concsolver)->nsolsrecvd = 0;
219 (*concsolver)->nsolsshared = 0;
220 (*concsolver)->ntighterbnds = 0;
221 (*concsolver)->ntighterintbnds = 0;
222 SCIP_CALL( SCIPcreateWallClock(set->scip, &(*concsolver)->totalsynctime) );
223
224 /* initialize synchronization fields */
225 (*concsolver)->nsyncs = 0;
226 (*concsolver)->syncdelay = 0.0;
227
228 /* in deterministic mode use number of nonzeros and variables to get a good initial synchronization frequency
229 * in opportunistic mode use the frequency as set by the user
230 */
231 if( set->parallel_mode == (int) SCIP_PARA_DETERMINISTIC )
232 (*concsolver)->syncfreq = 0.01 * set->scip->stat->nnz * SCIPgetNVars(set->scip) * set->concurrent_freqinit;
233 else
234 (*concsolver)->syncfreq = set->concurrent_freqinit;
235
236 (*concsolver)->syncdata = NULL;
237
238 SCIPdebugMessage("concsolver %s initialized sync freq to %f\n", (*concsolver)->name, (*concsolver)->syncfreq);
239 /* register concurrent solver */
240 (*concsolver)->idx = SCIPgetNConcurrentSolvers(set->scip);
241 SCIP_CALL( concsolvertype->concsolvercreateinst(set->scip, concsolvertype, *concsolver) );
242 SCIP_CALL( SCIPaddConcurrentSolver(set->scip, *concsolver) );
243
244 return SCIP_OKAY;
245 }
246
247 /** destroys an instance of the given concurrent solver */
SCIPconcsolverDestroyInstance(SCIP_SET * set,SCIP_CONCSOLVER ** concsolver)248 SCIP_RETCODE SCIPconcsolverDestroyInstance(
249 SCIP_SET* set, /**< global SCIP settings */
250 SCIP_CONCSOLVER** concsolver /**< concurrent solver */
251 )
252 {
253 assert(concsolver != NULL);
254 assert((*concsolver)->type != NULL);
255 assert(set != NULL);
256 assert((*concsolver)->type->concsolverdestroyinst != NULL);
257
258 SCIP_CALL( (*concsolver)->type->concsolverdestroyinst(set->scip, *concsolver) );
259 --(*concsolver)->type->ninstances;
260
261 SCIP_CALL( SCIPfreeClock(set->scip, &(*concsolver)->totalsynctime) );
262 BMSfreeMemoryArray(&(*concsolver)->name);
263
264 BMSfreeMemory(concsolver);
265
266 return SCIP_OKAY;
267 }
268
269 /** gets the data of a concurrent solver */
SCIPconcsolverGetData(SCIP_CONCSOLVER * concsolver)270 SCIP_CONCSOLVERDATA* SCIPconcsolverGetData(
271 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
272 )
273 {
274 assert(concsolver != NULL);
275
276 return concsolver->data;
277 }
278
279 /** sets the data of a concurrent solver */
SCIPconcsolverSetData(SCIP_CONCSOLVER * concsolver,SCIP_CONCSOLVERDATA * data)280 void SCIPconcsolverSetData(
281 SCIP_CONCSOLVER* concsolver, /**< concurrent solver */
282 SCIP_CONCSOLVERDATA* data /**< the concurrent solver's data */
283 )
284 {
285 assert(concsolver != NULL);
286
287 concsolver->data = data;
288 }
289
290 /** gets the name of a concurrent solver */
SCIPconcsolverGetName(SCIP_CONCSOLVER * concsolver)291 char* SCIPconcsolverGetName(
292 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
293 )
294 {
295 assert(concsolver != NULL);
296
297 return concsolver->name;
298 }
299
300 /** initializes the random seeds of a concurrent solver */
SCIPconcsolverInitSeeds(SCIP_CONCSOLVER * concsolver,unsigned int seed)301 SCIP_RETCODE SCIPconcsolverInitSeeds(
302 SCIP_CONCSOLVER* concsolver, /**< concurrent solver */
303 unsigned int seed /**< seed for initializing the solver's internal random seeds */
304 )
305 {
306 assert(concsolver != NULL);
307 assert(concsolver->type != NULL);
308
309 if( concsolver->type->concsolverinitseeds != NULL )
310 SCIP_CALL( concsolver->type->concsolverinitseeds(concsolver, seed) );
311
312 return SCIP_OKAY;
313 }
314
315 /** start the solving process of a concurrent solver */
SCIPconcsolverExec(SCIP_CONCSOLVER * concsolver)316 SCIP_RETCODE SCIPconcsolverExec(
317 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
318 )
319 {
320 assert(concsolver != NULL);
321 assert(concsolver->type != NULL);
322 assert(concsolver->type->concsolverexec != NULL);
323
324 /* set the stopped flag to false */
325 concsolver->stopped = FALSE;
326
327 /* then call the execute callback */
328 SCIP_CALL( concsolver->type->concsolverexec(concsolver, &concsolver->solvingtime, &concsolver->nlpiterations, &concsolver->nnodes) );
329
330 return SCIP_OKAY;
331 }
332
333 /** gets solving data of concurrent solver and stores it in the given SCIP instance */
SCIPconcsolverGetSolvingData(SCIP_CONCSOLVER * concsolver,SCIP * scip)334 SCIP_RETCODE SCIPconcsolverGetSolvingData(
335 SCIP_CONCSOLVER* concsolver, /**< concurrent solver */
336 SCIP* scip /**< SCIP datastructure */
337 )
338 {
339 assert(concsolver != NULL);
340 assert(concsolver->type != NULL);
341 assert(concsolver->type->concsolvercopysolvdata != NULL);
342
343 return concsolver->type->concsolvercopysolvdata(concsolver, scip);
344 }
345
346 /** interrupt solving in a concurrent solver */
SCIPconcsolverStop(SCIP_CONCSOLVER * concsolver)347 SCIP_RETCODE SCIPconcsolverStop(
348 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
349 )
350 {
351 assert(concsolver != NULL);
352 assert(concsolver->type != NULL);
353 assert(concsolver->type->concsolverstop != NULL);
354
355 SCIP_CALL( concsolver->type->concsolverstop(concsolver) );
356
357 /* set the stopped flag to true */
358 concsolver->stopped = TRUE;
359
360 return SCIP_OKAY;
361 }
362
363 /** let the given concurrent solver synchronize, i.e. pass its own solutions and bounds to
364 * the SPI.
365 */
SCIPconcsolverSync(SCIP_CONCSOLVER * concsolver,SCIP_SET * set)366 SCIP_RETCODE SCIPconcsolverSync(
367 SCIP_CONCSOLVER* concsolver, /**< concurrent solver */
368 SCIP_SET* set /**< global SCIP settings */
369 )
370 {
371 SCIP_SYNCDATA* syncdata;
372 SCIP_SYNCSTORE* syncstore;
373 int nsols;
374 int ntighterintbnds;
375 int ntighterbnds;
376 SCIP_CONCSOLVERTYPE* concsolvertype;
377
378 assert(concsolver != NULL);
379 assert(concsolver->type != NULL);
380 assert(concsolver->type->concsolversyncwrite != NULL);
381 assert(concsolver->type->concsolversyncread != NULL);
382
383 if( concsolver->stopped )
384 return SCIP_OKAY;
385
386 SCIP_CALL( SCIPstartClock(set->scip, concsolver->totalsynctime) );
387
388 concsolvertype = concsolver->type;
389
390 syncstore = SCIPgetSyncstore(set->scip);
391 assert(syncstore != NULL);
392
393 SCIP_CALL( SCIPsyncstoreStartSync(syncstore, concsolver->nsyncs, &syncdata) );
394
395 if( syncdata == NULL )
396 {
397 SCIP_CALL( SCIPstopClock(set->scip, concsolver->totalsynctime) );
398 return SCIP_OKAY;
399 }
400
401 SCIPdebugMessage("concsolver %s starts sync %lli\n", concsolver->name, concsolver->nsyncs);
402
403 SCIP_CALL( concsolvertype->concsolversyncwrite(concsolver, syncstore, syncdata, set->concurrent_nbestsols, set->concurrent_maxnsols, &nsols) );
404 concsolver->nsolsshared += nsols;
405
406 if( SCIPsyncdataGetStatus(syncdata) != SCIP_STATUS_UNKNOWN )
407 {
408 SCIP_CALL( SCIPconcsolverStop(concsolver) );
409 }
410 else if( SCIPsyncdataGetNSynced(syncdata) == SCIPsyncstoreGetNSolvers(syncstore) - 1 )
411 {
412 /* if this is the last concurrent solver that is synchronizing for this synchronization data
413 * it will adjust the synchronization frequency using the progress on the gap
414 */
415 SCIP_Bool lbok;
416 SCIP_Bool ubok;
417 SCIP_Real progress;
418 SCIP_Real prevub;
419 SCIP_Real prevlb;
420 SCIP_Real newub;
421 SCIP_Real newlb;
422 SCIP_Real freqfactor;
423 SCIP_Real newsyncfreq;
424 SCIP_SYNCDATA* prevsync;
425
426 if( concsolver->nsyncs == 0 )
427 {
428 SCIPsyncdataSetSyncFreq(syncstore, syncdata, concsolver->syncfreq);
429 }
430 else
431 {
432 prevsync = SCIPsyncstoreGetSyncdata(syncstore, concsolver->nsyncs - 1);
433 assert(SCIPsyncdataGetNSynced(prevsync) == SCIPsyncstoreGetNSolvers(syncstore));
434
435 prevub = SCIPsyncdataGetUpperbound(prevsync);
436 prevlb = SCIPsyncdataGetLowerbound(prevsync);
437 newub = SCIPsyncdataGetUpperbound(syncdata);
438 newlb = SCIPsyncdataGetLowerbound(syncdata);
439 lbok = prevlb > -SCIPsetInfinity(set);
440 ubok = prevub < SCIPsetInfinity(set);
441
442 if( lbok && ubok )
443 progress = SCIPrelDiff(prevub - prevlb, newub - newlb);
444 else if( lbok )
445 progress = SCIPrelDiff(newlb, prevlb);
446 else if( ubok )
447 progress = SCIPrelDiff(prevub, newub);
448 else if( !SCIPsetIsInfinity(set, -newlb) || !SCIPsetIsInfinity(set, newub) ||
449 SCIPboundstoreGetNChgs(SCIPsyncdataGetBoundChgs(syncdata)) > 0 )
450 progress = set->concurrent_targetprogress;
451 else
452 progress = 0.0;
453
454 /* should not be negative */
455 progress = MAX(progress, 0.0);
456 assert(SCIPsetIsGE(set, progress, 0.0));
457
458 if( progress < 0.5 * set->concurrent_targetprogress )
459 freqfactor = set->concurrent_freqfactor;
460 else if( progress > 2 * set->concurrent_targetprogress )
461 freqfactor = 0.5 + 0.5 / set->concurrent_freqfactor;
462 else
463 freqfactor = 1.0;
464
465 SCIPdebugMessage("syncfreq is %g and freqfactor is %f due to progress %f\n", concsolver->syncfreq, freqfactor, progress);
466 newsyncfreq = concsolver->syncfreq * freqfactor;
467 SCIPsyncdataSetSyncFreq(syncstore, syncdata, newsyncfreq);
468 SCIPdebugMessage("new syncfreq is %g\n", SCIPsyncdataGetSyncFreq(syncdata));
469 }
470 }
471
472 SCIPdebugMessage("concsolver %s finishing sync %lli\n", concsolver->name, concsolver->nsyncs);
473
474 SCIP_CALL( SCIPsyncstoreFinishSync(syncstore, &syncdata) );
475 ++concsolver->nsyncs;
476
477 concsolver->syncdelay += concsolver->timesincelastsync;
478
479 syncdata = SCIPsyncstoreGetNextSyncdata(syncstore, concsolver->syncdata, concsolver->syncfreq, concsolver->nsyncs, &concsolver->syncdelay);
480
481 while( syncdata != NULL )
482 {
483 SCIP_CALL( SCIPsyncstoreEnsureAllSynced(syncstore, syncdata) );
484 concsolver->syncdata = syncdata;
485 SCIP_CALL( concsolvertype->concsolversyncread(concsolver, syncstore, syncdata, &nsols, &ntighterbnds, &ntighterintbnds) );
486 concsolver->ntighterbnds += ntighterbnds;
487 concsolver->ntighterintbnds += ntighterintbnds;
488 concsolver->nsolsrecvd += nsols;
489 SCIPdebugMessage("syncfreq before reading the next syncdata is %g\n", concsolver->syncfreq);
490 concsolver->syncfreq = SCIPsyncdataGetSyncFreq(concsolver->syncdata);
491 SCIPdebugMessage("syncfreq after reading the next syncdata is %g\n", concsolver->syncfreq);
492 syncdata = SCIPsyncstoreGetNextSyncdata(syncstore, concsolver->syncdata, concsolver->syncfreq, concsolver->nsyncs, &concsolver->syncdelay);
493 }
494
495 SCIP_CALL( SCIPstopClock(set->scip, concsolver->totalsynctime) );
496
497 return SCIP_OKAY;
498 }
499
500 /** gets the current synchronization frequency of the concurent solver */
SCIPconcsolverGetSyncFreq(SCIP_CONCSOLVER * concsolver)501 SCIP_Real SCIPconcsolverGetSyncFreq(
502 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
503 )
504 {
505 assert(concsolver != NULL);
506
507 return concsolver->syncfreq;
508 }
509
510 /** gets the total memory used by the concurent solver */
SCIPconcsolverGetMemTotal(SCIP_CONCSOLVER * concsolver)511 SCIP_Longint SCIPconcsolverGetMemTotal(
512 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
513 )
514 {
515 assert(concsolver != NULL);
516
517 return concsolver->syncdata != NULL ? SCIPsyncdataGetMemTotal(concsolver->syncdata) : 0;
518 }
519
520 /** sets the time elapsed since the last synchronization. Must be set before the synchronization is
521 * started.
522 */
SCIPconcsolverSetTimeSinceLastSync(SCIP_CONCSOLVER * concsolver,SCIP_Real time)523 void SCIPconcsolverSetTimeSinceLastSync(
524 SCIP_CONCSOLVER* concsolver, /**< concurrent solver */
525 SCIP_Real time /**< the time passed since the last synchronization */
526 )
527 {
528 assert(concsolver != NULL);
529
530 concsolver->timesincelastsync = time;
531 }
532
533 /** gets the solving time of the concurrent solver */
SCIPconcsolverGetSolvingTime(SCIP_CONCSOLVER * concsolver)534 SCIP_Real SCIPconcsolverGetSolvingTime(
535 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
536 )
537 {
538 assert(concsolver != NULL);
539
540 return concsolver->solvingtime;
541 }
542
543 /** gets the time spent for synchronization for the concurrent solver */
SCIPconcsolverGetSyncTime(SCIP_CONCSOLVER * concsolver)544 SCIP_Real SCIPconcsolverGetSyncTime(
545 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
546 )
547 {
548 assert(concsolver != NULL);
549
550 return SCIPclockGetTime(concsolver->totalsynctime);
551 }
552
553 /** gets the number of lp iterations the concurrent solver used */
SCIPconcsolverGetNLPIterations(SCIP_CONCSOLVER * concsolver)554 SCIP_Longint SCIPconcsolverGetNLPIterations(
555 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
556 )
557 {
558 assert(concsolver != NULL);
559
560 return concsolver->nlpiterations;
561 }
562
563 /** gets the number of branch and bound nodes the concurrent solver used */
SCIPconcsolverGetNNodes(SCIP_CONCSOLVER * concsolver)564 SCIP_Longint SCIPconcsolverGetNNodes(
565 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
566 )
567 {
568 assert(concsolver != NULL);
569
570 return concsolver->nnodes;
571 }
572
573 /** gets the number of solutions the concurrent solver received during synchronization */
SCIPconcsolverGetNSolsRecvd(SCIP_CONCSOLVER * concsolver)574 SCIP_Longint SCIPconcsolverGetNSolsRecvd(
575 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
576 )
577 {
578 assert(concsolver != NULL);
579
580 return concsolver->nsolsrecvd;
581 }
582
583 /** gets the number of solutions the concurrent solver shared during synchronization */
SCIPconcsolverGetNSolsShared(SCIP_CONCSOLVER * concsolver)584 SCIP_Longint SCIPconcsolverGetNSolsShared(
585 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
586 )
587 {
588 assert(concsolver != NULL);
589
590 return concsolver->nsolsshared;
591 }
592
593 /** gets the number of tighter global variable bounds the solver received */
SCIPconcsolverGetNTighterBnds(SCIP_CONCSOLVER * concsolver)594 SCIP_Longint SCIPconcsolverGetNTighterBnds(
595 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
596 )
597 {
598 assert(concsolver != NULL);
599
600 return concsolver->ntighterbnds;
601 }
602
603 /** gets the number of tighter global variable bounds of integer variables the solver received */
SCIPconcsolverGetNTighterIntBnds(SCIP_CONCSOLVER * concsolver)604 SCIP_Longint SCIPconcsolverGetNTighterIntBnds(
605 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
606 )
607 {
608 assert(concsolver != NULL);
609
610 return concsolver->ntighterintbnds;
611 }
612
613 /** gets index of concurrent solver */
SCIPconcsolverGetIdx(SCIP_CONCSOLVER * concsolver)614 int SCIPconcsolverGetIdx(
615 SCIP_CONCSOLVER* concsolver /**< concurrent solver */
616 )
617 {
618 assert(concsolver != NULL);
619
620 return concsolver->idx;
621 }
622