source: trunk/Cbc/src/CbcNodeInfo.cpp @ 2097

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

try and improve memory leaks (and clean up Clp pthread build problem)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.2 KB
Line 
1// $Id: CbcNodeInfo.cpp 2097 2014-11-21 10:57: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// Edwin 11/24/09 carved from CbcNode
7
8#if defined(_MSC_VER)
9// Turn off compiler warning about long names
10#  pragma warning(disable:4786)
11#endif
12
13#include "CbcConfig.h"
14
15#include <string>
16//#define CBC_DEBUG 1
17//#define CHECK_CUT_COUNTS
18//#define CHECK_NODE
19//#define CBC_CHECK_BASIS
20#include <cassert>
21#include <cfloat>
22#define CUTS
23#include "OsiSolverInterface.hpp"
24#include "OsiChooseVariable.hpp"
25#include "OsiAuxInfo.hpp"
26#include "OsiSolverBranch.hpp"
27#include "CoinWarmStartBasis.hpp"
28#include "CoinTime.hpp"
29#include "CbcModel.hpp"
30#include "CbcNode.hpp"
31#include "CbcStatistics.hpp"
32#include "CbcStrategy.hpp"
33#include "CbcBranchActual.hpp"
34#include "CbcBranchDynamic.hpp"
35#include "OsiRowCut.hpp"
36#include "OsiRowCutDebugger.hpp"
37#include "OsiCuts.hpp"
38#include "CbcCountRowCut.hpp"
39#include "CbcFeasibilityBase.hpp"
40#include "CbcMessage.hpp"
41#ifdef COIN_HAS_CLP
42#include "OsiClpSolverInterface.hpp"
43#include "ClpSimplexOther.hpp"
44#endif
45using namespace std;
46#include "CglCutGenerator.hpp"
47#include "CbcNodeInfo.hpp"
48
49// Default Constructor
50CbcNodeInfo::CbcNodeInfo ()
51        :
52        numberPointingToThis_(0),
53        parent_(NULL),
54        parentBranch_(NULL),
55        owner_(NULL),
56        numberCuts_(0),
57        nodeNumber_(0),
58        cuts_(NULL),
59        numberRows_(0),
60        numberBranchesLeft_(0),
61        active_(7)
62{
63#ifdef CHECK_NODE
64    printf("CbcNodeInfo %p Constructor\n", this);
65#endif
66}
67
68void
69CbcNodeInfo::setParentBasedData()
70{
71    if (parent_) {
72        numberRows_ = parent_->numberRows_ + parent_->numberCuts_;
73        //parent_->increment();
74        if (parent_->owner()) {
75            const OsiBranchingObject* br = parent_->owner()->branchingObject();
76            assert(br);
77            parentBranch_ = br->clone();
78        }
79    }
80}
81
82void
83CbcNodeInfo::unsetParentBasedData()
84{
85    if (parent_) {
86        numberRows_ = 0;
87        if (parent_->owner()) {
88            delete parentBranch_;
89            parentBranch_ = NULL;
90        }
91    }
92}
93
94#ifdef JJF_ZERO
95// Constructor given parent
96CbcNodeInfo::CbcNodeInfo (CbcNodeInfo * parent)
97        :
98        numberPointingToThis_(2),
99        parent_(parent),
100        parentBranch_(NULL),
101        owner_(NULL),
102        numberCuts_(0),
103        nodeNumber_(0),
104        cuts_(NULL),
105        numberRows_(0),
106        numberBranchesLeft_(2),
107        active_(7)
108{
109#ifdef CHECK_NODE
110    printf("CbcNodeInfo %p Constructor from parent %p\n", this, parent_);
111#endif
112    //setParentBasedData();
113}
114#endif
115
116// Copy Constructor
117CbcNodeInfo::CbcNodeInfo (const CbcNodeInfo & rhs)
118        :
119        numberPointingToThis_(rhs.numberPointingToThis_),
120        parent_(rhs.parent_),
121        parentBranch_(NULL),
122        owner_(rhs.owner_),
123        numberCuts_(rhs.numberCuts_),
124        nodeNumber_(rhs.nodeNumber_),
125        cuts_(NULL),
126        numberRows_(rhs.numberRows_),
127        numberBranchesLeft_(rhs.numberBranchesLeft_),
128        active_(rhs.active_)
129{
130#ifdef CHECK_NODE
131    printf("CbcNodeInfo %p Copy constructor\n", this);
132#endif
133    if (numberCuts_) {
134        cuts_ = new CbcCountRowCut * [numberCuts_];
135        int n = 0;
136        for (int i = 0; i < numberCuts_; i++) {
137            CbcCountRowCut * thisCut = rhs.cuts_[i];
138            if (thisCut) {
139                // I think this is correct - new one should take priority
140                thisCut->setInfo(this, n);
141                thisCut->increment(numberBranchesLeft_);
142                cuts_[n++] = thisCut;
143            }
144        }
145        numberCuts_ = n;
146    }
147    if (rhs.parentBranch_) {
148        parentBranch_ = rhs.parentBranch_->clone();
149    }
150}
151// Constructor given parent and owner
152CbcNodeInfo::CbcNodeInfo (CbcNodeInfo * parent, CbcNode * owner)
153        :
154        numberPointingToThis_(2),
155        parent_(parent),
156        parentBranch_(NULL),
157        owner_(owner),
158        numberCuts_(0),
159        nodeNumber_(0),
160        cuts_(NULL),
161        numberRows_(0),
162        numberBranchesLeft_(2),
163        active_(7)
164{
165#ifdef CHECK_NODE
166    printf("CbcNodeInfo %p Constructor from parent %p\n", this, parent_);
167#endif
168    //setParentBasedData();
169}
170
171/**
172   Take care to detach from the owning CbcNode and decrement the reference
173   count in the parent.  If this is the last nodeInfo object pointing to the
174   parent, make a recursive call to delete the parent.
175*/
176CbcNodeInfo::~CbcNodeInfo()
177{
178#ifdef CHECK_NODE
179    printf("CbcNodeInfo %p Destructor parent %p\n", this, parent_);
180    printf("cuts %p - number %d\n",cuts_,numberCuts_);
181#endif
182
183    assert(!numberPointingToThis_);
184    // But there may be some left (max nodes?)
185    for (int i = 0; i < numberCuts_; i++) {
186        if (cuts_[i]) {
187#ifndef GLOBAL_CUTS_JUST_POINTERS
188            delete cuts_[i];
189#else
190            if (cuts_[i]->globallyValidAsInteger() != 2)
191                delete cuts_[i];
192#endif
193        }
194    }
195    delete [] cuts_;
196    if (owner_)
197        owner_->nullNodeInfo();
198    if (parent_) {
199        int numberLinks = parent_->decrement();
200        if (!numberLinks) delete parent_;
201    }
202    delete parentBranch_;
203}
204
205
206//#define ALLCUTS
207void
208CbcNodeInfo::decrementCuts(int change)
209{
210    int i;
211    // get rid of all remaining if negative
212    int changeThis;
213    if (change < 0)
214        changeThis = numberBranchesLeft_;
215    else
216        changeThis = change;
217    // decrement cut counts
218    for (i = 0; i < numberCuts_; i++) {
219        if (cuts_[i]) {
220            int number = cuts_[i]->decrement(changeThis);
221            if (!number) {
222                //printf("info %p del cut %d %p\n",this,i,cuts_[i]);
223#ifndef GLOBAL_CUTS_JUST_POINTERS
224                delete cuts_[i];
225#else
226                if (cuts_[i]->globallyValidAsInteger() != 2)
227                    delete cuts_[i];
228#endif
229                cuts_[i] = NULL;
230            }
231        }
232    }
233}
234void
235CbcNodeInfo::incrementCuts(int change)
236{
237    int i;
238    assert (change > 0);
239    // increment cut counts
240    for (i = 0; i < numberCuts_; i++) {
241        if (cuts_[i])
242            cuts_[i]->increment(change);
243    }
244}
245void
246CbcNodeInfo::decrementParentCuts(CbcModel * model, int change)
247{
248    if (parent_) {
249        // get rid of all remaining if negative
250        int changeThis;
251        if (change < 0)
252            changeThis = numberBranchesLeft_;
253        else
254            changeThis = change;
255        int i;
256        // Get over-estimate of space needed for basis
257        CoinWarmStartBasis & dummy = model->workingBasis();
258        dummy.setSize(0, numberRows_ + numberCuts_);
259        buildRowBasis(dummy);
260        /* everything is zero (i.e. free) so we can use to see
261           if latest basis */
262        CbcNodeInfo * thisInfo = parent_;
263        while (thisInfo)
264            thisInfo = thisInfo->buildRowBasis(dummy);
265        // decrement cut counts
266        thisInfo = parent_;
267        int numberRows = numberRows_;
268        while (thisInfo) {
269            for (i = thisInfo->numberCuts_ - 1; i >= 0; i--) {
270                CoinWarmStartBasis::Status status = dummy.getArtifStatus(--numberRows);
271#ifdef ALLCUTS
272                status = CoinWarmStartBasis::isFree;
273#endif
274                if (thisInfo->cuts_[i]) {
275                    int number = 1;
276                    if (status != CoinWarmStartBasis::basic) {
277                        // tight - drop 1 or 2
278                        if (change < 0)
279                            number = thisInfo->cuts_[i]->decrement(changeThis);
280                        else
281                            number = thisInfo->cuts_[i]->decrement(change);
282                    }
283                    if (!number) {
284#ifndef GLOBAL_CUTS_JUST_POINTERS
285                        delete thisInfo->cuts_[i];
286#else
287                        if (thisInfo->cuts_[i]->globallyValidAsInteger() != 2)
288                            delete thisInfo->cuts_[i];
289#endif
290                        thisInfo->cuts_[i] = NULL;
291                    }
292                }
293            }
294            thisInfo = thisInfo->parent_;
295        }
296    }
297}
298#ifdef JJF_ZERO
299void
300CbcNodeInfo::incrementParentCuts(CbcModel * model, int change)
301{
302    if (parent_) {
303        int i;
304        // Get over-estimate of space needed for basis
305        CoinWarmStartBasis & dummy = model->workingBasis();
306        dummy.setSize(0, numberRows_ + numberCuts_);
307        /* everything is zero (i.e. free) so we can use to see
308           if latest basis */
309        buildRowBasis(dummy);
310        CbcNodeInfo * thisInfo = parent_;
311        while (thisInfo)
312            thisInfo = thisInfo->buildRowBasis(dummy);
313        // increment cut counts
314        thisInfo = parent_;
315        int numberRows = numberRows_;
316        while (thisInfo) {
317            for (i = thisInfo->numberCuts_ - 1; i >= 0; i--) {
318                CoinWarmStartBasis::Status status = dummy.getArtifStatus(--numberRows);
319#ifdef ALLCUTS
320                status = CoinWarmStartBasis::isFree;
321#endif
322                if (thisInfo->cuts_[i] && status != CoinWarmStartBasis::basic) {
323                    thisInfo->cuts_[i]->increment(change);
324                }
325            }
326            thisInfo = thisInfo->parent_;
327        }
328    }
329}
330#endif
331/*
332  Append cuts to the cuts_ array in a nodeInfo. The initial reference count
333  is set to numberToBranchOn, which will normally be the number of arms
334  defined for the CbcBranchingObject attached to the CbcNode that owns this
335  CbcNodeInfo.
336*/
337void
338CbcNodeInfo::addCuts (OsiCuts & cuts, int numberToBranchOn,
339                      /*int * whichGenerator,*/int numberPointingToThis)
340{
341    int numberCuts = cuts.sizeRowCuts();
342    if (numberCuts) {
343        int i;
344        if (!numberCuts_) {
345            cuts_ = new CbcCountRowCut * [numberCuts];
346        } else {
347            CbcCountRowCut ** temp = new CbcCountRowCut * [numberCuts+numberCuts_];
348            memcpy(temp, cuts_, numberCuts_*sizeof(CbcCountRowCut *));
349            delete [] cuts_;
350            cuts_ = temp;
351        }
352        for (i = 0; i < numberCuts; i++) {
353            CbcCountRowCut * thisCut = new CbcCountRowCut(*cuts.rowCutPtr(i),
354                    this, numberCuts_,
355                    -1, numberPointingToThis);
356            thisCut->increment(numberToBranchOn);
357            cuts_[numberCuts_++] = thisCut;
358#ifdef CBC_DEBUG
359#if CBC_DEBUG>1
360            int n = thisCut->row().getNumElements();
361            printf("Cut %d has %d entries, rhs %g %g =>", i, n, thisCut->lb(),
362                   thisCut->ub());
363            int j;
364            const int * index = thisCut->row().getIndices();
365            const double * element = thisCut->row().getElements();
366            for (j = 0; j < n; j++) {
367                printf(" (%d,%g)", index[j], element[j]);
368                assert(fabs(element[j]) > 1.00e-12);
369            }
370            printf("\n");
371#else
372            int n = thisCut->row().getNumElements();
373            int j;
374            const double * element = thisCut->row().getElements();
375            for (j = 0; j < n; j++) {
376                assert(fabs(element[j]) > 1.00e-12);
377            }
378#endif
379#endif
380        }
381    }
382}
383
384void
385CbcNodeInfo::addCuts(int numberCuts, CbcCountRowCut ** cut,
386                     int numberToBranchOn)
387{
388    if (numberCuts) {
389        int i;
390        if (!numberCuts_) {
391            cuts_ = new CbcCountRowCut * [numberCuts];
392        } else {
393            CbcCountRowCut ** temp = new CbcCountRowCut * [numberCuts+numberCuts_];
394            memcpy(temp, cuts_, numberCuts_*sizeof(CbcCountRowCut *));
395            delete [] cuts_;
396            cuts_ = temp;
397        }
398        for (i = 0; i < numberCuts; i++) {
399            CbcCountRowCut * thisCut = cut[i];
400            thisCut->setInfo(this, numberCuts_);
401            //printf("info %p cut %d %p\n",this,i,thisCut);
402            thisCut->increment(numberToBranchOn);
403            cuts_[numberCuts_++] = thisCut;
404#ifdef CBC_DEBUG
405            int n = thisCut->row().getNumElements();
406#if CBC_DEBUG>1
407            printf("Cut %d has %d entries, rhs %g %g =>", i, n, thisCut->lb(),
408                   thisCut->ub());
409#endif
410            int j;
411#if CBC_DEBUG>1
412            const int * index = thisCut->row().getIndices();
413#endif
414            const double * element = thisCut->row().getElements();
415            for (j = 0; j < n; j++) {
416#if CBC_DEBUG>1
417                printf(" (%d,%g)", index[j], element[j]);
418#endif
419                assert(fabs(element[j]) > 1.00e-12);
420            }
421            printf("\n");
422#endif
423        }
424    }
425}
426
427// delete cuts
428void
429CbcNodeInfo::deleteCuts(int numberToDelete, CbcCountRowCut ** cuts)
430{
431    int i;
432    int j;
433    int last = -1;
434    for (i = 0; i < numberToDelete; i++) {
435        CbcCountRowCut * next = cuts[i];
436        for (j = last + 1; j < numberCuts_; j++) {
437            if (next == cuts_[j])
438                break;
439        }
440        if (j == numberCuts_) {
441            // start from beginning
442            for (j = 0; j < last; j++) {
443                if (next == cuts_[j])
444                    break;
445            }
446            assert(j < last);
447        }
448        last = j;
449        int number = cuts_[j]->decrement();
450        if (!number) {
451#ifndef GLOBAL_CUTS_JUST_POINTERS
452            delete cuts_[j];
453#else
454            if (cuts_[j]->globallyValidAsInteger() != 2)
455                delete cuts_[j];
456#endif
457        }
458        cuts_[j] = NULL;
459    }
460    j = 0;
461    for (i = 0; i < numberCuts_; i++) {
462        if (cuts_[i])
463            cuts_[j++] = cuts_[i];
464    }
465    numberCuts_ = j;
466}
467
468// delete cuts
469void
470CbcNodeInfo::deleteCuts(int numberToDelete, int * which)
471{
472    int i;
473    for (i = 0; i < numberToDelete; i++) {
474        int iCut = which[i];
475        int number = cuts_[iCut]->decrement();
476        if (!number) {
477#ifndef GLOBAL_CUTS_JUST_POINTERS
478            delete cuts_[iCut];
479#else
480            if (cuts_[iCut]->globallyValidAsInteger() != 2)
481                delete cuts_[iCut];
482#endif
483        }
484        cuts_[iCut] = NULL;
485    }
486    int j = 0;
487    for (i = 0; i < numberCuts_; i++) {
488        if (cuts_[i])
489            cuts_[j++] = cuts_[i];
490    }
491    numberCuts_ = j;
492}
493
494// Really delete a cut
495void
496CbcNodeInfo::deleteCut(int whichOne)
497{
498    assert(whichOne < numberCuts_);
499    cuts_[whichOne] = NULL;
500}
501/* Deactivate node information.
502   1 - bounds
503   2 - cuts
504   4 - basis!
505*/
506void
507CbcNodeInfo::deactivate(int mode)
508{
509    active_ &= (~mode);
510    if (mode==7) {
511      for (int i = 0; i < numberCuts_; i++) {
512        delete cuts_[i];
513        cuts_[i] = NULL;
514      }
515      delete [] cuts_;
516      cuts_=NULL;
517      numberCuts_=0;
518    }
519}
520
Note: See TracBrowser for help on using the repository browser.