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", &paramode) );
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