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