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