source: trunk/Cbc/src/CbcThread.cpp @ 1880

Last change on this file since 1880 was 1880, checked in by forrest, 7 years ago

make it easier to use slow exotic cuts
more on cutoff as constraint and multiple root solver fixes
general fixing of bugs found on MIQP etc

  • Property svn:keywords set to Author Date Id Revision
File size: 67.8 KB
Line 
1/* $Id: CbcThread.cpp 1880 2013-04-01 17:09:22Z 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 = absTime2.tv_sec + 1.0e-9 * 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 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]->synchronizeHandlers(1);
574#ifdef COIN_HAS_CLP
575            // Solver may need to know about model
576            CbcModel * thisModel = threadModel_[i];
577            CbcOsiSolver * solver =
578                dynamic_cast<CbcOsiSolver *>(thisModel->solver()) ;
579            if (solver)
580                solver->setCbcModel(thisModel);
581#endif
582            children_[i].setUsefulStuff(threadModel_[i], type_, &model,
583                                        children_ + numberThreads_, mutex_main);
584#ifdef THREAD_DEBUG
585            children_[i].threadNumber_ = i;
586            children_[i].lockCount_ = 0;
587#endif
588        }
589        model.setStrategy(saveStrategy);
590    }
591}
592// Stop threads
593void
594CbcBaseModel::stopThreads(int type)
595{
596    if (type < 0) {
597        // max nodes ?
598        bool finished = false;
599        while (!finished) {
600          finished = true;
601          for (int i = 0; i < numberThreads_; i++) {
602            if (abs(children_[i].returnCode()) != 1) {
603              children_[i].wait(1, 0); 
604              finished=false;
605            }
606          }
607        }
608        return;
609    }
610    for (int i = 0; i < numberThreads_; i++) {
611        children_[i].wait(1, 0);
612        assert (children_[i].returnCode() == -1);
613        threadModel_[i]->setInfoInChild(-2, NULL);
614        children_[i].setReturnCode( 0);
615        children_[i].exit();
616        children_[i].setStatus( 0);
617    }
618    // delete models and solvers
619    for (int i = 0; i < numberThreads_; i++) {
620        threadModel_[i]->setInfoInChild(type_, NULL);
621        delete threadModel_[i];
622    }
623    delete [] children_;
624    delete [] threadModel_;
625    for (int i = 0; i < numberObjects_; i++)
626        delete saveObjects_[i];
627    delete [] saveObjects_;
628    children_ = NULL;
629    threadModel_ = NULL;
630    saveObjects_ = NULL;
631    numberObjects_ = 0;
632    numberThreads_ = 0;
633}
634// Wait for threads in tree
635int
636CbcBaseModel::waitForThreadsInTree(int type)
637{
638    CbcModel * baseModel = children_[0].baseModel();
639    int anyLeft = 0;
640    // May be able to combine parts later
641
642    if (type == 0) {
643        bool locked = true;
644#ifdef COIN_DEVELOP
645        printf("empty\n");
646#endif
647        // may still be outstanding nodes
648        while (true) {
649            int iThread;
650            for (iThread = 0; iThread < numberThreads_; iThread++) {
651                if (children_[iThread].status()) {
652                    if (children_[iThread].returnCode() == 0)
653                        break;
654                }
655            }
656            if (iThread < numberThreads_) {
657#ifdef COIN_DEVELOP
658                printf("waiting for thread %d code 0\n", iThread);
659#endif
660                unlockThread();
661                locked = false;
662                children_[iThread].wait(1, 0);
663                assert(children_[iThread].returnCode() == 1);
664                threadModel_[iThread]->moveToModel(baseModel, 1);
665#ifdef THREAD_PRINT
666                printf("off thread2 %d node %x\n", iThread, children_[iThread].node());
667#endif
668                children_[iThread].setNode(NULL);
669                anyLeft = 1;
670                assert (children_[iThread].returnCode() == 1);
671                if (children_[iThread].dantzigState() == -1) {
672                    // 0 unset, -1 waiting to be set, 1 set
673                    children_[iThread].setDantzigState(1);
674                    CbcModel * model = children_[iThread].thisModel();
675                    OsiClpSolverInterface * clpSolver2
676                    = dynamic_cast<OsiClpSolverInterface *> (model->solver());
677                    assert (clpSolver2);
678                    ClpSimplex * simplex2 = clpSolver2->getModelPtr();
679                    ClpDualRowDantzig dantzig;
680                    simplex2->setDualRowPivotAlgorithm(dantzig);
681                }
682                // say available
683                children_[iThread].setReturnCode( -1);
684                threadStats_[4]++;
685#ifdef COIN_DEVELOP
686                printf("thread %d code now -1\n", iThread);
687#endif
688                break;
689            } else {
690#ifdef COIN_DEVELOP
691                printf("no threads at code 0 \n");
692#endif
693                // now check if any have just finished
694                for (iThread = 0; iThread < numberThreads_; iThread++) {
695                    if (children_[iThread].status()) {
696                        if (children_[iThread].returnCode() == 1)
697                            break;
698                    }
699                }
700                if (iThread < numberThreads_) {
701                    unlockThread();
702                    locked = false;
703                    threadModel_[iThread]->moveToModel(baseModel, 1);
704#ifdef THREAD_PRINT
705                    printf("off thread3 %d node %x\n", iThread, children_[iThread].node());
706#endif
707                    children_[iThread].setNode(NULL);
708                    anyLeft = 1;
709                    assert (children_[iThread].returnCode() == 1);
710                    // say available
711                    children_[iThread].setReturnCode( -1);
712                    threadStats_[4]++;
713#ifdef COIN_DEVELOP
714                    printf("thread %d code now -1\n", iThread);
715#endif
716                    break;
717                }
718            }
719            if (!baseModel->tree()->empty()) {
720#ifdef COIN_DEVELOP
721                printf("tree not empty!!!!!!\n");
722#endif
723                if (locked)
724                    unlockThread();
725                return 1;
726                break;
727            }
728            for (iThread = 0; iThread < numberThreads_; iThread++) {
729                if (children_[iThread].status()) {
730                    if (children_[iThread].returnCode() != -1) {
731                        printf("bad end of tree\n");
732                        abort();
733                    }
734                }
735            }
736            break;
737        }
738#ifdef COIN_DEVELOP
739        printf("finished ************\n");
740#endif
741        if (locked)
742            unlockThread();
743        return anyLeft;
744    } else if (type == 1) {
745        // normal
746        double cutoff = baseModel->getCutoff();
747        CbcNode * node = baseModel->tree()->bestNode(cutoff) ;
748        // Possible one on tree worse than cutoff
749        if (!node || node->objectiveValue() > cutoff)
750            return 1;
751        threadStats_[0]++;
752        //need to think
753        int iThread;
754        // Start one off if any available
755        for (iThread = 0; iThread < numberThreads_; iThread++) {
756            if (children_[iThread].returnCode() == -1)
757                break;
758        }
759        if (iThread < numberThreads_) {
760            children_[iThread].setNode(node);
761#ifdef THREAD_PRINT
762            printf("empty thread %d node %x\n", iThread, children_[iThread].node());
763#endif
764            assert (children_[iThread].returnCode() == -1);
765            // say in use
766            threadModel_[iThread]->moveToModel(baseModel, 0);
767            // This has to be AFTER moveToModel
768            children_[iThread].setReturnCode( 0);
769            children_[iThread].signal();
770            threadCount_[iThread]++;
771        }
772        lockThread();
773        // see if any finished
774        for (iThread = 0; iThread < numberThreads_; iThread++) {
775            if (children_[iThread].returnCode() > 0)
776                break;
777        }
778        unlockThread();
779        if (iThread < numberThreads_) {
780            threadModel_[iThread]->moveToModel(baseModel, 1);
781#ifdef THREAD_PRINT
782            printf("off thread4 %d node %x\n", iThread, children_[iThread].node());
783#endif
784            children_[iThread].setNode(NULL);
785            anyLeft = 1;
786            assert (children_[iThread].returnCode() == 1);
787            // say available
788            children_[iThread].setReturnCode( -1);
789            // carry on
790            threadStats_[3]++;
791        } else {
792            // Start one off if any available
793            for (iThread = 0; iThread < numberThreads_; iThread++) {
794                if (children_[iThread].returnCode() == -1)
795                    break;
796            }
797            if (iThread < numberThreads_) {
798                // If any on tree get
799                if (!baseModel->tree()->empty()) {
800                    //node = baseModel->tree()->bestNode(cutoff) ;
801                    //assert (node);
802                    threadStats_[1]++;
803                    return 1; // ** get another node
804                }
805            }
806            // wait (for debug could sleep and use test)
807            bool finished = false;
808            while (!finished) {
809                double time = getTime();
810                children_[numberThreads_].wait(0, 0);
811                children_[numberThreads_].incrementTimeInThread(getTime() - time);
812                for (iThread = 0; iThread < numberThreads_; iThread++) {
813                    if (children_[iThread].returnCode() > 0) {
814                        finished = true;
815                        break;
816                    } else if (children_[iThread].returnCode() == 0) {
817                        children_[iThread].signal(); // unlock
818                    }
819                }
820            }
821            assert (iThread < numberThreads_);
822            // move information to model
823            threadModel_[iThread]->moveToModel(baseModel, 1);
824            anyLeft = 1;
825#ifdef THREAD_PRINT
826            printf("off thread %d node %x\n", iThread, children_[iThread].node());
827#endif
828            children_[iThread].setNode(NULL);
829            assert (children_[iThread].returnCode() == 1);
830            // say available
831            children_[iThread].setReturnCode( -1);
832        }
833        // carry on
834        threadStats_[2]++;
835        for (int iThread = 0; iThread < numberThreads_; iThread++) {
836            if (children_[iThread].status()) {
837                if (children_[iThread].returnCode() != -1) {
838                    anyLeft = 1;
839                    break;
840                }
841            }
842        }
843        return anyLeft;
844    } else if (type == 2) {
845        if (!baseModel->tree()->empty()) {
846          // max nodes ?
847          bool finished = false;
848          while (!finished) {
849            finished = true;
850            for (int iThread = 0; iThread < numberThreads_; iThread++) {
851              if (children_[iThread].returnCode() == 0) { 
852                double time = getTime();
853                children_[numberThreads_].wait(0, 0);
854                children_[numberThreads_].incrementTimeInThread(getTime() - time);
855                finished = false;
856                children_[iThread].signal(); // unlock
857              }
858            }
859          }
860        }
861        int i;
862        // do statistics
863        // Seems to be bug in CoinCpu on Linux - does threads as well despite documentation
864        double time = 0.0;
865        for (i = 0; i < numberThreads_; i++)
866            time += children_[i].timeInThread();
867        bool goodTimer = time < (baseModel->getCurrentSeconds());
868        for (i = 0; i < numberThreads_; i++) {
869            while (children_[i].returnCode() == 0) {
870                children_[i].signal();
871                double time = getTime();
872                children_[numberThreads_].wait(0, 0);
873                children_[numberThreads_].incrementTimeInThread(getTime() - time);
874            }
875            children_[i].lockFromMaster();
876            threadModel_[i]->setNumberThreads(0); // say exit
877            if (children_[i].deterministic() > 0)
878                delete [] children_[i].delNode();
879            children_[i].setReturnCode( 0);
880            children_[i].unlockFromMaster();
881            int returnCode;
882            returnCode = children_[i].exit();
883            children_[i].setStatus( 0);
884            assert (!returnCode);
885            //else
886            threadModel_[i]->moveToModel(baseModel, 2);
887            assert (children_[i].numberTimesLocked() == children_[i].numberTimesUnlocked());
888            baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
889            << "Thread";
890            baseModel->messageHandler()->printing(true)
891            << i << threadCount_[i] << children_[i].timeWaitingToStart();
892            baseModel->messageHandler()->printing(goodTimer) << children_[i].timeInThread();
893            baseModel->messageHandler()->printing(false) << 0.0;
894            baseModel->messageHandler()->printing(true) << children_[i].numberTimesLocked()
895            << children_[i].timeLocked() << children_[i].timeWaitingToLock()
896            << CoinMessageEol;
897        }
898        assert (children_[numberThreads_].numberTimesLocked() == children_[numberThreads_].numberTimesUnlocked());
899        baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
900        << "Main thread";
901        baseModel->messageHandler()->printing(false) << 0 << 0 << 0.0;
902        baseModel->messageHandler()->printing(false) << 0.0;
903        baseModel->messageHandler()->printing(true) << children_[numberThreads_].timeInThread();
904        baseModel->messageHandler()->printing(true) << children_[numberThreads_].numberTimesLocked()
905        << children_[numberThreads_].timeLocked() << children_[numberThreads_].timeWaitingToLock()
906        << CoinMessageEol;
907        // delete models (here in case some point to others)
908        for (i = 0; i < numberThreads_; i++) {
909            // make sure handler will be deleted
910            threadModel_[i]->setDefaultHandler(true);
911            //delete threadModel_[i];
912        }
913    } else {
914        abort();
915    }
916    return 0;
917}
918void
919CbcBaseModel::waitForThreadsInCuts(int type, OsiCuts * eachCuts,
920                                   int whichGenerator)
921{
922    if (type == 0) {
923        // cuts while doing
924        bool finished = false;
925        int iThread = -1;
926        // see if any available
927        for (iThread = 0; iThread < numberThreads_; iThread++) {
928            if (children_[iThread].returnCode()) {
929                finished = true;
930                break;
931            } else if (children_[iThread].returnCode() == 0) {
932                children_[iThread].signal();
933            }
934        }
935        while (!finished) {
936            children_[numberThreads_].waitNano(1000000);
937            for (iThread = 0; iThread < numberThreads_; iThread++) {
938                if (children_[iThread].returnCode() > 0) {
939                    finished = true;
940                    break;
941                } else if (children_[iThread].returnCode() == 0) {
942                    children_[iThread].signal();
943                }
944            }
945        }
946        assert (iThread < numberThreads_);
947        assert (children_[iThread].returnCode());
948        // Use dantzigState to signal which generator
949        children_[iThread].setDantzigState(whichGenerator);
950        // and delNode for eachCuts
951        children_[iThread].fakeDelNode(reinterpret_cast<CbcNode **> (eachCuts));
952        // allow to start
953        children_[iThread].setReturnCode( 0);
954        children_[iThread].signal();
955    } else if (type == 1) {
956        // cuts - finish up
957        for (int iThread = 0; iThread < numberThreads_; iThread++) {
958            if (children_[iThread].returnCode() == 0) {
959                bool finished = false;
960                while (!finished) {
961                    children_[numberThreads_].wait(0, 0);
962                    if (children_[iThread].returnCode() > 0) {
963                        finished = true;
964                        break;
965                        //#ifndef NEW_STYLE_PTHREAD
966                        //} else if (children_[iThread].returnCode_ == 0) {
967                        //pthread_cond_signal(&children_[iThread].threadStuff_.condition2_); // unlock
968                        //#endif
969                    }
970                }
971            }
972            assert (children_[iThread].returnCode());
973            // say available
974            children_[iThread].setReturnCode( -1);
975            //delete threadModel_[iThread]->solver();
976            //threadModel_[iThread]->setSolver(NULL);
977        }
978    } else {
979        abort();
980    }
981}
982// Returns pointer to master thread
983CbcThread *
984CbcBaseModel::masterThread() const
985{
986    return children_ + numberThreads_;
987}
988
989// Split model and do work in deterministic parallel
990void
991CbcBaseModel::deterministicParallel()
992{
993    CbcModel * baseModel = children_[0].baseModel();
994    for (int i = 0; i < numberThreads_; i++)
995        threadCount_[i]++;
996    int saveTreeSize = baseModel->tree()->size();
997    // For now create threadModel - later modify splitModel
998    CbcModel ** threadModel = new CbcModel * [numberThreads_];
999    int iThread;
1000    for (iThread = 0; iThread < numberThreads_; iThread++)
1001        threadModel[iThread] = children_[iThread].thisModel();
1002
1003    int nAffected = baseModel->splitModel(numberThreads_, threadModel, defaultParallelNodes_);
1004    // do all until finished
1005    for (iThread = 0; iThread < numberThreads_; iThread++) {
1006        // obviously tune
1007        children_[iThread].setNDeleteNode(defaultParallelIterations_);
1008    }
1009    // Save current state
1010    int iObject;
1011    OsiObject ** object = baseModel->objects();
1012    for (iObject = 0; iObject < numberObjects_; iObject++) {
1013        saveObjects_[iObject]->updateBefore(object[iObject]);
1014    }
1015    //#define FAKE_PARALLEL
1016#ifndef FAKE_PARALLEL
1017    for (iThread = 0; iThread < numberThreads_; iThread++) {
1018        children_[iThread].setReturnCode( 0);
1019        children_[iThread].signal();
1020    }
1021    // wait
1022    bool finished = false;
1023    double time = getTime();
1024    while (!finished) {
1025        children_[numberThreads_].waitNano( 1000000); // millisecond
1026        finished = true;
1027        for (iThread = 0; iThread < numberThreads_; iThread++) {
1028            if (children_[iThread].returnCode() <= 0) {
1029                finished = false;
1030            }
1031        }
1032    }
1033    for (iThread = 0; iThread < numberThreads_; iThread++)
1034        children_[iThread].setReturnCode(-1);
1035#else
1036    // wait
1037    bool finished = false;
1038    double time = getTime();
1039    for (iThread = 0; iThread < numberThreads_; iThread++) {
1040        children_[iThread].setReturnCode( 0);
1041        children_[iThread].signal();
1042        while (!finished) {
1043          children_[numberThreads_].waitNano( 1000000); // millisecond
1044          finished = (children_[iThread].returnCode() >0);
1045        }
1046        children_[iThread].setReturnCode(-1);
1047        finished=false;
1048    }
1049#endif
1050    children_[numberThreads_].incrementTimeInThread(getTime() - time);
1051    // Unmark marked
1052    for (int i = 0; i < nAffected; i++) {
1053        baseModel->walkback()[i]->unmark();
1054    }
1055    int iModel;
1056    double scaleFactor = 1.0;
1057    for (iModel = 0; iModel < numberThreads_; iModel++) {
1058        //printf("model %d tree size %d\n",iModel,threadModel[iModel]->baseModel->tree()->size());
1059        if (saveTreeSize > 4*numberThreads_*defaultParallelNodes_) {
1060            if (!threadModel[iModel]->tree()->size()) {
1061                scaleFactor *= 1.05;
1062            }
1063        }
1064        threadModel[iModel]->moveToModel(baseModel, 11);
1065        // Update base model
1066        OsiObject ** threadObject = threadModel[iModel]->objects();
1067        for (iObject = 0; iObject < numberObjects_; iObject++) {
1068            object[iObject]->updateAfter(threadObject[iObject], saveObjects_[iObject]);
1069        }
1070    }
1071    if (scaleFactor != 1.0) {
1072        int newNumber = static_cast<int> (defaultParallelNodes_ * scaleFactor + 0.5001);
1073        if (newNumber*2 < defaultParallelIterations_) {
1074            if (defaultParallelNodes_ == 1)
1075                newNumber = 2;
1076            if (newNumber != defaultParallelNodes_) {
1077                char general[200];
1078                sprintf(general, "Changing tree size from %d to %d",
1079                        defaultParallelNodes_, newNumber);
1080                baseModel->messageHandler()->message(CBC_GENERAL,
1081                                                     baseModel->messages())
1082                << general << CoinMessageEol ;
1083                defaultParallelNodes_ = newNumber;
1084            }
1085        }
1086    }
1087    delete [] threadModel;
1088}
1089// Destructor
1090CbcBaseModel::~CbcBaseModel()
1091{
1092    delete [] threadCount_;
1093#if 1
1094    for (int i = 0; i < numberThreads_; i++)
1095        delete threadModel_[i];
1096    delete [] threadModel_;
1097    delete [] children_;
1098#endif
1099    for (int i = 0; i < numberObjects_; i++)
1100        delete saveObjects_[i];
1101    delete [] saveObjects_;
1102}
1103// Sets Dantzig state in children
1104void
1105CbcBaseModel::setDantzigState()
1106{
1107    for (int i = 0; i < numberThreads_; i++) {
1108        children_[i].setDantzigState(-1);
1109    }
1110}
1111static void * doNodesThread(void * voidInfo)
1112{
1113    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
1114    CbcModel * thisModel = stuff->thisModel();
1115    CbcModel * baseModel = stuff->baseModel();
1116    while (true) {
1117        stuff->waitThread();
1118        //printf("start node %x\n",stuff->node);
1119        int mode = thisModel->getNumberThreads();
1120        if (mode) {
1121            // normal
1122            double time2 = CoinCpuTime();
1123            assert (stuff->returnCode() == 0);
1124            if (thisModel->parallelMode() >= 0) {
1125                CbcNode * node = stuff->node();
1126                assert (node->nodeInfo());
1127                CbcNode * createdNode = stuff->createdNode();
1128                thisModel->doOneNode(baseModel, node, createdNode);
1129                stuff->setNode(node);
1130                stuff->setCreatedNode(createdNode);
1131                stuff->setReturnCode( 1);
1132            } else {
1133                assert (!stuff->node());
1134                assert (!stuff->createdNode());
1135                int numberIterations = stuff->nDeleteNode();
1136                int nDeleteNode = 0;
1137                int maxDeleteNode = stuff->maxDeleteNode();
1138                CbcNode ** delNode = stuff->delNode();
1139                int returnCode = 1;
1140                // this should be updated by heuristics strong branching etc etc
1141                assert (numberIterations > 0);
1142                thisModel->setNumberThreads(0);
1143                int nodesThisTime = thisModel->getNodeCount();
1144                int iterationsThisTime = thisModel->getIterationCount();
1145                int strongThisTime = thisModel->numberStrongIterations();
1146                thisModel->setStopNumberIterations(thisModel->getIterationCount() + numberIterations);
1147                int numberColumns = thisModel->getNumCols();
1148                int * used = CoinCopyOfArray(thisModel->usedInSolution(), numberColumns);
1149                int numberSolutions = thisModel->getSolutionCount();
1150                while (true) {
1151                    if (thisModel->tree()->empty()) {
1152                        returnCode = 1 + 1;
1153#ifdef CLP_INVESTIGATE_2
1154                        printf("%x tree empty - time %18.6f\n", thisModel, CoinGetTimeOfDay() - 1.2348e9);
1155#endif
1156                        break;
1157                    }
1158#define NODE_ITERATIONS 2
1159                    int nodesNow = thisModel->getNodeCount();
1160                    int iterationsNow = thisModel->getIterationCount();
1161                    int strongNow = thisModel->numberStrongIterations();
1162                    bool exit1 = (NODE_ITERATIONS * ((nodesNow - nodesThisTime) +
1163                                                     ((strongNow - strongThisTime) >> 1)) +
1164                                  (iterationsNow - iterationsThisTime) > numberIterations);
1165                    //bool exit2 =(thisModel->getIterationCount()>thisModel->getStopNumberIterations()) ;
1166                    //assert (exit1==exit2);
1167                    if (exit1 && nodesNow - nodesThisTime >= 10) {
1168                        // out of loop
1169                        //printf("out of loop\n");
1170#ifdef CLP_INVESTIGATE3
1171                        printf("%x tree %d nodes left, done %d and %d its - time %18.6f\n", thisModel,
1172                               thisModel->tree()->size(), nodesNow - nodesThisTime,
1173                               iterationsNow - iterationsThisTime, CoinGetTimeOfDay() - 1.2348e9);
1174#endif
1175                        break;
1176                    }
1177                    double cutoff = thisModel->getCutoff() ;
1178                    CbcNode *node = thisModel->tree()->bestNode(cutoff) ;
1179                    // Possible one on tree worse than cutoff
1180                    if (!node)
1181                        continue;
1182                    CbcNode * createdNode = NULL;
1183                    // Do real work of node
1184                    thisModel->doOneNode(NULL, node, createdNode);
1185                    assert (createdNode);
1186                    if (!createdNode->active()) {
1187                        delete createdNode;
1188                    } else {
1189                        // Say one more pointing to this **** postpone if marked
1190                        node->nodeInfo()->increment() ;
1191                        thisModel->tree()->push(createdNode) ;
1192                    }
1193                    if (node->active()) {
1194                        assert (node->nodeInfo());
1195                        if (node->nodeInfo()->numberBranchesLeft()) {
1196                            thisModel->tree()->push(node) ;
1197                        } else {
1198                            node->setActive(false);
1199                        }
1200                    } else {
1201                        if (node->nodeInfo()) {
1202                            if (!node->nodeInfo()->numberBranchesLeft())
1203                                node->nodeInfo()->allBranchesGone(); // can clean up
1204                            // So will delete underlying stuff
1205                            node->setActive(true);
1206                        }
1207                        if (nDeleteNode == maxDeleteNode) {
1208                            maxDeleteNode = (3 * maxDeleteNode) / 2 + 10;
1209                            stuff->setMaxDeleteNode(maxDeleteNode);
1210                            stuff->setDelNode(new CbcNode * [maxDeleteNode]);
1211                            for (int i = 0; i < nDeleteNode; i++)
1212                                stuff->delNode()[i] = delNode[i];
1213                            delete [] delNode;
1214                            delNode = stuff->delNode();
1215                        }
1216                        delNode[nDeleteNode++] = node;
1217                    }
1218                }
1219                // end of this sub-tree
1220                int * usedA = thisModel->usedInSolution();
1221                for (int i = 0; i < numberColumns; i++) {
1222                    usedA[i] -= used[i];
1223                }
1224                delete [] used;
1225                thisModel->setSolutionCount(thisModel->getSolutionCount() - numberSolutions);
1226                stuff->setNodesThisTime(thisModel->getNodeCount() - nodesThisTime);
1227                stuff->setIterationsThisTime(thisModel->getIterationCount() - iterationsThisTime);
1228                stuff->setNDeleteNode(nDeleteNode);
1229                stuff->setReturnCode( returnCode);
1230                thisModel->setNumberThreads(mode);
1231            }
1232            //printf("end node %x\n",stuff->node);
1233            stuff->unlockFromThread();
1234            stuff->incrementTimeInThread(CoinCpuTime() - time2);
1235        } else {
1236            // exit
1237            break;
1238        }
1239    }
1240    //printf("THREAD exiting\n");
1241    stuff->exitThread();
1242    return NULL;
1243}
1244static void * doHeurThread(void * voidInfo)
1245{
1246    typedef struct {
1247        double solutionValue;
1248        CbcModel * model;
1249        double * solution;
1250        int foundSol;
1251    } argBundle;
1252    argBundle * stuff = reinterpret_cast<argBundle *> (voidInfo);
1253    stuff->foundSol =
1254        stuff->model->heuristic(0)->solution(stuff->solutionValue,
1255                                             stuff->solution);
1256    return NULL;
1257}
1258static void * doCutsThread(void * voidInfo)
1259{
1260    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
1261    CbcModel * thisModel =  stuff->thisModel();
1262    while (true) {
1263        stuff->waitThread();
1264        //printf("start node %x\n",stuff->node);
1265        int mode = thisModel->getNumberThreads();
1266        if (mode) {
1267            // normal
1268            assert (stuff->returnCode() == 0);
1269            int fullScan = thisModel->getNodeCount() == 0 ? 1 : 0; //? was >0
1270            CbcCutGenerator * generator = thisModel->cutGenerator(stuff->dantzigState());
1271            generator->refreshModel(thisModel);
1272            OsiCuts * cuts = reinterpret_cast<OsiCuts *> (stuff->delNode());
1273            OsiSolverInterface * thisSolver = thisModel->solver();
1274            generator->generateCuts(*cuts, fullScan, thisSolver, NULL);
1275            stuff->setReturnCode( 1);
1276            stuff->unlockFromThread();
1277        } else {
1278            // exit
1279            break;
1280        }
1281    }
1282    stuff->exitThread();
1283    return NULL;
1284}
1285// Split up nodes - returns number of CbcNodeInfo's affected
1286int
1287CbcModel::splitModel(int numberModels, CbcModel ** model,
1288                     int numberNodes)
1289{
1290    int iModel;
1291    int i;
1292    for (iModel = 0; iModel < numberModels; iModel++) {
1293        CbcModel * otherModel = model[iModel];
1294        otherModel->moveToModel(this, 10);
1295        assert (!otherModel->tree()->size());
1296        otherModel->tree()->resetNodeNumbers();
1297        otherModel->bestPossibleObjective_ = bestPossibleObjective_;
1298        otherModel->sumChangeObjective1_ = sumChangeObjective1_;
1299        otherModel->sumChangeObjective2_ = sumChangeObjective2_;
1300        int numberColumns = solver_->getNumCols();
1301        if (otherModel->bestSolution_) {
1302            assert (bestSolution_);
1303            memcpy(otherModel->bestSolution_, bestSolution_, numberColumns*sizeof(double));
1304        } else if (bestSolution_) {
1305            otherModel->bestSolution_ = CoinCopyOfArray(bestSolution_, numberColumns);
1306        }
1307        otherModel->globalCuts_ = globalCuts_;
1308        otherModel->numberSolutions_ = numberSolutions_;
1309        otherModel->numberHeuristicSolutions_ = numberHeuristicSolutions_;
1310        otherModel->numberNodes_ = 1; //numberNodes_;
1311        otherModel->numberIterations_ = numberIterations_;
1312#ifdef JJF_ZERO
1313        if (maximumNumberCuts_ > otherModel->maximumNumberCuts_) {
1314            otherModel->maximumNumberCuts_ = maximumNumberCuts_;
1315            delete [] otherModel->addedCuts_;
1316            otherModel->addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
1317        }
1318        if (maximumDepth_ > otherModel->maximumDepth_) {
1319            otherModel->maximumDepth_ = maximumDepth_;
1320            delete [] otherModel->walkback_;
1321            otherModel->walkback_ = new CbcNodeInfo * [maximumDepth_];
1322        }
1323#endif
1324        otherModel->currentNumberCuts_ = currentNumberCuts_;
1325        if (otherModel->usedInSolution_) {
1326            assert (usedInSolution_);
1327            memcpy(otherModel->usedInSolution_, usedInSolution_, numberColumns*sizeof(int));
1328        } else if (usedInSolution_) {
1329            otherModel->usedInSolution_ = CoinCopyOfArray(usedInSolution_, numberColumns);
1330        }
1331        /// ??? tree_;
1332        // Need flag (stopNumberIterations_>0?) which says don't update cut etc counts
1333        for (i = 0; i < numberObjects_; i++) {
1334            otherModel->object_[i]->updateBefore(object_[i]);
1335        }
1336        otherModel->maximumDepthActual_ = maximumDepthActual_;
1337        // Real cuts are in node info
1338        otherModel->numberOldActiveCuts_ = numberOldActiveCuts_;
1339        otherModel->numberNewCuts_ = numberNewCuts_;
1340        otherModel->numberStrongIterations_ = numberStrongIterations_;
1341    }
1342    double cutoff = getCutoff();
1343    int nAffected = 0;
1344    while (!tree_->empty()) {
1345        for (iModel = 0; iModel < numberModels; iModel++) {
1346            if (tree_->empty())
1347                break;
1348            CbcModel * otherModel = model[iModel];
1349            CbcNode * node = tree_->bestNode(cutoff) ;
1350            CbcNodeInfo * nodeInfo = node->nodeInfo();
1351            assert (nodeInfo);
1352            if (!nodeInfo->marked()) {
1353                //while (nodeInfo&&!nodeInfo->marked()) {
1354                if (nAffected == maximumDepth_) {
1355                    redoWalkBack();
1356                }
1357                nodeInfo->mark();
1358                //nodeInfo->incrementCuts(1000000);
1359                walkback_[nAffected++] = nodeInfo;
1360                //nodeInfo = nodeInfo->parent() ;
1361                //}
1362            }
1363            // Make node join otherModel
1364            OsiBranchingObject * bobj = node->modifiableBranchingObject();
1365            CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
1366            //assert (cbcobj);
1367            if (cbcobj) {
1368                CbcObject * object = cbcobj->object();
1369                assert (object);
1370                int position = object->position();
1371                assert (position >= 0);
1372                assert (object_[position] == object);
1373                CbcObject * objectNew =
1374                    dynamic_cast<CbcObject *> (otherModel->object_[position]);
1375                cbcobj->setOriginalObject(objectNew);
1376            }
1377            otherModel->tree_->push(node);
1378        }
1379        numberNodes--;
1380        if (!numberNodes)
1381            break;
1382    }
1383    return nAffected;
1384}
1385// Start threads
1386void
1387CbcModel::startSplitModel(int /*numberIterations*/)
1388{
1389    abort();
1390}
1391// Merge models
1392void
1393CbcModel::mergeModels(int /*numberModel*/, CbcModel ** /*model*/,
1394                      int /*numberNodes*/)
1395{
1396    abort();
1397}
1398/* Move/copy information from one model to another
1399   -1 - initial setup
1400   0 - from base model
1401   1 - to base model (and reset)
1402   2 - add in final statistics etc (and reset so can do clean destruction)
1403   10 - from base model (deterministic)
1404   11 - to base model (deterministic)
1405*/
1406void
1407CbcModel::moveToModel(CbcModel * baseModel, int mode)
1408{
1409    if (mode == 0) {
1410        setCutoff(baseModel->getCutoff());
1411        bestObjective_ = baseModel->bestObjective_;
1412        //assert (!baseModel->globalCuts_.sizeRowCuts());
1413        if (numberSolutions_ < baseModel->numberSolutions_) {
1414          assert (baseModel->bestSolution_);
1415          int numberColumns = solver_->getNumCols();
1416          if (!bestSolution_)
1417            bestSolution_ = new double [numberColumns];
1418          memcpy(bestSolution_,baseModel->bestSolution_,
1419                 numberColumns*sizeof(double));
1420          numberSolutions_ = baseModel->numberSolutions_;
1421        }
1422        stateOfSearch_ = baseModel->stateOfSearch_;
1423        numberNodes_ = baseModel->numberNodes_;
1424        numberIterations_ = baseModel->numberIterations_;
1425        numberFixedAtRoot_ = numberIterations_; // for statistics
1426        numberSolves_ = 0;
1427        phase_ = baseModel->phase_;
1428        assert (!nextRowCut_);
1429        nodeCompare_ = baseModel->nodeCompare_;
1430        tree_ = baseModel->tree_;
1431        assert (!subTreeModel_);
1432        //branchingMethod_ = NULL; // need something but what
1433        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
1434        cutModifier_ = NULL;
1435        assert (!analyzeResults_);
1436        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1437        assert (stuff);
1438        //if (stuff)
1439        stuff->setCreatedNode(NULL);
1440        // ?? searchStrategy_;
1441        searchStrategy_ = baseModel->searchStrategy_;
1442        stuff->saveStuff()[0] = searchStrategy_;
1443        stateOfSearch_ = baseModel->stateOfSearch_;
1444        stuff->saveStuff()[1] = stateOfSearch_;
1445        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
1446            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
1447                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[iObject]) ;
1448            if (dynamicObject) {
1449                CbcSimpleIntegerDynamicPseudoCost * baseObject =
1450                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(baseModel->object_[iObject]) ;
1451                assert (baseObject);
1452                dynamicObject->copySome(baseObject);
1453            }
1454        }
1455    } else if (mode == 1) {
1456        lockThread();
1457        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1458        assert (stuff);
1459        //stateOfSearch_
1460        if (stuff->saveStuff()[0] != searchStrategy_) {
1461#ifdef COIN_DEVELOP
1462            printf("changing searchStrategy from %d to %d\n",
1463                   baseModel->searchStrategy_, searchStrategy_);
1464#endif
1465            baseModel->searchStrategy_ = searchStrategy_;
1466        }
1467        if (stuff->saveStuff()[1] != stateOfSearch_) {
1468#ifdef COIN_DEVELOP
1469            printf("changing stateOfSearch from %d to %d\n",
1470                   baseModel->stateOfSearch_, stateOfSearch_);
1471#endif
1472            baseModel->stateOfSearch_ = stateOfSearch_;
1473        }
1474        if (numberUpdateItems_) {
1475            for (int i = 0; i < numberUpdateItems_; i++) {
1476                CbcObjectUpdateData * update = updateItems_ + i;
1477                int objectNumber = update->objectNumber_;
1478                CbcObject * object = dynamic_cast<CbcObject *> (baseModel->object_[objectNumber]);
1479                if (object)
1480                    object->updateInformation(*update);
1481            }
1482            numberUpdateItems_ = 0;
1483        }
1484        if (eventHappened_)
1485            baseModel->eventHappened_ = true;
1486        baseModel->numberNodes_++;
1487        baseModel->numberIterations_ +=
1488            numberIterations_ - numberFixedAtRoot_;
1489        baseModel->numberSolves_ += numberSolves_;
1490        if (stuff->node())
1491            baseModel->tree_->push(stuff->node());
1492        if (stuff->createdNode())
1493            baseModel->tree_->push(stuff->createdNode());
1494        unlockThread();
1495    } else if (mode == 2) {
1496        baseModel->sumChangeObjective1_ += sumChangeObjective1_;
1497        baseModel->sumChangeObjective2_ += sumChangeObjective2_;
1498        //baseModel->numberIterations_ += numberIterations_;
1499        for (int iGenerator = 0; iGenerator < numberCutGenerators_; iGenerator++) {
1500            CbcCutGenerator * generator = baseModel->generator_[iGenerator];
1501            CbcCutGenerator * generator2 = generator_[iGenerator];
1502            generator->incrementNumberTimesEntered(generator2->numberTimesEntered());
1503            generator->incrementNumberCutsInTotal(generator2->numberCutsInTotal());
1504            generator->incrementNumberCutsActive(generator2->numberCutsActive());
1505            generator->incrementTimeInCutGenerator(generator2->timeInCutGenerator());
1506        }
1507        if (parallelMode() >= 0)
1508            nodeCompare_ = NULL;
1509        baseModel->maximumDepthActual_ = CoinMax(baseModel->maximumDepthActual_, maximumDepthActual_);
1510        baseModel->numberDJFixed_ += numberDJFixed_;
1511        baseModel->numberStrongIterations_ += numberStrongIterations_;
1512        int i;
1513        for (i = 0; i < 3; i++)
1514            baseModel->strongInfo_[i] += strongInfo_[i];
1515        if (parallelMode() >= 0) {
1516            walkback_ = NULL;
1517            lastNodeInfo_ = NULL;
1518            lastNumberCuts_ = NULL;
1519            lastCut_ = NULL;
1520            //addedCuts_ = NULL;
1521            tree_ = NULL;
1522        }
1523        eventHandler_ = NULL;
1524        delete solverCharacteristics_;
1525        solverCharacteristics_ = NULL;
1526        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
1527        if (newMethod) {
1528            // new method - we were using base models
1529            numberObjects_ = 0;
1530            object_ = NULL;
1531        }
1532    } else if (mode == -1) {
1533        delete eventHandler_;
1534        eventHandler_ = baseModel->eventHandler_;
1535        assert (!statistics_);
1536        assert(baseModel->solverCharacteristics_);
1537        solverCharacteristics_ = new OsiBabSolver (*baseModel->solverCharacteristics_);
1538        solverCharacteristics_->setSolver(solver_);
1539        setMaximumNodes(COIN_INT_MAX);
1540        if (parallelMode() >= 0) {
1541            delete [] walkback_;
1542            //delete [] addedCuts_;
1543            walkback_ = NULL;
1544            //addedCuts_ = NULL;
1545            delete [] lastNodeInfo_ ;
1546            lastNodeInfo_ = NULL;
1547            delete [] lastNumberCuts_ ;
1548            lastNumberCuts_ = NULL;
1549            delete [] lastCut_ ;
1550            lastCut_ = NULL;
1551            delete tree_;
1552            tree_ = NULL;
1553            delete nodeCompare_;
1554            nodeCompare_ = NULL;
1555        } else {
1556            delete tree_;
1557            tree_ = new CbcTree();
1558            tree_->setComparison(*nodeCompare_) ;
1559        }
1560        continuousSolver_ = baseModel->continuousSolver_->clone();
1561        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
1562        if (newMethod) {
1563            // new method uses solver - but point to base model
1564            // We may update an object in wrong order - shouldn't matter?
1565            numberObjects_ = baseModel->numberObjects_;
1566            if (parallelMode() >= 0) {
1567                object_ = baseModel->object_;
1568            } else {
1569                printf("*****WARNING - fix testosi option\n");
1570                object_ = baseModel->object_;
1571            }
1572        }
1573        int i;
1574        for (i = 0; i < numberHeuristics_; i++) {
1575            delete heuristic_[i];
1576            heuristic_[i] = baseModel->heuristic_[i]->clone();
1577            heuristic_[i]->setModelOnly(this);
1578        }
1579        for (i = 0; i < numberCutGenerators_; i++) {
1580            delete generator_[i];
1581            generator_[i] = new CbcCutGenerator(*baseModel->generator_[i]);
1582            // refreshModel was overkill as thought too many rows
1583            generator_[i]->setModel(this);
1584        }
1585    } else if (mode == 10) {
1586        setCutoff(baseModel->getCutoff());
1587        bestObjective_ = baseModel->bestObjective_;
1588        //assert (!baseModel->globalCuts_.sizeRowCuts());
1589        numberSolutions_ = baseModel->numberSolutions_;
1590        assert (usedInSolution_);
1591        assert (baseModel->usedInSolution_);
1592        memcpy(usedInSolution_, baseModel->usedInSolution_, solver_->getNumCols()*sizeof(int));
1593        stateOfSearch_ = baseModel->stateOfSearch_;
1594        //numberNodes_ = baseModel->numberNodes_;
1595        //numberIterations_ = baseModel->numberIterations_;
1596        //numberFixedAtRoot_ = numberIterations_; // for statistics
1597        phase_ = baseModel->phase_;
1598        assert (!nextRowCut_);
1599        delete nodeCompare_;
1600        nodeCompare_ = baseModel->nodeCompare_->clone();
1601        tree_->setComparison(*nodeCompare_) ;
1602        assert (!subTreeModel_);
1603        //branchingMethod_ = NULL; // need something but what
1604        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
1605        cutModifier_ = NULL;
1606        assert (!analyzeResults_);
1607        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1608        assert (stuff);
1609        //if (stuff)
1610        stuff->setCreatedNode(NULL);
1611        // ?? searchStrategy_;
1612        searchStrategy_ = baseModel->searchStrategy_;
1613        stuff->saveStuff()[0] = searchStrategy_;
1614        stateOfSearch_ = baseModel->stateOfSearch_;
1615        stuff->saveStuff()[1] = stateOfSearch_;
1616        OsiObject ** baseObject = baseModel->object_;
1617        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
1618            object_[iObject]->updateBefore(baseObject[iObject]);
1619        }
1620        //delete [] stuff->nodeCount;
1621        //stuff->nodeCount = new int [baseModel->maximumDepth_+1];
1622    } else if (mode == 11) {
1623        if (parallelMode() < 0) {
1624            // from deterministic
1625            CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1626            assert (stuff);
1627            // Move solution etc
1628            // might as well mark all including continuous
1629            int numberColumns = solver_->getNumCols();
1630            for (int i = 0; i < numberColumns; i++) {
1631                baseModel->usedInSolution_[i] += usedInSolution_[i];
1632                //usedInSolution_[i]=0;
1633            }
1634            baseModel->numberSolutions_ += numberSolutions_;
1635            if (bestObjective_ < baseModel->bestObjective_ && bestObjective_ < baseModel->getCutoff()) {
1636                baseModel->bestObjective_ = bestObjective_ ;
1637                int numberColumns = solver_->getNumCols();
1638                if (!baseModel->bestSolution_)
1639                    baseModel->bestSolution_ = new double[numberColumns];
1640                CoinCopyN(bestSolution_, numberColumns, baseModel->bestSolution_);
1641                baseModel->setCutoff(getCutoff());
1642            }
1643            //stateOfSearch_
1644            if (stuff->saveStuff()[0] != searchStrategy_) {
1645#ifdef COIN_DEVELOP
1646                printf("changing searchStrategy from %d to %d\n",
1647                       baseModel->searchStrategy_, searchStrategy_);
1648#endif
1649                baseModel->searchStrategy_ = searchStrategy_;
1650            }
1651            if (stuff->saveStuff()[1] != stateOfSearch_) {
1652#ifdef COIN_DEVELOP
1653                printf("changing stateOfSearch from %d to %d\n",
1654                       baseModel->stateOfSearch_, stateOfSearch_);
1655#endif
1656                baseModel->stateOfSearch_ = stateOfSearch_;
1657            }
1658            int i;
1659            if (eventHappened_)
1660                baseModel->eventHappened_ = true;
1661            baseModel->numberNodes_ += stuff->nodesThisTime();
1662            baseModel->numberIterations_ += stuff->iterationsThisTime();
1663            double cutoff = baseModel->getCutoff();
1664            while (!tree_->empty()) {
1665                CbcNode * node = tree_->bestNode(COIN_DBL_MAX) ;
1666                if (node->objectiveValue() < cutoff) {
1667                    assert(node->nodeInfo());
1668                    // Make node join correctly
1669                    OsiBranchingObject * bobj = node->modifiableBranchingObject();
1670                    CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
1671                    if (cbcobj) {
1672                        CbcObject * object = cbcobj->object();
1673                        assert (object);
1674                        int position = object->position();
1675                        assert (position >= 0);
1676                        assert (object_[position] == object);
1677                        CbcObject * objectNew =
1678                            dynamic_cast<CbcObject *> (baseModel->object_[position]);
1679                        cbcobj->setOriginalObject(objectNew);
1680                    }
1681                    baseModel->tree_->push(node);
1682                } else {
1683                    delete node;
1684                }
1685            }
1686            for (i = 0; i < stuff->nDeleteNode(); i++) {
1687                //printf("CbcNode %x stuff delete\n",stuff->delNode[i]);
1688                delete stuff->delNode()[i];
1689            }
1690        }
1691    } else {
1692        abort();
1693    }
1694}
1695// Generate one round of cuts - parallel mode
1696int
1697CbcModel::parallelCuts(CbcBaseModel * master, OsiCuts & theseCuts,
1698                       CbcNode * /*node*/, OsiCuts & slackCuts, int lastNumberCuts)
1699{
1700    /*
1701      Is it time to scan the cuts in order to remove redundant cuts? If so, set
1702      up to do it.
1703    */
1704    int fullScan = 0 ;
1705    if ((numberNodes_ % SCANCUTS) == 0 || (specialOptions_&256) != 0) {
1706        fullScan = 1 ;
1707        if (!numberNodes_ || (specialOptions_&256) != 0)
1708            fullScan = 2;
1709        specialOptions_ &= ~256; // mark as full scan done
1710    }
1711    // do cuts independently
1712    OsiCuts * eachCuts = new OsiCuts [numberCutGenerators_];;
1713    int i;
1714    assert (master);
1715    for (i = 0; i < numberThreads_; i++) {
1716        // set solver here after cloning
1717        master->model(i)->solver_ = solver_->clone();
1718        master->model(i)->numberNodes_ = (fullScan) ? 1 : 0;
1719    }
1720    // generate cuts
1721    int status = 0;
1722    const OsiRowCutDebugger * debugger = NULL;
1723    bool onOptimalPath = false;
1724    for (i = 0; i < numberCutGenerators_; i++) {
1725        bool generate = generator_[i]->normal();
1726        // skip if not optimal and should be (maybe a cut generator has fixed variables)
1727        if (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
1728            generate = false;
1729        if (generator_[i]->switchedOff())
1730            generate = false;;
1731        if (generate) {
1732            master->waitForThreadsInCuts(0, eachCuts + i, i);
1733        }
1734    }
1735    // wait
1736    master->waitForThreadsInCuts(1, eachCuts, 0);
1737    // Now put together
1738    for (i = 0; i < numberCutGenerators_; i++) {
1739        // add column cuts
1740        int numberColumnCutsBefore = theseCuts.sizeColCuts() ;
1741        int numberColumnCuts = eachCuts[i].sizeColCuts();
1742        int numberColumnCutsAfter = numberColumnCutsBefore
1743                                    + numberColumnCuts;
1744        int j;
1745        for (j = 0; j < numberColumnCuts; j++) {
1746            theseCuts.insert(eachCuts[i].colCut(j));
1747        }
1748        int numberRowCutsBefore = theseCuts.sizeRowCuts() ;
1749        int numberRowCuts = eachCuts[i].sizeRowCuts();
1750        // insert good cuts
1751        if (numberRowCuts) {
1752            int n = numberRowCuts;
1753            numberRowCuts = 0;
1754            for (j = 0; j < n; j++) {
1755                const OsiRowCut * thisCut = eachCuts[i].rowCutPtr(j) ;
1756                if (thisCut->lb() <= 1.0e10 && thisCut->ub() >= -1.0e10) {
1757                    theseCuts.insert(eachCuts[i].rowCut(j));
1758                    numberRowCuts++;
1759                }
1760            }
1761            if (generator_[i]->mustCallAgain() && status >= 0)
1762                status = 1; // say must go round
1763        }
1764        int numberRowCutsAfter = numberRowCutsBefore
1765                                 + numberRowCuts;
1766        if (numberRowCuts) {
1767            // Check last cut to see if infeasible
1768            const OsiRowCut * thisCut = theseCuts.rowCutPtr(numberRowCutsAfter - 1) ;
1769            if (thisCut->lb() > thisCut->ub()) {
1770                status = -1; // sub-problem is infeasible
1771                break;
1772            }
1773        }
1774#ifdef CBC_DEBUG
1775        {
1776            int k ;
1777            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1778                OsiRowCut thisCut = theseCuts.rowCut(k) ;
1779                /* check size of elements.
1780                   We can allow smaller but this helps debug generators as it
1781                   is unsafe to have small elements */
1782                int n = thisCut.row().getNumElements();
1783                const int * column = thisCut.row().getIndices();
1784                const double * element = thisCut.row().getElements();
1785                //assert (n);
1786                for (int i = 0; i < n; i++) {
1787                    double value = element[i];
1788                    assert(fabs(value) > 1.0e-12 && fabs(value) < 1.0e20);
1789                }
1790            }
1791        }
1792#endif
1793        if ((specialOptions_&1) != 0) {
1794            if (onOptimalPath) {
1795                int k ;
1796                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1797                    OsiRowCut thisCut = theseCuts.rowCut(k) ;
1798                    if (debugger->invalidCut(thisCut)) {
1799                        solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
1800                        solver_->writeMpsNative("badCut.mps", NULL, NULL, 2);
1801#ifdef NDEBUG
1802                        printf("Cut generator %d (%s) produced invalid cut (%dth in this go)\n",
1803                               i, generator_[i]->cutGeneratorName(), k - numberRowCutsBefore);
1804                        const double *lower = getColLower() ;
1805                        const double *upper = getColUpper() ;
1806                        int numberColumns = solver_->getNumCols();
1807                        for (int i = 0; i < numberColumns; i++)
1808                            printf("%d bounds %g,%g\n", i, lower[i], upper[i]);
1809                        abort();
1810#endif
1811                    }
1812                    assert(!debugger->invalidCut(thisCut)) ;
1813                }
1814            }
1815        }
1816        /*
1817          The cut generator has done its thing, and maybe it generated some
1818          cuts.  Do a bit of bookkeeping: load
1819          whichGenerator[i] with the index of the generator responsible for a cut,
1820          and place cuts flagged as global in the global cut pool for the model.
1821
1822          lastNumberCuts is the sum of cuts added in previous iterations; it's the
1823          offset to the proper starting position in whichGenerator.
1824        */
1825        int numberBefore =
1826            numberRowCutsBefore + numberColumnCutsBefore + lastNumberCuts ;
1827        int numberAfter =
1828            numberRowCutsAfter + numberColumnCutsAfter + lastNumberCuts ;
1829        // possibly extend whichGenerator
1830        resizeWhichGenerator(numberBefore, numberAfter);
1831
1832        for (j = numberRowCutsBefore; j < numberRowCutsAfter; j++) {
1833            whichGenerator_[numberBefore++] = i ;
1834            const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
1835            if (thisCut->lb() > thisCut->ub())
1836                status = -1; // sub-problem is infeasible
1837            if (thisCut->globallyValid()) {
1838                // add to global list
1839                OsiRowCut newCut(*thisCut);
1840                newCut.setGloballyValid(true);
1841                newCut.mutableRow().setTestForDuplicateIndex(false);
1842                globalCuts_.addCutIfNotDuplicate(newCut) ;
1843            }
1844        }
1845        for (j = numberColumnCutsBefore; j < numberColumnCutsAfter; j++) {
1846            //whichGenerator_[numberBefore++] = i ;
1847            const OsiColCut * thisCut = theseCuts.colCutPtr(j) ;
1848            if (thisCut->globallyValid()) {
1849                // add to global list
1850                makeGlobalCut(thisCut);
1851            }
1852        }
1853    }
1854    // Add in any violated saved cuts
1855    if (!theseCuts.sizeRowCuts() && !theseCuts.sizeColCuts()) {
1856        int numberOld = theseCuts.sizeRowCuts() + lastNumberCuts;
1857        int numberCuts = slackCuts.sizeRowCuts() ;
1858        int i;
1859        // possibly extend whichGenerator
1860        resizeWhichGenerator(numberOld, numberOld + numberCuts);
1861        double primalTolerance;
1862        solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
1863        for ( i = 0; i < numberCuts; i++) {
1864            const OsiRowCut * thisCut = slackCuts.rowCutPtr(i) ;
1865            if (thisCut->violated(cbcColSolution_) > 100.0*primalTolerance) {
1866                if (messageHandler()->logLevel() > 2)
1867                    printf("Old cut added - violation %g\n",
1868                           thisCut->violated(cbcColSolution_)) ;
1869                whichGenerator_[numberOld++] = -1;
1870                theseCuts.insert(*thisCut) ;
1871            }
1872        }
1873    }
1874    delete [] eachCuts;
1875    return status;
1876}
1877/*
1878  Locks a thread if parallel so that stuff like cut pool
1879  can be updated and/or used.
1880*/
1881void
1882CbcModel::lockThread()
1883{
1884    if (masterThread_ && (threadMode_&1) == 0)
1885        masterThread_->lockThread();
1886}
1887/*
1888  Unlocks a thread if parallel
1889*/
1890void
1891CbcModel::unlockThread()
1892{
1893    if (masterThread_ && (threadMode_&1) == 0)
1894        masterThread_->unlockThread();
1895}
1896// Returns true if locked
1897bool
1898CbcModel::isLocked() const
1899{
1900    if (masterThread_) {
1901        return (masterThread_->locked());
1902    } else {
1903        return true;
1904    }
1905}
1906// Stop a child
1907void
1908CbcModel::setInfoInChild(int type, CbcThread * info)
1909{
1910    if (type == -3) {
1911        // set up
1912        masterThread_ = info;
1913    } else if (type == -2) {
1914        numberThreads_ = 0; // signal to stop
1915    } else {
1916        // make sure message handler will be deleted
1917        defaultHandler_ = true;
1918        ownObjects_ = false;
1919        delete solverCharacteristics_;
1920        solverCharacteristics_ = NULL;
1921        if (type >= 0) {
1922            delete [] object_; // may be able to when all over to CbcThread
1923            for (int i = 0; i < numberCutGenerators_; i++) {
1924                delete generator_[i];
1925                generator_[i] = NULL;
1926                //delete virginGenerator_[i];
1927                //virginGenerator_[i]=NULL;
1928            }
1929            //generator_[0] = NULL;
1930            //delete [] generator_;
1931            //generator_ = NULL;
1932            numberCutGenerators_ = 0;
1933        } else {
1934            for (int i = 0; i < numberCutGenerators_; i++) {
1935                generator_[i] = NULL;
1936            }
1937        }
1938        object_ = NULL;
1939    }
1940}
1941
1942/// Indicates whether Cbc library has been compiled with multithreading support
1943bool CbcModel::haveMultiThreadSupport() { return true; }
1944
1945#else
1946// Default constructor
1947CbcBaseModel::CbcBaseModel() {}
1948
1949bool CbcModel::haveMultiThreadSupport() { return false; }
1950#endif
1951
Note: See TracBrowser for help on using the repository browser.