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