source: trunk/Cbc/src/CbcHeuristicFPump.cpp @ 1014

Last change on this file since 1014 was 1014, checked in by forrest, 11 years ago

left in printing by mistake!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.6 KB
Line 
1// Copyright (C) 2004, International Business Machines
2// Corporation and others.  All Rights Reserved.
3#if defined(_MSC_VER)
4// Turn off compiler warning about long names
5#  pragma warning(disable:4786)
6#endif
7#include <cassert>
8#include <cstdlib>
9#include <cmath>
10#include <cfloat>
11
12#include "OsiSolverInterface.hpp"
13#include "CbcModel.hpp"
14#include "CbcMessage.hpp"
15#include "CbcHeuristicFPump.hpp"
16#include "CbcBranchActual.hpp"
17#include "CoinHelperFunctions.hpp"
18#include "CoinWarmStartBasis.hpp"
19#include "CoinTime.hpp"
20#include "CbcEventHandler.hpp"
21
22
23// Default Constructor
24CbcHeuristicFPump::CbcHeuristicFPump() 
25  :CbcHeuristic(),
26   startTime_(0.0),
27   maximumTime_(0.0),
28   fakeCutoff_(COIN_DBL_MAX),
29   absoluteIncrement_(0.0),
30   relativeIncrement_(0.0),
31   defaultRounding_(0.49999),
32   initialWeight_(0.0),
33   weightFactor_(0.1),
34   artificialCost_(COIN_DBL_MAX),
35   iterationRatio_(0.0),
36   maximumPasses_(100),
37   maximumRetries_(1),
38   accumulate_(0),
39   fixOnReducedCosts_(1),
40   roundExpensive_(false)
41{
42  setWhen(1);
43}
44
45// Constructor from model
46CbcHeuristicFPump::CbcHeuristicFPump(CbcModel & model,
47                                     double downValue,bool roundExpensive)
48  :CbcHeuristic(model),
49   startTime_(0.0),
50   maximumTime_(0.0),
51   fakeCutoff_(COIN_DBL_MAX),
52   absoluteIncrement_(0.0),
53   relativeIncrement_(0.0),
54   defaultRounding_(downValue),
55   initialWeight_(0.0),
56   weightFactor_(0.1),
57   artificialCost_(COIN_DBL_MAX),
58   iterationRatio_(0.0),
59   maximumPasses_(100),
60   maximumRetries_(1),
61   accumulate_(0),
62   fixOnReducedCosts_(1),
63   roundExpensive_(roundExpensive)
64{
65  setWhen(1);
66}
67
68// Destructor
69CbcHeuristicFPump::~CbcHeuristicFPump ()
70{
71}
72
73// Clone
74CbcHeuristic *
75CbcHeuristicFPump::clone() const
76{
77  return new CbcHeuristicFPump(*this);
78}
79// Create C++ lines to get to current state
80void 
81CbcHeuristicFPump::generateCpp( FILE * fp) 
82{
83  CbcHeuristicFPump other;
84  fprintf(fp,"0#include \"CbcHeuristicFPump.hpp\"\n");
85  fprintf(fp,"3  CbcHeuristicFPump heuristicFPump(*cbcModel);\n");
86  CbcHeuristic::generateCpp(fp,"heuristicFPump");
87  if (maximumPasses_!=other.maximumPasses_)
88    fprintf(fp,"3  heuristicFPump.setMaximumPasses(%d);\n",maximumPasses_);
89  else
90    fprintf(fp,"4  heuristicFPump.setMaximumPasses(%d);\n",maximumPasses_);
91  if (maximumRetries_!=other.maximumRetries_)
92    fprintf(fp,"3  heuristicFPump.setMaximumRetries(%d);\n",maximumRetries_);
93  else
94    fprintf(fp,"4  heuristicFPump.setMaximumRetries(%d);\n",maximumRetries_);
95  if (accumulate_!=other.accumulate_)
96    fprintf(fp,"3  heuristicFPump.setAccumulate(%d);\n",accumulate_);
97  else
98    fprintf(fp,"4  heuristicFPump.setAccumulate(%d);\n",accumulate_);
99  if (fixOnReducedCosts_!=other.fixOnReducedCosts_)
100    fprintf(fp,"3  heuristicFPump.setFixOnReducedCosts(%d);\n",fixOnReducedCosts_);
101  else
102    fprintf(fp,"4  heuristicFPump.setFixOnReducedCosts(%d);\n",fixOnReducedCosts_);
103  if (maximumTime_!=other.maximumTime_)
104    fprintf(fp,"3  heuristicFPump.setMaximumTime(%g);\n",maximumTime_);
105  else
106    fprintf(fp,"4  heuristicFPump.setMaximumTime(%g);\n",maximumTime_);
107  if (fakeCutoff_!=other.fakeCutoff_)
108    fprintf(fp,"3  heuristicFPump.setFakeCutoff(%g);\n",fakeCutoff_);
109  else
110    fprintf(fp,"4  heuristicFPump.setFakeCutoff(%g);\n",fakeCutoff_);
111  if (absoluteIncrement_!=other.absoluteIncrement_)
112    fprintf(fp,"3  heuristicFPump.setAbsoluteIncrement(%g);\n",absoluteIncrement_);
113  else
114    fprintf(fp,"4  heuristicFPump.setAbsoluteIncrement(%g);\n",absoluteIncrement_);
115  if (relativeIncrement_!=other.relativeIncrement_)
116    fprintf(fp,"3  heuristicFPump.setRelativeIncrement(%g);\n",relativeIncrement_);
117  else
118    fprintf(fp,"4  heuristicFPump.setRelativeIncrement(%g);\n",relativeIncrement_);
119  if (defaultRounding_!=other.defaultRounding_)
120    fprintf(fp,"3  heuristicFPump.setDefaultRounding(%g);\n",defaultRounding_);
121  else
122    fprintf(fp,"4  heuristicFPump.setDefaultRounding(%g);\n",defaultRounding_);
123  fprintf(fp,"3  cbcModel->addHeuristic(&heuristicFPump);\n");
124  if (initialWeight_!=other.initialWeight_)
125    fprintf(fp,"3  heuristicFPump.setInitialWeight(%g);\n",initialWeight_);
126  else
127    fprintf(fp,"4  heuristicFPump.setInitialWeight(%g);\n",initialWeight_);
128  if (weightFactor_!=other.weightFactor_)
129    fprintf(fp,"3  heuristicFPump.setWeightFactor(%g);\n",weightFactor_);
130  else
131    fprintf(fp,"4  heuristicFPump.setWeightFactor(%g);\n",weightFactor_);
132}
133
134// Copy constructor
135CbcHeuristicFPump::CbcHeuristicFPump(const CbcHeuristicFPump & rhs)
136:
137  CbcHeuristic(rhs),
138  startTime_(rhs.startTime_),
139  maximumTime_(rhs.maximumTime_),
140  fakeCutoff_(rhs.fakeCutoff_),
141  absoluteIncrement_(rhs.absoluteIncrement_),
142  relativeIncrement_(rhs.relativeIncrement_),
143  defaultRounding_(rhs.defaultRounding_),
144  initialWeight_(rhs.initialWeight_),
145  weightFactor_(rhs.weightFactor_),
146  artificialCost_(rhs.artificialCost_),
147  iterationRatio_(rhs.iterationRatio_),
148  maximumPasses_(rhs.maximumPasses_),
149  maximumRetries_(rhs.maximumRetries_),
150  accumulate_(rhs.accumulate_),
151  fixOnReducedCosts_(rhs.fixOnReducedCosts_),
152  roundExpensive_(rhs.roundExpensive_)
153{
154}
155
156// Assignment operator
157CbcHeuristicFPump & 
158CbcHeuristicFPump::operator=( const CbcHeuristicFPump& rhs)
159{
160  if (this!=&rhs) {
161    CbcHeuristic::operator=(rhs);
162    startTime_ = rhs.startTime_;
163    maximumTime_ = rhs.maximumTime_;
164    fakeCutoff_ = rhs.fakeCutoff_;
165    absoluteIncrement_ = rhs.absoluteIncrement_;
166    relativeIncrement_ = rhs.relativeIncrement_;
167    defaultRounding_ = rhs.defaultRounding_;
168    initialWeight_ = rhs.initialWeight_;
169    weightFactor_ = rhs.weightFactor_;
170    artificialCost_ = rhs.artificialCost_;
171    iterationRatio_ = rhs.iterationRatio_;
172    maximumPasses_ = rhs.maximumPasses_;
173    maximumRetries_ = rhs.maximumRetries_;
174    accumulate_ = rhs.accumulate_;
175    fixOnReducedCosts_ = rhs.fixOnReducedCosts_;
176    roundExpensive_ = rhs.roundExpensive_;
177  }
178  return *this;
179}
180
181// Resets stuff if model changes
182void 
183CbcHeuristicFPump::resetModel(CbcModel * model)
184{
185}
186
187/**************************BEGIN MAIN PROCEDURE ***********************************/
188
189// See if feasibility pump will give better solution
190// Sets value of solution
191// Returns 1 if solution, 0 if not
192int
193CbcHeuristicFPump::solution(double & solutionValue,
194                         double * betterSolution)
195{
196  numCouldRun_++;
197  double incomingObjective = solutionValue;
198#define LEN_PRINT 200
199  char pumpPrint[LEN_PRINT];
200  pumpPrint[0]='\0';
201  if (!when()||(when()==1&&model_->phase()!=1))
202    return 0; // switched off
203  // See if at root node
204  bool atRoot = model_->getNodeCount()==0;
205  int passNumber = model_->getCurrentPassNumber();
206  // just do once
207  if (!atRoot||passNumber!=1)
208    return 0;
209  // probably a good idea
210  //if (model_->getSolutionCount()) return 0;
211  // loop round doing repeated pumps
212  double cutoff;
213  model_->solver()->getDblParam(OsiDualObjectiveLimit,cutoff);
214  double direction = model_->solver()->getObjSense();
215  cutoff *= direction;
216  int numberBandBsolutions=0;
217  double firstCutoff = fabs(cutoff);
218  cutoff = CoinMin(cutoff,solutionValue);
219  // check plausible and space for rounded solution
220  int numberColumns = model_->getNumCols();
221  int numberIntegers = model_->numberIntegers();
222  const int * integerVariableOrig = model_->integerVariable();
223  double iterationLimit = -1.0;
224  //iterationRatio_=1.0;
225  if (iterationRatio_>0.0)
226    iterationLimit = (2*model_->solver()->getNumRows()+2*numberColumns)*
227      iterationRatio_;
228  double totalNumberIterations=0.0;
229  // 1. initially check 0-1
230  int i,j;
231  int general=0;
232  int * integerVariable = new int[numberIntegers];
233  const double * lower = model_->solver()->getColLower();
234  const double * upper = model_->solver()->getColUpper();
235  bool doGeneral = (accumulate_&(4+8))!=0;
236  j=0;
237  for (i=0;i<numberIntegers;i++) {
238    int iColumn = integerVariableOrig[i];
239#ifndef NDEBUG
240    const OsiObject * object = model_->object(i);
241    const CbcSimpleInteger * integerObject = 
242      dynamic_cast<const  CbcSimpleInteger *> (object);
243    const OsiSimpleInteger * integerObject2 = 
244      dynamic_cast<const  OsiSimpleInteger *> (object);
245    assert(integerObject||integerObject2);
246#endif
247    if (upper[iColumn]-lower[iColumn]>1.000001) {
248      general++;
249      if (doGeneral)
250        integerVariable[j++]=iColumn;
251    } else {
252      integerVariable[j++]=iColumn;
253    }
254  }
255  if (general*3>2*numberIntegers&&!doGeneral) {
256    delete [] integerVariable;
257    return 0;
258  } else if ((accumulate_&8)==0) {
259    doGeneral=false;
260  }
261  if (!general)
262    doGeneral=false;
263  // For solution closest to feasible if none found
264  int * closestSolution = general ? NULL : new int[numberIntegers];
265  double closestObjectiveValue = COIN_DBL_MAX;
266 
267  int numberIntegersOrig = numberIntegers;
268  numberIntegers = j;
269  double * newSolution = new double [numberColumns];
270  double newSolutionValue=COIN_DBL_MAX;
271  bool solutionFound=false;
272  char * usedColumn = NULL;
273  double * lastSolution=NULL;
274  int fixContinuous=0;
275  bool fixInternal=false;
276  bool allSlack=false;
277  if (when_>=21&&when_<=25) {
278    when_ -= 10;
279    allSlack=true;
280  }
281  double time1 = CoinCpuTime();
282  model_->solver()->resolve();
283  if (!model_->solver()->isProvenOptimal()) {
284    // presumably max time or some such
285    return 0;
286  }
287  numRuns_++;
288  if (cutoff<1.0e50&&false) {
289    // Fix on djs
290    double direction = model_->solver()->getObjSense() ;
291    double gap = cutoff - model_->solver()->getObjValue()*direction ;
292    double tolerance;
293    model_->solver()->getDblParam(OsiDualTolerance,tolerance) ;
294    if (gap>0.0) {
295      gap += 100.0*tolerance;
296      int nFix=model_->solver()->reducedCostFix(gap);
297      printf("dj fixing fixed %d variables\n",nFix);
298    }
299  }
300  CoinWarmStartBasis saveBasis;
301  CoinWarmStartBasis * basis =
302    dynamic_cast<CoinWarmStartBasis *>(model_->solver()->getWarmStart()) ;
303  if (basis) {
304    saveBasis = * basis;
305    delete basis;
306  }
307  double continuousObjectiveValue = model_->solver()->getObjValue()*model_->solver()->getObjSense();
308  double * firstPerturbedObjective = NULL;
309  double * firstPerturbedSolution = NULL;
310  if (when_>=11&&when_<=15) {
311    fixInternal = when_ >11&&when_<15;
312    if (when_<13)
313      fixContinuous = 0;
314    else if (when_!=14)
315      fixContinuous=1;
316    else
317      fixContinuous=2;
318    when_=1;
319    usedColumn = new char [numberColumns];
320    memset(usedColumn,0,numberColumns);
321    lastSolution = CoinCopyOfArray(model_->solver()->getColSolution(),numberColumns);
322  }
323  int finalReturnCode=0;
324  int totalNumberPasses=0;
325  int numberTries=0;
326  CoinWarmStartBasis bestBasis;
327  bool exitAll=false;
328  double saveBestObjective = model_->getMinimizationObjValue();
329  int numberSolutions=0;
330  OsiSolverInterface * solver = NULL;
331  double artificialFactor = 0.00001;
332  // also try rounding!
333  double * roundingSolution = new double[numberColumns];
334  double roundingObjective = solutionValue;
335  CbcRounding roundingHeuristic(*model_);
336  while (!exitAll) {
337    int numberPasses=0;
338    artificialFactor *= 10.0;
339    int lastMove= (!numberTries) ? -10 : 1000000;
340    double lastSumInfeas=COIN_DBL_MAX;
341    numberTries++;
342    // Clone solver - otherwise annoys root node computations
343    solver = model_->solver()->clone();
344    if (CoinMin(fakeCutoff_,cutoff)<1.0e50) {
345      // Fix on djs
346      double direction = solver->getObjSense() ;
347      double gap = CoinMin(fakeCutoff_,cutoff) - solver->getObjValue()*direction ;
348      double tolerance;
349      solver->getDblParam(OsiDualTolerance,tolerance) ;
350      if (gap>0.0&&(fixOnReducedCosts_==1||(numberTries==1&&fixOnReducedCosts_==2))) {
351        gap += 100.0*tolerance;
352        int nFix=solver->reducedCostFix(gap);
353        if (nFix) {
354          sprintf(pumpPrint,"Reduced cost fixing fixed %d variables on major pass %d",nFix,numberTries);
355          model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
356            << pumpPrint
357            <<CoinMessageEol;
358          //pumpPrint[0]='\0';
359        }
360      }
361    }
362    // if cutoff exists then add constraint
363    bool useCutoff = (fabs(cutoff)<1.0e20&&(fakeCutoff_!=COIN_DBL_MAX||numberTries>1));
364    // but there may be a close one
365    if (firstCutoff<2.0*solutionValue&&numberTries==1) 
366      useCutoff=true;
367    if (useCutoff) {
368      cutoff = CoinMin(cutoff,fakeCutoff_);
369      const double * objective = solver->getObjCoefficients();
370      int numberColumns = solver->getNumCols();
371      int * which = new int[numberColumns];
372      double * els = new double[numberColumns];
373      int nel=0;
374      for (int i=0;i<numberColumns;i++) {
375        double value = objective[i];
376        if (value) {
377          which[nel]=i;
378          els[nel++] = direction*value;
379        }
380      }
381      double offset;
382      solver->getDblParam(OsiObjOffset,offset);
383#ifdef COIN_DEVELOP
384      if (offset)
385        printf("CbcHeuristicFPump obj offset %g\n",offset);
386#endif
387      solver->addRow(nel,which,els,-COIN_DBL_MAX,cutoff+offset*direction);
388      delete [] which;
389      delete [] els;
390      bool takeHint;
391      OsiHintStrength strength;
392      solver->getHintParam(OsiDoDualInResolve,takeHint,strength);
393      solver->setHintParam(OsiDoDualInResolve,true,OsiHintDo);
394      solver->resolve();
395      solver->setHintParam(OsiDoDualInResolve,takeHint,strength);
396      if (!solver->isProvenOptimal()) {
397        // presumably max time or some such
398        exitAll=true;
399        break;
400      }
401    }
402    solver->setDblParam(OsiDualObjectiveLimit,1.0e50);
403    solver->resolve();
404    // Solver may not be feasible
405    if (!solver->isProvenOptimal()) {
406      exitAll=true;
407      break;
408    }
409    const double * lower = solver->getColLower();
410    const double * upper = solver->getColUpper();
411    const double * solution = solver->getColSolution();
412    if (lastSolution)
413      memcpy(lastSolution,solution,numberColumns*sizeof(double));
414    double primalTolerance;
415    solver->getDblParam(OsiPrimalTolerance,primalTolerance);
416   
417   
418    // 2 space for last rounded solutions
419#define NUMBER_OLD 4
420    double ** oldSolution = new double * [NUMBER_OLD];
421    for (j=0;j<NUMBER_OLD;j++) {
422      oldSolution[j]= new double[numberColumns];
423      for (i=0;i<numberColumns;i++) oldSolution[j][i]=-COIN_DBL_MAX;
424    }
425   
426    // 3. Replace objective with an initial 0-valued objective
427    double * saveObjective = new double [numberColumns];
428    memcpy(saveObjective,solver->getObjCoefficients(),numberColumns*sizeof(double));
429    for (i=0;i<numberColumns;i++) {
430      solver->setObjCoeff(i,0.0);
431    }
432    bool finished=false;
433    double direction = solver->getObjSense();
434    int returnCode=0;
435    bool takeHint;
436    OsiHintStrength strength;
437    solver->getHintParam(OsiDoDualInResolve,takeHint,strength);
438    solver->setHintParam(OsiDoDualInResolve,false);
439    //solver->messageHandler()->setLogLevel(0);
440   
441    // 4. Save objective offset so we can see progress
442    double saveOffset;
443    solver->getDblParam(OsiObjOffset,saveOffset);
444    // Get amount for original objective
445    double scaleFactor = 0.0;
446#ifdef COIN_DEVELOP
447    double largestCost=0.0;
448    int nArtificial=0;
449#endif
450    for (i=0;i<numberColumns;i++) {
451      double value = saveObjective[i];
452      scaleFactor += value*value;
453#ifdef COIN_DEVELOP
454      largestCost=CoinMax(largestCost,fabs(value));
455      if (value*direction>=artificialCost_)
456        nArtificial++;
457#endif
458    }
459    if (scaleFactor)
460      scaleFactor = (initialWeight_*sqrt((double) numberIntegers))/sqrt(scaleFactor);
461#ifdef COIN_DEVELOP
462    if (scaleFactor)
463      printf("Using %g fraction of original objective - largest %g - %d artificials\n",scaleFactor,
464             largestCost,nArtificial);
465#endif
466    // 5. MAIN WHILE LOOP
467    //bool newLineNeeded=false;
468    while (!finished) {
469      double newTrueSolutionValue=0.0;
470      double newSumInfeas=0.0;
471      int newNumberInfeas=0;
472      returnCode=0;
473      if (model_->getCurrentSeconds()>model_->getMaximumSeconds()) {
474        exitAll=true;
475        break;
476      }
477      // see what changed
478      if (usedColumn) {
479        for (i=0;i<numberColumns;i++) {
480          if (fabs(solution[i]-lastSolution[i])>1.0e-8) 
481            usedColumn[i]=1;
482          lastSolution[i]=solution[i];
483        }
484      }
485      if (iterationLimit<0.0) {
486        if (numberPasses>=maximumPasses_) {
487          // If going well then keep going if maximumPasses_ small
488          if (lastMove<numberPasses-4||lastMove==1000000)
489            break;
490          if (maximumPasses_>20||numberPasses>=40)
491            break;
492        }
493      } else if (totalNumberIterations>iterationLimit&&numberPasses>15) {
494          // exiting on iteration count
495        break;
496      } else if (maximumPasses_<30&&numberPasses>100) {
497        // too many passes anyway
498        break;
499      }
500      if (maximumTime_>0.0&&CoinCpuTime()>=startTime_+maximumTime_) break;
501      memcpy(newSolution,solution,numberColumns*sizeof(double));
502      int flip;
503      if (numberPasses==0&&false) {
504        // always use same seed
505        randomNumberGenerator_.setSeed(987654321);
506      }
507      returnCode = rounds(solver, newSolution,saveObjective,numberIntegers,integerVariable,
508                          pumpPrint,numberPasses,roundExpensive_,defaultRounding_,&flip);
509      if (numberPasses==0&&false) {
510        // Make sure random will be different
511        for (i=1;i<numberTries;i++)
512          randomNumberGenerator_.randomDouble();
513      }
514      numberPasses++;
515      if (returnCode) {
516        // SOLUTION IS INTEGER
517        // Put back correct objective
518        for (i=0;i<numberColumns;i++)
519          solver->setObjCoeff(i,saveObjective[i]);
520
521        // solution - but may not be better
522        // Compute using dot product
523        solver->setDblParam(OsiObjOffset,saveOffset);
524        newSolutionValue = -saveOffset;
525        for (  i=0 ; i<numberColumns ; i++ )
526          newSolutionValue += saveObjective[i]*newSolution[i];
527        newSolutionValue *= direction;
528        sprintf(pumpPrint,"Solution found of %g",newSolutionValue);
529        model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
530          << pumpPrint
531          <<CoinMessageEol;
532        //newLineNeeded=false;
533        if (newSolutionValue<solutionValue) {
534          double saveValue = solutionValue;
535          if (!doGeneral) {
536            int numberLeft=0;
537            for (i=0;i<numberIntegersOrig;i++) {
538              int iColumn = integerVariableOrig[i];
539              double value = floor(newSolution[iColumn]+0.5);
540              if(solver->isBinary(iColumn)) {
541                solver->setColLower(iColumn,value);
542                solver->setColUpper(iColumn,value);
543              } else {
544                if (fabs(value-newSolution[iColumn])>1.0e-7) 
545                  numberLeft++;
546              }
547            }
548            if (numberLeft) {
549              sprintf(pumpPrint,"Branch and bound needed to clear up %d general integers",numberLeft);
550              model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
551                << pumpPrint
552                <<CoinMessageEol;
553              returnCode = smallBranchAndBound(solver,numberNodes_,newSolution,newSolutionValue,
554                                               solutionValue,"CbcHeuristicFpump");
555              if (returnCode<0) {
556                if (returnCode==-2)
557                  exitAll=true;
558                returnCode=0; // returned on size or event
559              }
560              if ((returnCode&2)!=0) {
561                // could add cut
562                returnCode &= ~2;
563              }
564              if (returnCode!=1)
565                newSolutionValue=saveValue;
566              if (returnCode&&newSolutionValue<saveValue) 
567                numberBandBsolutions++;
568            }
569          }
570          if (returnCode&&newSolutionValue<saveValue) {
571            memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
572            solutionFound=true;
573            CoinWarmStartBasis * basis =
574              dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
575            if (basis) {
576              bestBasis = * basis;
577              delete basis;
578              CbcEventHandler * handler = model_->getEventHandler();
579              if (handler) {
580                double * saveOldSolution = CoinCopyOfArray(model_->bestSolution(),numberColumns);
581                double saveObjectiveValue = model_->getMinimizationObjValue();
582                model_->setBestSolution(betterSolution,numberColumns,newSolutionValue);
583                int action = handler->event(CbcEventHandler::heuristicSolution);
584                if (saveOldSolution&&saveObjectiveValue<model_->getMinimizationObjValue())
585                  model_->setBestSolution(saveOldSolution,numberColumns,saveObjectiveValue);
586                delete [] saveOldSolution;
587                if (!action||model_->getCurrentSeconds()>model_->getMaximumSeconds()) {
588                  exitAll=true; // exit
589                  break;
590                }
591              }
592            }
593            if ((accumulate_&1)!=0) {
594              model_->incrementUsed(betterSolution); // for local search
595              numberSolutions++;
596            }
597            solutionValue=newSolutionValue;
598            solutionFound=true;
599            if (general&&saveValue!=newSolutionValue) {
600              sprintf(pumpPrint,"Cleaned solution of %g",solutionValue);
601              model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
602                << pumpPrint
603                <<CoinMessageEol;
604            }
605          } else {
606            sprintf(pumpPrint,"Mini branch and bound could not fix general integers");
607            model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
608              << pumpPrint
609              <<CoinMessageEol;
610          }
611        } else {
612          sprintf(pumpPrint,"After further testing solution no better than previous of %g",solutionValue);
613          model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
614            << pumpPrint
615            <<CoinMessageEol;
616          //newLineNeeded=false;
617          returnCode=0;
618        }     
619        break;
620      } else {
621        // SOLUTION IS not INTEGER
622        // 1. check for loop
623        bool matched;
624        for (int k = NUMBER_OLD-1; k > 0; k--) {
625          double * b = oldSolution[k];
626          matched = true;
627          for (i = 0; i <numberIntegers; i++) {
628            int iColumn = integerVariable[i];
629            if (newSolution[iColumn]!=b[iColumn]) {
630              matched=false;
631              break;
632            }
633          }
634          if (matched) break;
635        }
636        int numberPerturbed=0;
637        if (matched || numberPasses%100 == 0) {
638          // perturbation
639          //sprintf(pumpPrint+strlen(pumpPrint)," perturbation applied");
640          //newLineNeeded=true;
641          double factorX[10]={0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0};
642          double factor=1.0;
643          double target=-1.0;
644          double * randomX = new double [numberIntegers];
645          for (i=0;i<numberIntegers;i++) 
646            randomX[i] = max(0.0,randomNumberGenerator_.randomDouble()-0.3);
647          for (int k=0;k<10;k++) {
648#ifdef COIN_DEVELOP_x
649            printf("kpass %d\n",k);
650#endif
651            int numberX[10]={0,0,0,0,0,0,0,0,0,0};
652            for (i=0;i<numberIntegers;i++) {
653              int iColumn = integerVariable[i];
654              double value = randomX[i];
655              double difference = fabs(solution[iColumn]-newSolution[iColumn]);
656              for (int j=0;j<10;j++) {
657                if (difference+value*factorX[j]>0.5) 
658                  numberX[j]++;
659              }
660            }
661            if (target<0.0) {
662              if (numberX[9]<=200)
663                break; // not very many changes
664              target=CoinMax(200.0,CoinMin(0.05*numberX[9],1000.0));
665            }
666            int iX=-1;
667            int iBand=-1;
668            for (i=0;i<10;i++) {
669#ifdef COIN_DEVELOP_x
670              printf("** %d changed at %g\n",numberX[i],factorX[i]);
671#endif
672              if (numberX[i]>=target&&numberX[i]<2.0*target&&iX<0)
673                iX=i;
674              if (iBand<0&&numberX[i]>target) {
675                iBand=i;
676                factor=factorX[i];
677              }
678            }
679            if (iX>=0) {
680              factor=factorX[iX];
681              break;
682            } else {
683              assert (iBand>=0);
684              double hi = factor;
685              double lo = (iBand>0) ? factorX[iBand-1] : 0.0;
686              double diff = (hi-lo)/9.0;
687              for (i=0;i<10;i++) {
688                factorX[i]=lo;
689                lo += diff;
690              }
691            }
692          }
693          for (i=0;i<numberIntegers;i++) {
694            int iColumn = integerVariable[i];
695            double value = randomX[i];
696            double difference = fabs(solution[iColumn]-newSolution[iColumn]);
697            if (difference+value*factor>0.5) {
698              numberPerturbed++;
699              if (newSolution[iColumn]<lower[iColumn]+primalTolerance) {
700                newSolution[iColumn] += 1.0;
701              } else if (newSolution[iColumn]>upper[iColumn]-primalTolerance) {
702                newSolution[iColumn] -= 1.0;
703              } else {
704                // general integer
705                if (difference+value>0.75)
706                  newSolution[iColumn] += 1.0;
707                else
708                  newSolution[iColumn] -= 1.0;
709              }
710            }
711          }
712          delete [] randomX;
713        } else {
714          for (j=NUMBER_OLD-1;j>0;j--) {
715            for (i = 0; i < numberColumns; i++) oldSolution[j][i]=oldSolution[j-1][i];
716          }
717          for (j = 0; j < numberColumns; j++) oldSolution[0][j] = newSolution[j];
718        }
719       
720        // 2. update the objective function based on the new rounded solution
721        double offset=0.0;
722        double costValue = (1.0-scaleFactor)*solver->getObjSense();
723        int numberChanged=0;
724        const double * oldObjective = solver->getObjCoefficients();
725        for (i=0;i<numberColumns;i++) {
726          // below so we can keep original code and allow for objective
727          int iColumn = i;
728          // Special code for "artificials"
729          if (direction*saveObjective[iColumn]>=artificialCost_) {
730            //solver->setObjCoeff(iColumn,scaleFactor*saveObjective[iColumn]);
731            solver->setObjCoeff(iColumn,(artificialFactor*saveObjective[iColumn])/artificialCost_);
732          }
733          if(!solver->isBinary(iColumn)&&!doGeneral)
734            continue;
735          // deal with fixed variables (i.e., upper=lower)
736          if (fabs(lower[iColumn]-upper[iColumn]) < primalTolerance||!solver->isInteger(iColumn)) {
737            //if (lower[iColumn] > 1. - primalTolerance) solver->setObjCoeff(iColumn,-costValue);
738            //else                                       solver->setObjCoeff(iColumn,costValue);
739            continue;
740          }
741          double newValue=0.0;
742          if (newSolution[iColumn]<lower[iColumn]+primalTolerance) {
743            newValue = costValue+scaleFactor*saveObjective[iColumn];
744          } else {
745            if (newSolution[iColumn]>upper[iColumn]-primalTolerance) {
746              newValue = -costValue+scaleFactor*saveObjective[iColumn];
747            }
748          }
749          if (newValue!=oldObjective[iColumn])
750            numberChanged++;
751          solver->setObjCoeff(iColumn,newValue);
752          offset += costValue*newSolution[iColumn];
753        }
754        solver->setDblParam(OsiObjOffset,-offset);
755        if (!general&&false) {
756          // Solve in two goes - first keep satisfied ones fixed
757          double * saveLower = new double [numberIntegers];
758          double * saveUpper = new double [numberIntegers];
759          for (i=0;i<numberIntegers;i++) {
760            int iColumn = integerVariable[i];
761            saveLower[i]=COIN_DBL_MAX;
762            saveUpper[i]=-COIN_DBL_MAX;
763            if (solution[iColumn]<lower[iColumn]+primalTolerance) {
764              saveUpper[i]=upper[iColumn];
765              solver->setColUpper(iColumn,lower[iColumn]);
766            } else if (solution[iColumn]>upper[iColumn]-primalTolerance) {
767              saveLower[i]=lower[iColumn];
768              solver->setColLower(iColumn,upper[iColumn]);
769            }
770          }
771          solver->resolve();
772          if (!solver->isProvenOptimal()) {
773            // presumably max time or some such
774            exitAll=true;
775            break;
776          }
777          for (i=0;i<numberIntegers;i++) {
778            int iColumn = integerVariable[i];
779            if (saveLower[i]!=COIN_DBL_MAX)
780              solver->setColLower(iColumn,saveLower[i]);
781            if (saveUpper[i]!=-COIN_DBL_MAX)
782              solver->setColUpper(iColumn,saveUpper[i]);
783            saveUpper[i]=-COIN_DBL_MAX;
784          }
785          memcpy(newSolution,solution,numberColumns*sizeof(double));
786          int flip;
787          returnCode = rounds(solver, newSolution,saveObjective,numberIntegers,integerVariable,
788                              pumpPrint,numberPasses,roundExpensive_,defaultRounding_,&flip);
789          numberPasses++;
790          if (returnCode) {
791            // solution - but may not be better
792            // Compute using dot product
793            double newSolutionValue = -saveOffset;
794            for (  i=0 ; i<numberColumns ; i++ )
795              newSolutionValue += saveObjective[i]*newSolution[i];
796            newSolutionValue *= direction;
797            sprintf(pumpPrint,"Intermediate solution found of %g",newSolutionValue);
798            model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
799              << pumpPrint
800              <<CoinMessageEol;
801            if (newSolutionValue<solutionValue) {
802              memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
803              CoinWarmStartBasis * basis =
804                dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
805              solutionFound=true;
806              if (basis) {
807                bestBasis = * basis;
808                delete basis;
809                CbcEventHandler * handler = model_->getEventHandler();
810                if (handler) {
811                  double * saveOldSolution = CoinCopyOfArray(model_->bestSolution(),numberColumns);
812                  double saveObjectiveValue = model_->getMinimizationObjValue();
813                  model_->setBestSolution(betterSolution,numberColumns,newSolutionValue);
814                  int action = handler->event(CbcEventHandler::heuristicSolution);
815                  if (saveOldSolution&&saveObjectiveValue<model_->getMinimizationObjValue())
816                    model_->setBestSolution(saveOldSolution,numberColumns,saveObjectiveValue);
817                  delete [] saveOldSolution;
818                  if (!action||model_->getCurrentSeconds()>model_->getMaximumSeconds()) {
819                    exitAll=true; // exit
820                    break;
821                  }
822                }
823              }
824              if ((accumulate_&1)!=0) {
825                model_->incrementUsed(betterSolution); // for local search
826                numberSolutions++;
827              }
828              solutionValue=newSolutionValue;
829              solutionFound=true;
830            } else {
831              returnCode=0;
832            }
833          }     
834        }
835        if (!doGeneral) {
836          // faster to do from all slack!!!!
837          if (allSlack) {
838            CoinWarmStartBasis dummy;
839            solver->setWarmStart(&dummy);
840          }
841#ifdef COIN_DEVELOP
842          printf("%d perturbed out of %d columns (%d changed)\n",numberPerturbed,numberColumns,numberChanged);
843#endif
844          bool takeHint;
845          OsiHintStrength strength;
846          solver->getHintParam(OsiDoDualInResolve,takeHint,strength);
847          if (numberPerturbed>numberColumns)
848            solver->setHintParam(OsiDoDualInResolve,true); // dual may be better
849          if (numberTries>1&&numberPasses==1&&false) {
850            // use basis from first time
851            solver->setWarmStart(&saveBasis);
852            // and objective
853            solver->setObjective(firstPerturbedObjective);
854            // and solution
855            solver->setColSolution(firstPerturbedSolution);
856          }
857          solver->resolve();
858          if (!solver->isProvenOptimal()) {
859            // presumably max time or some such
860            exitAll=true;
861            break;
862          }
863          if (numberTries==1&&numberPasses==1&&false) {
864            // save basis
865            CoinWarmStartBasis * basis =
866              dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ;
867            if (basis) {
868              saveBasis = * basis;
869              delete basis;
870            }
871            firstPerturbedObjective = CoinCopyOfArray(solver->getObjCoefficients(),numberColumns);
872            firstPerturbedSolution = CoinCopyOfArray(solver->getColSolution(),numberColumns);
873          }
874          solver->setHintParam(OsiDoDualInResolve,takeHint);
875          newTrueSolutionValue = -saveOffset;
876          newSumInfeas=0.0;
877          newNumberInfeas=0;
878          {
879            const double * newSolution = solver->getColSolution();
880            for (  i=0 ; i<numberColumns ; i++ ) {
881              if (solver->isInteger(i)) {
882                double value = newSolution[i];
883                double nearest = floor(value+0.5);
884                newSumInfeas += fabs(value-nearest);
885                if (fabs(value-nearest)>1.0e-6)
886                  newNumberInfeas++;
887              }
888              newTrueSolutionValue += saveObjective[i]*newSolution[i];
889            }
890            newTrueSolutionValue *= direction;
891            if (newNumberInfeas&&newNumberInfeas<-20) {
892#if 0
893              roundingObjective=solutionValue;
894              OsiSolverInterface * saveSolver = model_->swapSolver(solver);
895              int ifSol = roundingHeuristic.solution(roundingObjective,roundingSolution);
896              model_->swapSolver(saveSolver);
897              if (ifSol>0)
898                abort();
899#endif
900              int numberRows=solver->getNumRows();
901              double * rowActivity = new double[numberRows];
902              memset(rowActivity,0,numberRows*sizeof(double));
903              int * which = new int[newNumberInfeas];
904              int * stack = new int[newNumberInfeas+1];
905              double * baseValue = new double[newNumberInfeas];
906              int * whichRow = new int[numberRows];
907              double * rowValue = new double[numberRows];
908              memset(rowValue,0,numberRows*sizeof(double));
909              int nRow=0;
910              // Column copy
911              const double * element = solver->getMatrixByCol()->getElements();
912              const int * row = solver->getMatrixByCol()->getIndices();
913              const CoinBigIndex * columnStart = solver->getMatrixByCol()->getVectorStarts();
914              const int * columnLength = solver->getMatrixByCol()->getVectorLengths();
915              int n=0;
916              double contrib = 0.0;
917              for (  i=0 ; i<numberColumns ; i++ ) {
918                double value = newSolution[i];
919                if (solver->isInteger(i)) {
920                  double nearest = floor(value+0.5);
921                  if (fabs(value-nearest)>1.0e-6) {
922                    //printf("Column %d value %g\n",i,value);
923                    for (CoinBigIndex j=columnStart[i];
924                         j<columnStart[i]+columnLength[i];j++) {
925                      int iRow=row[j];
926                      //printf("row %d element %g\n",iRow,element[j]);
927                      if (!rowValue[iRow]) {
928                        rowValue[iRow]=1.0;
929                        whichRow[nRow++]=iRow;
930                      }
931                    }
932                    baseValue[n]=floor(value);
933                    contrib += saveObjective[i]*value;
934                    value=0.0;
935                    stack[n]=0;
936                    which[n++]=i;
937                  }
938                }
939                for (CoinBigIndex j=columnStart[i];
940                     j<columnStart[i]+columnLength[i];j++) {
941                  int iRow=row[j];
942                  rowActivity[iRow] += value*element[j];
943                }
944              }
945              if (newNumberInfeas<15) {
946                stack[n]=newNumberInfeas+100;
947                int iStack=n;
948                memset(rowValue,0,numberRows*sizeof(double));
949                const double * rowLower = solver->getRowLower();
950                const double * rowUpper = solver->getRowUpper();
951                while (iStack>=0) {
952                  double contrib2=0.0;
953                  // Could do faster
954                  for (int k=0 ; k<n ; k++ ) {
955                    i=which[k];
956                    double value = baseValue[k]+stack[k];
957                    contrib2 += saveObjective[i]*value;
958                    for (CoinBigIndex j=columnStart[i];
959                         j<columnStart[i]+columnLength[i];j++) {
960                      int iRow=row[j];
961                      rowValue[iRow] += value*element[j];
962                    }
963                  }
964                  // check if feasible
965                  bool feasible=true;
966                  for (int k=0;k<nRow;k++) {
967                    i=whichRow[k];
968                    double value = rowValue[i]+rowActivity[i];
969                    rowValue[i]=0.0;
970                    if(value<rowLower[i]-1.0e-7||
971                       value>rowUpper[i]+1.0e-7)
972                      feasible=false;
973                  }
974                  if (feasible) {
975                    double newObj = newTrueSolutionValue * direction;
976                    newObj += contrib2-contrib;
977                    newObj *= direction;
978                    printf("FFFeasible! - obj %g\n",newObj);
979                    if (newObj<roundingObjective) {
980                      printf("FBetter\n");
981                      roundingObjective = newObj;
982                      memcpy(roundingSolution,newSolution,numberColumns*sizeof(double));
983                      for (int k=0 ; k<n ; k++ ) {
984                        i=which[k];
985                        double value = baseValue[k]+stack[k];
986                        roundingSolution[i]=value;
987                      }
988                    }
989                  }
990                  while (iStack>=0&&stack[iStack]) {
991                    stack[iStack]--;
992                    iStack--;
993                  }
994                  if (iStack>=0) {
995                    stack[iStack]=1;
996                    iStack=n;
997                    stack[n]=1;
998                  }
999                }
1000              }
1001              delete [] rowActivity;
1002              delete [] which;
1003              delete [] stack;
1004              delete [] baseValue;
1005              delete [] whichRow;
1006              delete [] rowValue;
1007            }
1008          }
1009          if (false) {
1010            OsiSolverInterface * saveSolver = model_->swapSolver(solver);
1011            CbcRounding heuristic1(*model_);
1012            heuristic1.setHeuristicName("rounding in feaspump!");
1013            heuristic1.setWhen(1);
1014            roundingObjective = newTrueSolutionValue;
1015            double testObjectiveValue = CoinMin(solutionValue,roundingObjective);
1016            int returnCode = heuristic1.solution(testObjectiveValue,roundingSolution,newTrueSolutionValue) ;
1017            if (returnCode==1) {
1018              assert(testObjectiveValue < CoinMin(solutionValue,roundingObjective));
1019              roundingObjective = testObjectiveValue;
1020            } else {
1021              roundingObjective = COIN_DBL_MAX;
1022            }
1023            model_->swapSolver(saveSolver);
1024          }
1025          if (!solver->isProvenOptimal()) {
1026            // presumably max time or some such
1027            exitAll=true;
1028            break;
1029          }
1030          // in case very dubious solver
1031          lower = solver->getColLower();
1032          upper = solver->getColUpper();
1033          solution = solver->getColSolution();
1034        } else {
1035          int * addStart = new int[2*general+1];
1036          int * addIndex = new int[4*general];
1037          double * addElement = new double[4*general];
1038          double * addLower = new double[2*general];
1039          double * addUpper = new double[2*general];
1040          double * obj = new double[general];
1041          int nAdd=0;
1042          for (i=0;i<numberIntegers;i++) {
1043            int iColumn = integerVariable[i];
1044            if (newSolution[iColumn]>lower[iColumn]+primalTolerance&&
1045                newSolution[iColumn]<upper[iColumn]-primalTolerance) {
1046              obj[nAdd]=1.0;
1047              addLower[nAdd]=0.0;
1048              addUpper[nAdd]=COIN_DBL_MAX;
1049              nAdd++;
1050            }
1051          }
1052          OsiSolverInterface * solver2 = solver;
1053          if (nAdd) {
1054            CoinZeroN(addStart,nAdd+1);
1055            solver2 = solver->clone();
1056            solver2->addCols(nAdd,addStart,NULL,NULL,addLower,addUpper,obj);
1057            // feasible solution
1058            double * sol = new double[nAdd+numberColumns];
1059            memcpy(sol,solution,numberColumns*sizeof(double));
1060            // now rows
1061            int nAdd=0;
1062            int nEl=0;
1063            int nAddRow=0;
1064            for (i=0;i<numberIntegers;i++) {
1065              int iColumn = integerVariable[i];
1066              if (newSolution[iColumn]>lower[iColumn]+primalTolerance&&
1067                  newSolution[iColumn]<upper[iColumn]-primalTolerance) {
1068                addLower[nAddRow]=-newSolution[iColumn];;
1069                addUpper[nAddRow]=COIN_DBL_MAX;
1070                addIndex[nEl] = iColumn;
1071                addElement[nEl++]=-1.0;
1072                addIndex[nEl] = numberColumns+nAdd;
1073                addElement[nEl++]=1.0;
1074                nAddRow++;
1075                addStart[nAddRow]=nEl;
1076                addLower[nAddRow]=newSolution[iColumn];;
1077                addUpper[nAddRow]=COIN_DBL_MAX;
1078                addIndex[nEl] = iColumn;
1079                addElement[nEl++]=1.0;
1080                addIndex[nEl] = numberColumns+nAdd;
1081                addElement[nEl++]=1.0;
1082                nAddRow++;
1083                addStart[nAddRow]=nEl;
1084                sol[nAdd+numberColumns] = fabs(sol[iColumn]-newSolution[iColumn]);
1085                nAdd++;
1086              }
1087            }
1088            solver2->setColSolution(sol);
1089            delete [] sol;
1090            solver2->addRows(nAddRow,addStart,addIndex,addElement,addLower,addUpper);
1091          }
1092          delete [] addStart;
1093          delete [] addIndex;
1094          delete [] addElement;
1095          delete [] addLower;
1096          delete [] addUpper;
1097          delete [] obj;
1098          solver2->resolve();
1099          if (!solver2->isProvenOptimal()) {
1100            // presumably max time or some such
1101            exitAll=true;
1102            break;
1103          }
1104          //assert (solver2->isProvenOptimal());
1105          if (nAdd) {
1106            solver->setColSolution(solver2->getColSolution());
1107            delete solver2;
1108          }
1109        }
1110        if (lastMove!=1000000) {
1111          if (newSumInfeas<lastSumInfeas) {
1112            lastMove=numberPasses;
1113            lastSumInfeas=newSumInfeas;
1114          } else if (newSumInfeas>lastSumInfeas+1.0e-5) {
1115            lastMove=1000000; // going up
1116          }
1117        }
1118        totalNumberIterations += solver->getIterationCount();
1119        if (solver->getNumRows()<3000)
1120          sprintf(pumpPrint,"Pass %3d: suminf. %10.5f (%d) obj. %g iterations %d", 
1121                  numberPasses+totalNumberPasses,
1122                  newSumInfeas,newNumberInfeas,
1123                  newTrueSolutionValue,solver->getIterationCount());
1124        else
1125          sprintf(pumpPrint,"Pass %3d: (%.2f seconds) suminf. %10.5f (%d) obj. %g iterations %d", numberPasses+totalNumberPasses,
1126                  model_->getCurrentSeconds(),newSumInfeas,newNumberInfeas,
1127                  newTrueSolutionValue,solver->getIterationCount());
1128        model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1129          << pumpPrint
1130          <<CoinMessageEol;
1131        if (closestSolution&&solver->getObjValue()<closestObjectiveValue) {
1132          int i;
1133          const double * objective = solver->getObjCoefficients();
1134          for (i=0;i<numberIntegersOrig;i++) {
1135            int iColumn=integerVariableOrig[i];
1136            if (objective[iColumn]>0.0)
1137              closestSolution[i]=0;
1138            else
1139              closestSolution[i]=1;
1140          }
1141          closestObjectiveValue = solver->getObjValue();
1142        }
1143        //newLineNeeded=true;
1144       
1145      }
1146      // reduce scale factor
1147      scaleFactor *= weightFactor_;
1148    } // END WHILE
1149    // see if rounding worked!
1150    if (roundingObjective<solutionValue) {
1151      sprintf(pumpPrint,"Rounding solution of %g is better than previous of %g !\n",
1152              roundingObjective,solutionValue);
1153      model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1154        << pumpPrint
1155        <<CoinMessageEol;
1156      solutionValue=roundingObjective;
1157      memcpy(betterSolution,roundingSolution,numberColumns*sizeof(double));
1158      solutionFound=true;
1159    }
1160    if (!solutionFound) { 
1161      sprintf(pumpPrint,"No solution found this major pass");
1162      model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1163        << pumpPrint
1164        <<CoinMessageEol;
1165    }
1166    //}
1167    delete solver;
1168    solver=NULL;
1169    for ( j=0;j<NUMBER_OLD;j++) 
1170      delete [] oldSolution[j];
1171    delete [] oldSolution;
1172    delete [] saveObjective;
1173    if (usedColumn&&!exitAll) {
1174      OsiSolverInterface * newSolver = model_->continuousSolver()->clone();
1175      const double * colLower = newSolver->getColLower();
1176      const double * colUpper = newSolver->getColUpper();
1177      int i;
1178      int nFix=0;
1179      int nFixI=0;
1180      int nFixC=0;
1181      int nFixC2=0;
1182      for (i=0;i<numberIntegersOrig;i++) {
1183        int iColumn=integerVariableOrig[i];
1184        //const OsiObject * object = model_->object(i);
1185        //double originalLower;
1186        //double originalUpper;
1187        //getIntegerInformation( object,originalLower, originalUpper);
1188        //assert(colLower[iColumn]==originalLower);
1189        //newSolver->setColLower(iColumn,CoinMax(colLower[iColumn],originalLower));
1190        newSolver->setColLower(iColumn,colLower[iColumn]);
1191        //assert(colUpper[iColumn]==originalUpper);
1192        //newSolver->setColUpper(iColumn,CoinMin(colUpper[iColumn],originalUpper));
1193        newSolver->setColUpper(iColumn,colUpper[iColumn]);
1194        if (!usedColumn[iColumn]) {
1195          double value=lastSolution[iColumn];
1196          double nearest = floor(value+0.5);
1197          if (fabs(value-nearest)<1.0e-7) {
1198            if (nearest==colLower[iColumn]) {
1199              newSolver->setColUpper(iColumn,colLower[iColumn]);
1200              nFix++;
1201            } else if (nearest==colUpper[iColumn]) {
1202              newSolver->setColLower(iColumn,colUpper[iColumn]);
1203              nFix++;
1204            } else if (fixInternal) {
1205              newSolver->setColLower(iColumn,nearest);
1206              newSolver->setColUpper(iColumn,nearest);
1207              nFix++;
1208              nFixI++;
1209            }
1210          }
1211        }
1212      }
1213      if (fixContinuous) {
1214        for (int iColumn=0;iColumn<numberColumns;iColumn++) {
1215          if (!newSolver->isInteger(iColumn)&&!usedColumn[iColumn]) {
1216            double value=lastSolution[iColumn];
1217            if (value<colLower[iColumn]+1.0e-8) {
1218              newSolver->setColUpper(iColumn,colLower[iColumn]);
1219              nFixC++;
1220            } else if (value>colUpper[iColumn]-1.0e-8) {
1221              newSolver->setColLower(iColumn,colUpper[iColumn]);
1222              nFixC++;
1223            } else if (fixContinuous==2) {
1224              newSolver->setColLower(iColumn,value);
1225              newSolver->setColUpper(iColumn,value);
1226              nFixC++;
1227              nFixC2++;
1228            }
1229          }
1230        }
1231      }
1232      newSolver->initialSolve();
1233      if (!newSolver->isProvenOptimal()) {
1234        //newSolver->writeMps("bad.mps");
1235        //assert (newSolver->isProvenOptimal());
1236        exitAll=true;
1237        break;
1238      }
1239      sprintf(pumpPrint,"Before mini branch and bound, %d integers at bound fixed and %d continuous",
1240             nFix,nFixC);
1241      if (nFixC2+nFixI!=0)
1242        sprintf(pumpPrint+strlen(pumpPrint)," of which %d were internal integer and %d internal continuous",
1243                nFixI,nFixC2);
1244      model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1245        << pumpPrint
1246        <<CoinMessageEol;
1247      double saveValue = newSolutionValue;
1248      if (newSolutionValue-model_->getCutoffIncrement()
1249          >continuousObjectiveValue-1.0e-7) {
1250        double saveFraction = fractionSmall_;
1251        if (numberTries>1&&!numberBandBsolutions)
1252          fractionSmall_ *= 0.5;
1253        // Give branch and bound a bit more freedom
1254        double cutoff2=newSolutionValue-model_->getCutoffIncrement();
1255        int returnCode2 = smallBranchAndBound(newSolver,numberNodes_,newSolution,newSolutionValue,
1256                                              cutoff2,"CbcHeuristicLocalAfterFPump");
1257        fractionSmall_ = saveFraction;
1258        if (returnCode2<0) {
1259          if (returnCode2==-2)
1260            exitAll=true;
1261          returnCode2=0; // returned on size (or event) - could try changing
1262        }
1263        if ((returnCode2&2)!=0) {
1264          // could add cut
1265          returnCode2 &= ~2;
1266        }
1267        if (returnCode2)
1268          numberBandBsolutions++;
1269      } else {
1270        // no need
1271        exitAll=true;
1272        //returnCode=0;
1273      }
1274      // recompute solution value
1275      if (returnCode&&true) {
1276        delete newSolver;
1277        newSolver = model_->continuousSolver()->clone();
1278        newSolutionValue = -saveOffset;
1279        double newSumInfeas=0.0;
1280        const double * obj = newSolver->getObjCoefficients();
1281        for (int i=0 ; i<numberColumns ; i++ ) {
1282          if (newSolver->isInteger(i)) {
1283            double value = newSolution[i];
1284            double nearest = floor(value+0.5);
1285            newSumInfeas += fabs(value-nearest);
1286          }
1287          newSolutionValue += obj[i]*newSolution[i];
1288        }
1289        newSolutionValue *= direction;
1290      }
1291      if (returnCode&&newSolutionValue<saveValue) {
1292        sprintf(pumpPrint,"Mini branch and bound improved solution from %g to %g (%.2f seconds)",
1293                saveValue,newSolutionValue,model_->getCurrentSeconds());
1294        model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1295          << pumpPrint
1296          <<CoinMessageEol;
1297        memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
1298        if (fixContinuous) {
1299          // may be able to do even better
1300          const double * lower = model_->solver()->getColLower();
1301          const double * upper = model_->solver()->getColUpper();
1302          for (int iColumn=0;iColumn<numberColumns;iColumn++) {
1303            if (newSolver->isInteger(iColumn)) {
1304              double value=floor(newSolution[iColumn]+0.5);
1305              newSolver->setColLower(iColumn,value);
1306              newSolver->setColUpper(iColumn,value);
1307            } else {
1308              newSolver->setColLower(iColumn,lower[iColumn]);
1309              newSolver->setColUpper(iColumn,upper[iColumn]);
1310            }
1311          }
1312          newSolver->initialSolve();
1313          if (newSolver->isProvenOptimal()) {
1314            double value = newSolver->getObjValue()*newSolver->getObjSense();
1315            if (value<newSolutionValue) {
1316              //newSolver->writeMps("query","mps");
1317#if 0
1318              {
1319                double saveOffset;
1320                newSolver->getDblParam(OsiObjOffset,saveOffset);
1321                const double * obj = newSolver->getObjCoefficients();
1322                double newTrueSolutionValue = -saveOffset;
1323                double newSumInfeas=0.0;
1324                int numberColumns = newSolver->getNumCols();
1325                const double * solution = newSolver->getColSolution();
1326                for (int  i=0 ; i<numberColumns ; i++ ) {
1327                  if (newSolver->isInteger(i)) {
1328                    double value = solution[i];
1329                    double nearest = floor(value+0.5);
1330                    newSumInfeas += fabs(value-nearest);
1331                  }
1332                  if (solution[i])
1333                    printf("%d obj %g val %g - total %g\n",i,obj[i],solution[i],
1334                           newTrueSolutionValue);
1335                  newTrueSolutionValue += obj[i]*solution[i];
1336                }
1337                printf("obj %g - inf %g\n",newTrueSolutionValue,
1338                       newSumInfeas);
1339              }
1340#endif
1341              sprintf(pumpPrint,"Freeing continuous variables gives a solution of %g", value);
1342              model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1343                << pumpPrint
1344                <<CoinMessageEol;
1345              newSolutionValue=value;
1346              memcpy(betterSolution,newSolver->getColSolution(),numberColumns*sizeof(double));
1347            }
1348          } else {
1349            //newSolver->writeMps("bad3.mps");
1350            exitAll=true;
1351            break;
1352          }
1353        } 
1354        if ((accumulate_&1)!=0) {
1355          model_->incrementUsed(betterSolution); // for local search
1356          numberSolutions++;
1357        }
1358        solutionValue=newSolutionValue;
1359        solutionFound=true;
1360        CoinWarmStartBasis * basis =
1361          dynamic_cast<CoinWarmStartBasis *>(newSolver->getWarmStart()) ;
1362        if (basis) {
1363          bestBasis = * basis;
1364          delete basis;
1365          CbcEventHandler * handler = model_->getEventHandler();
1366          if (handler) {
1367            double * saveOldSolution = CoinCopyOfArray(model_->bestSolution(),numberColumns);
1368            double saveObjectiveValue = model_->getMinimizationObjValue();
1369            model_->setBestSolution(betterSolution,numberColumns,newSolutionValue);
1370            int action = handler->event(CbcEventHandler::heuristicSolution);
1371            //printf("cutoff %g\n",model_->getCutoff());
1372            if (saveOldSolution&&saveObjectiveValue<model_->getMinimizationObjValue())
1373              model_->setBestSolution(saveOldSolution,numberColumns,saveObjectiveValue);
1374            delete [] saveOldSolution;
1375            if (!action||model_->getCurrentSeconds()>model_->getMaximumSeconds()) {
1376              exitAll=true; // exit
1377              break;
1378            }
1379          }
1380        }
1381      } else {
1382        sprintf(pumpPrint,"Mini branch and bound did not improve solution (%.2f seconds)",
1383                model_->getCurrentSeconds());
1384        model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1385          << pumpPrint
1386          <<CoinMessageEol;
1387      }
1388      delete newSolver;
1389    }
1390    if (solutionFound) finalReturnCode=1;
1391    cutoff = CoinMin(cutoff,solutionValue-model_->getCutoffIncrement());
1392    if (numberTries>=maximumRetries_||!solutionFound||exitAll||cutoff<continuousObjectiveValue+1.0e-7) {
1393      break;
1394    } else {
1395      solutionFound=false;
1396      if (absoluteIncrement_>0.0||relativeIncrement_>0.0) {
1397        double gap = relativeIncrement_*fabs(solutionValue);
1398        cutoff -= CoinMax(CoinMax(gap,absoluteIncrement_),model_->getCutoffIncrement());
1399      } else {
1400        double weights[10]={0.1,0.1,0.2,0.2,0.2,0.3,0.3,0.3,0.4,0.5};
1401        cutoff -= weights[CoinMin(numberTries-1,9)]*(cutoff-continuousObjectiveValue);
1402      }
1403      if (cutoff<continuousObjectiveValue)
1404        break;
1405      sprintf(pumpPrint,"Round again with cutoff of %g",cutoff);
1406      model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1407        << pumpPrint
1408        <<CoinMessageEol;
1409      if ((accumulate_&3)<2&&usedColumn)
1410        memset(usedColumn,0,numberColumns);
1411      totalNumberPasses += numberPasses-1;
1412    }
1413  }
1414  delete solver; // probably NULL but do anyway
1415  if (!finalReturnCode&&closestSolution&&closestObjectiveValue <= 10.0&&usedColumn) {
1416    // try a bit of branch and bound
1417    OsiSolverInterface * newSolver = model_->continuousSolver()->clone();
1418    const double * colLower = newSolver->getColLower();
1419    const double * colUpper = newSolver->getColUpper();
1420    int i;
1421    double rhs = 0.0;
1422    for (i=0;i<numberIntegersOrig;i++) {
1423      int iColumn=integerVariableOrig[i];
1424      int direction = closestSolution[i];
1425      closestSolution[i]=iColumn;
1426      if (direction==0) {
1427        // keep close to LB
1428        rhs += colLower[iColumn];
1429        lastSolution[i]=1.0;
1430      } else {
1431        // keep close to UB
1432        rhs -= colUpper[iColumn];
1433        lastSolution[i]=-1.0;
1434      }
1435    }
1436    newSolver->addRow(numberIntegersOrig,closestSolution,
1437                      lastSolution,-COIN_DBL_MAX,rhs+10.0);
1438    //double saveValue = newSolutionValue;
1439    //newSolver->writeMps("sub");
1440    int returnCode = smallBranchAndBound(newSolver,numberNodes_,newSolution,newSolutionValue,
1441                                     newSolutionValue,"CbcHeuristicLocalAfterFPump");
1442    if (returnCode<0)
1443      returnCode=0; // returned on size
1444    if ((returnCode&2)!=0) {
1445      // could add cut
1446      returnCode &= ~2;
1447    }
1448    if (returnCode) {
1449      //printf("old sol of %g new of %g\n",saveValue,newSolutionValue);
1450      memcpy(betterSolution,newSolution,numberColumns*sizeof(double));
1451      //abort();
1452      solutionValue=newSolutionValue;
1453      solutionFound=true;
1454    }
1455    delete newSolver;
1456  }
1457  delete [] roundingSolution;
1458  delete [] usedColumn;
1459  delete [] lastSolution;
1460  delete [] newSolution;
1461  delete [] closestSolution;
1462  delete [] integerVariable;
1463  delete [] firstPerturbedObjective;
1464  delete [] firstPerturbedSolution;
1465  if (solutionValue==incomingObjective) 
1466    sprintf(pumpPrint,"After %.2f seconds - Feasibility pump exiting - took %.2f seconds",
1467            model_->getCurrentSeconds(),CoinCpuTime()-time1);
1468  else
1469    sprintf(pumpPrint,"After %.2f seconds - Feasibility pump exiting with objective of %g - took %.2f seconds",
1470            model_->getCurrentSeconds(),solutionValue,CoinCpuTime()-time1);
1471  model_->messageHandler()->message(CBC_FPUMP1,model_->messages())
1472    << pumpPrint
1473    <<CoinMessageEol;
1474  if (bestBasis.getNumStructural())
1475    model_->setBestSolutionBasis(bestBasis);
1476  model_->setMinimizationObjValue(saveBestObjective);
1477  if ((accumulate_&1)!=0&&numberSolutions>1&&!model_->getSolutionCount()) {
1478    model_->setSolutionCount(1); // for local search
1479    model_->setNumberHeuristicSolutions(1); 
1480  }
1481#ifdef COIN_DEVELOP
1482  {
1483    double ncol = model_->solver()->getNumCols();
1484    double nrow = model_->solver()->getNumRows();
1485    printf("XXX total iterations %g ratios - %g %g %g\n",
1486           totalNumberIterations,
1487           totalNumberIterations/nrow,
1488           totalNumberIterations/ncol,
1489           totalNumberIterations/(2*nrow+2*ncol));
1490  }
1491#endif
1492  return finalReturnCode;
1493}
1494
1495/**************************END MAIN PROCEDURE ***********************************/
1496
1497// update model
1498void CbcHeuristicFPump::setModel(CbcModel * model)
1499{
1500  model_ = model;
1501}
1502
1503/* Rounds solution - down if < downValue
1504   returns 1 if current is a feasible solution
1505*/
1506int 
1507CbcHeuristicFPump::rounds(OsiSolverInterface * solver,double * solution,
1508                          const double * objective,
1509                          int numberIntegers, const int * integerVariable,
1510                          char * pumpPrint, int & iter,
1511                          bool roundExpensive, double downValue, int *flip)
1512{
1513  double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance);
1514  double primalTolerance ;
1515  solver->getDblParam(OsiPrimalTolerance,primalTolerance) ;
1516
1517  int i;
1518
1519  const double * cost = solver->getObjCoefficients();
1520  int flip_up = 0;
1521  int flip_down  = 0;
1522  double  v = randomNumberGenerator_.randomDouble() * 20.0;
1523  int nn = 10 + (int) v;
1524  int nnv = 0;
1525  int * list = new int [nn];
1526  double * val = new double [nn];
1527  for (i = 0; i < nn; i++) val[i] = .001;
1528
1529  const double * rowLower = solver->getRowLower();
1530  const double * rowUpper = solver->getRowUpper();
1531  int numberRows = solver->getNumRows();
1532#if 1
1533  // Do set covering variables
1534  const CoinPackedMatrix * matrixByRow = solver->getMatrixByRow();
1535  const double * elementByRow = matrixByRow->getElements();
1536  const int * column = matrixByRow->getIndices();
1537  const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
1538  const int * rowLength = matrixByRow->getVectorLengths();
1539  for (i=0;i<numberRows;i++) {
1540    if (rowLower[i]==1.0&&rowUpper[i]==1.0) {
1541      bool cover=true;
1542      double largest=0.0;
1543      int jColumn=-1;
1544      for (CoinBigIndex k=rowStart[i];k<rowStart[i]+rowLength[i];k++) {
1545        int iColumn = column[k];
1546        if (elementByRow[k]!=1.0||!solver->isInteger(iColumn)) {
1547          cover=false;
1548          break;
1549        } else {
1550          if (solution[iColumn]) {
1551            double value = solution[iColumn]*
1552              (randomNumberGenerator_.randomDouble()+5.0);
1553            if (value>largest) {
1554              largest=value;
1555              jColumn=iColumn;
1556            }
1557          }
1558        }
1559      }
1560      if (cover) {
1561        for (CoinBigIndex k=rowStart[i];k<rowStart[i]+rowLength[i];k++) {
1562          int iColumn = column[k];
1563          double value=solution[iColumn];
1564          if (iColumn==jColumn) 
1565            solution[iColumn]=1.0;
1566           else 
1567            solution[iColumn]=0.0;
1568#if 0
1569          if (value!=solution[iColumn])
1570            printf("%d sol changed from %g to %g\n",iColumn,value,solution[iColumn]);
1571          if (value>0.5&&solution[iColumn]<0.5)
1572            printf("why!\n");
1573#endif
1574        }
1575      }
1576    }
1577  }
1578#endif
1579#if 0
1580  // Do set covering variables
1581  const CoinPackedMatrix * matrixByRow = solver->getMatrixByRow();
1582  const double * elementByRow = matrixByRow->getElements();
1583  const int * column = matrixByRow->getIndices();
1584  const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
1585  const int * rowLength = matrixByRow->getVectorLengths();
1586  int numberColumns = solver->getNumCols();
1587  double * sortTemp = new double[numberColumns];
1588  int * whichTemp = new int [numberColumns];
1589  char * rowTemp = new char [numberRows];
1590  memset(rowTemp,0,numberRows);
1591  for (i=0;i<numberColumns;i++)
1592    whichTemp[i]=-1;
1593  int nSOS=0;
1594  for (i=0;i<numberRows;i++) {
1595    if (rowLower[i]==1.0&&rowUpper[i]==1.0) {
1596      bool cover=true;
1597      for (CoinBigIndex k=rowStart[i];k<rowStart[i]+rowLength[i];k++) {
1598        int iColumn = column[k];
1599        if (elementByRow[k]!=1.0||!solver->isInteger(iColumn)) {
1600          cover=false;
1601          break;
1602        }
1603      }
1604      if (cover) {
1605        rowTemp[i]=1;
1606        nSOS++;
1607        for (CoinBigIndex k=rowStart[i];k<rowStart[i]+rowLength[i];k++) {
1608          int iColumn = column[k];
1609          double value=solution[iColumn];
1610          whichTemp[iColumn]=iColumn;
1611        }
1612      }
1613    }
1614  }
1615  if (nSOS) {
1616    // Column copy
1617    const CoinPackedMatrix * matrixByColumn = solver->getMatrixByCol();
1618    //const double * element = matrixByColumn->getElements();
1619    const int * row = matrixByColumn->getIndices();
1620    const CoinBigIndex * columnStart = matrixByColumn->getVectorStarts();
1621    const int * columnLength = matrixByColumn->getVectorLengths();
1622    int nLook = 0;
1623    for (i=0;i<numberColumns;i++) {
1624      if (whichTemp[i]>=0) {
1625        whichTemp[nLook]=i;
1626        double value=solution[i];
1627        if (value<0.5)
1628          value *= (0.1*randomNumberGenerator_.randomDouble()+0.3);
1629        sortTemp[nLook++]=-value;
1630      }
1631    }
1632    CoinSort_2(sortTemp,sortTemp+nLook,whichTemp);
1633    double smallest=1.0;
1634    int nFix=0;
1635    int nOne=0;
1636    for (int j=0;j<nLook;j++) {
1637      int jColumn = whichTemp[j];
1638      double thisValue = solution[jColumn];
1639      if (!thisValue)
1640        continue;
1641      if (thisValue==1.0)
1642        nOne++;
1643      smallest = CoinMin(smallest,thisValue);
1644      solution[jColumn]=1.0;
1645      double largest=0.0;
1646      for (CoinBigIndex jEl=columnStart[jColumn];
1647           jEl<columnStart[jColumn]+columnLength[jColumn];jEl++) {
1648        int jRow = row[jEl];
1649        if (rowTemp[jRow]) {
1650          for (CoinBigIndex k=rowStart[jRow];k<rowStart[jRow]+rowLength[jRow];k++) {
1651            int iColumn = column[k];
1652            if (solution[iColumn]) {
1653              if (iColumn!=jColumn) {
1654                double value = solution[iColumn];
1655                if (value>largest)
1656                  largest=value;
1657                solution[iColumn]=0.0;
1658              }
1659            }
1660          }
1661        }
1662      }
1663      if (largest>thisValue)
1664        printf("%d was at %g - chosen over a value of %g\n",
1665               jColumn,thisValue,largest);
1666      nFix++;
1667    }
1668    printf("%d fixed out of %d (%d at one already)\n",
1669           nFix,nLook,nOne);
1670  }
1671  delete [] sortTemp;
1672  delete [] whichTemp;
1673  delete [] rowTemp;
1674#endif
1675  const double * columnLower = solver->getColLower();
1676  const double * columnUpper = solver->getColUpper();
1677  // return rounded solution
1678  for (i=0;i<numberIntegers;i++) {
1679    int iColumn = integerVariable[i];
1680    double value=solution[iColumn];
1681    double round = floor(value+primalTolerance);
1682    if (value-round > downValue) round += 1.;
1683#if 1
1684    if (round < integerTolerance && cost[iColumn] < -1. + integerTolerance) flip_down++;
1685    if (round > 1. - integerTolerance && cost[iColumn] > 1. - integerTolerance) flip_up++;
1686#else
1687    if (round < columnLower[iColumn]+integerTolerance && cost[iColumn] < -1. + integerTolerance) flip_down++;
1688    if (round > columnUpper[iColumn] - integerTolerance && cost[iColumn] > 1. - integerTolerance) flip_up++;
1689#endif
1690    if (flip_up + flip_down == 0) { 
1691       for (int k = 0; k < nn; k++) {
1692           if (fabs(value-round) > val[k]) {
1693              nnv++;
1694              for (int j = nn-2; j >= k; j--) {
1695                  val[j+1] = val[j];
1696                  list[j+1] = list[j];
1697              } 
1698              val[k] = fabs(value-round);
1699              list[k] = iColumn;
1700              break;
1701           }
1702       }
1703    }
1704    solution[iColumn] = round;
1705  }
1706
1707  if (nnv > nn) nnv = nn;
1708  //if (iter != 0)
1709  //sprintf(pumpPrint+strlen(pumpPrint),"up = %5d , down = %5d", flip_up, flip_down);
1710  *flip = flip_up + flip_down;
1711
1712  if (*flip == 0 && iter != 0) {
1713    //sprintf(pumpPrint+strlen(pumpPrint)," -- rand = %4d (%4d) ", nnv, nn);
1714     for (i = 0; i < nnv; i++) {
1715       // was solution[list[i]] = 1. - solution[list[i]]; but does that work for 7>=x>=6
1716       int index = list[i];
1717       double value = solution[index];
1718       if (value<=1.0) {
1719         solution[index] = 1.0-value;
1720       } else if (value<columnLower[index]+integerTolerance) {
1721         solution[index] = value+1.0;
1722       } else if (value>columnUpper[index]-integerTolerance) {
1723         solution[index] = value-1.0;
1724       } else {
1725         solution[index] = value-1.0;
1726       }
1727     }
1728     *flip = nnv;
1729  } else {
1730    //sprintf(pumpPrint+strlen(pumpPrint)," ");
1731  }
1732  delete [] list; delete [] val;
1733  //iter++;
1734   
1735  // get row activities
1736  double * rowActivity = new double[numberRows];
1737  memset(rowActivity,0,numberRows*sizeof(double));
1738  solver->getMatrixByCol()->times(solution,rowActivity) ;
1739  double largestInfeasibility =0.0;
1740  for (i=0 ; i < numberRows ; i++) {
1741    largestInfeasibility = max(largestInfeasibility,
1742                               rowLower[i]-rowActivity[i]);
1743    largestInfeasibility = max(largestInfeasibility,
1744                               rowActivity[i]-rowUpper[i]);
1745  }
1746  delete [] rowActivity;
1747  return (largestInfeasibility>primalTolerance) ? 0 : 1;
1748}
1749// Set maximum Time (default off) - also sets starttime to current
1750void 
1751CbcHeuristicFPump::setMaximumTime(double value)
1752{
1753  startTime_=CoinCpuTime();
1754  maximumTime_=value;
1755}
1756
1757 
Note: See TracBrowser for help on using the repository browser.