- Timestamp:
- Sep 7, 2010 6:26:41 PM (10 years ago)
- Location:
- trunk/Clp
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Clp/src/ClpLinearObjective.hpp
r1525 r1602 20 20 //@{ 21 21 22 /** Returns gradient. If Linear then solution may be NULL, 23 also returns an offset (to be added to current one) 24 If refresh is false then uses last solution 25 Uses model for scaling 26 includeLinear 0 - no, 1 as is, 2 as feasible 22 /** Returns objective coefficients. 23 24 Offset is always set to 0.0. All other parameters unused. 27 25 */ 28 26 virtual double * gradient(const ClpSimplex * model, -
trunk/Clp/src/OsiClp/OsiClpSolverInterface.cpp
r1595 r1602 63 63 double savedDualLimit=modelPtr_->dblParam_[ClpDualObjectiveLimit]; 64 64 if (fakeObjective_) { 65 // Clear (no objective, 0-1 and in B&B) 65 66 modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()&(~128)); 66 67 // See if all with costs fixed … … 78 79 } 79 80 if (i==numberColumns) { 81 // Check (Clp fast dual) 80 82 if ((specialOptions_&524288)==0) { 81 83 // Set fake … … 84 86 modelPtr_->dblParam_[ClpDualObjectiveLimit]=COIN_DBL_MAX; 85 87 } else { 88 // Set (no objective, 0-1 and in B&B) 86 89 modelPtr_->setMoreSpecialOptions(modelPtr_->moreSpecialOptions()|128); 87 90 } 88 91 } 89 92 } 93 // Check (in branch and bound) 90 94 if ((specialOptions_&1024)==0) { 91 95 solver = new ClpSimplex(true); … … 2791 2795 2792 2796 //------------------------------------------------------------------ 2793 std::vector<double*> OsiClpSolverInterface::getDualRays(int maxNumRays,2797 std::vector<double*> OsiClpSolverInterface::getDualRays(int /*maxNumRays*/, 2794 2798 bool fullRay) const 2795 2799 { … … 2892 2896 lastAlgorithm_=999; 2893 2897 modelPtr_->whatsChanged_ &= (0xffff&~64); 2894 CoinMemcpyN(array,modelPtr_->numberColumns(), 2895 modelPtr_->objective()); 2898 int n = modelPtr_->numberColumns() ; 2899 if (fakeMinInSimplex_) { 2900 std::transform(array,array+n, 2901 modelPtr_->objective(),std::negate<double>()) ; 2902 } else { 2903 CoinMemcpyN(array,n,modelPtr_->objective()); 2904 } 2896 2905 } 2897 2906 /* Set the lower bounds for all columns … … 3697 3706 : 3698 3707 OsiSolverInterface(), 3699 linearObjective_(NULL),3700 3708 rowsense_(NULL), 3701 3709 rhs_(NULL), … … 3716 3724 integerInformation_(NULL), 3717 3725 whichRange_(NULL), 3726 fakeMinInSimplex_(false), 3727 linearObjective_(NULL), 3718 3728 cleanupScaling_(0), 3719 3729 specialOptions_(0x80000000), … … 3780 3790 matrixByRowAtContinuous_(NULL), 3781 3791 integerInformation_(NULL), 3782 whichRange_(NULL) 3792 whichRange_(NULL), 3793 fakeMinInSimplex_(rhs.fakeMinInSimplex_) 3783 3794 { 3784 3795 //printf("in copy %x - > %x\n",&rhs,this); … … 3857 3868 integerInformation_(NULL), 3858 3869 whichRange_(NULL), 3870 fakeMinInSimplex_(false), 3859 3871 cleanupScaling_(0), 3860 3872 specialOptions_(0x80000000), … … 4962 4974 //printf("obj a %g %g\n",modelPtr_->objectiveValue(), 4963 4975 // OsiSolverInterface::getObjValue()); 4964 return modelPtr_->objectiveValue(); 4976 if (fakeMinInSimplex_) 4977 return -modelPtr_->objectiveValue() ; 4978 else 4979 return modelPtr_->objectiveValue(); 4965 4980 } else { 4966 4981 return OsiSolverInterface::getObjValue(); … … 4981 4996 } 4982 4997 #endif 4983 modelPtr_->setObjectiveCoefficient(elementIndex,elementValue); 4998 modelPtr_->setObjectiveCoefficient(elementIndex, 4999 ((fakeMinInSimplex_)?-elementValue:elementValue)); 4984 5000 } 4985 5001 … … 5284 5300 } 5285 5301 } 5286 /*Enables normal operation of subsequent functions. 5287 This method is supposed to ensure that all typical things (like 5288 reduced costs, etc.) are updated when individual pivots are executed 5289 and can be queried by other methods 5302 5303 /* 5304 Clp's copy-in/copy-out design paradigm is a challenge for the simplex modes. 5305 Normal operation goes like this: 5306 * startup() loads clp's work arrays, performing scaling for numerical 5307 stability and compensating for max. 5308 * clp solves the problem 5309 * finish() unloads the work arrays into answer arrays, undoing scaling 5310 and max compensation. 5311 There are two solutions: undo scaling and max on demand, or make them 5312 into noops. The various getBInv* methods undo scaling on demand (but 5313 see special option 512) and do not need to worry about max. Other get 5314 solution methods are not coded to do this, so the second approach is 5315 used. For simplex modes, turn off scaling (necessary for both primal and 5316 dual solutions) and temporarily convert max to min (necessary for dual 5317 solution). This makes the unscaling in getBInv* superfluous, but don't 5318 remove it. Arguably the better solution here would be to go through and 5319 add unscaling and max compensation to the get solution methods. Look for 5320 fakeMinInSimplex to see the places this propagates to. 5321 5322 TODO: setRowPrice never has worked properly, and I didn't try to fix it in 5323 this go-round. 5324 5325 As of 100907, change applied to [enable|disable]Factorization (mode 1). 5326 Limitation of [enable|disable]SimplexInterface (mode 2) noted in 5327 documentation. -- lh, 100907 -- 5328 */ 5329 /* 5330 Enables normal operation of subsequent functions. This method is supposed 5331 to ensure that all typical things (like reduced costs, etc.) are updated 5332 when individual pivots are executed and can be queried by other methods 5290 5333 */ 5291 5334 void … … 5351 5394 modelPtr_->setSolveType(1); 5352 5395 } 5396 5397 /* 5398 Force scaling off. If the client thinks we're maximising, arrange it so 5399 that clp sees minimisation while the client still sees maximisation. In 5400 keeping with the spirit of the getBInv methods, special option 512 will 5401 leave all work to the client. 5402 */ 5353 5403 void 5354 5404 OsiClpSolverInterface::enableFactorization() const 5355 5405 { 5356 specialOptions_ &= ~0x80000000;5357 5406 saveData_.specialOptions_=specialOptions_; 5358 int saveStatus = modelPtr_->problemStatus_;5407 // Try to preserve work regions, reuse factorization 5359 5408 if ((specialOptions_&(1+8))!=1+8) 5360 5409 setSpecialOptionsMutable((1+8)|specialOptions_); 5410 // Are we allowed to make the output sensible to mere mortals? 5411 if ((specialOptions_&512)==0) { 5412 // Force scaling to off 5413 saveData_.scalingFlag_ = modelPtr_->scalingFlag() ; 5414 modelPtr_->scaling(0) ; 5415 // Temporarily force to min but keep a copy of original objective. 5416 if (getObjSense() < 0.0) { 5417 fakeMinInSimplex_ = true ; 5418 modelPtr_->setOptimizationDirection(1.0) ; 5419 double *c = modelPtr_->objective() ; 5420 int n = getNumCols() ; 5421 linearObjective_ = new double[n] ; 5422 CoinMemcpyN(c,n,linearObjective_) ; 5423 std::transform(c,c+n,c,std::negate<double>()) ; 5424 } 5425 } 5426 int saveStatus = modelPtr_->problemStatus_; 5361 5427 #ifdef NDEBUG 5362 5428 modelPtr_->startup(0); … … 5368 5434 } 5369 5435 5370 //Undo whatever setting changes the above method had to make 5436 /* 5437 Undo enableFactorization. Retrieve the special options and scaling and 5438 remove the temporary objective used to fake minimisation in clp. 5439 */ 5371 5440 void 5372 5441 OsiClpSolverInterface::disableFactorization() const … … 5378 5447 int saveMessageLevel=modelPtr_->messageHandler()->logLevel(); 5379 5448 modelPtr_->messageHandler()->setLogLevel(0); 5380 // Should re-do - for moment save arrays5381 double * sol = CoinCopyOfArray(modelPtr_->columnActivity_,modelPtr_->numberColumns_);5382 double * dj = CoinCopyOfArray(modelPtr_->reducedCost_,modelPtr_->numberColumns_);5383 double * rsol = CoinCopyOfArray(modelPtr_->rowActivity_,modelPtr_->numberRows_);5384 double * dual = CoinCopyOfArray(modelPtr_->dual_,modelPtr_->numberRows_);5385 5449 modelPtr_->finish(); 5386 CoinMemcpyN(sol,modelPtr_->numberColumns_,modelPtr_->columnActivity_);5387 CoinMemcpyN(dj,modelPtr_->numberColumns_,modelPtr_->reducedCost_);5388 CoinMemcpyN(rsol,modelPtr_->numberRows_,modelPtr_->rowActivity_);5389 CoinMemcpyN(dual,modelPtr_->numberRows_,modelPtr_->dual_);5390 delete [] sol;5391 delete [] dj;5392 delete [] rsol;5393 delete [] dual;5394 5450 modelPtr_->messageHandler()->setLogLevel(saveMessageLevel); 5395 } 5451 // Client asked for transforms on the way in, so back out. 5452 if ((specialOptions_&512)==0) { 5453 modelPtr_->scaling(saveData_.scalingFlag_) ; 5454 if (fakeMinInSimplex_ == true) { 5455 fakeMinInSimplex_ = false ; 5456 modelPtr_->setOptimizationDirection(-1.0) ; 5457 double *c = modelPtr_->objective() ; 5458 int n = getNumCols() ; 5459 std::transform(c,c+n,c,std::negate<double>()) ; 5460 delete[] linearObjective_ ; 5461 } 5462 } 5463 } 5464 5465 5466 5396 5467 /* The following two methods may be replaced by the 5397 5468 methods of OsiSolverInterface using OsiWarmStartBasis if: … … 5641 5712 } 5642 5713 5643 //Get the reduced gradient for the cost vector c 5714 /* 5715 This method should not leave a permanent change in the solver. For 5716 this reason, save a copy of the cost region and replace it after we've 5717 calculated the duals and reduced costs. 5718 5719 On the good side, if we're maximising, we should negate the objective on 5720 the way in and negate the duals on the way out. Since clp won't be doing 5721 anything more with c, we can exploit (-1)(-1) = 1 and do nothing. 5722 */ 5644 5723 void 5645 5724 OsiClpSolverInterface::getReducedGradient( … … 5648 5727 const double * c) const 5649 5728 { 5650 assert (modelPtr_->solveType()==2);5729 //assert (modelPtr_->solveType()==2); 5651 5730 // could do this faster with coding inside Clp 5652 5731 // save current costs 5653 5732 int numberColumns = modelPtr_->numberColumns(); 5654 5733 double * save = new double [numberColumns]; 5655 CoinMemcpyN(modelPtr_->costRegion(),numberColumns,save); 5656 CoinMemcpyN(c,numberColumns,modelPtr_->costRegion()); 5734 double * obj = modelPtr_->costRegion(); 5735 CoinMemcpyN(obj,numberColumns,save); 5736 // Compute new duals and reduced costs. 5737 const double * columnScale = modelPtr_->columnScale(); 5738 if (!columnScale) { 5739 CoinMemcpyN(c,numberColumns,obj) ; 5740 } else { 5741 // need to scale 5742 for (int i=0;i<numberColumns;i++) 5743 obj[i] = c[i]*columnScale[i]; 5744 } 5657 5745 modelPtr_->computeDuals(NULL); 5658 CoinMemcpyN(save,numberColumns,modelPtr_->costRegion()); 5746 5747 // Restore previous cost vector 5748 CoinMemcpyN(save,numberColumns,obj); 5659 5749 delete [] save; 5750 5751 // Transfer results to parameters 5660 5752 int numberRows = modelPtr_->numberRows(); 5661 CoinMemcpyN(modelPtr_->dualRowSolution(),numberRows,duals); 5662 CoinMemcpyN(modelPtr_->djRegion(1), numberColumns,columnReducedCosts); 5753 const double * dualScaled = modelPtr_->dualRowSolution(); 5754 const double * djScaled = modelPtr_->djRegion(1); 5755 if (!columnScale) { 5756 CoinMemcpyN(dualScaled,numberRows,duals) ; 5757 CoinMemcpyN(djScaled,numberColumns,columnReducedCosts) ; 5758 } else { 5759 // need to scale 5760 const double * rowScale = modelPtr_->rowScale(); 5761 for (int i=0;i<numberRows;i++) 5762 duals[i] = dualScaled[i]*rowScale[i]; 5763 for (int i=0;i<numberColumns;i++) 5764 columnReducedCosts[i] = djScaled[i]/columnScale[i]; 5765 } 5663 5766 } 5664 5767 … … 6153 6256 notOwned_=false; 6154 6257 modelPtr_ = new ClpSimplex(); 6155 // This is also deleted by Clp --tkr 7/31/036156 // delete linearObjective_;6157 6258 linearObjective_ = NULL; 6158 6259 fillParamMaps(); -
trunk/Clp/src/OsiClp/OsiClpSolverInterface.hpp
r1595 r1602 63 63 //@} 64 64 65 / //@name OsiSimplexInterface methods66 //@{67 68 /**Enables normal operation of subsequent functions.69 This method is supposed to ensure that all typical things (like70 reduced costs, etc.) are updated when individual pivots are executed71 and can be queried by other methods72 */73 virtual void enableSimplexInterface(bool doingPrimal);74 75 ///Undo whatever setting changes the above method had to make76 virtual void disableSimplexInterface();77 /** Returns1 if can just do getBInv etc78 2 if has all OsiSimplex methods79 and 0 if it has none*/65 /*! @name OsiSimplexInterface methods 66 \brief Methods for the Osi Simplex API. 67 68 The current implementation should work for both minimisation and 69 maximisation in mode 1 (tableau access). In mode 2 (single pivot), only 70 minimisation is supported as of 100907. 71 */ 72 //@{ 73 /** \brief Simplex API capability. 74 75 Returns 76 - 0 if no simplex API 77 - 1 if can just do getBInv etc 78 - 2 if has all OsiSimplex methods 79 */ 80 80 virtual int canDoSimplexInterface() const; 81 /** Tells solver that calls to getBInv etc are about to take place. 82 Underlying code may need mutable as this may be called from 83 CglCut:;generateCuts which is const. If that is too horrific then 84 each solver e.g. BCP or CBC will have to do something outside 85 main loop. 81 82 /*! \brief Enables simplex mode 1 (tableau access) 83 84 Tells solver that calls to getBInv etc are about to take place. 85 Underlying code may need mutable as this may be called from 86 CglCut::generateCuts which is const. If that is too horrific then 87 each solver e.g. BCP or CBC will have to do something outside 88 main loop. 86 89 */ 87 90 virtual void enableFactorization() const; 88 /// and stop 91 92 /*! \brief Undo any setting changes made by #enableFactorization */ 89 93 virtual void disableFactorization() const; 90 94 91 /** Sets up solver for repeated use by Osi interface.92 The normal usage does things like keeping factorization around so can be used.93 Will also do things like keep scaling and row copy of matrix if94 matrix does not change.95 adventure:96 0 - safe stuff as above97 1 - will take more risks - if it does not work then bug which will be fixed98 2 - don't bother doing most extreme termination checks e.g. don't bother99 re-factorizing if less than 20 iterations.100 3 - Actually safer than 1 (mainly just keeps factorization)101 102 printOut - -1 always skip round common messages instead of doing some work103 0 skip if normal defaults104 1 leaves105 */106 void setupForRepeatedUse(int senseOfAdventure=0, int printOut=0);107 /// Synchronize model (really if no cuts in tree)108 virtual void synchronizeModel();109 // Sleazy methods to fool const requirements (no less safe as modelPtr_ mutable)110 void setSpecialOptionsMutable(unsigned int value) const;111 112 95 /** Returns true if a basis is available 113 96 AND problem is optimal. This should be used to see if … … 145 128 virtual int setBasisStatus(const int* cstat, const int* rstat); 146 129 130 ///Get the reduced gradient for the cost vector c 131 virtual void getReducedGradient(double* columnReducedCosts, 132 double * duals, 133 const double * c) const ; 134 135 ///Get a row of the tableau (slack part in slack if not NULL) 136 virtual void getBInvARow(int row, double* z, double * slack=NULL) const; 137 138 /** Get a row of the tableau (slack part in slack if not NULL) 139 If keepScaled is true then scale factors not applied after so 140 user has to use coding similar to what is in this method 141 */ 142 virtual void getBInvARow(int row, CoinIndexedVector * z, CoinIndexedVector * slack=NULL, 143 bool keepScaled=false) const; 144 145 ///Get a row of the basis inverse 146 virtual void getBInvRow(int row, double* z) const; 147 148 ///Get a column of the tableau 149 virtual void getBInvACol(int col, double* vec) const ; 150 151 ///Get a column of the tableau 152 virtual void getBInvACol(int col, CoinIndexedVector * vec) const ; 153 154 /** Update (i.e. ftran) the vector passed in. 155 Unscaling is applied after - can't be applied before 156 */ 157 158 virtual void getBInvACol(CoinIndexedVector * vec) const ; 159 160 ///Get a column of the basis inverse 161 virtual void getBInvCol(int col, double* vec) const ; 162 163 /** Get basic indices (order of indices corresponds to the 164 order of elements in a vector retured by getBInvACol() and 165 getBInvCol()). 166 */ 167 virtual void getBasics(int* index) const; 168 169 /*! \brief Enables simplex mode 2 (individual pivot control) 170 171 This method is supposed to ensure that all typical things (like 172 reduced costs, etc.) are updated when individual pivots are executed 173 and can be queried by other methods. 174 */ 175 virtual void enableSimplexInterface(bool doingPrimal); 176 177 /*! \brief Undo setting changes made by #enableSimplexInterface */ 178 virtual void disableSimplexInterface(); 179 147 180 /** Perform a pivot by substituting a colIn for colOut in the basis. 148 181 The status of the leaving variable is given in statOut. Where … … 179 212 double& t, CoinPackedVector* dx); 180 213 181 ///Get the reduced gradient for the cost vector c182 virtual void getReducedGradient(double* columnReducedCosts,183 double * duals,184 const double * c) const ;185 186 ///Get a row of the tableau (slack part in slack if not NULL)187 virtual void getBInvARow(int row, double* z, double * slack=NULL) const;188 189 /** Get a row of the tableau (slack part in slack if not NULL)190 If keepScaled is true then scale factors not applied after so191 user has to use coding similar to what is in this method192 */193 virtual void getBInvARow(int row, CoinIndexedVector * z, CoinIndexedVector * slack=NULL,194 bool keepScaled=false) const;195 196 ///Get a row of the basis inverse197 virtual void getBInvRow(int row, double* z) const;198 199 ///Get a column of the tableau200 virtual void getBInvACol(int col, double* vec) const ;201 202 ///Get a column of the tableau203 virtual void getBInvACol(int col, CoinIndexedVector * vec) const ;204 205 /** Update (i.e. ftran) the vector passed in.206 Unscaling is applied after - can't be applied before207 */208 209 virtual void getBInvACol(CoinIndexedVector * vec) const ;210 211 ///Get a column of the basis inverse212 virtual void getBInvCol(int col, double* vec) const ;213 214 /** Get basic indices (order of indices corresponds to the215 order of elements in a vector retured by getBInvACol() and216 getBInvCol()).217 */218 virtual void getBasics(int* index) const;219 214 220 215 //@} … … 310 305 311 306 //--------------------------------------------------------------------------- 312 /**@name Hotstart related methods (primarily used in strong branching). <br>307 /**@name Hotstart related methods (primarily used in strong branching). 313 308 The user can create a hotstart (a snapshot) of the optimization process 314 309 then reoptimize over and over again always starting from there.<br> … … 423 418 /// Get pointer to array[getNumCols()] of objective function coefficients 424 419 virtual const double * getObjCoefficients() const 425 { return modelPtr_->objective(); } 420 { if (fakeMinInSimplex_) 421 return linearObjective_ ; 422 else 423 return modelPtr_->objective(); } 426 424 427 425 /// Get objective function sense (1 for min (default), -1 for max) 428 426 virtual double getObjSense() const 429 { return modelPtr_->optimizationDirection(); } 427 { return ((fakeMinInSimplex_)?-modelPtr_->optimizationDirection(): 428 modelPtr_->optimizationDirection()); } 430 429 431 430 /// Return true if column is continuous … … 1077 1076 /// Set fake objective 1078 1077 void setFakeObjective(double * fakeObjective); 1078 /*! \brief Set up solver for repeated use by Osi interface. 1079 1080 The normal usage does things like keeping factorization around so can be 1081 used. Will also do things like keep scaling and row copy of matrix if 1082 matrix does not change. 1083 1084 \p senseOfAdventure: 1085 - 0 - safe stuff as above 1086 - 1 - will take more risks - if it does not work then bug which will be 1087 fixed 1088 - 2 - don't bother doing most extreme termination checks e.g. don't bother 1089 re-factorizing if less than 20 iterations. 1090 - 3 - Actually safer than 1 (mainly just keeps factorization) 1091 1092 \p printOut 1093 - -1 always skip round common messages instead of doing some work 1094 - 0 skip if normal defaults 1095 - 1 leaves 1096 */ 1097 void setupForRepeatedUse(int senseOfAdventure=0, int printOut=0); 1098 /// Synchronize model (really if no cuts in tree) 1099 virtual void synchronizeModel(); 1100 /*! \brief Set special options in underlying clp solver. 1101 1102 Safe as const because #modelPtr_ is mutable. 1103 */ 1104 void setSpecialOptionsMutable(unsigned int value) const; 1105 1079 1106 //@} 1080 1107 … … 1199 1226 /// Sort of lexicographic resolve 1200 1227 void lexSolve(); 1228 //@} 1229 1201 1230 protected: 1202 //@}1203 1204 1231 /**@name Protected member data */ 1205 1232 //@{ 1206 1233 /// Clp model represented by this class instance 1207 1234 mutable ClpSimplex * modelPtr_; 1208 /// Linear objective - just points to ClpModel 1209 double * linearObjective_; 1235 //@} 1210 1236 /**@name Cached information derived from the OSL model */ 1211 1237 //@{ … … 1254 1280 int itlimOrig_; 1255 1281 1256 /// Last algorithm used , 1 = primal, 2 = dual 1282 /*! \brief Last algorithm used 1283 1284 Coded as 1285 - 0 invalid 1286 - 1 primal 1287 - 2 dual 1288 - -911 disaster in the algorithm that was attempted 1289 - 999 current solution no longer optimal due to change in problem or 1290 basis 1291 */ 1257 1292 mutable int lastAlgorithm_; 1258 1293 … … 1279 1314 //std::map<OsiStrParam, ClpStrParam> strParamMap_; 1280 1315 1316 /*! \brief Faking min to get proper dual solution signs in simplex API */ 1317 mutable bool fakeMinInSimplex_ ; 1318 /*! \brief Linear objective 1319 1320 Normally a pointer to the linear coefficient array in the clp objective. 1321 An independent copy when #fakeMinInSimplex_ is true, because we need 1322 something permanent to point to when #getObjCoefficients is called. 1323 */ 1324 mutable double *linearObjective_; 1325 1281 1326 /// To save data in OsiSimplex stuff 1282 1327 mutable ClpDataSave saveData_; … … 1308 1353 128 Model will only change in column bounds 1309 1354 256 Clean up model before hot start 1310 512 Give user direct access to Clp regions in getBInvARow etc 1355 512 Give user direct access to Clp regions in getBInvARow etc (i.e., 1356 do not unscale, and do not return result in getBInv parameters; 1357 you have to know where to look for the answer) 1311 1358 1024 Don't "borrow" model in initialSolve 1312 1359 2048 Don't crunch … … 1421 1468 /// Are we in trouble 1422 1469 bool inTrouble_; 1423 1424 1470 //@} 1425 1471 }; -
trunk/Clp/test/OsiClpSolverInterfaceTest.cpp
r1595 r1602 1390 1390 const double * rowScale = clp->rowScale(); 1391 1391 const double * columnScale = clp->columnScale(); 1392 # if 0 1392 1393 if (!iPass) 1393 1394 assert (!rowScale); 1394 1395 else 1395 1396 assert (rowScale); // only true for this example 1397 # endif 1396 1398 /* has to be exactly correct as in OsiClpsolverInterface.cpp 1397 1399 (also redo each pass as may change
Note: See TracChangeset
for help on using the changeset viewer.