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 syncstore.c
17 * @ingroup PARALLEL
18 * @brief the function definitions of the synchronization store
19 * @author Leona Gottwald
20 * @author Stephen J. Maher
21 */
22
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24
25 #include <assert.h>
26
27 #include "scip/def.h"
28 #include "scip/pub_message.h"
29 #include "scip/concsolver.h"
30 #include "scip/struct_concsolver.h"
31 #include "scip/prob.h"
32 #include "scip/scip.h"
33 #include "blockmemshell/memory.h"
34 #include "tpi/tpi.h"
35 #include "scip/struct_syncstore.h"
36 #include "scip/concurrent.h"
37 #include "scip/syncstore.h"
38 #include "scip/boundstore.h"
39
40
41 /** computes the size of the array of synchronization datas, such that
42 * it cannot ever happen that a synchronization data is reused while still
43 * not read by any thread */
44 static
getNSyncdata(SCIP * scip)45 int getNSyncdata(
46 SCIP* scip /**< SCIP main datastructure */
47 )
48 {
49 int maxnsyncdelay;
50
51 SCIP_CALL_ABORT( SCIPgetIntParam(scip, "concurrent/sync/maxnsyncdelay", &maxnsyncdelay) );
52
53 return 2 * (maxnsyncdelay + 1);
54 }
55
56 /** creates and captures a new synchronization store */
SCIPsyncstoreCreate(SCIP_SYNCSTORE ** syncstore)57 SCIP_RETCODE SCIPsyncstoreCreate(
58 SCIP_SYNCSTORE** syncstore /**< pointer to return the created synchronization store */
59 )
60 {
61 assert(syncstore != NULL);
62
63 SCIPdebugMessage("SCIPsyncstoreCreate()\n");
64
65 SCIP_ALLOC( BMSallocMemory(syncstore) );
66
67 (*syncstore)->mode = SCIP_PARA_DETERMINISTIC; /* initialising the mode */
68 (*syncstore)->initialized = FALSE;
69 (*syncstore)->syncdata = NULL;
70 (*syncstore)->stopped = FALSE;
71 (*syncstore)->nuses = 1;
72 SCIP_CALL( SCIPtpiInitLock(&(*syncstore)->lock) );
73
74 return SCIP_OKAY;
75 }
76
77 /** releases a synchronization store */
SCIPsyncstoreRelease(SCIP_SYNCSTORE ** syncstore)78 SCIP_RETCODE SCIPsyncstoreRelease(
79 SCIP_SYNCSTORE** syncstore /**< pointer to the synchronization store */
80 )
81 {
82 int references;
83
84 assert(syncstore != NULL);
85 if( *syncstore == NULL )
86 return SCIP_OKAY;
87
88 SCIP_CALL( SCIPtpiAcquireLock(&(*syncstore)->lock) );
89 (*syncstore)->nuses -= 1;
90 references = (*syncstore)->nuses;
91 SCIP_CALL( SCIPtpiReleaseLock(&(*syncstore)->lock) );
92
93 if( references == 0 )
94 {
95 if( (*syncstore)->initialized )
96 {
97 SCIP_CALL( SCIPsyncstoreExit(*syncstore) );
98 }
99
100 assert(!(*syncstore)->initialized);
101 SCIPtpiDestroyLock(&(*syncstore)->lock);
102 BMSfreeMemory(syncstore);
103 }
104 else
105 {
106 *syncstore = NULL;
107 }
108
109 return SCIP_OKAY;
110 }
111
112 /** captures a synchronization store */
SCIPsyncstoreCapture(SCIP_SYNCSTORE * syncstore)113 SCIP_RETCODE SCIPsyncstoreCapture(
114 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
115 )
116 {
117 SCIP_CALL( SCIPtpiAcquireLock(&syncstore->lock) );
118
119 ++(syncstore->nuses);
120
121 SCIP_CALL( SCIPtpiReleaseLock(&syncstore->lock) );
122
123 return SCIP_OKAY;
124 }
125
126 /** initialize the syncstore for the given SCIP instance */
SCIPsyncstoreInit(SCIP * scip)127 SCIP_RETCODE SCIPsyncstoreInit(
128 SCIP* scip /**< SCIP main datastructure */
129 )
130 {
131 SCIP_SYNCSTORE* syncstore;
132 int i;
133 int j;
134 int paramode;
135
136 assert(scip != NULL);
137 syncstore = SCIPgetSyncstore(scip);
138 assert(syncstore != NULL);
139 syncstore->mainscip = scip;
140 syncstore->lastsync = NULL;
141 syncstore->nsolvers = SCIPgetNConcurrentSolvers(scip);
142
143 syncstore->ninitvars = SCIPgetNVars(scip);
144 SCIP_CALL( SCIPgetIntParam(scip, "concurrent/sync/maxnsols", &syncstore->maxnsols) );
145 SCIP_CALL( SCIPgetIntParam(scip, "concurrent/sync/maxnsyncdelay", &syncstore->maxnsyncdelay) );
146 SCIP_CALL( SCIPgetRealParam(scip, "concurrent/sync/minsyncdelay", &syncstore->minsyncdelay) );
147 SCIP_CALL( SCIPgetRealParam(scip, "concurrent/sync/freqinit", &syncstore->syncfreqinit) );
148 SCIP_CALL( SCIPgetRealParam(scip, "concurrent/sync/freqmax", &syncstore->syncfreqmax) );
149 syncstore->nsyncdata = getNSyncdata(scip);
150 SCIP_CALL( SCIPallocBlockMemoryArray(syncstore->mainscip, &(syncstore->syncdata), syncstore->nsyncdata) );
151
152 for( i = 0; i < syncstore->nsyncdata; ++i )
153 {
154 syncstore->syncdata[i].syncnum = -1;
155 SCIP_CALL( SCIPboundstoreCreate(syncstore->mainscip, &syncstore->syncdata[i].boundstore, syncstore->ninitvars) );
156 SCIP_CALL( SCIPallocBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].solobj, syncstore->maxnsols) );
157 SCIP_CALL( SCIPallocBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].solsource, syncstore->maxnsols) );
158 SCIP_CALL( SCIPallocBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].sols, syncstore->maxnsols) );
159
160 for( j = 0; j < syncstore->maxnsols; ++j )
161 {
162 SCIP_CALL( SCIPallocBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].sols[j], syncstore->ninitvars) );
163 }
164
165 SCIP_CALL( SCIPtpiInitLock(&(syncstore->syncdata[i].lock)) );
166 SCIP_CALL( SCIPtpiInitCondition(&(syncstore->syncdata[i].allsynced)) );
167 }
168
169 syncstore->initialized = TRUE;
170 syncstore->stopped = FALSE;
171
172 SCIP_CALL( SCIPgetIntParam(scip, "parallel/mode", ¶mode) );
173 syncstore->mode = (SCIP_PARALLELMODE) paramode;
174
175 SCIP_CALL( SCIPtpiInit(syncstore->nsolvers, INT_MAX, FALSE) );
176 SCIP_CALL( SCIPautoselectDisps(scip) );
177
178 if( syncstore->mode == SCIP_PARA_DETERMINISTIC )
179 {
180 /* in deterministic mode use the number of non-zeros and the number of variables to get a good
181 * syncdelay and maximum syncfreq
182 */
183 syncstore->minsyncdelay *= 0.01 * (SCIPgetNNZs(scip) * SCIPgetNVars(scip)); /*lint !e790*/
184 syncstore->syncfreqmax *= 0.01 * (SCIPgetNNZs(scip) * SCIPgetNVars(scip)); /*lint !e790*/
185 }
186
187 return SCIP_OKAY;
188 }
189
190 /** deinitializes the synchronization store */
SCIPsyncstoreExit(SCIP_SYNCSTORE * syncstore)191 SCIP_RETCODE SCIPsyncstoreExit(
192 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
193 )
194 {
195 int i;
196 int j;
197
198 assert(syncstore != NULL);
199 assert(syncstore->initialized);
200
201 SCIP_CALL( SCIPtpiExit() );
202
203 for( i = 0; i < syncstore->nsyncdata; ++i )
204 {
205 SCIPtpiDestroyLock(&(syncstore->syncdata[i].lock));
206 SCIPtpiDestroyCondition(&(syncstore->syncdata[i].allsynced));
207 SCIPfreeBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].solobj, syncstore->maxnsols);
208 SCIPfreeBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].solsource, syncstore->maxnsols);
209 SCIPboundstoreFree(syncstore->mainscip, &syncstore->syncdata[i].boundstore);
210
211 for( j = 0; j < syncstore->maxnsols; ++j )
212 {
213 SCIPfreeBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].sols[j], syncstore->ninitvars);
214 }
215
216 SCIPfreeBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata[i].sols, syncstore->maxnsols);
217 }
218
219 SCIPfreeBlockMemoryArray(syncstore->mainscip, &syncstore->syncdata, syncstore->nsyncdata);
220
221 syncstore->initialized = FALSE;
222 syncstore->stopped = FALSE;
223
224 return SCIP_OKAY;
225 }
226
227 /** checks whether the solve-is-stopped flag in the syncstore has been set by any thread */
SCIPsyncstoreSolveIsStopped(SCIP_SYNCSTORE * syncstore)228 SCIP_Bool SCIPsyncstoreSolveIsStopped(
229 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
230 )
231 {
232 SCIP_Bool stopped;
233
234 SCIP_CALL_ABORT( SCIPtpiAcquireLock(&syncstore->lock) );
235
236 stopped = syncstore->stopped;
237
238 SCIP_CALL_ABORT( SCIPtpiReleaseLock(&syncstore->lock) );
239
240 return stopped;
241 }
242
243 /** sets the solve-is-stopped flag in the syncstore so that subsequent calls to
244 * SCIPsyncstoreSolveIsStopped will return the given value in any thread
245 */
SCIPsyncstoreSetSolveIsStopped(SCIP_SYNCSTORE * syncstore,SCIP_Bool stopped)246 void SCIPsyncstoreSetSolveIsStopped(
247 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
248 SCIP_Bool stopped /**< flag if the solve is stopped */
249 )
250 {
251 SCIP_CALL_ABORT( SCIPtpiAcquireLock(&syncstore->lock) );
252
253 syncstore->stopped = stopped;
254
255 SCIP_CALL_ABORT( SCIPtpiReleaseLock(&syncstore->lock) );
256 }
257
258 /** gets the upperbound from the last synchronization */
SCIPsyncstoreGetLastUpperbound(SCIP_SYNCSTORE * syncstore)259 SCIP_Real SCIPsyncstoreGetLastUpperbound(
260 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
261 )
262 {
263 assert(syncstore != NULL);
264 assert(syncstore->initialized);
265
266 return syncstore->lastsync == NULL ? SCIPinfinity(syncstore->mainscip) : syncstore->lastsync->bestupperbound;
267 }
268
269 /** gets the lowerbound from the last synchronization */
SCIPsyncstoreGetLastLowerbound(SCIP_SYNCSTORE * syncstore)270 SCIP_Real SCIPsyncstoreGetLastLowerbound(
271 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
272 )
273 {
274 assert(syncstore != NULL);
275 assert(syncstore->initialized);
276
277 return syncstore->lastsync == NULL ? -SCIPinfinity(syncstore->mainscip) : syncstore->lastsync->bestlowerbound;
278 }
279
280 /** gets the number of solutions from the last synchronization */
SCIPsyncstoreGetLastNSols(SCIP_SYNCSTORE * syncstore)281 int SCIPsyncstoreGetLastNSols(
282 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
283 )
284 {
285 assert(syncstore != NULL);
286 assert(syncstore->initialized);
287
288 return syncstore->lastsync == NULL ? 0 : syncstore->lastsync->nsols;
289 }
290
291 /** gets the number of boundchanges from the last synchronization */
SCIPsyncstoreGetLastNBounds(SCIP_SYNCSTORE * syncstore)292 int SCIPsyncstoreGetLastNBounds(
293 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
294 )
295 {
296 assert(syncstore != NULL);
297 assert(syncstore->initialized);
298
299 return syncstore->lastsync == NULL ? 0 : SCIPboundstoreGetNChgs(syncstore->lastsync->boundstore);
300 }
301
302 /** gets total memory used by all solvers from the last synchronization */
SCIPsyncstoreGetLastMemTotal(SCIP_SYNCSTORE * syncstore)303 SCIP_Longint SCIPsyncstoreGetLastMemTotal(
304 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
305 )
306 {
307 assert(syncstore != NULL);
308 assert(syncstore->initialized);
309
310 return syncstore->lastsync == NULL ? 0 : syncstore->lastsync->memtotal;
311 }
312
313 /** gets the synchronization frequency from the last synchronization */
SCIPsyncstoreGetLastSyncfreq(SCIP_SYNCSTORE * syncstore)314 SCIP_Real SCIPsyncstoreGetLastSyncfreq(
315 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
316 )
317 {
318 assert(syncstore != NULL);
319 assert(syncstore->initialized);
320
321 return syncstore->lastsync == NULL ? 0.0 : syncstore->lastsync->syncfreq;
322 }
323
324 /** get synchronization data with given number. It is the responsibility of the caller
325 * to only ask for a synchronization number that still exists, which is checked
326 * with an assert in debug mode. */
SCIPsyncstoreGetSyncdata(SCIP_SYNCSTORE * syncstore,SCIP_Longint syncnum)327 SCIP_SYNCDATA* SCIPsyncstoreGetSyncdata(
328 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
329 SCIP_Longint syncnum /**< the number of the synchronization to start, which
330 * must be increasing between calls of the same thread */
331 )
332 {
333 int j;
334
335 assert(syncstore != NULL);
336 assert(syncstore->initialized);
337
338 j = (int) syncnum % syncstore->nsyncdata;
339
340 /* check if requested syncnumber still exists if in debug mode */
341 assert(syncstore->syncdata[j].syncnum == syncnum);
342
343 return &syncstore->syncdata[j];
344 }
345
346 /** get the next synchronization data that should be read and
347 * adjust the delay. Returns NULL if no more data should be read due to minimum delay */
SCIPsyncstoreGetNextSyncdata(SCIP_SYNCSTORE * syncstore,SCIP_SYNCDATA * syncdata,SCIP_Real syncfreq,SCIP_Longint writenum,SCIP_Real * delay)348 SCIP_SYNCDATA* SCIPsyncstoreGetNextSyncdata(
349 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
350 SCIP_SYNCDATA* syncdata, /**< the synchronization data */
351 SCIP_Real syncfreq, /**< the current synchronization frequency */
352 SCIP_Longint writenum, /**< number of synchronizations the solver has written to */
353 SCIP_Real* delay /**< pointer holding the current synchronization delay */
354 )
355 {
356 SCIP_Real newdelay;
357 SCIP_Longint nextsyncnum;
358
359 assert(syncstore != NULL);
360 assert(syncstore->initialized);
361 assert(delay != NULL);
362
363 if( syncdata == NULL )
364 {
365 nextsyncnum = 0;
366 }
367 else
368 {
369 if( syncdata->status != SCIP_STATUS_UNKNOWN )
370 return NULL;
371
372 nextsyncnum = syncdata->syncnum + 1;
373 }
374
375 if( nextsyncnum == writenum )
376 return NULL;
377
378 newdelay = *delay - syncfreq;
379
380 /* if the delay would get too small we dont want to read the next syncdata.
381 * But due to the limited length of the syncdata array we might need to
382 * read this synchronization data anyways which is checked by the second part
383 * of the if condition
384 */
385 if( newdelay < syncstore->minsyncdelay && nextsyncnum >= writenum - syncstore->maxnsyncdelay )
386 return NULL;
387
388 *delay = newdelay;
389 assert(syncstore->syncdata[nextsyncnum % syncstore->nsyncdata].syncnum == nextsyncnum);
390
391 return &syncstore->syncdata[nextsyncnum % syncstore->nsyncdata];
392 }
393
394 /** ensures that the given synchronization data has been written by
395 * all solvers upon return of this function and blocks the caller if necessary. */
SCIPsyncstoreEnsureAllSynced(SCIP_SYNCSTORE * syncstore,SCIP_SYNCDATA * syncdata)396 SCIP_RETCODE SCIPsyncstoreEnsureAllSynced(
397 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
398 SCIP_SYNCDATA* syncdata /**< the synchronization data */
399 )
400 {
401 assert(syncdata != NULL);
402 assert(syncstore != NULL);
403 assert(syncstore->initialized);
404
405 /* check if waiting is required, make sure to hold the lock */
406 SCIP_CALL( SCIPtpiAcquireLock(&syncdata->lock) );
407
408 while( syncdata->syncedcount < syncstore->nsolvers )
409 {
410 /* yes, so wait on the condition variable
411 * (automatically releases the lock and reacquires it after the waiting)
412 */
413 SCIP_CALL( SCIPtpiWaitCondition(&syncdata->allsynced, &syncdata->lock) );
414 }
415
416 SCIP_CALL( SCIPtpiReleaseLock(&syncdata->lock) );
417
418 return SCIP_OKAY;
419 }
420
421 /** Start synchronization for the given concurrent solver.
422 * Needs to be followed by a call to SCIPsyncstoreFinishSync if
423 * the syncdata that is returned is not NULL
424 */
SCIPsyncstoreStartSync(SCIP_SYNCSTORE * syncstore,SCIP_Longint syncnum,SCIP_SYNCDATA ** syncdata)425 SCIP_RETCODE SCIPsyncstoreStartSync(
426 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
427 SCIP_Longint syncnum, /**< the number of the synchronization to start, which
428 * must be increasing between calls of the same thread */
429 SCIP_SYNCDATA** syncdata /**< pointer to return the synchronization data */
430 )
431 {
432 int i;
433
434 assert(syncdata != NULL);
435 assert(syncstore != NULL);
436 assert(syncstore->initialized);
437
438 if( SCIPsyncstoreSolveIsStopped(syncstore) )
439 {
440 *syncdata = NULL;
441 return SCIP_OKAY;
442 }
443
444 i = syncnum % syncstore->nsyncdata; /*lint !e712*/
445 *syncdata = &syncstore->syncdata[i];
446 assert(*syncdata != NULL);
447
448 SCIP_CALL( SCIPtpiAcquireLock(&(*syncdata)->lock) );
449
450 if( (*syncdata)->syncnum != syncnum )
451 {
452 SCIPboundstoreClear((*syncdata)->boundstore);
453 (*syncdata)->nsols = 0;
454 (*syncdata)->memtotal = SCIPgetMemTotal(syncstore->mainscip);
455 (*syncdata)->syncedcount = 0;
456 (*syncdata)->bestupperbound = SCIPinfinity(syncstore->mainscip);
457 (*syncdata)->bestlowerbound = -(*syncdata)->bestupperbound;
458 (*syncdata)->status = SCIP_STATUS_UNKNOWN;
459 (*syncdata)->winner = 0;
460 (*syncdata)->syncnum = syncnum;
461 (*syncdata)->syncfreq = 0.0;
462 }
463
464 return SCIP_OKAY;
465 }
466
467 /** finishes synchronization for the synchronization data */
SCIPsyncstoreFinishSync(SCIP_SYNCSTORE * syncstore,SCIP_SYNCDATA ** syncdata)468 SCIP_RETCODE SCIPsyncstoreFinishSync(
469 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
470 SCIP_SYNCDATA** syncdata /**< the synchronization data */
471 )
472 {
473 SCIP_Bool printline = FALSE;
474
475 assert(syncdata != NULL);
476 assert((*syncdata) != NULL);
477 assert(syncstore != NULL);
478 assert(syncstore->initialized);
479
480 ++(*syncdata)->syncedcount;
481
482 if( (*syncdata)->syncedcount == syncstore->nsolvers )
483 {
484 if( (*syncdata)->status != SCIP_STATUS_UNKNOWN )
485 SCIPsyncstoreSetSolveIsStopped(syncstore, TRUE);
486
487 syncstore->lastsync = *syncdata;
488 printline = TRUE;
489
490 SCIP_CALL( SCIPtpiBroadcastCondition(&(*syncdata)->allsynced) );
491 }
492
493 SCIP_CALL( SCIPtpiReleaseLock(&(*syncdata)->lock) );
494
495 if( printline )
496 {
497 SCIP_CALL( SCIPprintDisplayLine(syncstore->mainscip, NULL, SCIP_VERBLEVEL_HIGH, TRUE) );
498 }
499
500 *syncdata = NULL;
501
502 return SCIP_OKAY;
503 }
504
505 /** gets status in synchronization data */
SCIPsyncdataGetStatus(SCIP_SYNCDATA * syncdata)506 SCIP_STATUS SCIPsyncdataGetStatus(
507 SCIP_SYNCDATA* syncdata /**< the synchronization data */
508 )
509 {
510 assert(syncdata != NULL);
511
512 return syncdata->status;
513 }
514
515 /** gets the solver that had the best status, or -1 if solve is not stopped yet */
SCIPsyncstoreGetWinner(SCIP_SYNCSTORE * syncstore)516 int SCIPsyncstoreGetWinner(
517 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
518 )
519 {
520 assert(syncstore != NULL);
521 assert(syncstore->initialized);
522
523 if( syncstore->lastsync == NULL || syncstore->lastsync->status == SCIP_STATUS_UNKNOWN )
524 return -1;
525
526 return syncstore->lastsync->winner;
527 }
528
529 /** how many solvers have already finished synchronizing on this sychronization data */
SCIPsyncdataGetNSynced(SCIP_SYNCDATA * syncdata)530 int SCIPsyncdataGetNSynced(
531 SCIP_SYNCDATA* syncdata /**< the synchronization data */
532 )
533 {
534 assert(syncdata != NULL);
535
536 return syncdata->syncedcount;
537 }
538
539 /** how many solvers have are running concurrently */
SCIPsyncstoreGetNSolvers(SCIP_SYNCSTORE * syncstore)540 int SCIPsyncstoreGetNSolvers(
541 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
542 )
543 {
544 assert(syncstore != NULL);
545 assert(syncstore->initialized);
546
547 return syncstore->nsolvers;
548 }
549
550 /** read amount total memory used from synchronization data */
SCIPsyncdataGetMemTotal(SCIP_SYNCDATA * syncdata)551 SCIP_Longint SCIPsyncdataGetMemTotal(
552 SCIP_SYNCDATA* syncdata /**< the synchronization data */
553 )
554 {
555 assert(syncdata != NULL);
556
557 return syncdata->memtotal;
558 }
559
560 /** read the synchronization frequency from a synchronization data */
SCIPsyncdataGetSyncFreq(SCIP_SYNCDATA * syncdata)561 SCIP_Real SCIPsyncdataGetSyncFreq(
562 SCIP_SYNCDATA* syncdata /**< the synchronization data */
563 )
564 {
565 assert(syncdata != NULL);
566
567 return syncdata->syncfreq;
568 }
569
570 /** read the upperbound stored in a synchronization data */
SCIPsyncdataGetUpperbound(SCIP_SYNCDATA * syncdata)571 SCIP_Real SCIPsyncdataGetUpperbound(
572 SCIP_SYNCDATA* syncdata /**< the synchronization data */
573 )
574 {
575 assert(syncdata != NULL);
576
577 return syncdata->bestupperbound;
578 }
579
580 /** read the lowerbound stored in a synchronization data */
SCIPsyncdataGetLowerbound(SCIP_SYNCDATA * syncdata)581 SCIP_Real SCIPsyncdataGetLowerbound(
582 SCIP_SYNCDATA* syncdata /**< the synchronization data */
583 )
584 {
585 assert(syncdata != NULL);
586
587 return syncdata->bestlowerbound;
588 }
589
590 /** read the solutions stored in a synchronization data */
SCIPsyncdataGetSolutions(SCIP_SYNCDATA * syncdata,SCIP_Real *** solvalues,int ** solowner,int * nsols)591 void SCIPsyncdataGetSolutions(
592 SCIP_SYNCDATA* syncdata, /**< the synchronization data */
593 SCIP_Real*** solvalues, /**< array of buffers containing the solution values */
594 int** solowner, /**< array of ownerids of solutions */
595 int* nsols /**< pointer to return number of solutions */
596 )
597 {
598 assert(syncdata != NULL);
599 assert(solvalues != NULL);
600 assert(solowner != NULL);
601 assert(nsols != NULL);
602
603 *solvalues = syncdata->sols;
604 *solowner = syncdata->solsource;
605 *nsols = syncdata->nsols;
606 }
607
608 /** read bound changes stored in the synchronization data */
SCIPsyncdataGetBoundChgs(SCIP_SYNCDATA * syncdata)609 SCIP_BOUNDSTORE* SCIPsyncdataGetBoundChgs(
610 SCIP_SYNCDATA* syncdata /**< the synchronization data */
611 )
612 {
613 assert(syncdata != NULL);
614
615 return syncdata->boundstore;
616 }
617
618 /** write the synchronization frequency to a synchronization data */
SCIPsyncdataSetSyncFreq(SCIP_SYNCSTORE * syncstore,SCIP_SYNCDATA * syncdata,SCIP_Real syncfreq)619 void SCIPsyncdataSetSyncFreq(
620 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
621 SCIP_SYNCDATA* syncdata, /**< the synchronization data */
622 SCIP_Real syncfreq /**< the synchronization frequency */
623 )
624 {
625 assert(syncstore != NULL);
626 assert(syncstore->initialized);
627 assert(syncdata != NULL);
628
629 syncdata->syncfreq = MIN(syncfreq, syncstore->syncfreqmax);
630 }
631
632 /** set status in the synchronization data */
SCIPsyncdataSetStatus(SCIP_SYNCDATA * syncdata,SCIP_STATUS status,int solverid)633 void SCIPsyncdataSetStatus(
634 SCIP_SYNCDATA* syncdata, /**< the synchronization data the upperbound should be added to */
635 SCIP_STATUS status, /**< the status */
636 int solverid /**< identifier of te solver that has this status */
637 )
638 {
639 assert(syncdata != NULL);
640
641 /* check if status is better than current one (closer to SCIP_STATUS_OPTIMAL),
642 * break ties by the solverid, and remember the solver wit the best status
643 * so that the winner will be selected deterministically
644 */
645 if( syncdata->status < SCIP_STATUS_OPTIMAL )
646 {
647 if( status > syncdata->status || (status == syncdata->status && solverid < syncdata->winner) )
648 {
649 syncdata->status = status;
650 syncdata->winner = solverid;
651 }
652 }
653 else if( syncdata->status > SCIP_STATUS_OPTIMAL && status >= SCIP_STATUS_OPTIMAL )
654 {
655 if( status < syncdata->status || (status == syncdata->status && solverid < syncdata->winner) )
656 {
657 syncdata->status = status;
658 syncdata->winner = solverid;
659 }
660 }
661 }
662
663 /** adds memory used to the synchronization data */
SCIPsyncdataAddMemTotal(SCIP_SYNCDATA * syncdata,SCIP_Longint memtotal)664 void SCIPsyncdataAddMemTotal(
665 SCIP_SYNCDATA* syncdata, /**< the synchronization data the solution should be added to */
666 SCIP_Longint memtotal /**< the number of bytes used */
667 )
668 {
669 assert(syncdata != NULL);
670
671 syncdata->memtotal += memtotal;
672 }
673
674 /** set upperbound to the synchronization data */
SCIPsyncdataSetUpperbound(SCIP_SYNCDATA * syncdata,SCIP_Real upperbound)675 void SCIPsyncdataSetUpperbound(
676 SCIP_SYNCDATA* syncdata, /**< the synchronization data the upperbound should be added to */
677 SCIP_Real upperbound /**< the upperbound */
678 )
679 {
680 assert(syncdata != NULL);
681
682 syncdata->bestupperbound = MIN(syncdata->bestupperbound, upperbound);
683 }
684
685 /** set lowerbound to the synchronization data */
SCIPsyncdataSetLowerbound(SCIP_SYNCDATA * syncdata,SCIP_Real lowerbound)686 void SCIPsyncdataSetLowerbound(
687 SCIP_SYNCDATA* syncdata, /**< the synchronization data the lowerbound should be added to */
688 SCIP_Real lowerbound /**< the lowerbound */
689 )
690 {
691 assert(syncdata != NULL);
692
693 syncdata->bestlowerbound = MAX(syncdata->bestlowerbound, lowerbound);
694 }
695
696 /** gives a buffer to store the solution values, or NULL if solution should not be stored
697 * because there are already better solutions stored.
698 */
SCIPsyncdataGetSolutionBuffer(SCIP_SYNCSTORE * syncstore,SCIP_SYNCDATA * syncdata,SCIP_Real solobj,int ownerid,SCIP_Real ** buffer)699 void SCIPsyncdataGetSolutionBuffer(
700 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
701 SCIP_SYNCDATA* syncdata, /**< the synchronization data the solution should be added to */
702 SCIP_Real solobj, /**< the objective value of the solution */
703 int ownerid, /**< an identifier for the owner of the solution, e.g. the thread number */
704 SCIP_Real** buffer /**< pointer to return a buffer for the solution values, which must be set
705 * if the buffer is not NULL */
706 )
707 {
708 int pos;
709 int i;
710
711 assert(syncstore != NULL);
712 assert(syncstore->initialized);
713 assert(syncdata != NULL);
714 assert(buffer != NULL);
715
716 for( pos = 0; pos < syncdata->nsols; ++pos )
717 {
718 if( syncdata->solobj[pos] < solobj || (syncdata->solobj[pos] == solobj && ownerid < syncdata->solsource[pos]) ) /*lint !e777*/
719 break;
720 }
721
722 if( syncdata->nsols < syncstore->maxnsols )
723 {
724 for( i = syncdata->nsols; i > pos; --i )
725 {
726 syncdata->solobj[i] = syncdata->solobj[i - 1];
727 syncdata->solsource[i] = syncdata->solsource[i - 1];
728 SCIPswapPointers((void**) &syncdata->sols[i], (void**) &syncdata->sols[i - 1]);
729 }
730
731 ++syncdata->nsols;
732 }
733 else
734 {
735 --pos;
736
737 for( i = 0; i < pos; ++i )
738 {
739 syncdata->solobj[i] = syncdata->solobj[i + 1];
740 syncdata->solsource[i] = syncdata->solsource[i + 1];
741 SCIPswapPointers((void**) &syncdata->sols[i], (void**) &syncdata->sols[i + 1]);
742 }
743 }
744
745 if( pos >= 0 )
746 {
747 syncdata->solobj[pos] = solobj;
748 syncdata->solsource[pos] = ownerid;
749 *buffer = syncdata->sols[pos];
750 }
751 else
752 {
753 *buffer = NULL;
754 }
755 }
756
757 /** adds bound changes to the synchronization data */
SCIPsyncdataAddBoundChanges(SCIP_SYNCSTORE * syncstore,SCIP_SYNCDATA * syncdata,SCIP_BOUNDSTORE * boundstore)758 SCIP_RETCODE SCIPsyncdataAddBoundChanges(
759 SCIP_SYNCSTORE* syncstore, /**< the synchronization store */
760 SCIP_SYNCDATA* syncdata, /**< the synchronization data */
761 SCIP_BOUNDSTORE* boundstore /**< bound store containing the bounds to add */
762 )
763 {
764 assert(syncstore != NULL);
765 assert(syncstore->initialized);
766 assert(syncdata != NULL);
767 assert(boundstore != NULL);
768
769 SCIP_CALL( SCIPboundstoreMerge(syncstore->mainscip, syncdata->boundstore, boundstore) );
770
771 return SCIP_OKAY;
772 }
773
774 /** is synchronization store initialized */
SCIPsyncstoreIsInitialized(SCIP_SYNCSTORE * syncstore)775 SCIP_Bool SCIPsyncstoreIsInitialized(
776 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
777 )
778 {
779 assert(syncstore != NULL);
780
781 return syncstore->initialized;
782 }
783
784 /** returns the mode of the synchronization store */
SCIPsyncstoreGetMode(SCIP_SYNCSTORE * syncstore)785 SCIP_PARALLELMODE SCIPsyncstoreGetMode(
786 SCIP_SYNCSTORE* syncstore /**< the synchronization store */
787 )
788 {
789 assert(syncstore != NULL);
790
791 return syncstore->mode;
792 }
793