source: stable/2.8/Cbc/src/CbcThread.cpp @ 2077

Last change on this file since 2077 was 2077, checked in by forrest, 4 years ago

make derived message handlers threadsafe

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.2 KB
Line 
1/* $Id: CbcThread.cpp 2077 2014-09-22 17:15:17Z forrest $ */
2// Copyright (C) 2002, International Business Machines
3// Corporation and others.  All Rights Reserved.
4// This code is licensed under the terms of the Eclipse Public License (EPL).
5
6#if defined(_MSC_VER)
7// Turn off compiler warning about long names
8#  pragma warning(disable:4786)
9#endif
10
11#include "CbcConfig.h"
12
13//#define THREAD_DEBUG
14#include <string>
15#include <cassert>
16#include <cmath>
17#include <cfloat>
18
19#include "CbcEventHandler.hpp"
20
21#include "OsiSolverInterface.hpp"
22#include "OsiRowCutDebugger.hpp"
23#include "CbcThread.hpp"
24#include "CbcTree.hpp"
25#include "CbcHeuristic.hpp"
26#include "CbcCutGenerator.hpp"
27#include "CbcModel.hpp"
28#include "CbcFathom.hpp"
29#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
30#include "ClpDualRowDantzig.hpp"
31#include "OsiAuxInfo.hpp"
32
33#include "CoinTime.hpp"
34#ifdef CBC_THREAD
35/// Thread functions
36static void * doNodesThread(void * voidInfo);
37static void * doCutsThread(void * voidInfo);
38static void * doHeurThread(void * voidInfo);
39// Default Constructor
40CbcSpecificThread::CbcSpecificThread ()
41        : basePointer_(NULL),
42        masterMutex_(NULL),
43        locked_(false)
44{
45#ifdef CBC_PTHREAD
46    pthread_mutex_init(&mutex2_, NULL);
47    pthread_cond_init(&condition2_, NULL);
48    threadId_.status = 0;
49#else
50#endif
51}
52// Useful Constructor
53CbcSpecificThread::CbcSpecificThread (CbcSpecificThread * master, pthread_mutex_t * masterMutex)
54        : basePointer_(master),
55        masterMutex_(masterMutex),
56        locked_(false)
57
58{
59#ifdef CBC_PTHREAD
60    pthread_mutex_init(&mutex2_, NULL);
61    pthread_cond_init(&condition2_, NULL);
62    threadId_.status = 0;
63#else
64#endif
65
66}
67// Useful stuff
68void
69CbcSpecificThread::setUsefulStuff (CbcSpecificThread * master, void *& masterMutex)
70
71{
72#ifdef CBC_PTHREAD
73    basePointer_ = master;
74    if (masterMutex) {
75        masterMutex_ = reinterpret_cast<pthread_mutex_t *>(masterMutex);
76    } else {
77        // create master mutex
78        masterMutex_ = new pthread_mutex_t;
79        pthread_mutex_init(masterMutex_, NULL);
80        masterMutex = reinterpret_cast<void *>(masterMutex_);
81    }
82#else
83#endif
84}
85
86CbcSpecificThread::~CbcSpecificThread()
87{
88#ifdef CBC_PTHREAD
89    pthread_mutex_destroy (&mutex2_);
90    if (basePointer_ == this) {
91        pthread_mutex_destroy (masterMutex_);
92        delete masterMutex_;
93    }
94#else
95#endif
96}
97/*
98  Locks a thread if parallel so that stuff like cut pool
99  can be updated and/or used.
100*/
101void
102CbcSpecificThread::lockThread()
103{
104#ifdef CBC_PTHREAD
105    // Use master mutex
106    assert (basePointer_->masterMutex_ == masterMutex_);
107    pthread_mutex_lock (masterMutex_);
108#else
109#endif
110}
111/*
112  Unlocks a thread if parallel to say cut pool stuff not needed
113*/
114void
115CbcSpecificThread::unlockThread()
116{
117#ifdef CBC_PTHREAD
118    // Use master mutex
119    pthread_mutex_unlock (masterMutex_);
120#else
121#endif
122}
123//  Locks a thread for testing whether to start etc
124void
125CbcSpecificThread::lockThread2(bool doAnyway)
126{
127    if (!locked_ || doAnyway) {
128#ifdef CBC_PTHREAD
129        pthread_mutex_lock (&mutex2_);
130#else
131#endif
132        locked_ = true;
133    }
134}
135//  Unlocks a thread for testing whether to start etc
136void
137CbcSpecificThread::unlockThread2(bool doAnyway)
138{
139    if (locked_ || doAnyway) {
140#ifdef CBC_PTHREAD
141        pthread_mutex_unlock (&mutex2_);
142#else
143#endif
144        locked_ = false;
145    }
146}
147#ifdef HAVE_CLOCK_GETTIME
148inline int my_gettime(struct timespec* tp)
149{
150    return clock_gettime(CLOCK_REALTIME, tp);
151}
152#else
153#ifndef _MSC_VER
154inline int my_gettime(struct timespec* tp)
155{
156    struct timeval tv;
157    int ret = gettimeofday(&tv, NULL);
158    tp->tv_sec = tv.tv_sec;
159    tp->tv_nsec = tv.tv_usec * 1000;
160    return ret;
161}
162#else
163inline int my_gettime(struct timespec* tp)
164{
165    double t = CoinGetTimeOfDay();
166    tp->tv_sec = (int)floor(t);
167    tp->tv_nsec = (int)((tp->tv_sec - floor(t)) / 1000000.0);
168    return 0;
169}
170#endif
171#endif
172// Get time
173static double getTime()
174{
175    struct timespec absTime2;
176    my_gettime(&absTime2);
177    double time2 = (double)absTime2.tv_sec + 1.0e-9 * (double)absTime2.tv_nsec;
178    return time2;
179}
180// Timed wait in nanoseconds - if negative then seconds
181void
182CbcSpecificThread::timedWait(int time)
183{
184
185#ifdef CBC_PTHREAD
186    struct timespec absTime;
187    my_gettime(&absTime);
188    if (time > 0) {
189        absTime.tv_nsec += time;
190        if (absTime.tv_nsec >= 1000000000) {
191            absTime.tv_nsec -= 1000000000;
192            absTime.tv_sec++;
193        }
194    } else {
195        absTime.tv_sec -= time;
196    }
197    pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
198#else
199#endif
200}
201// Signal
202void
203CbcSpecificThread::signal()
204{
205#ifdef CBC_PTHREAD
206    pthread_cond_signal(&condition2_);
207#else
208#endif
209}
210// Actually starts a thread
211void
212CbcSpecificThread::startThread(void * (*routine ) (void *), CbcThread * thread)
213{
214#ifdef CBC_PTHREAD
215    pthread_create(&(threadId_.thr), NULL, routine, thread);
216    threadId_.status = 1;
217#else
218#endif
219}
220// Exits thread (from master)
221int
222CbcSpecificThread::exit()
223{
224#ifdef CBC_PTHREAD
225    pthread_cond_signal(&condition2_); // unlock
226    return pthread_join(threadId_.thr, NULL);
227#else
228#endif
229}
230// Exits thread
231void
232CbcSpecificThread::exitThread()
233{
234#ifdef CBC_PTHREAD
235    pthread_mutex_unlock(&mutex2_);
236    pthread_exit(NULL);
237#else
238#endif
239
240}
241// Get status
242int
243CbcSpecificThread::status() const
244{
245#ifdef CBC_PTHREAD
246    return static_cast<int>(threadId_.status);
247#else
248#endif
249}
250// Set status
251void
252CbcSpecificThread::setStatus(int value)
253{
254#ifdef CBC_PTHREAD
255    threadId_.status = value;
256#else
257#endif
258}
259// Parallel heuristics
260void
261parallelHeuristics (int numberThreads,
262                    int sizeOfData,
263                    void * argBundle)
264{
265    Coin_pthread_t * threadId = new Coin_pthread_t [numberThreads];
266    char * args = reinterpret_cast<char *>(argBundle);
267    for (int i = 0; i < numberThreads; i++) {
268        pthread_create(&(threadId[i].thr), NULL, doHeurThread,
269                       args + i*sizeOfData);
270    }
271    // now wait
272    for (int i = 0; i < numberThreads; i++) {
273        pthread_join(threadId[i].thr, NULL);
274    }
275    delete [] threadId;
276}
277// End of specific thread stuff
278
279/// Default constructor
280CbcThread::CbcThread()
281        :
282        baseModel_(NULL),
283        thisModel_(NULL),
284        node_(NULL), // filled in every time
285        createdNode_(NULL), // filled in every time on return
286        returnCode_(-1), // -1 available, 0 busy, 1 finished , 2??
287        timeLocked_(0.0),
288        timeWaitingToLock_(0.0),
289        timeWaitingToStart_(0.0),
290        timeInThread_(0.0),
291        numberTimesLocked_(0),
292        numberTimesUnlocked_(0),
293        numberTimesWaitingToStart_(0),
294        dantzigState_(0), // 0 unset, -1 waiting to be set, 1 set
295        locked_(false),
296        nDeleteNode_(0),
297        delNode_(NULL),
298        maxDeleteNode_(0),
299        nodesThisTime_(0),
300        iterationsThisTime_(0),
301        deterministic_(0)
302{
303}
304void
305CbcThread::gutsOfDelete()
306{
307    baseModel_ = NULL;
308    thisModel_ = NULL;
309    node_ = NULL;
310    createdNode_ = NULL;
311    delNode_ = NULL;
312}
313// Destructor
314CbcThread::~CbcThread()
315{
316}
317// Fills in useful stuff
318void
319CbcThread::setUsefulStuff (CbcModel * model, int deterministic, CbcModel * baseModel,
320                           CbcThread * master,
321                           void *& masterMutex)
322{
323    baseModel_ = baseModel;
324    thisModel_ = model;
325    deterministic_ = deterministic;
326    threadStuff_.setUsefulStuff(&master->threadStuff_, masterMutex);
327    node_ = NULL;
328    createdNode_ = NULL;
329    master_ = master;
330    returnCode_ = -1;
331    timeLocked_ = 0.0;
332    timeWaitingToLock_ = 0.0;
333    timeWaitingToStart_ = 0.0;
334    timeInThread_ = 0.0;
335    numberTimesLocked_ = 0;
336    numberTimesUnlocked_ = 0;
337    numberTimesWaitingToStart_ = 0;
338    dantzigState_ = 0; // 0 unset, -1 waiting to be set, 1 set
339    locked_ = false;
340    delNode_ = NULL;
341    maxDeleteNode_ = 0;
342    nDeleteNode_ = 0;
343    nodesThisTime_ = 0;
344    iterationsThisTime_ = 0;
345    if (model != baseModel) {
346        // thread
347        thisModel_->setInfoInChild(-3, this);
348        if (deterministic_ >= 0)
349            thisModel_->moveToModel(baseModel, -1);
350        if (deterministic == -1)
351            threadStuff_.startThread( doCutsThread, this);
352        else
353            threadStuff_.startThread( doNodesThread, this);
354    }
355}
356/*
357  Locks a thread if parallel so that stuff like cut pool
358  can be updated and/or used.
359*/
360void
361CbcThread::lockThread()
362{
363    if (!locked_) {
364        double time2 = getTime();
365        threadStuff_.lockThread();
366        locked_ = true;
367        timeWhenLocked_ = getTime();
368        timeWaitingToLock_ += timeWhenLocked_ - time2;;
369        numberTimesLocked_++;
370#ifdef THREAD_DEBUG
371        lockCount_ ++;
372#if THREAD_DEBUG>1
373        if (threadNumber_ == -1)
374            printf("locking master %d\n", lockCount_);
375        else
376            printf("locking thread %d %d\n", threadNumber_, lockCount_);
377#endif
378    } else {
379        if (threadNumber_ == -1)
380            printf("master already locked %d\n", lockCount_);
381        else
382            printf("thread already locked %d %d\n", threadNumber_, lockCount_);
383#endif
384    }
385}
386/*
387  Unlocks a thread if parallel
388*/
389void
390CbcThread::unlockThread()
391{
392    if (locked_) {
393        locked_ = false;
394        threadStuff_.unlockThread();
395        double time2 = getTime();
396        timeLocked_ += time2 - timeWhenLocked_;
397        numberTimesUnlocked_++;
398#ifdef THREAD_DEBUG
399#if THREAD_DEBUG>1
400        if (threadNumber_ == -1)
401            printf("unlocking master %d\n", lockCount_);
402        else
403            printf("unlocking thread %d %d\n", threadNumber_, lockCount_);
404#endif
405    } else {
406        if (threadNumber_ == -1)
407            printf("master already unlocked %d\n", lockCount_);
408        else
409            printf("thread already unlocked %d %d\n", threadNumber_, lockCount_);
410#endif
411    }
412}
413/* Wait for child to have return code NOT == to currentCode
414   type - 0 timed wait
415   1 wait
416   returns true if return code changed */
417bool
418CbcThread::wait(int type, int currentCode)
419{
420    if (!type) {
421        // just timed wait
422        master_->threadStuff_.lockThread2();
423        master_->threadStuff_.timedWait(1000000);
424        master_->threadStuff_.unlockThread2();
425    } else {
426        // wait until return code changes
427        while (returnCode_ == currentCode) {
428            threadStuff_.signal();
429            master_->threadStuff_.lockThread2();
430            master_->threadStuff_.timedWait(1000000);
431            master_->threadStuff_.unlockThread2();
432        }
433    }
434    return (returnCode_ != currentCode);
435}
436#if 0
437pthread_cond_signal(&condition2_);
438-
439if (!locked_)
440{
441    pthread_mutex_lock (&mutex2_);
442    locked_ = true;
443}
444-
445pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
446-
447if (locked_)
448{
449    pthread_mutex_unlock (&mutex2_);
450    locked_ = false;
451}
452#endif
453// Waits until returnCode_ goes to zero
454void
455CbcThread::waitThread()
456{
457    double time = getTime();
458    threadStuff_.lockThread2();
459    while (returnCode_) {
460        threadStuff_.timedWait(-10); // 10 seconds
461    }
462    timeWaitingToStart_ += getTime() - time;
463    numberTimesWaitingToStart_++;
464}
465// Just wait for so many nanoseconds
466void
467CbcThread::waitNano(int time)
468{
469    threadStuff_.lockThread2();
470    threadStuff_.timedWait(time);
471    threadStuff_.unlockThread2();
472}
473// Signal child to carry on
474void
475CbcThread::signal()
476{
477    threadStuff_.signal();
478}
479// Lock from master with mutex2 and signal before lock
480void
481CbcThread::lockFromMaster()
482{
483    threadStuff_.signal();
484    master_->threadStuff_.lockThread2(true);
485}
486// Unlock from master with mutex2 and signal after unlock
487void
488CbcThread::unlockFromMaster()
489{
490    master_->threadStuff_.unlockThread2(true); // unlock anyway
491    threadStuff_.signal();
492}
493// Lock from thread with mutex2 and signal before lock
494void
495CbcThread::lockFromThread()
496{
497    master_->threadStuff_.signal();
498    threadStuff_.lockThread2();
499}
500// Unlock from thread with mutex2 and signal after unlock
501void
502CbcThread::unlockFromThread()
503{
504    master_->threadStuff_.signal();
505    threadStuff_.unlockThread2();
506}
507// Exits thread (from master)
508int
509CbcThread::exit()
510{
511    return threadStuff_.exit();
512}
513// Exits thread
514void
515CbcThread::exitThread()
516{
517    threadStuff_.exitThread();
518}
519// Default constructor
520CbcBaseModel::CbcBaseModel()
521        :
522        numberThreads_(0),
523        children_(NULL),
524        type_(0),
525        threadCount_(NULL),
526        threadModel_(NULL),
527        numberObjects_(0),
528        saveObjects_(NULL),
529        defaultParallelIterations_(400),
530        defaultParallelNodes_(2)
531{
532}
533// Constructor with model
534CbcBaseModel::CbcBaseModel (CbcModel & model,  int type)
535        :
536        children_(NULL),
537        type_(type),
538        threadCount_(NULL),
539        threadModel_(NULL),
540        numberObjects_(0),
541        saveObjects_(NULL),
542        defaultParallelIterations_(400),
543        defaultParallelNodes_(2)
544{
545    numberThreads_ = model.getNumberThreads();
546    if (numberThreads_) {
547        children_ = new CbcThread [numberThreads_+1];
548        // Do a partial one for base model
549        void * mutex_main = NULL;
550        children_[numberThreads_].setUsefulStuff(&model, type_, &model,
551                children_ + numberThreads_, mutex_main);
552#ifdef THREAD_DEBUG
553        children_[numberThreads_].threadNumber_ = -1;
554        children_[numberThreads_].lockCount_ = 0;
555#endif
556        threadCount_ = new int [numberThreads_];
557        CoinZeroN(threadCount_, numberThreads_);
558        threadModel_ = new CbcModel * [numberThreads_+1];
559        memset(threadStats_, 0, sizeof(threadStats_));
560        if (type_ > 0) {
561            // May need for deterministic
562            numberObjects_ = model.numberObjects();
563            saveObjects_ = new OsiObject * [numberObjects_];
564            for (int i = 0; i < numberObjects_; i++) {
565                saveObjects_[i] = model.object(i)->clone();
566            }
567        }
568        // we don't want a strategy object
569        CbcStrategy * saveStrategy = model.strategy();
570        model.setStrategy(NULL);
571        for (int i = 0; i < numberThreads_; i++) {
572            //threadModel_[i] = new CbcModel(model, true);
573            threadModel_[i] = model. clone (true);
574            threadModel_[i]->synchronizeHandlers(1);
575#ifdef COIN_HAS_CLP
576            // Solver may need to know about model
577            CbcModel * thisModel = threadModel_[i];
578            CbcOsiSolver * solver =
579                dynamic_cast<CbcOsiSolver *>(thisModel->solver()) ;
580            if (solver)
581                solver->setCbcModel(thisModel);
582#endif
583            children_[i].setUsefulStuff(threadModel_[i], type_, &model,
584                                        children_ + numberThreads_, mutex_main);
585#ifdef THREAD_DEBUG
586            children_[i].threadNumber_ = i;
587            children_[i].lockCount_ = 0;
588#endif
589        }
590        model.setStrategy(saveStrategy);
591    }
592}
593// Stop threads
594void
595CbcBaseModel::stopThreads(int type)
596{
597    if (type < 0) {
598        // max nodes ?
599        bool finished = false;
600        while (!finished) {
601          finished = true;
602          for (int i = 0; i < numberThreads_; i++) {
603            if (abs(children_[i].returnCode()) != 1) {
604              children_[i].wait(1, 0); 
605              finished=false;
606            }
607          }
608        }
609        return;
610    }
611    for (int i = 0; i < numberThreads_; i++) {
612        children_[i].wait(1, 0);
613        assert (children_[i].returnCode() == -1);
614        threadModel_[i]->setInfoInChild(-2, NULL);
615        children_[i].setReturnCode( 0);
616        children_[i].exit();
617        children_[i].setStatus( 0);
618    }
619    // delete models and solvers
620    for (int i = 0; i < numberThreads_; i++) {
621        threadModel_[i]->setInfoInChild(type_, NULL);
622        delete threadModel_[i];
623    }
624    delete [] children_;
625    delete [] threadModel_;
626    for (int i = 0; i < numberObjects_; i++)
627        delete saveObjects_[i];
628    delete [] saveObjects_;
629    children_ = NULL;
630    threadModel_ = NULL;
631    saveObjects_ = NULL;
632    numberObjects_ = 0;
633    numberThreads_ = 0;
634}
635// Wait for threads in tree
636int
637CbcBaseModel::waitForThreadsInTree(int type)
638{
639    CbcModel * baseModel = children_[0].baseModel();
640    int anyLeft = 0;
641    // May be able to combine parts later
642
643    if (type == 0) {
644        bool locked = true;
645#ifdef COIN_DEVELOP
646        printf("empty\n");
647#endif
648        // may still be outstanding nodes
649        while (true) {
650            int iThread;
651            for (iThread = 0; iThread < numberThreads_; iThread++) {
652                if (children_[iThread].status()) {
653                    if (children_[iThread].returnCode() == 0)
654                        break;
655                }
656            }
657            if (iThread < numberThreads_) {
658#ifdef COIN_DEVELOP
659                printf("waiting for thread %d code 0\n", iThread);
660#endif
661                unlockThread();
662                locked = false;
663                children_[iThread].wait(1, 0);
664                assert(children_[iThread].returnCode() == 1);
665                threadModel_[iThread]->moveToModel(baseModel, 1);
666#ifdef THREAD_PRINT
667                printf("off thread2 %d node %x\n", iThread, children_[iThread].node());
668#endif
669                children_[iThread].setNode(NULL);
670                anyLeft = 1;
671                assert (children_[iThread].returnCode() == 1);
672                if (children_[iThread].dantzigState() == -1) {
673                    // 0 unset, -1 waiting to be set, 1 set
674                    children_[iThread].setDantzigState(1);
675                    CbcModel * model = children_[iThread].thisModel();
676                    OsiClpSolverInterface * clpSolver2
677                    = dynamic_cast<OsiClpSolverInterface *> (model->solver());
678                    assert (clpSolver2);
679                    ClpSimplex * simplex2 = clpSolver2->getModelPtr();
680                    ClpDualRowDantzig dantzig;
681                    simplex2->setDualRowPivotAlgorithm(dantzig);
682                }
683                // say available
684                children_[iThread].setReturnCode( -1);
685                threadStats_[4]++;
686#ifdef COIN_DEVELOP
687                printf("thread %d code now -1\n", iThread);
688#endif
689                break;
690            } else {
691#ifdef COIN_DEVELOP
692                printf("no threads at code 0 \n");
693#endif
694                // now check if any have just finished
695                for (iThread = 0; iThread < numberThreads_; iThread++) {
696                    if (children_[iThread].status()) {
697                        if (children_[iThread].returnCode() == 1)
698                            break;
699                    }
700                }
701                if (iThread < numberThreads_) {
702                    unlockThread();
703                    locked = false;
704                    threadModel_[iThread]->moveToModel(baseModel, 1);
705#ifdef THREAD_PRINT
706                    printf("off thread3 %d node %x\n", iThread, children_[iThread].node());
707#endif
708                    children_[iThread].setNode(NULL);
709                    anyLeft = 1;
710                    assert (children_[iThread].returnCode() == 1);
711                    // say available
712                    children_[iThread].setReturnCode( -1);
713                    threadStats_[4]++;
714#ifdef COIN_DEVELOP
715                    printf("thread %d code now -1\n", iThread);
716#endif
717                    break;
718                }
719            }
720            if (!baseModel->tree()->empty()) {
721#ifdef COIN_DEVELOP
722                printf("tree not empty!!!!!!\n");
723#endif
724                if (locked)
725                    unlockThread();
726                return 1;
727                break;
728            }
729            for (iThread = 0; iThread < numberThreads_; iThread++) {
730                if (children_[iThread].status()) {
731                    if (children_[iThread].returnCode() != -1) {
732                        printf("bad end of tree\n");
733                        abort();
734                    }
735                }
736            }
737            break;
738        }
739#ifdef COIN_DEVELOP
740        printf("finished ************\n");
741#endif
742        if (locked)
743            unlockThread();
744        return anyLeft;
745    } else if (type == 1) {
746        // normal
747        double cutoff = baseModel->getCutoff();
748        CbcNode * node = baseModel->tree()->bestNode(cutoff) ;
749        // Possible one on tree worse than cutoff
750        if (!node || node->objectiveValue() > cutoff)
751            return 1;
752        threadStats_[0]++;
753        //need to think
754        int iThread;
755        // Start one off if any available
756        for (iThread = 0; iThread < numberThreads_; iThread++) {
757            if (children_[iThread].returnCode() == -1)
758                break;
759        }
760        if (iThread < numberThreads_) {
761            children_[iThread].setNode(node);
762#ifdef THREAD_PRINT
763            printf("empty thread %d node %x\n", iThread, children_[iThread].node());
764#endif
765            assert (children_[iThread].returnCode() == -1);
766            // say in use
767            threadModel_[iThread]->moveToModel(baseModel, 0);
768            // This has to be AFTER moveToModel
769            children_[iThread].setReturnCode( 0);
770            children_[iThread].signal();
771            threadCount_[iThread]++;
772        }
773        lockThread();
774        // see if any finished
775        for (iThread = 0; iThread < numberThreads_; iThread++) {
776            if (children_[iThread].returnCode() > 0)
777                break;
778        }
779        unlockThread();
780        if (iThread < numberThreads_) {
781            threadModel_[iThread]->moveToModel(baseModel, 1);
782#ifdef THREAD_PRINT
783            printf("off thread4 %d node %x\n", iThread, children_[iThread].node());
784#endif
785            children_[iThread].setNode(NULL);
786            anyLeft = 1;
787            assert (children_[iThread].returnCode() == 1);
788            // say available
789            children_[iThread].setReturnCode( -1);
790            // carry on
791            threadStats_[3]++;
792        } else {
793            // Start one off if any available
794            for (iThread = 0; iThread < numberThreads_; iThread++) {
795                if (children_[iThread].returnCode() == -1)
796                    break;
797            }
798            if (iThread < numberThreads_) {
799                // If any on tree get
800                if (!baseModel->tree()->empty()) {
801                    //node = baseModel->tree()->bestNode(cutoff) ;
802                    //assert (node);
803                    threadStats_[1]++;
804                    return 1; // ** get another node
805                }
806            }
807            // wait (for debug could sleep and use test)
808            bool finished = false;
809            while (!finished) {
810                double time = getTime();
811                children_[numberThreads_].wait(0, 0);
812                children_[numberThreads_].incrementTimeInThread(getTime() - time);
813                for (iThread = 0; iThread < numberThreads_; iThread++) {
814                    if (children_[iThread].returnCode() > 0) {
815                        finished = true;
816                        break;
817                    } else if (children_[iThread].returnCode() == 0) {
818                        children_[iThread].signal(); // unlock
819                    }
820                }
821            }
822            assert (iThread < numberThreads_);
823            // move information to model
824            threadModel_[iThread]->moveToModel(baseModel, 1);
825            anyLeft = 1;
826#ifdef THREAD_PRINT
827            printf("off thread %d node %x\n", iThread, children_[iThread].node());
828#endif
829            children_[iThread].setNode(NULL);
830            assert (children_[iThread].returnCode() == 1);
831            // say available
832            children_[iThread].setReturnCode( -1);
833        }
834        // carry on
835        threadStats_[2]++;
836        for (int iThread = 0; iThread < numberThreads_; iThread++) {
837            if (children_[iThread].status()) {
838                if (children_[iThread].returnCode() != -1) {
839                    anyLeft = 1;
840                    break;
841                }
842            }
843        }
844        return anyLeft;
845    } else if (type == 2) {
846        if (!baseModel->tree()->empty()) {
847          // max nodes ?
848          bool finished = false;
849          while (!finished) {
850            finished = true;
851            for (int iThread = 0; iThread < numberThreads_; iThread++) {
852              if (children_[iThread].returnCode() == 0) { 
853                double time = getTime();
854                children_[numberThreads_].wait(0, 0);
855                children_[numberThreads_].incrementTimeInThread(getTime() - time);
856                finished = false;
857                children_[iThread].signal(); // unlock
858              }
859            }
860          }
861        }
862        int i;
863        // do statistics
864        // Seems to be bug in CoinCpu on Linux - does threads as well despite documentation
865        double time = 0.0;
866        for (i = 0; i < numberThreads_; i++)
867            time += children_[i].timeInThread();
868        bool goodTimer = time < (baseModel->getCurrentSeconds());
869        for (i = 0; i < numberThreads_; i++) {
870            while (children_[i].returnCode() == 0) {
871                children_[i].signal();
872                double time = getTime();
873                children_[numberThreads_].wait(0, 0);
874                children_[numberThreads_].incrementTimeInThread(getTime() - time);
875            }
876            children_[i].lockFromMaster();
877            threadModel_[i]->setNumberThreads(0); // say exit
878            if (children_[i].deterministic() > 0)
879                delete [] children_[i].delNode();
880            children_[i].setReturnCode( 0);
881            children_[i].unlockFromMaster();
882#ifndef NDEBUG
883            int returnCode = children_[i].exit();
884            assert (!returnCode);
885#else
886            children_[i].exit();
887#endif
888            children_[i].setStatus( 0);
889            //else
890            threadModel_[i]->moveToModel(baseModel, 2);
891            assert (children_[i].numberTimesLocked() == children_[i].numberTimesUnlocked());
892            baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
893            << "Thread";
894            baseModel->messageHandler()->printing(true)
895            << i << threadCount_[i] << children_[i].timeWaitingToStart();
896            baseModel->messageHandler()->printing(goodTimer) << children_[i].timeInThread();
897            baseModel->messageHandler()->printing(false) << 0.0;
898            baseModel->messageHandler()->printing(true) << children_[i].numberTimesLocked()
899            << children_[i].timeLocked() << children_[i].timeWaitingToLock()
900            << CoinMessageEol;
901        }
902        assert (children_[numberThreads_].numberTimesLocked() == children_[numberThreads_].numberTimesUnlocked());
903        baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
904        << "Main thread";
905        baseModel->messageHandler()->printing(false) << 0 << 0 << 0.0;
906        baseModel->messageHandler()->printing(false) << 0.0;
907        baseModel->messageHandler()->printing(true) << children_[numberThreads_].timeInThread();
908        baseModel->messageHandler()->printing(true) << children_[numberThreads_].numberTimesLocked()
909        << children_[numberThreads_].timeLocked() << children_[numberThreads_].timeWaitingToLock()
910        << CoinMessageEol;
911        // delete models (here in case some point to others)
912        for (i = 0; i < numberThreads_; i++) {
913            // make sure handler will be deleted
914            threadModel_[i]->setDefaultHandler(true);
915            //delete threadModel_[i];
916        }
917    } else {
918        abort();
919    }
920    return 0;
921}
922void
923CbcBaseModel::waitForThreadsInCuts(int type, OsiCuts * eachCuts,
924                                   int whichGenerator)
925{
926    if (type == 0) {
927        // cuts while doing
928        bool finished = false;
929        int iThread = -1;
930        // see if any available
931        for (iThread = 0; iThread < numberThreads_; iThread++) {
932            if (children_[iThread].returnCode()) {
933                finished = true;
934                break;
935            } else if (children_[iThread].returnCode() == 0) {
936                children_[iThread].signal();
937            }
938        }
939        while (!finished) {
940            children_[numberThreads_].waitNano(1000000);
941            for (iThread = 0; iThread < numberThreads_; iThread++) {
942                if (children_[iThread].returnCode() > 0) {
943                    finished = true;
944                    break;
945                } else if (children_[iThread].returnCode() == 0) {
946                    children_[iThread].signal();
947                }
948            }
949        }
950        assert (iThread < numberThreads_);
951        assert (children_[iThread].returnCode());
952        // Use dantzigState to signal which generator
953        children_[iThread].setDantzigState(whichGenerator);
954        // and delNode for eachCuts
955        children_[iThread].fakeDelNode(reinterpret_cast<CbcNode **> (eachCuts));
956        // allow to start
957        children_[iThread].setReturnCode( 0);
958        children_[iThread].signal();
959    } else if (type == 1) {
960        // cuts - finish up
961        for (int iThread = 0; iThread < numberThreads_; iThread++) {
962            if (children_[iThread].returnCode() == 0) {
963                bool finished = false;
964                while (!finished) {
965                    children_[numberThreads_].wait(0, 0);
966                    if (children_[iThread].returnCode() > 0) {
967                        finished = true;
968                        break;
969                        //#ifndef NEW_STYLE_PTHREAD
970                        //} else if (children_[iThread].returnCode_ == 0) {
971                        //pthread_cond_signal(&children_[iThread].threadStuff_.condition2_); // unlock
972                        //#endif
973                    }
974                }
975            }
976            assert (children_[iThread].returnCode());
977            // say available
978            children_[iThread].setReturnCode( -1);
979            //delete threadModel_[iThread]->solver();
980            //threadModel_[iThread]->setSolver(NULL);
981        }
982    } else {
983        abort();
984    }
985}
986// Returns pointer to master thread
987CbcThread *
988CbcBaseModel::masterThread() const
989{
990    return children_ + numberThreads_;
991}
992
993// Split model and do work in deterministic parallel
994void
995CbcBaseModel::deterministicParallel()
996{
997    CbcModel * baseModel = children_[0].baseModel();
998    for (int i = 0; i < numberThreads_; i++)
999        threadCount_[i]++;
1000    int saveTreeSize = baseModel->tree()->size();
1001    // For now create threadModel - later modify splitModel
1002    CbcModel ** threadModel = new CbcModel * [numberThreads_];
1003    int iThread;
1004    for (iThread = 0; iThread < numberThreads_; iThread++)
1005        threadModel[iThread] = children_[iThread].thisModel();
1006
1007    int nAffected = baseModel->splitModel(numberThreads_, threadModel, defaultParallelNodes_);
1008    // do all until finished
1009    for (iThread = 0; iThread < numberThreads_; iThread++) {
1010        // obviously tune
1011        children_[iThread].setNDeleteNode(defaultParallelIterations_);
1012    }
1013    // Save current state
1014    int iObject;
1015    OsiObject ** object = baseModel->objects();
1016    for (iObject = 0; iObject < numberObjects_; iObject++) {
1017        saveObjects_[iObject]->updateBefore(object[iObject]);
1018    }
1019    //#define FAKE_PARALLEL
1020#ifndef FAKE_PARALLEL
1021    for (iThread = 0; iThread < numberThreads_; iThread++) {
1022        children_[iThread].setReturnCode( 0);
1023        children_[iThread].signal();
1024    }
1025    // wait
1026    bool finished = false;
1027    double time = getTime();
1028    while (!finished) {
1029        children_[numberThreads_].waitNano( 1000000); // millisecond
1030        finished = true;
1031        for (iThread = 0; iThread < numberThreads_; iThread++) {
1032            if (children_[iThread].returnCode() <= 0) {
1033                finished = false;
1034            }
1035        }
1036    }
1037    for (iThread = 0; iThread < numberThreads_; iThread++)
1038        children_[iThread].setReturnCode(-1);
1039#else
1040    // wait
1041    bool finished = false;
1042    double time = getTime();
1043    for (iThread = 0; iThread < numberThreads_; iThread++) {
1044        children_[iThread].setReturnCode( 0);
1045        children_[iThread].signal();
1046        while (!finished) {
1047          children_[numberThreads_].waitNano( 1000000); // millisecond
1048          finished = (children_[iThread].returnCode() >0);
1049        }
1050        children_[iThread].setReturnCode(-1);
1051        finished=false;
1052    }
1053#endif
1054    children_[numberThreads_].incrementTimeInThread(getTime() - time);
1055    // Unmark marked
1056    for (int i = 0; i < nAffected; i++) {
1057        baseModel->walkback()[i]->unmark();
1058    }
1059    int iModel;
1060    double scaleFactor = 1.0;
1061    for (iModel = 0; iModel < numberThreads_; iModel++) {
1062        //printf("model %d tree size %d\n",iModel,threadModel[iModel]->baseModel->tree()->size());
1063        if (saveTreeSize > 4*numberThreads_*defaultParallelNodes_) {
1064            if (!threadModel[iModel]->tree()->size()) {
1065                scaleFactor *= 1.05;
1066            }
1067        }
1068        threadModel[iModel]->moveToModel(baseModel, 11);
1069        // Update base model
1070        OsiObject ** threadObject = threadModel[iModel]->objects();
1071        for (iObject = 0; iObject < numberObjects_; iObject++) {
1072            object[iObject]->updateAfter(threadObject[iObject], saveObjects_[iObject]);
1073        }
1074    }
1075    if (scaleFactor != 1.0) {
1076        int newNumber = static_cast<int> (defaultParallelNodes_ * scaleFactor + 0.5001);
1077        if (newNumber*2 < defaultParallelIterations_) {
1078            if (defaultParallelNodes_ == 1)
1079                newNumber = 2;
1080            if (newNumber != defaultParallelNodes_) {
1081                char general[200];
1082                sprintf(general, "Changing tree size from %d to %d",
1083                        defaultParallelNodes_, newNumber);
1084                baseModel->messageHandler()->message(CBC_GENERAL,
1085                                                     baseModel->messages())
1086                << general << CoinMessageEol ;
1087                defaultParallelNodes_ = newNumber;
1088            }
1089        }
1090    }
1091    delete [] threadModel;
1092}
1093// Destructor
1094CbcBaseModel::~CbcBaseModel()
1095{
1096    delete [] threadCount_;
1097#if 1
1098    for (int i = 0; i < numberThreads_; i++)
1099        delete threadModel_[i];
1100    delete [] threadModel_;
1101    delete [] children_;
1102#endif
1103    for (int i = 0; i < numberObjects_; i++)
1104        delete saveObjects_[i];
1105    delete [] saveObjects_;
1106}
1107// Sets Dantzig state in children
1108void
1109CbcBaseModel::setDantzigState()
1110{
1111    for (int i = 0; i < numberThreads_; i++) {
1112        children_[i].setDantzigState(-1);
1113    }
1114}
1115static void * doNodesThread(void * voidInfo)
1116{
1117    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
1118    CbcModel * thisModel = stuff->thisModel();
1119    CbcModel * baseModel = stuff->baseModel();
1120    while (true) {
1121        stuff->waitThread();
1122        //printf("start node %x\n",stuff->node);
1123        int mode = thisModel->getNumberThreads();
1124        if (mode) {
1125            // normal
1126            double time2 = CoinCpuTime();
1127            assert (stuff->returnCode() == 0);
1128            if (thisModel->parallelMode() >= 0) {
1129                CbcNode * node = stuff->node();
1130                //assert (node->nodeInfo());
1131                CbcNode * createdNode = stuff->createdNode();
1132                // try and see if this has slipped through
1133                if (node) {
1134                  thisModel->doOneNode(baseModel, node, createdNode);
1135                } else {
1136                  //printf("null node\n");
1137                  createdNode=NULL;
1138                }
1139                stuff->setNode(node);
1140                stuff->setCreatedNode(createdNode);
1141                stuff->setReturnCode( 1);
1142            } else {
1143                assert (!stuff->node());
1144                assert (!stuff->createdNode());
1145                int numberIterations = stuff->nDeleteNode();
1146                int nDeleteNode = 0;
1147                int maxDeleteNode = stuff->maxDeleteNode();
1148                CbcNode ** delNode = stuff->delNode();
1149                int returnCode = 1;
1150                // this should be updated by heuristics strong branching etc etc
1151                assert (numberIterations > 0);
1152                thisModel->setNumberThreads(0);
1153                int nodesThisTime = thisModel->getNodeCount();
1154                int iterationsThisTime = thisModel->getIterationCount();
1155                int strongThisTime = thisModel->numberStrongIterations();
1156                thisModel->setStopNumberIterations(thisModel->getIterationCount() + numberIterations);
1157                int numberColumns = thisModel->getNumCols();
1158                int * used = CoinCopyOfArray(thisModel->usedInSolution(), numberColumns);
1159                int numberSolutions = thisModel->getSolutionCount();
1160                while (true) {
1161                    if (thisModel->tree()->empty()) {
1162                        returnCode = 1 + 1;
1163#ifdef CLP_INVESTIGATE_2
1164                        printf("%x tree empty - time %18.6f\n", thisModel, CoinGetTimeOfDay() - 1.2348e9);
1165#endif
1166                        break;
1167                    }
1168#define NODE_ITERATIONS 2
1169                    int nodesNow = thisModel->getNodeCount();
1170                    int iterationsNow = thisModel->getIterationCount();
1171                    int strongNow = thisModel->numberStrongIterations();
1172                    bool exit1 = (NODE_ITERATIONS * ((nodesNow - nodesThisTime) +
1173                                                     ((strongNow - strongThisTime) >> 1)) +
1174                                  (iterationsNow - iterationsThisTime) > numberIterations);
1175                    //bool exit2 =(thisModel->getIterationCount()>thisModel->getStopNumberIterations()) ;
1176                    //assert (exit1==exit2);
1177                    if (exit1 && nodesNow - nodesThisTime >= 10) {
1178                        // out of loop
1179                        //printf("out of loop\n");
1180#ifdef CLP_INVESTIGATE3
1181                        printf("%x tree %d nodes left, done %d and %d its - time %18.6f\n", thisModel,
1182                               thisModel->tree()->size(), nodesNow - nodesThisTime,
1183                               iterationsNow - iterationsThisTime, CoinGetTimeOfDay() - 1.2348e9);
1184#endif
1185                        break;
1186                    }
1187                    double cutoff = thisModel->getCutoff() ;
1188                    CbcNode *node = thisModel->tree()->bestNode(cutoff) ;
1189                    // Possible one on tree worse than cutoff
1190                    if (!node)
1191                        continue;
1192                    CbcNode * createdNode = NULL;
1193                    // Do real work of node
1194                    thisModel->doOneNode(NULL, node, createdNode);
1195                    assert (createdNode);
1196                    if (!createdNode->active()) {
1197                        delete createdNode;
1198                    } else {
1199                        // Say one more pointing to this **** postpone if marked
1200                        node->nodeInfo()->increment() ;
1201                        thisModel->tree()->push(createdNode) ;
1202                    }
1203                    if (node->active()) {
1204                        assert (node->nodeInfo());
1205                        if (node->nodeInfo()->numberBranchesLeft()) {
1206                            thisModel->tree()->push(node) ;
1207                        } else {
1208                            node->setActive(false);
1209                        }
1210                    } else {
1211                        if (node->nodeInfo()) {
1212                            if (!node->nodeInfo()->numberBranchesLeft())
1213                                node->nodeInfo()->allBranchesGone(); // can clean up
1214                            // So will delete underlying stuff
1215                            node->setActive(true);
1216                        }
1217                        if (nDeleteNode == maxDeleteNode) {
1218                            maxDeleteNode = (3 * maxDeleteNode) / 2 + 10;
1219                            stuff->setMaxDeleteNode(maxDeleteNode);
1220                            stuff->setDelNode(new CbcNode * [maxDeleteNode]);
1221                            for (int i = 0; i < nDeleteNode; i++)
1222                                stuff->delNode()[i] = delNode[i];
1223                            delete [] delNode;
1224                            delNode = stuff->delNode();
1225                        }
1226                        delNode[nDeleteNode++] = node;
1227                    }
1228                }
1229                // end of this sub-tree
1230                int * usedA = thisModel->usedInSolution();
1231                for (int i = 0; i < numberColumns; i++) {
1232                    usedA[i] -= used[i];
1233                }
1234                delete [] used;
1235                thisModel->setSolutionCount(thisModel->getSolutionCount() - numberSolutions);
1236                stuff->setNodesThisTime(thisModel->getNodeCount() - nodesThisTime);
1237                stuff->setIterationsThisTime(thisModel->getIterationCount() - iterationsThisTime);
1238                stuff->setNDeleteNode(nDeleteNode);
1239                stuff->setReturnCode( returnCode);
1240                thisModel->setNumberThreads(mode);
1241            }
1242            //printf("end node %x\n",stuff->node);
1243            stuff->unlockFromThread();
1244            stuff->incrementTimeInThread(CoinCpuTime() - time2);
1245        } else {
1246            // exit
1247            break;
1248        }
1249    }
1250    //printf("THREAD exiting\n");
1251    stuff->exitThread();
1252    return NULL;
1253}
1254static void * doHeurThread(void * voidInfo)
1255{
1256    typedef struct {
1257        double solutionValue;
1258        CbcModel * model;
1259        double * solution;
1260        int foundSol;
1261    } argBundle;
1262    argBundle * stuff = reinterpret_cast<argBundle *> (voidInfo);
1263    stuff->foundSol =
1264        stuff->model->heuristic(0)->solution(stuff->solutionValue,
1265                                             stuff->solution);
1266    return NULL;
1267}
1268static void * doCutsThread(void * voidInfo)
1269{
1270    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
1271    CbcModel * thisModel =  stuff->thisModel();
1272    while (true) {
1273        stuff->waitThread();
1274        //printf("start node %x\n",stuff->node);
1275        int mode = thisModel->getNumberThreads();
1276        if (mode) {
1277            // normal
1278            assert (stuff->returnCode() == 0);
1279            int fullScan = thisModel->getNodeCount() == 0 ? 1 : 0; //? was >0
1280            CbcCutGenerator * generator = thisModel->cutGenerator(stuff->dantzigState());
1281            generator->refreshModel(thisModel);
1282            OsiCuts * cuts = reinterpret_cast<OsiCuts *> (stuff->delNode());
1283            OsiSolverInterface * thisSolver = thisModel->solver();
1284            generator->generateCuts(*cuts, fullScan, thisSolver, NULL);
1285            stuff->setReturnCode( 1);
1286            stuff->unlockFromThread();
1287        } else {
1288            // exit
1289            break;
1290        }
1291    }
1292    stuff->exitThread();
1293    return NULL;
1294}
1295// Split up nodes - returns number of CbcNodeInfo's affected
1296int
1297CbcModel::splitModel(int numberModels, CbcModel ** model,
1298                     int numberNodes)
1299{
1300    int iModel;
1301    int i;
1302    for (iModel = 0; iModel < numberModels; iModel++) {
1303        CbcModel * otherModel = model[iModel];
1304        otherModel->moveToModel(this, 10);
1305        assert (!otherModel->tree()->size());
1306        otherModel->tree()->resetNodeNumbers();
1307        otherModel->bestPossibleObjective_ = bestPossibleObjective_;
1308        otherModel->sumChangeObjective1_ = sumChangeObjective1_;
1309        otherModel->sumChangeObjective2_ = sumChangeObjective2_;
1310        int numberColumns = solver_->getNumCols();
1311        if (otherModel->bestSolution_) {
1312            assert (bestSolution_);
1313            memcpy(otherModel->bestSolution_, bestSolution_, numberColumns*sizeof(double));
1314        } else if (bestSolution_) {
1315            otherModel->bestSolution_ = CoinCopyOfArray(bestSolution_, numberColumns);
1316        }
1317        otherModel->globalCuts_ = globalCuts_;
1318        otherModel->numberSolutions_ = numberSolutions_;
1319        otherModel->numberHeuristicSolutions_ = numberHeuristicSolutions_;
1320        otherModel->numberNodes_ = 1; //numberNodes_;
1321        otherModel->numberIterations_ = numberIterations_;
1322#ifdef JJF_ZERO
1323        if (maximumNumberCuts_ > otherModel->maximumNumberCuts_) {
1324            otherModel->maximumNumberCuts_ = maximumNumberCuts_;
1325            delete [] otherModel->addedCuts_;
1326            otherModel->addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
1327        }
1328        if (maximumDepth_ > otherModel->maximumDepth_) {
1329            otherModel->maximumDepth_ = maximumDepth_;
1330            delete [] otherModel->walkback_;
1331            otherModel->walkback_ = new CbcNodeInfo * [maximumDepth_];
1332        }
1333#endif
1334        otherModel->currentNumberCuts_ = currentNumberCuts_;
1335        if (otherModel->usedInSolution_) {
1336            assert (usedInSolution_);
1337            memcpy(otherModel->usedInSolution_, usedInSolution_, numberColumns*sizeof(int));
1338        } else if (usedInSolution_) {
1339            otherModel->usedInSolution_ = CoinCopyOfArray(usedInSolution_, numberColumns);
1340        }
1341        /// ??? tree_;
1342        // Need flag (stopNumberIterations_>0?) which says don't update cut etc counts
1343        for (i = 0; i < numberObjects_; i++) {
1344            otherModel->object_[i]->updateBefore(object_[i]);
1345        }
1346        otherModel->maximumDepthActual_ = maximumDepthActual_;
1347        // Real cuts are in node info
1348        otherModel->numberOldActiveCuts_ = numberOldActiveCuts_;
1349        otherModel->numberNewCuts_ = numberNewCuts_;
1350        otherModel->numberStrongIterations_ = numberStrongIterations_;
1351    }
1352    double cutoff = getCutoff();
1353    int nAffected = 0;
1354    while (!tree_->empty()) {
1355        for (iModel = 0; iModel < numberModels; iModel++) {
1356            if (tree_->empty())
1357                break;
1358            CbcModel * otherModel = model[iModel];
1359            CbcNode * node = tree_->bestNode(cutoff) ;
1360            CbcNodeInfo * nodeInfo = node->nodeInfo();
1361            assert (nodeInfo);
1362            if (!nodeInfo->marked()) {
1363                //while (nodeInfo&&!nodeInfo->marked()) {
1364                if (nAffected == maximumDepth_) {
1365                    redoWalkBack();
1366                }
1367                nodeInfo->mark();
1368                //nodeInfo->incrementCuts(1000000);
1369                walkback_[nAffected++] = nodeInfo;
1370                //nodeInfo = nodeInfo->parent() ;
1371                //}
1372            }
1373            // Make node join otherModel
1374            OsiBranchingObject * bobj = node->modifiableBranchingObject();
1375            CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
1376            //assert (cbcobj);
1377            if (cbcobj) {
1378                CbcObject * object = cbcobj->object();
1379                assert (object);
1380                int position = object->position();
1381                assert (position >= 0);
1382                assert (object_[position] == object);
1383                CbcObject * objectNew =
1384                    dynamic_cast<CbcObject *> (otherModel->object_[position]);
1385                cbcobj->setOriginalObject(objectNew);
1386            }
1387            otherModel->tree_->push(node);
1388        }
1389        numberNodes--;
1390        if (!numberNodes)
1391            break;
1392    }
1393    return nAffected;
1394}
1395// Start threads
1396void
1397CbcModel::startSplitModel(int /*numberIterations*/)
1398{
1399    abort();
1400}
1401// Merge models
1402void
1403CbcModel::mergeModels(int /*numberModel*/, CbcModel ** /*model*/,
1404                      int /*numberNodes*/)
1405{
1406    abort();
1407}
1408/* Move/copy information from one model to another
1409   -1 - initial setup
1410   0 - from base model
1411   1 - to base model (and reset)
1412   2 - add in final statistics etc (and reset so can do clean destruction)
1413   10 - from base model (deterministic)
1414   11 - to base model (deterministic)
1415*/
1416void
1417CbcModel::moveToModel(CbcModel * baseModel, int mode)
1418{
1419    if (mode == 0) {
1420        setCutoff(baseModel->getCutoff());
1421        bestObjective_ = baseModel->bestObjective_;
1422        //assert (!baseModel->globalCuts_.sizeRowCuts());
1423        if (numberSolutions_ < baseModel->numberSolutions_) {
1424          assert (baseModel->bestSolution_);
1425          int numberColumns = solver_->getNumCols();
1426          if (!bestSolution_)
1427            bestSolution_ = new double [numberColumns];
1428          memcpy(bestSolution_,baseModel->bestSolution_,
1429                 numberColumns*sizeof(double));
1430          numberSolutions_ = baseModel->numberSolutions_;
1431        }
1432        stateOfSearch_ = baseModel->stateOfSearch_;
1433        numberNodes_ = baseModel->numberNodes_;
1434        numberIterations_ = baseModel->numberIterations_;
1435        numberFixedAtRoot_ = numberIterations_; // for statistics
1436        numberSolves_ = 0;
1437        phase_ = baseModel->phase_;
1438        assert (!nextRowCut_);
1439        nodeCompare_ = baseModel->nodeCompare_;
1440        tree_ = baseModel->tree_;
1441        assert (!subTreeModel_);
1442        //branchingMethod_ = NULL; // need something but what
1443        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
1444        cutModifier_ = NULL;
1445        assert (!analyzeResults_);
1446        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1447        assert (stuff);
1448        //if (stuff)
1449        stuff->setCreatedNode(NULL);
1450        // ?? searchStrategy_;
1451        searchStrategy_ = baseModel->searchStrategy_;
1452        stuff->saveStuff()[0] = searchStrategy_;
1453        stateOfSearch_ = baseModel->stateOfSearch_;
1454        stuff->saveStuff()[1] = stateOfSearch_;
1455        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
1456            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
1457                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[iObject]) ;
1458            if (dynamicObject) {
1459                CbcSimpleIntegerDynamicPseudoCost * baseObject =
1460                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(baseModel->object_[iObject]) ;
1461                assert (baseObject);
1462                dynamicObject->copySome(baseObject);
1463            }
1464        }
1465    } else if (mode == 1) {
1466        lockThread();
1467        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1468        assert (stuff);
1469        //stateOfSearch_
1470        if (stuff->saveStuff()[0] != searchStrategy_) {
1471#ifdef COIN_DEVELOP
1472            printf("changing searchStrategy from %d to %d\n",
1473                   baseModel->searchStrategy_, searchStrategy_);
1474#endif
1475            baseModel->searchStrategy_ = searchStrategy_;
1476        }
1477        if (stuff->saveStuff()[1] != stateOfSearch_) {
1478#ifdef COIN_DEVELOP
1479            printf("changing stateOfSearch from %d to %d\n",
1480                   baseModel->stateOfSearch_, stateOfSearch_);
1481#endif
1482            baseModel->stateOfSearch_ = stateOfSearch_;
1483        }
1484        if (numberUpdateItems_) {
1485            for (int i = 0; i < numberUpdateItems_; i++) {
1486                CbcObjectUpdateData * update = updateItems_ + i;
1487                int objectNumber = update->objectNumber_;
1488                CbcObject * object = dynamic_cast<CbcObject *> (baseModel->object_[objectNumber]);
1489                if (object)
1490                    object->updateInformation(*update);
1491            }
1492            numberUpdateItems_ = 0;
1493        }
1494        if (eventHappened_)
1495            baseModel->eventHappened_ = true;
1496        baseModel->numberNodes_++;
1497        baseModel->numberIterations_ +=
1498            numberIterations_ - numberFixedAtRoot_;
1499        baseModel->numberSolves_ += numberSolves_;
1500        if (stuff->node())
1501            baseModel->tree_->push(stuff->node());
1502        if (stuff->createdNode())
1503            baseModel->tree_->push(stuff->createdNode());
1504        unlockThread();
1505    } else if (mode == 2) {
1506        baseModel->sumChangeObjective1_ += sumChangeObjective1_;
1507        baseModel->sumChangeObjective2_ += sumChangeObjective2_;
1508        //baseModel->numberIterations_ += numberIterations_;
1509        for (int iGenerator = 0; iGenerator < numberCutGenerators_; iGenerator++) {
1510            CbcCutGenerator * generator = baseModel->generator_[iGenerator];
1511            CbcCutGenerator * generator2 = generator_[iGenerator];
1512            generator->incrementNumberTimesEntered(generator2->numberTimesEntered());
1513            generator->incrementNumberCutsInTotal(generator2->numberCutsInTotal());
1514            generator->incrementNumberCutsActive(generator2->numberCutsActive());
1515            generator->incrementTimeInCutGenerator(generator2->timeInCutGenerator());
1516        }
1517        if (parallelMode() >= 0)
1518            nodeCompare_ = NULL;
1519        baseModel->maximumDepthActual_ = CoinMax(baseModel->maximumDepthActual_, maximumDepthActual_);
1520        baseModel->numberDJFixed_ += numberDJFixed_;
1521        baseModel->numberStrongIterations_ += numberStrongIterations_;
1522        int i;
1523        for (i = 0; i < 3; i++)
1524            baseModel->strongInfo_[i] += strongInfo_[i];
1525        if (parallelMode() >= 0) {
1526            walkback_ = NULL;
1527            lastNodeInfo_ = NULL;
1528            lastNumberCuts_ = NULL;
1529            lastCut_ = NULL;
1530            //addedCuts_ = NULL;
1531            tree_ = NULL;
1532        }
1533        eventHandler_ = NULL;
1534        delete solverCharacteristics_;
1535        solverCharacteristics_ = NULL;
1536        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
1537        if (newMethod) {
1538            // new method - we were using base models
1539            numberObjects_ = 0;
1540            object_ = NULL;
1541        }
1542    } else if (mode == -1) {
1543        delete eventHandler_;
1544        eventHandler_ = baseModel->eventHandler_;
1545        assert (!statistics_);
1546        assert(baseModel->solverCharacteristics_);
1547        solverCharacteristics_ = new OsiBabSolver (*baseModel->solverCharacteristics_);
1548        solverCharacteristics_->setSolver(solver_);
1549        setMaximumNodes(COIN_INT_MAX);
1550        if (parallelMode() >= 0) {
1551            delete [] walkback_;
1552            //delete [] addedCuts_;
1553            walkback_ = NULL;
1554            //addedCuts_ = NULL;
1555            delete [] lastNodeInfo_ ;
1556            lastNodeInfo_ = NULL;
1557            delete [] lastNumberCuts_ ;
1558            lastNumberCuts_ = NULL;
1559            delete [] lastCut_ ;
1560            lastCut_ = NULL;
1561            delete tree_;
1562            tree_ = NULL;
1563            delete nodeCompare_;
1564            nodeCompare_ = NULL;
1565        } else {
1566            delete tree_;
1567            tree_ = new CbcTree();
1568            tree_->setComparison(*nodeCompare_) ;
1569        }
1570        continuousSolver_ = baseModel->continuousSolver_->clone();
1571        // make sure solvers have correct message handler
1572        solver_->passInMessageHandler(handler_);
1573        continuousSolver_->passInMessageHandler(handler_);
1574        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
1575        if (newMethod) {
1576            // new method uses solver - but point to base model
1577            // We may update an object in wrong order - shouldn't matter?
1578            numberObjects_ = baseModel->numberObjects_;
1579            if (parallelMode() >= 0) {
1580                object_ = baseModel->object_;
1581            } else {
1582                printf("*****WARNING - fix testosi option\n");
1583                object_ = baseModel->object_;
1584            }
1585        }
1586        int i;
1587        for (i = 0; i < numberHeuristics_; i++) {
1588            delete heuristic_[i];
1589            heuristic_[i] = baseModel->heuristic_[i]->clone();
1590            heuristic_[i]->setModelOnly(this);
1591        }
1592        for (i = 0; i < numberCutGenerators_; i++) {
1593            delete generator_[i];
1594            generator_[i] = new CbcCutGenerator(*baseModel->generator_[i]);
1595            // refreshModel was overkill as thought too many rows
1596            generator_[i]->setModel(this);
1597        }
1598    } else if (mode == 10) {
1599        setCutoff(baseModel->getCutoff());
1600        bestObjective_ = baseModel->bestObjective_;
1601        //assert (!baseModel->globalCuts_.sizeRowCuts());
1602        numberSolutions_ = baseModel->numberSolutions_;
1603        assert (usedInSolution_);
1604        assert (baseModel->usedInSolution_);
1605        memcpy(usedInSolution_, baseModel->usedInSolution_, solver_->getNumCols()*sizeof(int));
1606        stateOfSearch_ = baseModel->stateOfSearch_;
1607        //numberNodes_ = baseModel->numberNodes_;
1608        //numberIterations_ = baseModel->numberIterations_;
1609        //numberFixedAtRoot_ = numberIterations_; // for statistics
1610        phase_ = baseModel->phase_;
1611        assert (!nextRowCut_);
1612        delete nodeCompare_;
1613        nodeCompare_ = baseModel->nodeCompare_->clone();
1614        tree_->setComparison(*nodeCompare_) ;
1615        assert (!subTreeModel_);
1616        //branchingMethod_ = NULL; // need something but what
1617        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
1618        cutModifier_ = NULL;
1619        assert (!analyzeResults_);
1620        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1621        assert (stuff);
1622        //if (stuff)
1623        stuff->setCreatedNode(NULL);
1624        // ?? searchStrategy_;
1625        searchStrategy_ = baseModel->searchStrategy_;
1626        stuff->saveStuff()[0] = searchStrategy_;
1627        stateOfSearch_ = baseModel->stateOfSearch_;
1628        stuff->saveStuff()[1] = stateOfSearch_;
1629        OsiObject ** baseObject = baseModel->object_;
1630        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
1631            object_[iObject]->updateBefore(baseObject[iObject]);
1632        }
1633        //delete [] stuff->nodeCount;
1634        //stuff->nodeCount = new int [baseModel->maximumDepth_+1];
1635    } else if (mode == 11) {
1636        if (parallelMode() < 0) {
1637            // from deterministic
1638            CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1639            assert (stuff);
1640            // Move solution etc
1641            // might as well mark all including continuous
1642            int numberColumns = solver_->getNumCols();
1643            for (int i = 0; i < numberColumns; i++) {
1644                baseModel->usedInSolution_[i] += usedInSolution_[i];
1645                //usedInSolution_[i]=0;
1646            }
1647            baseModel->numberSolutions_ += numberSolutions_;
1648            if (bestObjective_ < baseModel->bestObjective_ && bestObjective_ < baseModel->getCutoff()) {
1649                baseModel->bestObjective_ = bestObjective_ ;
1650                int numberColumns = solver_->getNumCols();
1651                if (!baseModel->bestSolution_)
1652                    baseModel->bestSolution_ = new double[numberColumns];
1653                CoinCopyN(bestSolution_, numberColumns, baseModel->bestSolution_);
1654                baseModel->setCutoff(getCutoff());
1655            }
1656            //stateOfSearch_
1657            if (stuff->saveStuff()[0] != searchStrategy_) {
1658#ifdef COIN_DEVELOP
1659                printf("changing searchStrategy from %d to %d\n",
1660                       baseModel->searchStrategy_, searchStrategy_);
1661#endif
1662                baseModel->searchStrategy_ = searchStrategy_;
1663            }
1664            if (stuff->saveStuff()[1] != stateOfSearch_) {
1665#ifdef COIN_DEVELOP
1666                printf("changing stateOfSearch from %d to %d\n",
1667                       baseModel->stateOfSearch_, stateOfSearch_);
1668#endif
1669                baseModel->stateOfSearch_ = stateOfSearch_;
1670            }
1671            int i;
1672            if (eventHappened_)
1673                baseModel->eventHappened_ = true;
1674            baseModel->numberNodes_ += stuff->nodesThisTime();
1675            baseModel->numberIterations_ += stuff->iterationsThisTime();
1676            double cutoff = baseModel->getCutoff();
1677            while (!tree_->empty()) {
1678                CbcNode * node = tree_->bestNode(COIN_DBL_MAX) ;
1679                if (node->objectiveValue() < cutoff) {
1680                    assert(node->nodeInfo());
1681                    // Make node join correctly
1682                    OsiBranchingObject * bobj = node->modifiableBranchingObject();
1683                    CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
1684                    if (cbcobj) {
1685                        CbcObject * object = cbcobj->object();
1686                        assert (object);
1687                        int position = object->position();
1688                        assert (position >= 0);
1689                        assert (object_[position] == object);
1690                        CbcObject * objectNew =
1691                            dynamic_cast<CbcObject *> (baseModel->object_[position]);
1692                        cbcobj->setOriginalObject(objectNew);
1693                    }
1694                    baseModel->tree_->push(node);
1695                } else {
1696                    delete node;
1697                }
1698            }
1699            for (i = 0; i < stuff->nDeleteNode(); i++) {
1700                //printf("CbcNode %x stuff delete\n",stuff->delNode[i]);
1701                delete stuff->delNode()[i];
1702            }
1703        }
1704    } else {
1705        abort();
1706    }
1707}
1708// Generate one round of cuts - parallel mode
1709int
1710CbcModel::parallelCuts(CbcBaseModel * master, OsiCuts & theseCuts,
1711                       CbcNode * /*node*/, OsiCuts & slackCuts, int lastNumberCuts)
1712{
1713    /*
1714      Is it time to scan the cuts in order to remove redundant cuts? If so, set
1715      up to do it.
1716    */
1717    int fullScan = 0 ;
1718    if ((numberNodes_ % SCANCUTS) == 0 || (specialOptions_&256) != 0) {
1719        fullScan = 1 ;
1720        if (!numberNodes_ || (specialOptions_&256) != 0)
1721            fullScan = 2;
1722        specialOptions_ &= ~256; // mark as full scan done
1723    }
1724    // do cuts independently
1725    OsiCuts * eachCuts = new OsiCuts [numberCutGenerators_];;
1726    int i;
1727    assert (master);
1728    for (i = 0; i < numberThreads_; i++) {
1729        // set solver here after cloning
1730        master->model(i)->solver_ = solver_->clone();
1731        master->model(i)->numberNodes_ = (fullScan) ? 1 : 0;
1732    }
1733    // generate cuts
1734    int status = 0;
1735    const OsiRowCutDebugger * debugger = NULL;
1736    bool onOptimalPath = false;
1737    for (i = 0; i < numberCutGenerators_; i++) {
1738        bool generate = generator_[i]->normal();
1739        // skip if not optimal and should be (maybe a cut generator has fixed variables)
1740        if (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
1741            generate = false;
1742        if (generator_[i]->switchedOff())
1743            generate = false;;
1744        if (generate) {
1745            master->waitForThreadsInCuts(0, eachCuts + i, i);
1746        }
1747    }
1748    // wait
1749    master->waitForThreadsInCuts(1, eachCuts, 0);
1750    // Now put together
1751    for (i = 0; i < numberCutGenerators_; i++) {
1752        // add column cuts
1753        int numberColumnCutsBefore = theseCuts.sizeColCuts() ;
1754        int numberColumnCuts = eachCuts[i].sizeColCuts();
1755        int numberColumnCutsAfter = numberColumnCutsBefore
1756                                    + numberColumnCuts;
1757        int j;
1758        for (j = 0; j < numberColumnCuts; j++) {
1759            theseCuts.insert(eachCuts[i].colCut(j));
1760        }
1761        int numberRowCutsBefore = theseCuts.sizeRowCuts() ;
1762        int numberRowCuts = eachCuts[i].sizeRowCuts();
1763        // insert good cuts
1764        if (numberRowCuts) {
1765            int n = numberRowCuts;
1766            numberRowCuts = 0;
1767            for (j = 0; j < n; j++) {
1768                const OsiRowCut * thisCut = eachCuts[i].rowCutPtr(j) ;
1769                if (thisCut->lb() <= 1.0e10 && thisCut->ub() >= -1.0e10) {
1770                    theseCuts.insert(eachCuts[i].rowCut(j));
1771                    numberRowCuts++;
1772                }
1773            }
1774            if (generator_[i]->mustCallAgain() && status >= 0)
1775                status = 1; // say must go round
1776        }
1777        int numberRowCutsAfter = numberRowCutsBefore
1778                                 + numberRowCuts;
1779        if (numberRowCuts) {
1780            // Check last cut to see if infeasible
1781            const OsiRowCut * thisCut = theseCuts.rowCutPtr(numberRowCutsAfter - 1) ;
1782            if (thisCut->lb() > thisCut->ub()) {
1783                status = -1; // sub-problem is infeasible
1784                break;
1785            }
1786        }
1787#ifdef CBC_DEBUG
1788        {
1789            int k ;
1790            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1791                OsiRowCut thisCut = theseCuts.rowCut(k) ;
1792                /* check size of elements.
1793                   We can allow smaller but this helps debug generators as it
1794                   is unsafe to have small elements */
1795                int n = thisCut.row().getNumElements();
1796                const int * column = thisCut.row().getIndices();
1797                const double * element = thisCut.row().getElements();
1798                //assert (n);
1799                for (int i = 0; i < n; i++) {
1800                    double value = element[i];
1801                    assert(fabs(value) > 1.0e-12 && fabs(value) < 1.0e20);
1802                }
1803            }
1804        }
1805#endif
1806        if ((specialOptions_&1) != 0) {
1807            if (onOptimalPath) {
1808                int k ;
1809                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1810                    OsiRowCut thisCut = theseCuts.rowCut(k) ;
1811                    if (debugger->invalidCut(thisCut)) {
1812                        solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
1813                        solver_->writeMpsNative("badCut.mps", NULL, NULL, 2);
1814#ifdef NDEBUG
1815                        printf("Cut generator %d (%s) produced invalid cut (%dth in this go)\n",
1816                               i, generator_[i]->cutGeneratorName(), k - numberRowCutsBefore);
1817                        const double *lower = getColLower() ;
1818                        const double *upper = getColUpper() ;
1819                        int numberColumns = solver_->getNumCols();
1820                        for (int i = 0; i < numberColumns; i++)
1821                            printf("%d bounds %g,%g\n", i, lower[i], upper[i]);
1822                        abort();
1823#endif
1824                    }
1825                    assert(!debugger->invalidCut(thisCut)) ;
1826                }
1827            }
1828        }
1829        /*
1830          The cut generator has done its thing, and maybe it generated some
1831          cuts.  Do a bit of bookkeeping: load
1832          whichGenerator[i] with the index of the generator responsible for a cut,
1833          and place cuts flagged as global in the global cut pool for the model.
1834
1835          lastNumberCuts is the sum of cuts added in previous iterations; it's the
1836          offset to the proper starting position in whichGenerator.
1837        */
1838        int numberBefore =
1839            numberRowCutsBefore + numberColumnCutsBefore + lastNumberCuts ;
1840        int numberAfter =
1841            numberRowCutsAfter + numberColumnCutsAfter + lastNumberCuts ;
1842        // possibly extend whichGenerator
1843        resizeWhichGenerator(numberBefore, numberAfter);
1844
1845        for (j = numberRowCutsBefore; j < numberRowCutsAfter; j++) {
1846            whichGenerator_[numberBefore++] = i ;
1847            const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
1848            if (thisCut->lb() > thisCut->ub())
1849                status = -1; // sub-problem is infeasible
1850            if (thisCut->globallyValid()) {
1851                // add to global list
1852                OsiRowCut newCut(*thisCut);
1853                newCut.setGloballyValid(true);
1854                newCut.mutableRow().setTestForDuplicateIndex(false);
1855                globalCuts_.addCutIfNotDuplicate(newCut) ;
1856            }
1857        }
1858        for (j = numberColumnCutsBefore; j < numberColumnCutsAfter; j++) {
1859            //whichGenerator_[numberBefore++] = i ;
1860            const OsiColCut * thisCut = theseCuts.colCutPtr(j) ;
1861            if (thisCut->globallyValid()) {
1862                // add to global list
1863                makeGlobalCut(thisCut);
1864            }
1865        }
1866    }
1867    // Add in any violated saved cuts
1868    if (!theseCuts.sizeRowCuts() && !theseCuts.sizeColCuts()) {
1869        int numberOld = theseCuts.sizeRowCuts() + lastNumberCuts;
1870        int numberCuts = slackCuts.sizeRowCuts() ;
1871        int i;
1872        // possibly extend whichGenerator
1873        resizeWhichGenerator(numberOld, numberOld + numberCuts);
1874        double primalTolerance;
1875        solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
1876        for ( i = 0; i < numberCuts; i++) {
1877            const OsiRowCut * thisCut = slackCuts.rowCutPtr(i) ;
1878            if (thisCut->violated(cbcColSolution_) > 100.0*primalTolerance) {
1879                if (messageHandler()->logLevel() > 2)
1880                    printf("Old cut added - violation %g\n",
1881                           thisCut->violated(cbcColSolution_)) ;
1882                whichGenerator_[numberOld++] = -1;
1883                theseCuts.insert(*thisCut) ;
1884            }
1885        }
1886    }
1887    delete [] eachCuts;
1888    return status;
1889}
1890/*
1891  Locks a thread if parallel so that stuff like cut pool
1892  can be updated and/or used.
1893*/
1894void
1895CbcModel::lockThread()
1896{
1897    if (masterThread_ && (threadMode_&1) == 0)
1898        masterThread_->lockThread();
1899}
1900/*
1901  Unlocks a thread if parallel
1902*/
1903void
1904CbcModel::unlockThread()
1905{
1906    if (masterThread_ && (threadMode_&1) == 0)
1907        masterThread_->unlockThread();
1908}
1909// Returns true if locked
1910bool
1911CbcModel::isLocked() const
1912{
1913    if (masterThread_) {
1914        return (masterThread_->locked());
1915    } else {
1916        return true;
1917    }
1918}
1919// Stop a child
1920void
1921CbcModel::setInfoInChild(int type, CbcThread * info)
1922{
1923    if (type == -3) {
1924        // set up
1925        masterThread_ = info;
1926    } else if (type == -2) {
1927        numberThreads_ = 0; // signal to stop
1928    } else {
1929        // make sure message handler will be deleted
1930        defaultHandler_ = true;
1931        ownObjects_ = false;
1932        delete solverCharacteristics_;
1933        solverCharacteristics_ = NULL;
1934        if (type >= 0) {
1935            delete [] object_; // may be able to when all over to CbcThread
1936            for (int i = 0; i < numberCutGenerators_; i++) {
1937                delete generator_[i];
1938                generator_[i] = NULL;
1939                //delete virginGenerator_[i];
1940                //virginGenerator_[i]=NULL;
1941            }
1942            //generator_[0] = NULL;
1943            //delete [] generator_;
1944            //generator_ = NULL;
1945            numberCutGenerators_ = 0;
1946        } else {
1947            for (int i = 0; i < numberCutGenerators_; i++) {
1948                generator_[i] = NULL;
1949            }
1950        }
1951        object_ = NULL;
1952    }
1953}
1954
1955/// Indicates whether Cbc library has been compiled with multithreading support
1956bool CbcModel::haveMultiThreadSupport() { return true; }
1957
1958#else
1959// Default constructor
1960CbcBaseModel::CbcBaseModel() {}
1961
1962bool CbcModel::haveMultiThreadSupport() { return false; }
1963#endif
1964
Note: See TracBrowser for help on using the repository browser.