LTP GCOV extension - code coverage report
Current view:directory - packages/pico/src/milp/pico - milpNode.cpp
Test:Acro
Date:2008-10-11Instrumented lines:860
Code covered:45.9 %Executed lines:395

       1                 : /*  _________________________________________________________________________
       2                 :  *
       3                 :  *  PICO: A C++ library of scalable branch-and-bound and related methods.
       4                 :  *  Copyright (c) 2001, Sandia National Laboratories.
       5                 :  *  This software is distributed under the GNU Lesser General Public License.
       6                 :  *  For more information, see the README file in the top PICO directory.
       7                 :  *  _________________________________________________________________________
       8                 :  */
       9                 : //
      10                 : // milpNode.cpp
      11                 : //
      12                 : // Basic serial code for MILP solving in PICO (subproblem level code).
      13                 : //
      14                 : // Cindy Phillips
      15                 : //
      16                 : 
      17                 : #include <acro_config.h>
      18                 : #include <utilib/_math.h>
      19                 : #include <utilib/DUniform.h>
      20                 : #include <utilib/seconds.h>
      21                 : #include <pebbl/gRandom.h>
      22                 : #include <pebbl/fundamentals.h>
      23                 : #include <pico/milpNode.h>
      24                 : #include <pico/BasisArray.h>
      25                 : #include <pico/mipHeuristic.h>
      26                 : 
      27                 : #include <iostream>
      28                 : #include <iomanip>
      29                 : #include <vector>
      30                 : #include <utility> 
      31                 : 
      32                 : using namespace std;
      33                 : using namespace utilib;
      34                 : 
      35                 : /*  CAP: I hope this just goes away and the new intialization will work.  Keep this through the
      36                 :     next attempt to run on Janus
      37                 : #if defined(COUGAR) 
      38                 : 
      39                 : namespace utilib {
      40                 : 
      41                 : template<>
      42                 : int        EnumBitArray<1,pico::basisState>::enum_count    = 4;
      43                 : 
      44                 : template<>
      45                 : char*      EnumBitArray<1,pico::basisState>::enum_labels = "oLBU";
      46                 : 
      47                 : template<>
      48                 : pico::basisState EnumBitArray<1,pico::basisState>::enum_vals[]   = { pico::other, pico::atLower, pico::basic, pico::atUpper };
      49                 : 
      50                 : }
      51                 : #endif
      52                 : 
      53                 : */
      54                 : 
      55                 : namespace pico {
      56                 : 
      57                 : 
      58                 : int MILPNode::numChildren = 2;
      59                 : 
      60                 : 
      61                 : // For making the root
      62                 : 
      63              17 : void MILPNode::MILPNodeFromMILP(MILP* master)
      64                 : {
      65              17 :   lp = master->lp;
      66              17 :   globalPtr = master;
      67              17 :   bound = -(mGlobal()->sense)*MAXDOUBLE;
      68              17 :   MILPNodeInit();
      69                 : 
      70                 :   // For heuristic -- mfValue unknown, use HUGE_VAL and inform the heuristic
      71              17 :   if (mGlobal()->mipHeuristicPtr)
      72                 :     {
      73               0 :       mfValue = HUGE_VAL;
      74               0 :       mGlobal()->mipHeuristicPtr->inform(this);
      75                 :     }
      76              17 : }
      77                 : 
      78                 : // For making a nonroot node
      79                 : 
      80          184076 : void MILPNode::MILPNodeAsChildOf(MILPNode *parent, bool initVB) 
      81                 : {
      82          184076 :   if (initVB)
      83          184076 :     branchSubAsChildOf(parent);
      84          184076 :   lp = parent->mGlobal()->lp;
      85          184076 :   globalPtr = parent->mGlobal();
      86                 : 
      87                 :   // Use mfValue from the parent, until this
      88                 :   // subproblem has been bounded
      89          184076 :   if (mGlobal()->mipHeuristicPtr)
      90                 :     {
      91               0 :       mfValue = parent->mfValue;
      92               0 :       mGlobal()->mipHeuristicPtr->inform(this);
      93                 :     }
      94                 : 
      95          184076 :   MILPNodeInit();
      96          184076 : }
      97                 : 
      98          184093 : void MILPNode::MILPNodeInit()
      99                 : {
     100                 :   //
     101                 :   // Initialize the local LP solver
     102                 :   //
     103                 :   // Try doing this directly in the constructor to avoid exessive make/deletes
     104                 :   //lp &= mGlobal()->lp;
     105                 : 
     106                 :   //DEBUGPR(4, ucout << "Entering MILPNode::MILPNode" << endl;);
     107                 :   
     108                 :   // get local reference to lp and mip()
     109          184093 :   MILPProblem* localMipRef = mip();
     110                 :  
     111                 :   // We use this a lot for this routine, so keep local.
     112          184093 :   int numInts = localMipRef->numIntegerVars();
     113          184093 :   basisValid=false;
     114          184093 :   basis.resize(initialBasisSize());
     115          184093 :   solVector.resize(numInts);  // This is enlarged later for terminal nodes...
     116          184093 :   fixed.resize(numInts);     // ... otherwise we don't care about cts variables 
     117          184093 :   if (localMipRef->numBinaryVars() > 0)
     118          184093 :   binary_vals.resize(numInts);
     119                 : 
     120          184093 :   intLowerBounds.resize(localMipRef->numGeneralIntVars());
     121          184093 :   intUpperBounds.resize(localMipRef->numGeneralIntVars());
     122                 : 
     123          184093 :   size_type num_sets = (size_type)localMipRef->numSets();
     124          184093 :   spSetLowerBounds.resize(num_sets);
     125          184093 :   spSetUpperBounds.resize(num_sets);
     126          184093 :   setCandidateNdx.resize(num_sets);
     127          184093 :   spSetBranchValues.resize(num_sets);
     128                 : 
     129                 :   // nFrac is not valid until the problem is solved
     130          184093 :   nFrac = localMipRef->numIntegerVars() + 1;
     131          184093 :   nSetCandidates = 0; // also not valid, but if we aren't using sets, we'll want a reasonable number.
     132          184093 :   FracVarNdx.resize(numInts);
     133          184093 :   reducedCosts.resize(numInts);
     134                 : 
     135          184093 :   branchType = no_branch;
     136          184093 :   branchValue = -999.0;         // This should never be used, but...
     137          184093 :   lpBound = MAXDOUBLE * globalPtr->sense;
     138          184093 : }
     139                 : 
     140                 :  
     141                 : // This is to make the root node (no parent).  It assumes the LP is loaded.
     142                 :  
     143              17 : void MILPNode::setRootComputation()
     144                 : {
     145                 :   // Note that basis is not valid till the problem is solved.  
     146                 : 
     147              17 :   binary_vals.reset();
     148                 : 
     149                 :   // Root starts with just the bounds from the original problem.
     150              17 :   if (!mip()->getbounds(fixed,intLowerBounds,intUpperBounds,binary_vals, spSetLowerBounds, spSetUpperBounds))
     151               0 :     setState(dead);
     152                 : 
     153                 :   // Root has no parent.  We can make this value a named constant
     154                 :   // if it makes sense.
     155                 : 
     156              17 :   parentId.setEmpty();
     157                 : 
     158                 :   // branchVariable also not valid initially
     159              17 :   branchVariable = -1;  // valid entries should be 0 to numInts - 1
     160              17 :   recordPCost = FALSE;  // no parent value to compare to
     161                 :   
     162              17 :   DEBUGPR(10, ucout << "MILPNode::setRootComputation() invoked.\n");
     163              17 : };
     164                 : 
     165                 : 
     166                 : 
     167                 : //---------------------------------------------
     168                 : // Create a child node
     169                 : //---------------------------------------------
     170                 : 
     171               0 : pebbl::branchSub * MILPNode::makeChild(int whichChild) 
     172                 : {
     173                 :   MEMDEBUG_START_NEW("MILPNode")
     174               0 :     MILPNode *child = new MILPNode();
     175                 : #ifdef ACRO_VALIDATING
     176                 :  if (child == NULL)
     177                 :    EXCEPTION_MNGR(runtime_error, "Failed to allocate new MILPNode\n");
     178                 : #endif
     179               0 :     child->MILPNodeAsChildOf(this);
     180                 :   MEMDEBUG_END_NEW("MILPNode")
     181                 :     
     182                 :   MEMDEBUG_START_RESIZE("MILPNode")
     183               0 :     childInit(child, whichChild);
     184                 :   MEMDEBUG_END_RESIZE("MILPNode")
     185                 : 
     186               0 :   return(child);
     187                 : }
     188                 : 
     189                 : // Branches in preferred direction for child 0 and in opposite direction
     190                 : // for child 1.  If a higher number is given, this will duplicate child
     191                 : // 1.  Assume there are checks elsewhere for generation of too many children.
     192                 : 
     193                 : // Remember, if you add a field to the milp node (e.g. initialized here),
     194                 : // you also have to initialize in packChild, and add to pack, unpack, and sp
     195                 : // (subproblem) sizing routine (the one that estimates the packed size of
     196                 : // a subproblem.
     197                 : 
     198          184076 : void MILPNode::childInit(MILPNode *child, int whichChild)
     199                 : {
     200          184076 :   child->lpBound = lpBound;
     201          184076 :   child->recordPCost = recordPCost;
     202          184076 :   child->basis << basis;  // This should be a copy, not a link
     203                 : 
     204          184076 :   child->fixed << fixed;
     205          184076 :   child->binary_vals << binary_vals;
     206                 : 
     207                 :   // This is true for starters.  At least one more will be restricted later.
     208          184076 :   child->intLowerBounds << intLowerBounds;
     209          184076 :   child->intUpperBounds << intUpperBounds;
     210          184076 :   if (mGlobal()->useSets)
     211                 :     {
     212          184076 :       child->spSetLowerBounds << spSetLowerBounds;
     213          184076 :       child->spSetUpperBounds << spSetUpperBounds;
     214                 :     }
     215                 : 
     216          184076 :   child->branchVariable = branchVariable;
     217          184076 :   child->branchValue = branchValue;
     218                 : 
     219                 :   // Update the branch type and upper/lower bounds.  If we have
     220                 :   // fractional variables, we use adjustNodeBounds in the usual way.
     221                 :   // Otherwise, we must be enumerating, which requires branch and cut,
     222                 :   // so we'll let BCMip::childInit handle the bounds and setting the
     223                 :   // branch type.
     224                 : 
     225          184076 :   if (nFrac > 0)
     226                 :     {
     227          184076 :       child->branchType = childBranchType(child, whichChild);
     228          184076 :       child->adjustNodeBounds(branchVariable, child->branchType);
     229                 :     }
     230                 :   
     231                 :   // Pretty much done now...
     232                 : 
     233          184076 :   if (mGlobal()->debug >= 10) {
     234                 :     ucout << "parent= " << id << ", child = " << child->id 
     235                 :           << ", branchVar = " << branchVariable << ", type = " 
     236               0 :           << (int)(child->branchType) << "\n";
     237                 :   }
     238                 : 
     239          184076 :   child->parentId = id;
     240                 : 
     241                 :   // verbosity tag
     242                 : 
     243          184076 :   DEBUGPR(10, ucout << "Created child of " << this << '\n');
     244          184076 : }
     245                 : 
     246                 : 
     247          184076 : branch_type MILPNode::childBranchType(MILPNode *child, int whichChild)
     248                 : {
     249                 :   // branchType indicates preferred branch direction, which is defined to
     250                 :   // be child 0.
     251          184076 :   if (whichChild == 0)
     252           92038 :     return(branchType);
     253                 :   else {
     254           92038 :     if (branchType == branch_up)  return(branch_down);
     255           74961 :     else if (branchType == branch_down) return(branch_up);
     256               0 :     else EXCEPTION_MNGR(runtime_error,"Trying to create a child for a "
     257                 :                         "parent without branching indicator");
     258               0 :     return(no_branch); // to keep compiler happy
     259                 :   }
     260                 : }
     261                 : 
     262                 : 
     263                 : 
     264                 : // Presumably all the arrays are automatically collected, since weren't
     265                 : // allocated with new() (done with vector mechanism).
     266          184090 : MILPNode::~MILPNode() 
     267                 : {
     268          184090 : }
     269                 : 
     270                 : // For heuristic, delete mfValue of this subproblem from the
     271                 : // population, then call the original method
     272                 : 
     273          184090 : void MILPNode::recycle()
     274                 : {
     275          184090 :   if (mGlobal()->mipHeuristicPtr)
     276               0 :     mGlobal()->mipHeuristicPtr->remove(this);
     277                 :  
     278          184090 :   branchSub::recycle();
     279          184090 : }
     280                 : 
     281                 : //
     282                 : // Use LP to compute the lower bound.  Has to work for root too with
     283                 : // current search framework.
     284                 : //
     285          184093 : void MILPNode::boundComputation(double* controlParam) 
     286                 : {
     287                 : 
     288          184093 :   DEBUGPR(5, ucout << "Bounding problem " 
     289                 :           << this << " branchVariable=" << branchVariable 
     290                 :           << " branchType=" << branchType << "\n");
     291                 : 
     292                 : #ifdef ACRO_VALIDATING
     293                 :   DEBUGPR(2,if (mGlobal()->mipHeuristicPtr) 
     294                 :           mGlobal()->mipHeuristicPtr->checkLP("boundComputation"));
     295                 : #endif
     296                 : 
     297                 :   // Added by JE.  Says we're doing one subproblem.  Later, we may
     298                 :   // change this to be the number of pivots executed (set after calling solver)
     299          184093 :   *controlParam = 1;
     300                 : 
     301          184093 :   makeActiveLP();
     302                 : 
     303                 :   // TODO: temp
     304                 :   //  cout << "In boundComputation: \n";
     305                 :   //  printIntegerVariableSettings();
     306                 : 
     307          184093 :   double parent_bound = lpBound;
     308                 :  
     309          184093 :   PicoLPInterface::problemState solvedState = boundComputationGuts();
     310                 :  
     311          184091 :   if (solvedState == PicoLPInterface::solved) {
     312                 : 
     313           92155 :     setState(bounded);
     314                 : 
     315                 :     // Do some post-LP calculations and lock variables.  Don't bother
     316                 :     // if this solution will be thrown away
     317                 : 
     318                 :     // As long as we're not enumerating (in which case the node could live
     319                 :     // on), I think it's OK to not deactivate this, since it will be
     320                 :     // eliminated as soon as the candidate is recorded (no children.
     321                 :     // No need to store cuts, increment reference counts, etc, just to
     322                 :     // undo that).  If noLongerActiveLP gains new functionality,
     323                 :     // consider changes here.
     324                 : 
     325           92155 :     if (candidateSolution())
     326                 :       {
     327              10 :         if (bGlobal()->enumerating)
     328               0 :           noLongerActiveLP();
     329                 :         else 
     330              10 :           return;
     331                 :       }
     332           92145 :     else if (!canFathom()) 
     333                 :       {
     334                 : 
     335                 :         // Need the solution for the integer variables to see how many integer
     336                 :         // variables are fractional
     337                 : 
     338           92126 :         lockVariables();
     339           92126 :         noLongerActiveLP();
     340                 : 
     341                 :         // JE -- this should probably go away once the E-N heuristic
     342                 :         // is moved into the general heuristic framework.
     343                 : 
     344           92126 :         if (mGlobal()->mipHeuristicPtr)
     345               0 :           mGlobal()->mipHeuristicPtr->update(this);
     346                 :       }
     347                 :     
     348           92145 :     return;
     349                 :   }
     350                 : 
     351                 :   // Serious problems would have been detected in boundComputationGuts().
     352                 :   // Otherwise the problem is infeasible or past the cutoff, both of which
     353                 :   // are valid reasons to fathom the problem (i.e. make it dead without error)
     354           91936 :   setState(dead);
     355           91936 :   if (!recordPCost) {
     356               1 :     return;
     357                 :   }
     358           91935 :   if (solvedState == PicoLPInterface::infeasible) {
     359           91935 :     mGlobal()->updateFromInfeasible(branchVariable, branchType);
     360                 :   }
     361                 :   // hit cutoff; for update use the LP cutoff, which may not correspond
     362                 :   // to the incumbent at this time
     363                 :   else
     364                 :     mGlobal()->updateFromCutoff(branchVariable, 
     365                 :                                 branchType, 
     366                 :                                 branchValue, 
     367                 :                                 parent_bound,
     368               0 :                                 lp->getDualCutoff());
     369           91935 :   return;
     370                 : }
     371                 : 
     372                 : // Set the LP solver environment to reflect this subproblem
     373                 : 
     374          184246 : void MILPNode::makeActiveLP()
     375                 : {
     376                 :   // Cut off set to incumbent value in the updateIncumbent routine of MILP
     377          184246 :   if (isRoot()) {
     378              51 :     if (mGlobal()->useSavedRootSolution)
     379               0 :         setSolverMethod(mGlobal()->warmSimplexMethod);
     380                 :     else
     381              51 :         setSolverMethod(mGlobal()->rootSimplexMethod);
     382              51 :     allowWarmStart();
     383              51 :     updateLastID();
     384              51 :     return;
     385                 :   }
     386                 :   // Only done if necessary
     387          184195 :   setBounds();
     388          184195 :   if (isWarmStart()) {
     389            6209 :     setSolverMethod(mGlobal()->warmSimplexMethod);
     390                 :   } else {
     391          177986 :     setSolverMethod(mGlobal()->nonwarmSimplexMethod);
     392          177986 :     setBasis();
     393                 :   }
     394                 :   // Have to do this at the end to make sure we update bounds, etc, correctly.
     395          184195 :   allowWarmStart();
     396          184195 :   updateLastID();
     397                 : }
     398                 : 
     399                 : // Set LP bounds to reflect this subproblem.  Bounds in this subproblem already reflect
     400                 : // any differences from the parent.
     401                 : 
     402          184085 : void MILPNode::setBounds() {
     403          184085 :   if (!isWarmStart()) {
     404          177986 :     setAllLPBounds(fixed, intLowerBounds, intUpperBounds, binary_vals);
     405          177986 :     return;
     406                 :   }
     407                 :   // For now, a child differs from its parent in only one variable.
     408            6099 :   DEBUGPR(150, ucout << "warm start\n");
     409                 : 
     410            6099 :   MILPProblem* localMipRef = mip();
     411            6099 :   if (mGlobal()->useSets && branchVariable >= localMipRef->numIntegerVars())
     412                 :     {
     413                 :       // Branching on a set.  Set variables in the set outside the indicated index range to 0.
     414               0 :     int setNum = branchVariable - localMipRef->numIntegerVars();
     415               0 :     IntVector& thisSet = localMipRef->specialSets[setNum];
     416                 :     size_type k;
     417                 :     size_type setStart, setEnd;  // range of variables (indices into set) to be adjusted
     418               0 :     if (branchType == branch_up)
     419                 :       {
     420               0 :       setStart = (size_type) parentSetBound;
     421               0 :       setEnd = (size_type) floor(branchValue);
     422                 :       }
     423                 :     else
     424                 :       {
     425               0 :       setStart = (size_type) ceil(branchValue);
     426               0 :       setEnd = (size_type) parentSetBound;
     427                 :       }
     428                 :       // Only one variable allowed to receive the 1, so set it
     429               0 :     if (spSetLowerBounds[setNum] == spSetUpperBounds[setNum])
     430               0 :       lp->setColLower(localMipRef->integerVarNdx[thisSet[spSetUpperBounds[setNum]]], 1.0);
     431                 : 
     432               0 :     for (k= setStart; k <= setEnd; k++)
     433               0 :       lp->setColUpper(localMipRef->integerVarNdx[thisSet[k]], 0.0);
     434               0 :     return;
     435                 :     }
     436                 :   // get LP variable number
     437            6099 :   int thisVarIndex = localMipRef->integerVarNdx[branchVariable];
     438            6099 :   if (localMipRef->vtype[thisVarIndex] == generalInteger) {
     439            5786 :     if (branchType == branch_up)
     440                 :       lp->setColLower(thisVarIndex,
     441             550 :                               intLowerBounds[localMipRef->reverseBoundsNdx[branchVariable]]);
     442                 :     else 
     443                 :       lp->setColUpper(thisVarIndex,
     444            5236 :                               intUpperBounds[localMipRef->reverseBoundsNdx[branchVariable]]);
     445             313 :   } else if (localMipRef->vtype[thisVarIndex] == binary) {
     446             313 :     if (branchType == branch_up)
     447             139 :       lp->setColLower(thisVarIndex, (double) 1);
     448                 :     else 
     449             174 :       lp->setColUpper(thisVarIndex, (double) 0);
     450                 :   }
     451               0 :   else EXCEPTION_MNGR(runtime_error,"*** Trying to branch on noninteger variable");
     452                 : }
     453                 : 
     454                 : // Adjust some bounds in the LP associated with a single branch choice
     455                 : // (one variable or one set). This is used during pseudocost
     456                 : // initialization, so we assume the node has the full ranges reflected
     457                 : // in its variable/set bounds. branchChoice is encoded the way the
     458                 : // MILP class encodes branching choices: the first # integers values
     459                 : // are for variables, the next # sets values are for the sets.  If
     460                 : // reset is true, then this actually *undoes* a branch (e.g. after
     461                 : // "fake" branching for pseudocost initialization).
     462                 : 
     463                 : // Note -- JE -- added ability to modify an arbitrary LP instead of the 
     464                 : // usual one.
     465                 : 
     466                 : void MILPNode::adjustLPBounds(OsiSolverInterface* whichLP,
     467                 :                               int                 branchChoice, 
     468                 :                               branch_type         direction, 
     469             653 :                               bool                reset) 
     470                 : {
     471             653 :   DEBUGPR(200,ucout << "MILPNode::adjustLPBounds invoked"
     472                 :           << (reset ? " (reset flag)" : "") << endl);
     473                 :   
     474             653 :   MILPProblem* localMipRef = mip();
     475                 : 
     476             653 :   if (mGlobal()->useSets && branchChoice >= localMipRef->numIntegerVars())
     477                 :     {
     478                 :       // Branching on a set.  Set variables in the set 
     479                 :       // outside the indicated index range to 0.
     480                 : 
     481               0 :       DEBUGPR(200,ucout << "SOS set " 
     482                 :                         << branchChoice - localMipRef->numIntegerVars()<<endl);
     483                 :  
     484               0 :       int setNum = branchChoice - localMipRef->numIntegerVars();
     485               0 :       IntVector& thisSet = localMipRef->specialSets[setNum];
     486                 :       size_type k;
     487                 :       size_type setStart;       // Range of variables (indices into set)
     488                 :       size_type setEnd;         // to be adjusted
     489                 : 
     490               0 :       if (direction == branch_up)
     491                 :         {
     492               0 :           setStart = (size_type) spSetLowerBounds[setNum];
     493               0 :           setEnd = (size_type) floor(spSetBranchValues[setNum]);
     494                 :         }
     495                 :       else
     496                 :         {
     497               0 :           setStart = (size_type) ceil(spSetBranchValues[setNum]);
     498               0 :           setEnd = (size_type) spSetUpperBounds[setNum];
     499                 :         }
     500                 : #ifdef ACRO_VALIDATING
     501                 :       if (setEnd > 10000)
     502                 :                 cout << "milpNode.cpp:471: heres a bad set: " << setNum<<endl;
     503                 : #endif
     504                 :       int intVarNum;
     505               0 :       for (k=setStart; k<=setEnd; k++)
     506                 :         {
     507               0 :           intVarNum = thisSet[k];
     508                 :           // Some of the variables in a special set range 
     509                 :           // could already be fixed (in this case to 0)
     510               0 :           if (!fixed(intVarNum))
     511                 :             {
     512                 :               whichLP->setColUpper(localMipRef->integerVarNdx[intVarNum], 
     513               0 :                                    (reset ? 1.0 : 0.0));
     514               0 :               DEBUGPR(200,ucout << "Set upper bound of variable "
     515                 :                       << intVarNum << '/'
     516                 :                       << localMipRef->integerVarNdx[intVarNum]
     517                 :                       << " to " << (reset ? 1.0 : 0.0) << endl);
     518                 :             }
     519                 :         }
     520               0 :       return;
     521                 :     }
     522                 : 
     523                 :   // Regular variable.  Get LP variable number
     524                 : 
     525             653 :   int thisLPVarIndex = localMipRef->integerVarNdx[branchChoice];
     526                 : 
     527             653 :   if (localMipRef->vtype[thisLPVarIndex] == generalInteger) 
     528                 :     {
     529             187 :       int genIntNum = localMipRef->reverseBoundsNdx[branchChoice];
     530                 :       int newVal;
     531                 : 
     532                 :       // Could do this with ? : syntax too, but it would make 
     533                 :       // it a bit harder to read
     534                 : 
     535             187 :       if (direction == branch_up)
     536                 :         {
     537              92 :           if (reset)
     538              46 :             newVal = intLowerBounds[genIntNum];
     539              46 :           else newVal = (int) ceil(solVector[branchChoice]);
     540              92 :           whichLP->setColLower(thisLPVarIndex, newVal);
     541              92 :           DEBUGPR(200,ucout << "Set lower bound of general variable "
     542                 :                   << branchChoice << '/' << thisLPVarIndex
     543                 :                   << " to " << newVal << ", solVector[" << branchChoice
     544                 :                   << "]=" << solVector[branchChoice] << endl);
     545                 :         }
     546                 :       else 
     547                 :         {
     548              95 :           if (reset)
     549              46 :             newVal = intUpperBounds[genIntNum];
     550              49 :           else newVal = (int) floor(solVector[branchChoice]);
     551              95 :           whichLP->setColUpper(thisLPVarIndex, newVal);
     552              95 :           DEBUGPR(100,ucout << "Set upper bound of general variable "
     553                 :                   << branchChoice << '/' << thisLPVarIndex
     554                 :                   << " to " << newVal << "solVector[" << branchChoice
     555                 :                   << "]=" << solVector[branchChoice] << endl);
     556                 :         }
     557                 :     }
     558                 :   else  //binary
     559                 :     {
     560             466 :       if (direction == branch_up)
     561                 :         {
     562             224 :           whichLP->setColLower(thisLPVarIndex, reset ? 0.0: 1.0);
     563             224 :           DEBUGPR(100,ucout << "Set lower bound of binary variable "
     564                 :                   << branchChoice << '/' << thisLPVarIndex
     565                 :                   << " to " << (reset ? 0.0: 1.0) << endl);
     566                 :         }
     567                 :       else 
     568                 :         {
     569             242 :           whichLP->setColUpper(thisLPVarIndex, reset ? 1.0 : 0.0);
     570             242 :           DEBUGPR(100,ucout << "Set upper bound of binary variable "
     571                 :                   << branchChoice << '/' << thisLPVarIndex
     572                 :                   << " to " << (reset ? 1.0 : 0.0) << endl);
     573                 :         }
     574                 :     }
     575                 : }
     576                 : 
     577                 : 
     578                 : // Runs the LP.  If the problem has serious problems, signal an error, which
     579                 : // is assumed to abort the computation.  Otherwise, return the state (either
     580                 : // solved, infeasible, or past cut-off).
     581                 : 
     582          184678 : PicoLPInterface::problemState MILPNode::runLP()
     583                 : {
     584          184678 :   if (!isRoot())
     585          184562 :     lp->solve(true); // know the primal is bounded
     586                 :   else  // doing pseudocost init on the root if the state is bounded (hence primal bounded)
     587             116 :      lp->solve(state==beingSeparated);
     588                 :  
     589          184678 :   PicoLPInterface::problemState solvedState = lp->state();
     590                 :  
     591          184678 :   if (solvedState == PicoLPInterface::unsolved)
     592               0 :     EXCEPTION_MNGR(runtime_error, "LP Returned Unsolved State");
     593          184678 :   if (solvedState == PicoLPInterface::unbounded)
     594                 :     {
     595               0 :     EXCEPTION_MNGR(runtime_error, "LP Instance Unbounded");
     596                 :     }
     597          184678 :   if (solvedState == PicoLPInterface::broken) {
     598                 :     //    printMILPNode();
     599                 :     //    lp->testLP();
     600                 :     // DELETE THIS FIRST ONE
     601               0 :     lp->write("bad.mps", mps_format);
     602               0 :     lp->printBrokenInfo();
     603               0 :     checkLPBounds();
     604               0 :     EXCEPTION_MNGR(runtime_error, "LP Instance Broken");
     605                 :   }
     606                 : 
     607          184678 :   return(solvedState);
     608                 : }
     609                 : 
     610                 : // Warning: changes here should be propagated to
     611                 : // parMILPNode::boundingSolve().  TODO: can we clean
     612                 : // these methods up and avoid code duplication?
     613                 : 
     614          184368 : PicoLPInterface::problemState MILPNode::boundingSolve()
     615                 : {
     616                 :   PicoLPInterface::problemState solvedState;
     617          184368 :   double parent_bound = lpBound;
     618          184368 :   if (useSavedSolutionNow())
     619                 :     {
     620               0 :     solvedState = retrieveRootSolution();
     621               0 :     if (solvedState != PicoLPInterface::solved)
     622               0 :       return(solvedState);
     623                 :     // Make the LP solver look as though it has just finished this bounding
     624               0 :     restoreLPSolver();
     625                 :     }
     626                 :   else
     627                 :     {
     628          184368 :     solvedState = runLP();
     629          184368 :     if (solvedState != PicoLPInterface::solved)
     630           91931 :       return(solvedState);
     631           92437 :     lpBound = lp->getObjValue();
     632           92437 :     getSolution();
     633                 :     //    cout << "Ran LP for problem " << id << ". New solution is: " << solution << "\n";
     634           92437 :     getBasis(basis);
     635                 :     // Temporary for basis experiments
     636           92437 :     if (mGlobal()->recordBasisInfo)
     637                 :       {
     638               0 :       *(mGlobal()->basisOutfile) << basis << "\n";
     639                 :     //    cout << "New basis is: " << basis << "\n";
     640                 :       // use serial numbers produced as a surrogate for # of bases output.  Most problems are
     641                 :       // bounded before they're stored I think.
     642               0 :       if (mGlobal()->probCounter > mGlobal()->earlyStopBasisInfoCount)
     643               0 :         EXCEPTION_MNGR(runtime_error, "Hit the limit for basis recording.  Stopping computation\n");
     644                 :       }
     645                 :     }
     646                 :     // LP value could improve the bound
     647           92437 :   if (lround(lp->getObjSense()) == pebbl::minimize)
     648           92432 :     bound = max(bound, lpBound);
     649               5 :   else bound = min(bound, lpBound);
     650           92437 :   nFrac = computeFracVars(); // Also sets FracVarNdx, and computes set candidates
     651                 : 
     652                 :   // This should be true except for the root (which has no parent for
     653                 :   // comparison) and cases where pseudocosts were recorded during a
     654                 :   // pseudocost initialization phase and then the parent is separated
     655                 :   // using one of these newly-initialized variables (i.e. this check
     656                 :   // prevents a double recording).
     657                 : 
     658           92437 :   if (updatePCFromBoundingSolve())
     659                 :     updatePseudoCosts(lpBound, parent_bound, branchType,  
     660           92158 :                       branchVariable, branchValue);
     661                 : 
     662           92437 :   return(PicoLPInterface::solved);
     663                 : }
     664                 : 
     665                 :   // Get the root solution from a file (e.g. when the root subproblem has been solved by
     666                 :   // another solver, perhaps on another platform).  This is particularly useful for
     667                 :   // parallel runs when the root solve is much more expensive than a re-solve.
     668                 : 
     669               0 : PicoLPInterface::problemState MILPNode::retrieveRootSolution()
     670                 : {
     671                 :   PicoLPInterface::problemState solvedState;
     672                 :   int tempState;
     673                 :   // Just to be sure...
     674               0 :   forceColdStart();
     675               0 :   string rootSolFileName(mGlobal()->problemName);
     676               0 :   if (rootSolFileName.length() > 0)
     677               0 :     rootSolFileName += "-bounding-info.bin";
     678               0 :   else rootSolFileName = "root-bounding-info.bin";
     679               0 :   ifstream savedSolution(rootSolFileName.c_str());
     680               0 :   if (savedSolution.bad())
     681               0 :     EXCEPTION_MNGR(runtime_error, "Can't open the saved root solution");
     682               0 :   savedSolution >> tempState;
     683               0 :   solvedState = (PicoLPInterface::problemState) tempState;
     684               0 :   if (solvedState != PicoLPInterface::solved)
     685               0 :     return(solvedState);
     686               0 :   savedSolution >> lpBound;
     687               0 :   savedSolution >> solVector;
     688                 :   // Till we have the CLP basis problems fixed
     689                 :   int basisAvailInt;
     690               0 :   savedSolution >> basisAvailInt;
     691               0 :   if (basisAvailInt == 1)
     692               0 :     basisValid = true;
     693               0 :   else basisValid = false;
     694               0 :   savedSolution >> basis;
     695               0 :   return(PicoLPInterface::solved);
     696                 : }
     697                 : 
     698          184400 : void MILPNode::setSolverMethod(MILP::LPMethodType method)
     699                 : {
     700          184400 :   if (method == MILP::dual)
     701          184349 :     lp->setLPMethod(PicoLPInterface::dualSimplex);
     702              51 :   else if (method == MILP::primal)
     703              51 :     lp->setLPMethod(PicoLPInterface::primalSimplex);
     704                 :   // Shouldn't happen if we really have an LPMethodType passed in
     705               0 :   else EXCEPTION_MNGR(runtime_error, "Illegal LP method: %d\n");
     706          184400 : }
     707                 : 
     708                 : 
     709                 : //---------------------------------------------
     710                 : // Decide how many children to compute
     711                 : // Also, decide how children are generated
     712                 : //---------------------------------------------
     713                 : 
     714           92038 : int MILPNode::splitComputation()
     715                 : {
     716           92038 :   DEBUGPRX(100,bGlobal(),"In MILPNode::splitComputation\n");
     717                 : 
     718                 :   // get local reference to mip()
     719           92038 :   MILPProblem* localMipRef = mip();
     720                 : 
     721                 :   // This compiles, but doesn't actually appear to turn on debugging.
     722                 :   //if (id.serial==5) localMipRef->setDebug(100);
     723                 : 
     724           92038 :   int numInts = localMipRef->numIntegerVars();
     725                 : 
     726                 :   // JE: if we actually have a terminal node being branched for
     727                 :   // enumeration, do a different computation instead of the usual one
     728                 :   // by calling terminalSplit.  This routine will throw an exception
     729                 :   // unless we have cuts.
     730                 : 
     731           92038 :   if (nFrac == 0)
     732               0 :     return terminalSplit();
     733                 :  
     734                 :   double minBenefit; // dummy for this (used to track quality of branching)
     735                 :   // Note:  branchtype passed by reference; will be filled in
     736           92038 :   branchVariable = chooseBranchVariable(branchType, minBenefit);
     737           92038 :   if (state == dead) return(0);
     738                 : 
     739           92038 :   if (mGlobal()->useSets && (branchVariable >= numInts))
     740               0 :     branchValue = spSetBranchValues[branchVariable-numInts];
     741           92038 :   else branchValue = solVector[branchVariable];
     742                 :   // For now, we are assuming only two children, even for general integer vars
     743                 :   // childrenLeft is set in branchSub::splitProblem
     744           92038 :   setState(separated);   // Added by JE when beingSeparated state introduced.
     745           92038 :   return 2;
     746                 : }
     747                 : 
     748                 : // Initialize some of the pseudocosts.  numBranches is the number of
     749                 : // variables/sets to initialize.  It should never be 0, but the code
     750                 : // will work even if it is. initVars has indices into the full set of
     751                 : // branching choices.  If the entry is < # integer variables, it's a
     752                 : // variable.  Otherwise it's a set. If dontRemoveAllBranchChoices is true, then
     753                 : // even if all the choices are half infeasible, make sure that one
     754                 : // still has its original bounds so we can legitimately branch on a
     755                 : // choice with highest priority (at least for now, all these variables
     756                 : // have the highest priority among all branching
     757                 : // choices). removeBranchChoiceNow=false suppresses actions on half-infeasible
     758                 : // branching choices (i.e. bounds narrowing and removal from branching
     759                 : // consideration).  This is false for derived parallel methods and when there is
     760                 : // a possibility of overlapping SOS among the branch choices.
     761                 : // The boolean parameter stopOnInfeasible set to true means that as soon as
     762                 : // this method detects subproblem infeasibility (both branches of a branch choice
     763                 : // are LP infeasible), then it stops computing any more pseudocosts.  This is
     764                 : // default.  The only time it is false is in parallel ramp up when the processor
     765                 : // would otherwise be idle.
     766                 : 
     767                 : 
     768                 : void MILPNode::pseudoCostInit(IntVector &initVars, 
     769                 :                               int numBranches,
     770                 :                               bool dontRemoveAllBranchChoices,
     771                 :                               bool removeBranchChoiceNow, 
     772             153 :                               bool stopOnInfeasible)
     773                 : {
     774                 :   double upBound, downBound, bestBound;
     775                 :   // TODO: remove
     776                 :   //  ucout << "Initializing " << numBranches << " branches.\n";
     777                 :   /*  ucout << "pseudoCostInit, " << numBranches << " to init. Vars are: \n";
     778                 :      for (int tempry = 0; tempry < numBranches; tempry++)
     779                 :      ucout << initVars[tempry] << ", ";
     780                 :      ucout << "\n"; */
     781                 : 
     782                 :   int branchChoice;
     783                 :   bool upRunInfeasible, downRunInfeasible;
     784                 : 
     785                 : #ifdef ACRO_VALIDATING
     786                 :   double PCStart = CPUSeconds();
     787                 : #endif
     788                 : 
     789             153 :   makeActiveLP();
     790                 : 
     791             150 :   do {
     792             154 :     branchChoice = initVars[--numBranches];
     793                 :     // Reset to this subproblem's basis for each run.  For some problems, we were
     794                 :     // getting numerical problems on subsequent down branching.  On all iterations after
     795                 :     // the first, the up branch will also have two variable changes.  See if this improves
     796                 :     // stability.
     797             154 :     setBasis();
     798                 : 
     799             154 :     adjustLPBounds(branchChoice, branch_up);
     800                 : 
     801             154 :     upRunInfeasible = boundAndRecord(branch_up, branchChoice);
     802                 : 
     803             154 :     postPseudoBranch(branchChoice, branch_up);
     804             154 :     upBound = lp->getObjValue();
     805                 : 
     806                 : 
     807                 :     // Restore bounds in LP
     808             154 :     adjustLPBounds(branchChoice, branch_up, true);
     809                 : 
     810                 :     // Set variable bounds for the down branch. 
     811             154 :     adjustLPBounds(branchChoice, branch_down);
     812                 :       
     813             154 :     setSolverMethod((MILP::LPMethodType)(mGlobal()->warmSimplexMethod));
     814                 :       // Reset to this subproblem's basis for each run.  For some problems, we were
     815                 :       // getting numerical problems on subsequent down branching.
     816             154 :     setBasis();
     817             154 :     downRunInfeasible = boundAndRecord(branch_down, branchChoice);
     818             154 :     postPseudoBranch(branchChoice, branch_down);
     819             154 :     downBound = lp->getObjValue();
     820                 : 
     821                 :     // restore LP bounds
     822             154 :     adjustLPBounds(branchChoice, branch_down, true);
     823                 : 
     824             154 :     if (upRunInfeasible)
     825                 :       {
     826              33 :         upBound = bGlobal()->sense * MAXDOUBLE;
     827              33 :         mGlobal()->updateFromInfeasible(branchChoice, branch_up);
     828                 : 
     829              33 :         if (downRunInfeasible) // subproblem can be fathomed
     830                 :           {
     831               4 :             setState(dead);
     832               4 :             downBound = bGlobal()->sense * MAXDOUBLE;
     833               4 :             mGlobal()->updateFromInfeasible(branchChoice, branch_down);
     834               4 :             if (stopOnInfeasible)
     835               4 :               break;
     836                 :           }
     837                 :           // Take advantage of the half infeasibility by narrowing ranges and removing from consideration
     838                 :           // for branching.  We cannot do this if this is the last initialization
     839                 :           // and all previous ones have been half infeasible too.
     840              29 :         else if ((!dontRemoveAllBranchChoices || numBranches > 0) && removeBranchChoiceNow)
     841                 :           {
     842              29 :           removeBranchChoice(branchChoice);
     843                 :   // This is necessary for B&C, and no harm for straight B&B
     844              29 :           adjustLPBounds(branchChoice, branch_down);
     845                 :           // Have to adjust LP bounds first since that relies on node bounds
     846              29 :           adjustNodeBounds(branchChoice, branch_down);
     847                 :           }
     848                 :       }
     849                 : 
     850             121 :     else if (downRunInfeasible)
     851                 :       {
     852                 :           // See above similar case for explanation
     853               9 :         if ((!dontRemoveAllBranchChoices || numBranches > 0) && removeBranchChoiceNow)
     854                 :           {
     855               8 :             removeBranchChoice(branchChoice);
     856               8 :             adjustLPBounds(branchChoice, branch_up);
     857                 :             // Have to adjust LP bounds first since that relies on node bounds
     858               8 :             adjustNodeBounds(branchChoice, branch_up);
     859                 :           }
     860               9 :         downBound = bGlobal()->sense * MAXDOUBLE;
     861               9 :         mGlobal()->updateFromInfeasible(branchChoice, branch_down);
     862                 :       }
     863                 :     /*
     864                 :     ucout << "Branch Choice = " << branchChoice << " upBound = " << upBound << ", downBound = " << downBound << ", bound = " << bound << "\n";
     865                 :     */
     866             150 :     if (lround(lp->getObjSense()) == pebbl::minimize)
     867                 :       {
     868             150 :         bestBound = min(upBound, downBound); // valid bound for the subproblem
     869             150 :         bound = max(bestBound, bound); // could have seen a better one in other
     870                 :         // subproblems
     871                 :       }
     872                 :     else
     873                 :       {
     874               0 :         bestBound = max(upBound, downBound);
     875               0 :         bound = min(bestBound, bound);
     876                 :       }
     877                 :     //  ucout << ", new bound = " << bound << "\n";
     878                 :   } while (numBranches > 0);
     879             153 :   if (state == beingSeparated)  // in branch & cut world, might still be active
     880              20 :       noLongerActiveLP();
     881                 :   /*     mGlobal()->printPseudoCosts();
     882                 :          ucout << Flush; */
     883                 : #ifdef ACRO_VALIDATING
     884                 :    mGlobal()->MIPTimingInfo[PCInit] += CPUSeconds() - PCStart;
     885                 : #endif
     886             153 : }
     887                 : 
     888                 : // Used in initializing pseudocosts.  The LP has been set already.  Returns
     889                 : // 0 if the problem solved and 1 if the problem is infeasible or otherwise
     890                 : // fathomable.  Major errors will result in an abort at the time of the solve.
     891                 : 
     892             308 : int MILPNode::boundAndRecord(branch_type branchDirection, int branchingVar)
     893                 : {
     894             308 :   PicoLPInterface::problemState solvedState = PCInitSolve();
     895                 : 
     896             308 :   if (solvedState == PicoLPInterface::solved) {
     897                 :     //   ucout << "BAR calling UPC\n";
     898             262 :     int numInts = mip()->numIntegerVars();
     899                 :     double branchingVal;
     900             262 :     if (branchingVar >= numInts) // a set
     901                 :       {
     902               0 :       branchingVal = spSetBranchValues[branchingVar-numInts];
     903                 :       // the integer part encodes a place in the set list.  The
     904                 :       // real branching part is just the fractional piece.
     905               0 :       branchingVal -= floor(branchingVal);
     906                 :       }
     907             262 :     else branchingVal = solVector[branchingVar];
     908                 :       
     909                 :     updatePseudoCosts(lp->getObjValue(), lpBound, branchDirection,
     910             262 :                       branchingVar, branchingVal);
     911             262 :     return(0);
     912                 :   }
     913              46 :   else return(1);
     914                 : }
     915                 :   
     916                 : // Adjust the bounds within a MILPNode to implement a branch.  Used to
     917                 : // create children, in locking variables, and when infeasible branches
     918                 : // are discovered during the computation of pseudocosts. This
     919                 : // functionality is duplicated in packChild (changes should be
     920                 : // propagated).
     921                 : 
     922                 : void MILPNode::adjustNodeBounds(const int thisBranchVariable, 
     923          184113 :                                 branch_type branch_flag)
     924                 : {
     925          184113 :   MILPProblem* localMipRef = mip();
     926                 :   double thisBranchVal;
     927                 : 
     928                 :   // branching on a special set
     929          184113 :   if (mGlobal()->useSets && 
     930                 :       thisBranchVariable >= localMipRef->numIntegerVars())
     931                 :     {
     932               0 :     int setNum = thisBranchVariable - localMipRef->numIntegerVars();
     933               0 :     if (state == boundable)
     934               0 :       thisBranchVal = branchValue;
     935               0 :     else  thisBranchVal = spSetBranchValues[setNum];
     936                 :     // Branching on a set.  Set variables in the set outside the
     937                 :     // indicated index range to 0.
     938               0 :     IntVector& thisSet = localMipRef->specialSets[setNum];
     939                 :     size_type k, setStart, setEnd;
     940                 :     int thisSetVar;
     941                 :     // Figure out which binary variables will be forced to 0.
     942                 :     // This are delimited by setStart and setEnd.
     943               0 :     if (branch_flag == branch_up)
     944                 :       {
     945               0 :       setStart = (size_type) spSetLowerBounds[setNum];
     946                 :       // Next step not necessary if this is for infeasibility during
     947                 :       // pseudocost computation, but in that case, this value won't be
     948                 :       // used anymore.
     949               0 :       parentSetBound = setStart;
     950               0 :       setEnd = (size_type) floor(thisBranchVal);
     951               0 :       spSetLowerBounds[setNum] = setEnd+1;
     952                 : #ifdef ACRO_VALIDATING
     953                 :       if ((size_type) spSetUpperBounds[setNum] < setEnd+1)
     954                 :         EXCEPTION_MNGR(runtime_error,"Inconsistent set bounds for set" 
     955                 :                        << setNum << " (" << setEnd+1 
     956                 :                        << "," << spSetUpperBounds[setNum] 
     957                 :                        << "), branching up. setStart = " << setStart 
     958                 :                        << ", branchValue = " << thisBranchVal 
     959                 :                        << ". Node " << id << ". parent: " << parentId << "\n");
     960                 : #endif
     961                 :       // Only one variable allowed to receive the 1, so fix it
     962               0 :       if (spSetUpperBounds[setNum] == (int) setEnd+1)
     963                 :         {
     964               0 :         thisSetVar = thisSet[setEnd+1];
     965               0 :         fixed.set(thisSetVar);
     966               0 :         binary_vals.set(thisSetVar);
     967                 :         }
     968                 :       }
     969                 :     else // branching down
     970                 :       {
     971               0 :       setStart = (size_type) ceil(thisBranchVal);
     972               0 :       setEnd = (size_type) spSetUpperBounds[setNum];
     973               0 :       parentSetBound = setEnd;
     974               0 :       spSetUpperBounds[setNum] = setStart - 1;
     975                 : #ifdef ACRO_VALIDATING
     976                 :       if ((size_type) spSetLowerBounds[setNum] > setStart-1)
     977                 :         EXCEPTION_MNGR(runtime_error,"Inconsistent set bounds for set" << setNum << " (" << spSetLowerBounds[setNum] << "," << setStart-1 << ").  branching down. setEnd = " << setEnd << "branch value = " << thisBranchVal << "\n");
     978                 : #endif
     979                 : 
     980                 :       // Only one variable allowed to receive the 1, so fix it
     981               0 :       if (spSetLowerBounds[setNum] == (int) setStart-1)
     982                 :         {
     983               0 :         thisSetVar = thisSet[setStart-1];
     984               0 :         fixed.set(thisSetVar);
     985               0 :         binary_vals.set(thisSetVar);
     986                 :         }
     987                 :       }
     988               0 :     for (k= setStart; k <= setEnd; k++)
     989                 :       {
     990               0 :       thisSetVar = thisSet[k];
     991                 : #ifdef ACRO_VALIDATING
     992                 :       if (fixed(thisSetVar) && binary_vals(thisSetVar))
     993                 :         {
     994                 :           printMILPNode();
     995                 :         EXCEPTION_MNGR(runtime_error, "MilpNode::fix:  branching on set" 
     996                 :                        << thisBranchVariable - localMipRef->numIntegerVars() 
     997                 :                        << " when member var " << thisSetVar 
     998                 :                        << " already fixed to 1\n");
     999                 :         }
    1000                 : #endif
    1001                 : 
    1002                 :       // It's OK to redo this if already fixed to 0 (this is possible)
    1003               0 :       fixed.set(thisSetVar);
    1004               0 :       binary_vals.reset(thisSetVar);
    1005                 :       }
    1006               0 :     return;
    1007                 :     }
    1008                 : 
    1009                 :   //
    1010                 :   // branching on a variable
    1011                 :   //
    1012          184113 :   if (localMipRef->vtype[localMipRef->integerVarNdx[thisBranchVariable]] == binary) {
    1013           19838 :     fixed.set(thisBranchVariable);
    1014           19838 :     if (branch_flag == branch_up)
    1015            9910 :       binary_vals.set(thisBranchVariable);
    1016                 :     else
    1017            9928 :       binary_vals.reset(thisBranchVariable);
    1018                 :   }
    1019                 :   else {
    1020          164275 :     if (state == boundable)
    1021          164272 :       thisBranchVal = branchValue;
    1022               3 :     else  thisBranchVal = solVector[thisBranchVariable];
    1023          164275 :     int genIntVarNumber = localMipRef->reverseBoundsNdx[thisBranchVariable];
    1024          164275 :     if (branch_flag == branch_up)
    1025           82136 :       intLowerBounds[genIntVarNumber] = (int) ceil(thisBranchVal);
    1026                 :     else
    1027           82139 :       intUpperBounds[genIntVarNumber] = (int) floor(thisBranchVal);
    1028          164275 :     if (intLowerBounds[genIntVarNumber] == intUpperBounds[genIntVarNumber])
    1029           81465 :       fixed.set(thisBranchVariable);
    1030                 : #ifdef ACRO_VALIDATING
    1031                 :     if (intLowerBounds[genIntVarNumber] > intUpperBounds[genIntVarNumber])
    1032                 :       EXCEPTION_MNGR(runtime_error, 
    1033                 :                      "MilpNode::fix:  general variable with infeasible bounds."
    1034                 :                      "Integer Variable: " << genIntVarNumber << ", (" 
    1035                 :                      << intLowerBounds[genIntVarNumber] << "," 
    1036                 :                      << intUpperBounds[genIntVarNumber] << ")");
    1037                 : #endif
    1038                 :   }
    1039                 : }
    1040                 : 
    1041                 : // Called when the pseudocost initialization routine finds that a branch
    1042                 : // can be fathomed.  Since the range will be narrowed, don't allow branching
    1043                 : // on this variable (remove from fractional variable list).
    1044                 : 
    1045                 : // TODO: also have to remove individual variables as choices when a set is removed
    1046                 : // (at least one side; that may need another argument).
    1047                 : 
    1048              37 : void MILPNode::removeBranchChoice(int branchChoice)
    1049                 : {
    1050                 :   int i;
    1051              37 :   if (branchChoice >= mip()->numIntegerVars())
    1052                 :     {
    1053                 : #ifdef ACRO_VALIDATING
    1054                 :     bool found = false;
    1055                 : #endif
    1056               0 :     int setNum = branchChoice - mip()->numIntegerVars();
    1057               0 :     for (i = 0; i < nSetCandidates; i++)
    1058               0 :       if (setCandidateNdx[i] == setNum)
    1059                 :         {
    1060               0 :         setCandidateNdx[i] = setCandidateNdx[nSetCandidates-1];
    1061                 : #ifdef ACRO_VALIDATING
    1062                 :         found = true;
    1063                 : #endif  
    1064               0 :         break;
    1065                 :         }
    1066                 : #ifdef ACRO_VALIDATING
    1067                 :     if (!found)
    1068                 :       EXCEPTION_MNGR(runtime_error, "Trying to remove branchChoice " << branchChoice << " (set " << setNum << "). Not found\n");
    1069                 : #endif
    1070               0 :     nSetCandidates--;
    1071               0 :     return;
    1072                 :     }
    1073             115 :   for (i = 0; i < nFrac; i++) {
    1074             115 :     if (FracVarNdx[i] == branchChoice) {
    1075                 :       // Note:  if only 1 left, its index will still be in FracVarNdx[0]
    1076              37 :       FracVarNdx[i] = FracVarNdx[nFrac-1];
    1077              37 :       break;
    1078                 :     }
    1079                 :   }
    1080              37 :   nFrac--;
    1081                 : }
    1082                 : 
    1083                 : 
    1084               0 : double MILPNode::improveIncumbent() 
    1085                 : {
    1086                 :   // verbosity tag
    1087               0 :   DEBUGPR(10, ucout << "Trying to improve incumbent...\n");
    1088                 : 
    1089               0 :   if (state == beingBounded)
    1090               0 :     return incumbentValue();
    1091                 : 
    1092               0 :   if (nFrac == 0)
    1093               0 :     EXCEPTION_MNGR(runtime_error, "Trying to improve terminal solution");
    1094                 : 
    1095                 :   // A heuristic could go here, but not in the present approach
    1096                 : 
    1097               0 :   return incumbentValue();
    1098                 : };
    1099                 : 
    1100                 : 
    1101                 : // Not called unless this is a candidate solution (e.g.  no fractional
    1102                 : // variables), in which case solution should be valid.  But with a
    1103                 : // high integer tolerance, this may not be the case, so we check.
    1104                 : // Also set the integer variables to their exact integer values.
    1105                 : // Among other things, this makes it easier to compare solutions
    1106                 : // using, eg, standard utilib ==.  Node solution only contains integer
    1107                 : // variables, but the incumbent contains them all, so need to pull in
    1108                 : // the full solution now.
    1109                 : 
    1110                 : // JE: CP had this code in updateIncumbent() -- now it is extractSolution()
    1111                 : 
    1112               2 : pebbl::solution* MILPNode::extractSolution() 
    1113                 : {
    1114               2 :   MILPProblem* localMipRef = mip();
    1115                 :  
    1116               2 :   DEBUGPR(300,ucout << "MILPNode::extractSolution" << endl);
    1117               2 :   int numVars = localMipRef->numAllVars();
    1118               2 :   DoubleVector fullSolution(numVars);
    1119               2 :   lp->getColSolution(fullSolution.data());
    1120               2 :   DEBUGPR(300,ucout << "Got solution" << endl);
    1121                 :   int j;
    1122                 :   int intVal;
    1123               2 :   int numInts = localMipRef->numIntegerVars();
    1124                 :   // round all the integer variables (already tested for integrality)
    1125             118 :   for (int i=0; i < numInts; i++) {
    1126             116 :     j = localMipRef->integerVarNdx[i]; // get LP var# for this int var #
    1127             116 :     intVal = lround(fullSolution[j]);
    1128             116 :     fullSolution[j] = intVal;
    1129                 :     // Fix lower and upper bounds (doesn't matter if general or binary)
    1130                 :     // bounds of continuous variables are never changed   
    1131             116 :     lp->setColLower(j, intVal);
    1132             116 :     lp->setColUpper(j, intVal);
    1133                 :   }
    1134                 : 
    1135                 :   bool feasible;
    1136               2 :   if (numInts == numVars) // pure integer
    1137               0 :     feasible = lp->checkFeasibility(fullSolution);
    1138                 :   else
    1139                 :     {
    1140               2 :       PicoLPInterface::problemState solvedState = runLPWithIntsSet();
    1141               2 :       if (solvedState == PicoLPInterface::solved)
    1142               2 :         feasible = true;
    1143               0 :       else feasible = false;
    1144                 :     }
    1145                 : 
    1146                 :   // If we really have a solution, this node is now dead unless we are
    1147                 :   // enumerating.
    1148                 : 
    1149               2 :   if (feasible && !(bGlobal()->enumerating))
    1150               2 :     setState(dead);
    1151                 : 
    1152                 :   // JE: the end of the routine is different from the old updateIncumbent...
    1153                 : 
    1154               2 :   if (feasible) 
    1155                 :     {
    1156                 :       // JE: not sure that this code does or if it's in the right
    1157                 :       // place any more.
    1158               2 :       if (state == beingBounded)
    1159               0 :         mGlobal()->needPruning = false;
    1160                 : 
    1161               2 :       DEBUGPR(1,ucout << "***** " << "Terminal node yielded solution "
    1162                 :                 << lpBound << " *****\n");
    1163                 : 
    1164               2 :       return new MILPSolution(fullSolution,mGlobal(),lpBound);
    1165                 :     }
    1166                 : 
    1167                 :   // Something is fishy...
    1168                 : 
    1169               0 :   if (!(mGlobal()->suppressWarnings)) 
    1170                 :     ucout << "Warning: Not recording infeasible incumbent candidate,"
    1171               0 :           << " id: " << id << "\n";
    1172                 : 
    1173               0 :   return NULL;    // PEBBL will ignore this value
    1174                 : }
    1175                 : 
    1176                 : 
    1177                 : // Verify that the candidate solution is still feasible when integer
    1178                 : // values are set exactly.  Updates continuous variables via LP.  Also
    1179                 : // update lpBound (if the solution is valid).
    1180                 : 
    1181               2 : PicoLPInterface::problemState MILPNode::runLPWithIntsSet()
    1182                 : {
    1183               2 : DEBUGPR(300,ucout << "Integer variables rounded.\n" << Flush);
    1184               2 :   lp->setLPMethod(PicoLPInterface::primalSimplex);
    1185               2 :   DEBUGPR(300,ucout << "Method set" << endl << Flush);
    1186                 : 
    1187                 :   // Setting the basis at this point could cause some problems with
    1188                 :   // the B&C derived class (don't know or care what cuts are loaded),
    1189                 :   // so let's not set the basis for now.  Hopefully won't be a problem
    1190                 :   // because all the variables are fixed.
    1191                 : 
    1192                 :   //  setBasis();  // presumably the final basis of the solve.
    1193                 :   //  DEBUGPR(300,ucout << "Basis set" << endl << Flush);
    1194                 :   // if this is infeasible, hope the LP solver won't bomb.
    1195                 : 
    1196               2 :   PicoLPInterface::problemState recheckState = runLP();
    1197               2 :   if (recheckState == PicoLPInterface::solved)
    1198               2 :     lpBound = lp->getObjValue();
    1199                 : 
    1200               2 :   return(recheckState);
    1201                 : }
    1202                 : 
    1203                 : 
    1204          184181 : void MILPNode::incumbentHeuristic(void)
    1205                 : {
    1206          184181 :   DEBUGPR(20,ucout << "In MILPNode::incumbentHeuristic\n");
    1207                 : 
    1208                 :   // Call all enabled incumbent heuristics in order.
    1209                 :   // They are expected to police themselves.  This should
    1210                 :   // not be called if all heuristics are disabled.
    1211          184181 :   if (mGlobal()->stopPICOHeuristicsOnIncumbent && mGlobal()->haveIncumbent())
    1212               0 :     return;
    1213                 : 
    1214                 : #ifdef ACRO_VALIDATING
    1215                 :   double MHStart;
    1216                 : #endif
    1217                 : 
    1218                 :   // This will generally require a valid LP bound.  For now,
    1219                 :   // assume it's called at an appropriate time
    1220          184181 :   mGlobal()->runHeuristicsOnSubproblem(this);
    1221                 : 
    1222                 :   //This code used to activate randomized rounding.  Turn off, since
    1223                 :   //we're trying to activate randomized rounding through the new
    1224                 :   //general framework.
    1225                 : //   if (mGlobal()->RRTrialsPerCall > 0 && mGlobal()->maxRRDepth > 0)
    1226                 : //     {
    1227                 : // #ifdef ACRO_VALIDATING
    1228                 : //     MHStart = CPUSeconds();
    1229                 : // #endif
    1230                 : //     RRheuristic();
    1231                 : // #ifdef ACRO_VALIDATING
    1232                 : //     mGlobal()->MIPTimingInfo[MIPHeur] += CPUSeconds() - MHStart;
    1233                 : // #endif
    1234                 : //     }
    1235                 :   // Right now, remaining heuristics still run piecemeal...
    1236                 : 
    1237          184178 :   if (mGlobal()->stopPICOHeuristicsOnIncumbent && mGlobal()->haveIncumbent())
    1238               0 :     return;
    1239                 : 
    1240          184178 :   if (mGlobal()->mipHeuristicPtr)
    1241                 :     {
    1242                 : #ifdef ACRO_VALIDATING
    1243                 :     MHStart = CPUSeconds();
    1244                 : #endif
    1245               0 :     BBHincumbentHeuristic();
    1246                 : #ifdef ACRO_VALIDATING
    1247                 :     mGlobal()->MIPTimingInfo[MIPHeur] += CPUSeconds() - MHStart;
    1248                 : #endif
    1249                 :     }
    1250                 : }