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   concurrent.c
17  * @ingroup PARALLEL
18  * @brief  helper functions for concurrent SCIP solvers
19  * @author Leona Gottwald
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include "scip/concurrent.h"
25 #include "scip/struct_concurrent.h"
26 #include "scip/concsolver.h"
27 #include "scip/event.h"
28 #include "scip/struct_scip.h"
29 #include "scip/stat.h"
30 #include "scip/struct_set.h"
31 #include "scip/struct_primal.h"
32 #include "scip/struct_stat.h"
33 #include "scip/struct_sol.h"
34 #include "scip/struct_prop.h"
35 #include "scip/struct_heur.h"
36 #include "scip/struct_sepa.h"
37 #include "scip/struct_presol.h"
38 #include "scip/prob.h"
39 #include "scip/prop_sync.h"
40 #include "scip/heur_sync.h"
41 #include "scip/event_globalbnd.h"
42 #include "scip/scip.h"
43 #include "scip/syncstore.h"
44 #include "scip/set.h"
45 #include "tpi/tpi.h"
46 
47 /** create concurrent data */
SCIPcreateConcurrent(SCIP * scip,SCIP_CONCSOLVER * concsolver,int * varperm)48 SCIP_RETCODE SCIPcreateConcurrent(
49    SCIP*                 scip,               /**< SCIP datastructure */
50    SCIP_CONCSOLVER*      concsolver,         /**< concurrent solver of given SCIP instance */
51    int*                  varperm             /**< permutation of variables for communication */
52    )
53 {
54    int nvars;
55 
56    assert(scip != NULL);
57    assert(concsolver != NULL);
58    assert(varperm != NULL);
59    assert(scip->concurrent == NULL);
60 
61    SCIP_CALL( SCIPallocBlockMemory(scip, &scip->concurrent) );
62 
63    nvars = SCIPgetNOrigVars(scip);
64    scip->concurrent->varperm = NULL;
65 
66    SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &scip->concurrent->varperm, varperm, nvars) );
67 
68    scip->concurrent->concsolver = concsolver;
69    scip->concurrent->mainscip = scip;
70    scip->concurrent->solidx = scip->stat->solindex;
71    scip->stat->subscipdepth = 0;
72 
73    if( scip->set->parallel_mode == (int) SCIP_PARA_DETERMINISTIC )
74    {
75       scip->concurrent->dettime = 0.0;
76       scip->concurrent->wallclock = NULL;
77    }
78    else
79    {
80       SCIP_CALL( SCIPcreateWallClock(scip, &scip->concurrent->wallclock) );
81       SCIP_CALL( SCIPstartClock(scip, scip->concurrent->wallclock) );
82    }
83 
84    assert(SCIPfindHeur(scip, "sync") == NULL);
85 
86    SCIP_CALL( SCIPincludeHeurSync(scip) );
87    scip->concurrent->heursync = SCIPfindHeur(scip, "sync");
88 
89    assert(SCIPfindProp(scip, "sync") == NULL);
90 
91    SCIP_CALL( SCIPincludePropSync(scip) );
92    scip->concurrent->propsync = SCIPfindProp(scip, "sync");
93 
94    scip->concurrent->eventglobalbnd = NULL;
95    assert(SCIPfindEventhdlr(scip, "globalbnd") == NULL);
96 
97    if( scip->set->concurrent_commvarbnds )
98    {
99       SCIP_CALL( SCIPincludeEventHdlrGlobalbnd(scip) );
100       scip->concurrent->eventglobalbnd = SCIPfindEventhdlr(scip, "globalbnd");
101    }
102 
103    return SCIP_OKAY;
104 }
105 
106 /** get number of initialized concurrent solvers */
SCIPgetNConcurrentSolvers(SCIP * scip)107 int SCIPgetNConcurrentSolvers(
108    SCIP*                 scip                /**< SCIP datastructure */
109    )
110 {
111    assert(scip != NULL);
112    assert(scip->set != NULL);
113 
114    return scip->set->nconcsolvers;
115 }
116 
117 /** gets the initialized concurrent solvers */
SCIPgetConcurrentSolvers(SCIP * scip)118 SCIP_CONCSOLVER** SCIPgetConcurrentSolvers(
119    SCIP*                 scip                /**< SCIP datastructure */
120    )
121 {
122    assert(scip != NULL);
123    assert(scip->set != NULL);
124 
125    return scip->set->concsolvers;
126 }
127 
128 /** adds an initialized concurrent solver */
SCIPaddConcurrentSolver(SCIP * scip,SCIP_CONCSOLVER * concsolver)129 SCIP_RETCODE SCIPaddConcurrentSolver(
130    SCIP*                 scip,               /**< SCIP datastructure */
131    SCIP_CONCSOLVER*      concsolver          /**< concurrent solver of given SCIP instance */
132    )
133 {
134    assert(scip != NULL);
135 
136    SCIP_CALL( SCIPsetIncludeConcsolver(scip->set, concsolver) );
137 
138    return SCIP_OKAY;
139 }
140 
141 /** frees concurrent data */
SCIPfreeConcurrent(SCIP * scip)142 SCIP_RETCODE SCIPfreeConcurrent(
143    SCIP*                 scip                /**< SCIP datastructure */
144    )
145 {
146    assert(scip != NULL);
147 
148    if( scip->concurrent == NULL )
149       return SCIP_OKAY;
150 
151    assert(scip->concurrent->varperm != NULL);
152 
153    /* check if we are the SCIP that is responsible for freeing this concurent struct
154     * or just a subscip */
155    if( scip->concurrent->mainscip != scip )
156    {
157       /* we are just a subscip, so don't free the concurrent structure and add the
158        * deterministic time that was counted in the subscip but not yet added to the main SCIP */
159       scip->concurrent->mainscip->stat->detertimecnt += scip->stat->detertimecnt;
160       scip->stat->detertimecnt = 0;
161       scip->concurrent = NULL;
162    }
163    else
164    {
165       /* we are in the main SCIP so free the concurrent structure */
166       if( scip->concurrent->wallclock != NULL )
167       {
168          SCIP_CALL( SCIPfreeClock(scip, &scip->concurrent->wallclock) );
169       }
170 
171       SCIPfreeBlockMemoryArray(scip, &scip->concurrent->varperm, SCIPgetNOrigVars(scip));
172 
173       SCIPfreeBlockMemory(scip, &scip->concurrent);
174    }
175 
176    return SCIP_OKAY;
177 }
178 
179 /** increments the time counter for synchronization */
SCIPincrementConcurrentTime(SCIP * scip,SCIP_Real val)180 SCIP_RETCODE SCIPincrementConcurrentTime(
181    SCIP*                 scip,               /**< SCIP datastructure */
182    SCIP_Real             val                 /**< value by which the time counter for synchronization is incremented */
183    )
184 {
185    SCIP_Real           syncfreq;
186    SCIP*               mainscip;
187    SCIP_CLOCK*         wallclock;
188 
189    assert(scip != NULL);
190 
191    if( scip->concurrent == NULL )
192       return SCIP_OKAY;
193 
194    syncfreq = SCIPconcsolverGetSyncFreq(scip->concurrent->concsolver);
195    wallclock = scip->concurrent->wallclock;
196    mainscip = scip->concurrent->mainscip;
197 
198    if( wallclock == NULL )
199    {
200       scip->concurrent->dettime += val;
201 
202       if( scip->concurrent->dettime >= syncfreq  )
203       {
204          SCIP_EVENT* event;
205          SCIPconcsolverSetTimeSinceLastSync(scip->concurrent->concsolver, scip->concurrent->dettime);
206          scip->concurrent->dettime = 0.0;
207          SCIP_CALL( SCIPeventCreateSync(&event, SCIPblkmem(mainscip)) );
208          SCIP_CALL( SCIPeventqueueAdd(mainscip->eventqueue, SCIPblkmem(mainscip), mainscip->set,
209                                       NULL, NULL, NULL, mainscip->eventfilter, &event) );
210       }
211    }
212    else
213    {
214       SCIP_Real timesincelastsync;
215       timesincelastsync = SCIPgetClockTime(mainscip, wallclock);
216 
217       if( timesincelastsync >= syncfreq )
218       {
219          SCIP_EVENT* event;
220          SCIPconcsolverSetTimeSinceLastSync(scip->concurrent->concsolver, timesincelastsync);
221 
222          SCIP_CALL( SCIPeventCreateSync(&event, SCIPblkmem(mainscip)) );
223          SCIP_CALL( SCIPeventqueueAdd(mainscip->eventqueue, SCIPblkmem(mainscip), mainscip->set,
224                                       NULL, NULL, NULL, mainscip->eventfilter, &event) );
225 
226          SCIP_CALL( SCIPresetClock(mainscip, wallclock) );
227          SCIP_CALL( SCIPstartClock(mainscip, wallclock) );
228       }
229    }
230 
231    return SCIP_OKAY;
232 }
233 
234 
235 /** synchronize with other concurrent solvers */
SCIPsynchronize(SCIP * scip)236 SCIP_RETCODE SCIPsynchronize(
237    SCIP*                 scip                /**< SCIP datastructure */
238    )
239 {
240    assert(scip != NULL);
241    assert(scip->concurrent != NULL);
242 
243    SCIP_CALL( SCIPconcsolverSync(scip->concurrent->concsolver, scip->concurrent->mainscip->set) );
244 
245    scip->concurrent->mainscip->concurrent->solidx = scip->concurrent->mainscip->stat->solindex;
246 
247    if( scip->concurrent->eventglobalbnd != NULL )
248       SCIPeventGlobalbndClearBoundChanges(scip->concurrent->eventglobalbnd);
249 
250    return SCIP_OKAY;
251 }
252 
253 /** disables storing global bound changes */
SCIPdisableConcurrentBoundStorage(SCIP * scip)254 void SCIPdisableConcurrentBoundStorage(
255    SCIP*                 scip                /**< SCIP data structure */
256    )
257 {
258    assert(scip != NULL);
259    assert(scip->concurrent != NULL);
260 
261    if( scip->concurrent->eventglobalbnd != NULL )
262       SCIPeventGlobalbndDisableBoundStorage(scip->concurrent->eventglobalbnd);
263 }
264 
265 /** enables storing global bound changes */
SCIPenableConcurrentBoundStorage(SCIP * scip)266 void SCIPenableConcurrentBoundStorage(
267    SCIP*                 scip                /**< SCIP data structure */
268    )
269 {
270    assert(scip != NULL);
271    assert(scip->concurrent != NULL);
272 
273    if( scip->concurrent->eventglobalbnd != NULL )
274       SCIPeventGlobalbndEnableBoundStorage(scip->concurrent->eventglobalbnd);
275 }
276 
277 /** gets total memory usage of all concurrent solvers together */
SCIPgetConcurrentMemTotal(SCIP * scip)278 SCIP_Longint SCIPgetConcurrentMemTotal(
279    SCIP*                 scip                /**< SCIP data structure */
280    )
281 {
282    SCIP_Longint memtotal = SCIPgetMemTotal(scip);
283 
284    assert(scip != NULL);
285 
286    if( scip->concurrent == NULL || scip->concurrent->mainscip != scip || scip->concurrent->concsolver == NULL )
287       return memtotal;
288    else
289    {
290       SCIP_Longint concmemtotal = SCIPconcsolverGetMemTotal(scip->concurrent->concsolver);
291       return MAX(memtotal, concmemtotal);
292    }
293 }
294 
295 /** gets the dualbound in the last synchronization */
SCIPgetConcurrentDualbound(SCIP * scip)296 SCIP_Real SCIPgetConcurrentDualbound(
297    SCIP*                 scip                /**< SCIP data structure */
298    )
299 {
300    SCIP_SYNCSTORE* syncstore;
301 
302    assert(scip != NULL);
303 
304    syncstore = SCIPgetSyncstore(scip);
305    assert(syncstore != NULL);
306 
307    return SCIPprobExternObjval(scip->transprob, scip->origprob, scip->set, SCIPsyncstoreGetLastLowerbound(syncstore));
308 }
309 
310 /** gets the primalbound in the last synchronization */
SCIPgetConcurrentPrimalbound(SCIP * scip)311 SCIP_Real SCIPgetConcurrentPrimalbound(
312    SCIP*                 scip                /**< SCIP data structure */
313    )
314 {
315    SCIP_SYNCSTORE* syncstore;
316 
317    assert(scip != NULL);
318 
319    syncstore = SCIPgetSyncstore(scip);
320    assert(syncstore != NULL);
321 
322    return SCIPprobExternObjval(scip->transprob, scip->origprob, scip->set, SCIPsyncstoreGetLastUpperbound(syncstore));
323 }
324 
325 /** gets the gap in the last synchronization */
SCIPgetConcurrentGap(SCIP * scip)326 SCIP_Real SCIPgetConcurrentGap(
327    SCIP*                 scip                /**< SCIP data structure */
328    )
329 {
330    SCIP_Real primalbound;
331    SCIP_Real dualbound;
332 
333    primalbound = SCIPgetConcurrentPrimalbound(scip);
334    dualbound = SCIPgetConcurrentDualbound(scip);
335 
336    return SCIPcomputeGap(SCIPepsilon(scip), SCIPinfinity(scip), primalbound, dualbound);
337 }
338 
339 /** gives the total number of tightened bounds received from other concurrent solvers */
SCIPgetConcurrentNTightenedBnds(SCIP * scip)340 SCIP_Longint SCIPgetConcurrentNTightenedBnds(
341    SCIP*                 scip                /**< SCIP data structure */
342    )
343 {
344    assert(scip->concurrent != NULL);
345 
346    return scip->concurrent->propsync != NULL ? SCIPpropSyncGetNTightenedBnds(scip->concurrent->propsync) : 0;
347 }
348 
349 /** gives the total number of tightened bounds for integer variables received from
350  *  other concurrent solvers */
SCIPgetConcurrentNTightenedIntBnds(SCIP * scip)351 SCIP_Longint SCIPgetConcurrentNTightenedIntBnds(
352    SCIP*                 scip                /**< SCIP data structure */
353    )
354 {
355    assert(scip->concurrent != NULL);
356 
357    return scip->concurrent->propsync != NULL ? SCIPpropSyncGetNTightenedIntBnds(scip->concurrent->propsync) : 0;
358 }
359 
360 /** pass a solution to the given SCIP instance using that was received via synchronization by using
361  * the sync heuristic */
SCIPaddConcurrentSol(SCIP * scip,SCIP_SOL * sol)362 SCIP_RETCODE SCIPaddConcurrentSol(
363    SCIP*                 scip,               /**< SCIP datastructure */
364    SCIP_SOL*             sol                 /**< solution */
365    )
366 {
367    assert(scip != NULL);
368    assert(scip->concurrent != NULL);
369    assert(sol != NULL);
370 
371    SCIP_CALL( SCIPheurSyncPassSol(scip, scip->concurrent->heursync, sol) );
372 
373    return SCIP_OKAY;
374 }
375 
376 /** adds a global boundchange to the given SCIP, by passing it to the sync propagator */
SCIPaddConcurrentBndchg(SCIP * scip,SCIP_VAR * var,SCIP_Real val,SCIP_BOUNDTYPE bndtype)377 SCIP_RETCODE SCIPaddConcurrentBndchg(
378    SCIP*                 scip,               /**< SCIP data structure */
379    SCIP_VAR*             var,                /**< variable for bound */
380    SCIP_Real             val,                /**< value of bound */
381    SCIP_BOUNDTYPE        bndtype             /**< type of bound */
382    )
383 {
384    assert(scip != NULL);
385    assert(var != NULL);
386    assert(scip->concurrent != NULL);
387    assert(scip->concurrent->propsync != NULL);
388 
389    SCIP_CALL( SCIPpropSyncAddBndchg(scip->concurrent->mainscip, scip->concurrent->propsync, var, val, bndtype) );
390 
391    return SCIP_OKAY;
392 }
393 
394 /** copy the nodenumber, depth, time, and runnumber of one solution to another one */
SCIPcopySolStats(SCIP_SOL * source,SCIP_SOL * target)395 SCIP_RETCODE SCIPcopySolStats(
396    SCIP_SOL*             source,             /**< source for solution statistics */
397    SCIP_SOL*             target              /**< target for solution statistics */
398    )
399 {
400    assert(source != NULL);
401    assert(target != NULL);
402 
403    target->depth = source->depth;
404    target->time = source->time;
405    target->nodenum = source->nodenum;
406    target->runnum = source->runnum;
407 
408    return SCIP_OKAY;
409 }
410 
411 
412 /** get variable index of original variable that is the same between concurrent solvers */
SCIPgetConcurrentVaridx(SCIP * scip,SCIP_VAR * var)413 int SCIPgetConcurrentVaridx(
414    SCIP*                 scip,               /**< SCIP data structure */
415    SCIP_VAR*             var                 /**< variable */
416    )
417 {
418    assert(scip != NULL);
419    assert(scip->concurrent != NULL);
420    assert(scip->concurrent->varperm != NULL);
421    assert(var != NULL);
422    assert(SCIPvarIsOriginal(var));
423    assert(SCIPvarGetIndex(var) < SCIPgetNOrigVars(scip));
424 
425    return scip->concurrent->varperm[SCIPvarGetIndex(var)];
426 }
427 
428 /** is the solution new since the last synchronization point */
SCIPIsConcurrentSolNew(SCIP * scip,SCIP_SOL * sol)429 SCIP_Bool SCIPIsConcurrentSolNew(
430    SCIP*                 scip,               /**< SCIP data structure */
431    SCIP_SOL*             sol                 /**< the solution */
432    )
433 {
434    assert(scip != NULL);
435    assert(scip->concurrent != NULL);
436    assert(sol != NULL);
437 
438    return SCIPsolGetIndex(sol) >= scip->concurrent->solidx;
439 }
440 
441 /** gets the global lower bound changes since the last synchronization point */
SCIPgetConcurrentGlobalBoundChanges(SCIP * scip)442 SCIP_BOUNDSTORE* SCIPgetConcurrentGlobalBoundChanges(
443    SCIP*                 scip                /**< SCIP data structure */
444    )
445 {
446    assert(scip != NULL);
447    assert(scip->concurrent != NULL);
448 
449    if( scip->concurrent->eventglobalbnd != NULL )
450       return SCIPeventGlobalbndGetBoundChanges(scip->concurrent->eventglobalbnd);
451 
452    return NULL;
453 }
454 
455 /** executes the concurrent solver corresponding to the current thread */
456 static
execConcsolver(void * args)457 SCIP_RETCODE execConcsolver(
458    void*                 args                /**< SCIP data structure passed in as a void pointer */
459    )
460 {
461    SCIP* scip;
462 
463    assert(args != NULL);
464 
465    scip = (SCIP*) args;
466 
467    SCIP_CALL( SCIPconcsolverExec(scip->set->concsolvers[SCIPtpiGetThreadNum()]) );
468    SCIP_CALL( SCIPconcsolverSync(scip->set->concsolvers[SCIPtpiGetThreadNum()], scip->set) );
469 
470    return SCIP_OKAY;
471 }
472 
473 /** start solving in parallel using the given set of concurrent solvers */
SCIPconcurrentSolve(SCIP * scip)474 SCIP_RETCODE SCIPconcurrentSolve(
475    SCIP*                 scip                /**< pointer to scip datastructure */
476    )
477 {
478    SCIP_SYNCSTORE*   syncstore;
479    int               idx;
480    int               jobid;
481    int               i;
482    SCIP_RETCODE      retcode;
483    SCIP_CONCSOLVER** concsolvers;
484    int               nconcsolvers;
485 
486    assert(scip != NULL);
487 
488    syncstore = SCIPgetSyncstore(scip);
489    concsolvers = scip->set->concsolvers;
490    nconcsolvers = scip->set->nconcsolvers;
491 
492    assert(SCIPsyncstoreIsInitialized(syncstore));
493    assert(SCIPsyncstoreGetNSolvers(syncstore) == nconcsolvers);
494 
495    SCIPsyncstoreSetSolveIsStopped(syncstore, FALSE);
496    jobid = SCIPtpiGetNewJobID();
497 
498    TPI_PARA
499    {
500       TPI_SINGLE
501       {
502          for( i = 0; i < nconcsolvers; ++i )
503          {
504             /* cppcheck-suppress unassignedVariable */
505             SCIP_JOB*         job;
506             SCIP_SUBMITSTATUS status;
507 
508             SCIP_CALL_ABORT( SCIPtpiCreateJob(&job, jobid, execConcsolver, scip) );
509             SCIP_CALL_ABORT( SCIPtpiSumbitJob(job, &status) );
510 
511             assert(status == SCIP_SUBMIT_SUCCESS);
512          }
513       }
514    }
515 
516    retcode = SCIPtpiCollectJobs(jobid);
517    idx = SCIPsyncstoreGetWinner(syncstore);
518    assert(idx >= 0 && idx < nconcsolvers);
519 
520    SCIP_CALL( SCIPconcsolverGetSolvingData(concsolvers[idx], scip) );
521 
522    return retcode;
523 }
524 
525 /** copy solving statistics */
SCIPcopyConcurrentSolvingStats(SCIP * source,SCIP * target)526 SCIP_RETCODE SCIPcopyConcurrentSolvingStats(
527    SCIP*                 source,             /**< SCIP data structure */
528    SCIP*                 target              /**< target SCIP data structure */
529    )
530 {
531    SCIP_Real     tmptime;
532    SCIP_HEUR*    heur;
533    SCIP_NODE*    root;
534    SCIP_PROP*    prop;
535    SCIP_SEPA*    sepa;
536    SCIP_PRESOL*  presol;
537    SCIP_HEUR**   heurs;
538    int           nheurs;
539    SCIP_PROP**   props;
540    int           nprops;
541    SCIP_SEPA**   sepas;
542    int           nsepas;
543    SCIP_PRESOL** presols;
544    int           npresols;
545    int           i;
546 
547    assert(source != NULL);
548    assert(target != NULL);
549 
550    heurs = SCIPgetHeurs(target);
551    nheurs = SCIPgetNHeurs(target);
552 
553    for( i = 0; i < nheurs; ++i )
554    {
555       heur = SCIPfindHeur(source, SCIPheurGetName(heurs[i]));
556 
557       if( heur != NULL )
558       {
559          heurs[i]->nbestsolsfound += heur->nbestsolsfound;
560          heurs[i]->ncalls += heur->ncalls;
561          heurs[i]->nsolsfound += heur->nsolsfound;
562          /* TODO divesets */
563          tmptime = SCIPgetClockTime(target, heurs[i]->setuptime);
564          tmptime += SCIPgetClockTime(source, heur->setuptime);
565          SCIP_CALL( SCIPsetClockTime(target, heurs[i]->setuptime, tmptime) );
566 
567          tmptime = SCIPgetClockTime(target, heurs[i]->heurclock);
568          tmptime += SCIPgetClockTime(source, heur->heurclock);
569          SCIP_CALL( SCIPsetClockTime(target, heurs[i]->heurclock, tmptime) );
570       }
571    }
572 
573    props = SCIPgetProps(target);
574    nprops = SCIPgetNProps(target);
575 
576    for( i = 0; i < nprops; ++i )
577    {
578       prop = SCIPfindProp(source, SCIPpropGetName(props[i]));
579 
580       if( prop != NULL )
581       {
582          props[i]->ncalls += prop->ncalls;
583          props[i]->nrespropcalls += prop->nrespropcalls;
584          props[i]->ncutoffs += prop->ncutoffs;
585          props[i]->ndomredsfound += prop->ndomredsfound;
586 
587          tmptime = SCIPgetClockTime(target, props[i]->proptime);
588          tmptime += SCIPgetClockTime(source, prop->proptime);
589          SCIP_CALL( SCIPsetClockTime(target, props[i]->proptime, tmptime) );
590 
591          tmptime = SCIPgetClockTime(target, props[i]->sbproptime);
592          tmptime += SCIPgetClockTime(source, prop->sbproptime);
593          SCIP_CALL( SCIPsetClockTime(target, props[i]->sbproptime, tmptime) );
594 
595          tmptime = SCIPgetClockTime(target, props[i]->resproptime);
596          tmptime += SCIPgetClockTime(source, prop->resproptime);
597          SCIP_CALL( SCIPsetClockTime(target, props[i]->resproptime, tmptime) );
598 
599          tmptime = SCIPgetClockTime(target, props[i]->presoltime);
600          tmptime += SCIPgetClockTime(source, prop->presoltime);
601          SCIP_CALL( SCIPsetClockTime(target, props[i]->presoltime, tmptime) );
602 
603          tmptime = SCIPgetClockTime(target, props[i]->setuptime);
604          tmptime += SCIPgetClockTime(source, prop->setuptime);
605          SCIP_CALL( SCIPsetClockTime(target, props[i]->setuptime, tmptime) );
606       }
607    }
608 
609    presols = SCIPgetPresols(target);
610    npresols = SCIPgetNPresols(target);
611 
612    for( i = 0; i < npresols; ++i )
613    {
614       presol = SCIPfindPresol(source, SCIPpresolGetName(presols[i]));
615 
616       if( presol != NULL )
617       {
618          presols[i]->ncalls += presol->ncalls;
619          presols[i]->nfixedvars += presol->nfixedvars;
620          presols[i]->naggrvars += presol->naggrvars;
621          presols[i]->nchgvartypes += presol->nchgvartypes;
622          presols[i]->nchgbds += presol->nchgbds;
623          presols[i]->naddholes += presol->naddholes;
624          presols[i]->ndelconss += presol->ndelconss;
625          presols[i]->naddconss += presol->naddconss;
626          presols[i]->nupgdconss += presol->nupgdconss;
627          presols[i]->nchgcoefs += presol->nchgcoefs;
628          presols[i]->nchgsides += presol->nchgsides;
629          presols[i]->nfixedvars += presol->nfixedvars;
630          presols[i]->nfixedvars += presol->nfixedvars;
631          presols[i]->nfixedvars += presol->nfixedvars;
632 
633          tmptime = SCIPgetClockTime(target, presols[i]->setuptime);
634          tmptime += SCIPgetClockTime(source, presol->setuptime);
635          SCIP_CALL( SCIPsetClockTime(target, presols[i]->setuptime, tmptime) );
636 
637          tmptime = SCIPgetClockTime(target, presols[i]->presolclock);
638          tmptime += SCIPgetClockTime(source, presol->presolclock);
639          SCIP_CALL( SCIPsetClockTime(target, presols[i]->presolclock, tmptime) );
640       }
641    }
642 
643    sepas = SCIPgetSepas(target);
644    nsepas = SCIPgetNSepas(target);
645 
646    for( i = 0; i < nsepas; ++i )
647    {
648       sepa = SCIPfindSepa(source, SCIPsepaGetName(sepas[i]));
649 
650       if( sepa != NULL )
651       {
652          sepas[i]->lastsepanode = sepa->lastsepanode;
653          sepas[i]->ncalls += sepa->ncalls;
654          sepas[i]->ncutoffs += sepa->ncutoffs;
655          sepas[i]->ncutsfound += sepa->ncutsfound;
656          sepas[i]->ncutsapplied += sepa->ncutsapplied;
657          sepas[i]->nconssfound += sepa->nconssfound;
658          sepas[i]->ndomredsfound += sepa->ndomredsfound;
659          sepas[i]->maxbounddist = MAX(sepas[i]->maxbounddist, sepa->maxbounddist);
660 
661          tmptime = SCIPgetClockTime(target, sepas[i]->setuptime);
662          tmptime += SCIPgetClockTime(source, sepa->setuptime);
663          SCIP_CALL( SCIPsetClockTime(target, sepas[i]->setuptime, tmptime) );
664 
665          tmptime = SCIPgetClockTime(target, sepas[i]->sepaclock);
666          tmptime += SCIPgetClockTime(source, sepa->sepaclock);
667          SCIP_CALL( SCIPsetClockTime(target, sepas[i]->sepaclock, tmptime) );
668       }
669    }
670 
671    target->primal->nsolsfound = source->primal->nsolsfound;
672    target->primal->nbestsolsfound = source->primal->nbestsolsfound;
673    target->primal->nlimsolsfound = source->primal->nlimsolsfound;
674    SCIPprobSetDualbound(target->transprob, SCIPprobExternObjval(target->transprob, target->origprob, target->set, SCIPgetDualbound(source)));
675    root = SCIPgetRootNode(target);
676 
677    if( root != NULL )
678    {
679       /* in the copied SCIP the dualbound is in the transformed space of the target */
680       SCIP_CALL( SCIPupdateNodeLowerbound(target, root, SCIPgetDualbound(source)) );
681    }
682 
683    target->stat->nlpiterations = source->stat->nlpiterations;
684    target->stat->nrootlpiterations = source->stat->nrootlpiterations;
685    target->stat->nrootfirstlpiterations = source->stat->nrootfirstlpiterations;
686    target->stat->nprimallpiterations = source->stat->nprimallpiterations;
687    target->stat->nduallpiterations = source->stat->nduallpiterations;
688    target->stat->nlexduallpiterations = source->stat->nlexduallpiterations;
689    target->stat->nbarrierlpiterations = source->stat->nbarrierlpiterations;
690    target->stat->nprimalresolvelpiterations = source->stat->nprimalresolvelpiterations;
691    target->stat->ndualresolvelpiterations = source->stat->ndualresolvelpiterations;
692    target->stat->nlexdualresolvelpiterations = source->stat->nlexdualresolvelpiterations;
693    target->stat->nnodelpiterations = source->stat->nnodelpiterations;
694    target->stat->ninitlpiterations = source->stat->ninitlpiterations;
695    target->stat->ndivinglpiterations = source->stat->ndivinglpiterations;
696    target->stat->ndivesetlpiterations = source->stat->ndivesetlpiterations;
697    target->stat->nsbdivinglpiterations = source->stat->nsbdivinglpiterations;
698    target->stat->nsblpiterations = source->stat->nsblpiterations;
699    target->stat->nrootsblpiterations = source->stat->nrootsblpiterations;
700    target->stat->nconflictlpiterations = source->stat->nconflictlpiterations;
701    target->stat->nnodes = source->stat->nnodes;
702    target->stat->ninternalnodes = source->stat->ninternalnodes;
703    target->stat->nobjleaves = source->stat->nobjleaves;
704    target->stat->nfeasleaves = source->stat->nfeasleaves;
705    target->stat->ninfeasleaves = source->stat->ninfeasleaves;
706    target->stat->ntotalnodes = source->stat->ntotalnodes;
707    target->stat->ntotalinternalnodes = source->stat->ntotalinternalnodes;
708    target->stat->ncreatednodes = source->stat->ncreatednodes;
709    target->stat->ncreatednodesrun = source->stat->ncreatednodesrun;
710    target->stat->nactivatednodes = source->stat->nactivatednodes;
711    target->stat->ndeactivatednodes = source->stat->ndeactivatednodes;
712    target->stat->nearlybacktracks = source->stat->nearlybacktracks;
713    target->stat->nnodesaboverefbound = source->stat->nnodesaboverefbound;
714    target->stat->nbacktracks = source->stat->nbacktracks;
715    target->stat->ndelayedcutoffs = source->stat->ndelayedcutoffs;
716    target->stat->nreprops = source->stat->nreprops;
717    target->stat->nrepropboundchgs = source->stat->nrepropboundchgs;
718    target->stat->nrepropcutoffs = source->stat->nrepropcutoffs;
719    target->stat->nlpsolsfound = source->stat->nlpsolsfound;
720    target->stat->npssolsfound = source->stat->npssolsfound;
721    target->stat->nsbsolsfound = source->stat->nsbsolsfound;
722    target->stat->nlpbestsolsfound = source->stat->nlpbestsolsfound;
723    target->stat->npsbestsolsfound = source->stat->npsbestsolsfound;
724    target->stat->nsbbestsolsfound = source->stat->nsbbestsolsfound;
725    target->stat->nexternalsolsfound = source->stat->nexternalsolsfound;
726    target->stat->lastdispnode = source->stat->lastdispnode;
727    target->stat->lastdivenode = source->stat->lastdivenode;
728    target->stat->lastconflictnode = source->stat->lastconflictnode;
729    target->stat->bestsolnode = source->stat->bestsolnode;
730    target->stat->domchgcount = source->stat->domchgcount;
731    target->stat->nboundchgs = source->stat->nboundchgs;
732    target->stat->nholechgs = source->stat->nholechgs;
733    target->stat->nprobboundchgs = source->stat->nprobboundchgs;
734    target->stat->nprobholechgs = source->stat->nprobholechgs;
735    target->stat->nsbdowndomchgs = source->stat->nsbdowndomchgs;
736    target->stat->nsbupdomchgs = source->stat->nsbupdomchgs;
737    target->stat->nsbtimesiterlimhit = source->stat->nsbtimesiterlimhit;
738    target->stat->nnodesbeforefirst = source->stat->nnodesbeforefirst;
739    target->stat->ninitconssadded = source->stat->ninitconssadded;
740    target->stat->firstlpdualbound = SCIPprobExternObjval(target->transprob, target->origprob, target->set, source->stat->firstlpdualbound);
741    target->stat->rootlowerbound = SCIPprobExternObjval(source->transprob, source->origprob, source->set, source->stat->rootlowerbound);
742    target->stat->vsidsweight = source->stat->vsidsweight;
743    target->stat->firstprimalbound = SCIPprobExternObjval(target->transprob, target->origprob, target->set, source->stat->firstprimalbound);
744    target->stat->firstprimaltime = source->stat->firstprimaltime;
745    target->stat->firstsolgap = source->stat->firstsolgap;
746    target->stat->lastsolgap = source->stat->lastsolgap;
747    target->stat->primalzeroittime = source->stat->primalzeroittime;
748    target->stat->dualzeroittime = source->stat->dualzeroittime;
749    target->stat->barrierzeroittime = source->stat->barrierzeroittime;
750    target->stat->maxcopytime = MAX(source->stat->maxcopytime, target->stat->maxcopytime);
751    target->stat->mincopytime = MIN(source->stat->mincopytime, target->stat->mincopytime);
752    target->stat->firstlptime = source->stat->firstlptime;
753    target->stat->lastbranchvalue = source->stat->lastbranchvalue;
754    target->stat->dualrefintegral = source->stat->dualrefintegral;
755    target->stat->primalrefintegral = source->stat->primalrefintegral;
756    target->stat->primaldualintegral = source->stat->primaldualintegral;
757    target->stat->previousgap = source->stat->previousgap;
758    target->stat->previousdualrefgap = source->stat->previousdualrefgap;
759    target->stat->previousprimalrefgap = source->stat->previousprimalrefgap;
760    target->stat->previntegralevaltime = source->stat->previntegralevaltime;
761    target->stat->lastprimalbound = SCIPprobExternObjval(source->transprob, source->origprob, source->set, source->stat->lastprimalbound);
762    target->stat->lastdualbound = SCIPprobExternObjval(source->transprob, source->origprob, source->set, source->stat->lastdualbound);
763    target->stat->lastlowerbound = SCIPprobExternObjval(source->transprob, source->origprob, source->set, source->stat->lastlowerbound);
764    target->stat->lastupperbound = SCIPprobExternObjval(source->transprob, source->origprob, source->set, source->stat->lastupperbound);
765    target->stat->rootlpbestestimate = source->stat->rootlpbestestimate;
766    target->stat->referencebound = source->stat->referencebound;
767 
768    /*tmptime = SCIPgetClockTime(target, target->stat->solvingtime);
769    tmptime += SCIPgetClockTime(source, source->stat->solvingtime);
770    SCIP_CALL( SCIPsetClockTime(target, target->stat->solvingtime, tmptime) );*/
771 
772    /* TODO */
773    tmptime = SCIPgetClockTime(target, target->stat->solvingtimeoverall);
774    tmptime += SCIPgetClockTime(source, source->stat->solvingtimeoverall);
775    SCIP_CALL( SCIPsetClockTime(target, target->stat->solvingtimeoverall, tmptime) );
776 
777    tmptime = SCIPgetClockTime(target, target->stat->presolvingtime);
778    tmptime += SCIPgetClockTime(source, source->stat->presolvingtime);
779    SCIP_CALL( SCIPsetClockTime(target, target->stat->presolvingtime, tmptime) );
780 
781    tmptime = SCIPgetClockTime(target, target->stat->presolvingtimeoverall);
782    tmptime += SCIPgetClockTime(source, source->stat->presolvingtimeoverall);
783    SCIP_CALL( SCIPsetClockTime(target, target->stat->presolvingtimeoverall, tmptime) );
784 
785    tmptime = SCIPgetClockTime(target, target->stat->primallptime);
786    tmptime += SCIPgetClockTime(source, source->stat->primallptime);
787    SCIP_CALL( SCIPsetClockTime(target, target->stat->primallptime, tmptime) );
788 
789    tmptime = SCIPgetClockTime(target, target->stat->duallptime);
790    tmptime += SCIPgetClockTime(source, source->stat->duallptime);
791    SCIP_CALL( SCIPsetClockTime(target, target->stat->duallptime, tmptime) );
792 
793    tmptime = SCIPgetClockTime(target, target->stat->lexduallptime);
794    tmptime += SCIPgetClockTime(source, source->stat->lexduallptime);
795    SCIP_CALL( SCIPsetClockTime(target, target->stat->lexduallptime, tmptime) );
796 
797    tmptime = SCIPgetClockTime(target, target->stat->barrierlptime);
798    tmptime += SCIPgetClockTime(source, source->stat->barrierlptime);
799    SCIP_CALL( SCIPsetClockTime(target, target->stat->barrierlptime, tmptime) );
800 
801    tmptime = SCIPgetClockTime(target, target->stat->divinglptime);
802    tmptime += SCIPgetClockTime(source, source->stat->divinglptime);
803    SCIP_CALL( SCIPsetClockTime(target, target->stat->divinglptime, tmptime) );
804 
805    tmptime = SCIPgetClockTime(target, target->stat->strongbranchtime);
806    tmptime += SCIPgetClockTime(source, source->stat->strongbranchtime);
807    SCIP_CALL( SCIPsetClockTime(target, target->stat->strongbranchtime, tmptime) );
808 
809    tmptime = SCIPgetClockTime(target, target->stat->conflictlptime);
810    tmptime += SCIPgetClockTime(source, source->stat->conflictlptime);
811    SCIP_CALL( SCIPsetClockTime(target, target->stat->conflictlptime, tmptime) );
812 
813    tmptime = SCIPgetClockTime(target, target->stat->lpsoltime);
814    tmptime += SCIPgetClockTime(source, source->stat->lpsoltime);
815    SCIP_CALL( SCIPsetClockTime(target, target->stat->lpsoltime, tmptime) );
816 
817    tmptime = SCIPgetClockTime(target, target->stat->pseudosoltime);
818    tmptime += SCIPgetClockTime(source, source->stat->pseudosoltime);
819    SCIP_CALL( SCIPsetClockTime(target, target->stat->pseudosoltime, tmptime) );
820 
821    tmptime = SCIPgetClockTime(target, target->stat->sbsoltime);
822    tmptime += SCIPgetClockTime(source, source->stat->sbsoltime);
823    SCIP_CALL( SCIPsetClockTime(target, target->stat->sbsoltime, tmptime) );
824 
825    tmptime = SCIPgetClockTime(target, target->stat->nodeactivationtime);
826    tmptime += SCIPgetClockTime(source, source->stat->nodeactivationtime);
827    SCIP_CALL( SCIPsetClockTime(target, target->stat->nodeactivationtime, tmptime) );
828 
829    tmptime = SCIPgetClockTime(target, target->stat->nlpsoltime);
830    tmptime += SCIPgetClockTime(source, source->stat->nlpsoltime);
831    SCIP_CALL( SCIPsetClockTime(target, target->stat->nlpsoltime, tmptime) );
832 
833    tmptime = SCIPgetClockTime(target, target->stat->strongpropclock);
834    tmptime += SCIPgetClockTime(source, source->stat->strongpropclock);
835    SCIP_CALL( SCIPsetClockTime(target, target->stat->strongpropclock, tmptime) );
836 
837    tmptime = SCIPgetClockTime(target, target->stat->reoptupdatetime);
838    tmptime += SCIPgetClockTime(source, source->stat->reoptupdatetime);
839    SCIP_CALL( SCIPsetClockTime(target, target->stat->reoptupdatetime, tmptime) );
840 
841    heur = source->stat->firstprimalheur;
842 
843    if( heur != NULL )
844       target->stat->firstprimalheur = SCIPfindHeur(target, SCIPheurGetName(heur));
845 
846    target->stat->status = source->stat->status;
847    target->stat->lastbranchdir = source->stat->lastbranchdir;
848    target->stat->lastsblpsolstats[0] = source->stat->lastsblpsolstats[0];
849    target->stat->lastsblpsolstats[1] = source->stat->lastsblpsolstats[1];
850    target->stat->nnz = source->stat->nnz;
851    target->stat->lpcount = source->stat->lpcount;
852    target->stat->nlps = source->stat->nlps;
853    target->stat->nrootlps = source->stat->nrootlps;
854    target->stat->nprimallps = source->stat->nprimallps;
855    target->stat->nprimalzeroitlps = source->stat->nprimalzeroitlps;
856    target->stat->nduallps = source->stat->nduallps;
857    target->stat->ndualzeroitlps = source->stat->ndualzeroitlps;
858    target->stat->nlexduallps = source->stat->nlexduallps;
859    target->stat->nbarrierlps = source->stat->nbarrierlps;
860    target->stat->nbarrierzeroitlps = source->stat->nbarrierzeroitlps;
861    target->stat->nprimalresolvelps = source->stat->nprimalresolvelps;
862    target->stat->ndualresolvelps = source->stat->ndualresolvelps;
863    target->stat->nlexdualresolvelps = source->stat->nlexdualresolvelps;
864    target->stat->nnodelps = source->stat->nnodelps;
865    target->stat->ninitlps = source->stat->ninitlps;
866    target->stat->ndivinglps = source->stat->ndivinglps;
867    target->stat->ndivesetlps = source->stat->ndivesetlps;
868    target->stat->nsbdivinglps = source->stat->nsbdivinglps;
869    target->stat->nstrongbranchs = source->stat->nstrongbranchs;
870    target->stat->nrootstrongbranchs = source->stat->nrootstrongbranchs;
871    target->stat->nconflictlps = source->stat->nconflictlps;
872    target->stat->nnlps = source->stat->nnlps;
873    target->stat->nisstoppedcalls = source->stat->nisstoppedcalls;
874    target->stat->totaldivesetdepth = source->stat->totaldivesetdepth;
875    target->stat->ndivesetcalls = source->stat->ndivesetcalls;
876    target->stat->nruns = source->stat->nruns;
877    target->stat->nconfrestarts = source->stat->nconfrestarts;
878    target->stat->nrootboundchgs = source->stat->nrootboundchgs;
879    target->stat->nrootboundchgsrun = source->stat->nrootboundchgsrun;
880    target->stat->nrootintfixings = source->stat->nrootintfixings;
881    target->stat->nrootintfixingsrun = source->stat->nrootintfixingsrun;
882    target->stat->prevrunnvars = source->stat->prevrunnvars;
883    target->stat->npricerounds = source->stat->npricerounds;
884    target->stat->nseparounds = source->stat->nseparounds;
885    target->stat->maxdepth = source->stat->maxdepth;
886    target->stat->maxtotaldepth = source->stat->maxtotaldepth;
887    target->stat->plungedepth = source->stat->plungedepth;
888    target->stat->npresolrounds += source->stat->npresolrounds;
889    target->stat->npresolroundsfast += source->stat->npresolroundsfast;
890    target->stat->npresolroundsmed += source->stat->npresolroundsmed;
891    target->stat->npresolroundsext += source->stat->npresolroundsext;
892    target->stat->npresolfixedvars += source->stat->npresolfixedvars;
893    target->stat->npresolaggrvars += source->stat->npresolaggrvars;
894    target->stat->npresolchgvartypes += source->stat->npresolchgvartypes;
895    target->stat->npresolchgbds += source->stat->npresolchgbds;
896    target->stat->npresoladdholes += source->stat->npresoladdholes;
897    target->stat->npresoldelconss += source->stat->npresoldelconss;
898    target->stat->npresoladdconss += source->stat->npresoladdconss;
899    target->stat->npresolupgdconss += source->stat->npresolupgdconss;
900    target->stat->npresolchgcoefs += source->stat->npresolchgcoefs;
901    target->stat->npresolchgsides += source->stat->npresolchgsides;
902    target->stat->nrunsbeforefirst = source->stat->nrunsbeforefirst;
903    target->stat->firstprimaldepth = source->stat->firstprimaldepth;
904    target->stat->ncopies += source->stat->ncopies;
905    target->stat->nreoptruns = source->stat->nreoptruns;
906 
907    /* set the stage but do not set to earlier stage */
908    target->set->stage = MAX(source->set->stage, target->set->stage);
909 
910    return SCIP_OKAY;
911 }
912