1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others.  All Rights Reserved.
3 // This file is licensed under the terms of Eclipse Public License (EPL).
4 
5 // this is a copy of OsiVolSolverInterface (trunk rev. 1466) renamed to OsiTestSolverInterface
6 
7 #include "CoinPragma.hpp"
8 
9 #include <cstdlib>
10 #include <numeric>
11 #include <cassert>
12 #include <cmath>
13 
14 #include "CoinHelperFunctions.hpp"
15 #include "CoinWarmStartDual.hpp"
16 
17 #include "OsiTestSolverInterface.hpp"
18 #include "OsiRowCut.hpp"
19 #include "OsiColCut.hpp"
20 
21 //#######################################################################
22 //  Private helper methods
23 //#######################################################################
24 
25 void
updateRowMatrix_() const26 OsiTestSolverInterface::updateRowMatrix_() const
27 {
28    if (! rowMatrixCurrent_) {
29       rowMatrix_.reverseOrderedCopyOf(colMatrix_);
30       rowMatrixCurrent_ = true;
31    }
32 }
33 
34 void
updateColMatrix_() const35 OsiTestSolverInterface::updateColMatrix_() const
36 {
37    if (! colMatrixCurrent_) {
38       colMatrix_.reverseOrderedCopyOf(rowMatrix_);
39       colMatrixCurrent_ = true;
40    }
41 }
42 
43 //-----------------------------------------------------------------------------
44 
45 void
checkData_() const46 OsiTestSolverInterface::checkData_() const
47 {
48    int i;
49    for (i = getNumRows() - 1; i >= 0; --i) {
50       if (rowlower_[i] > -1.0e20 &&
51 	  rowupper_[i] < 1.0e20 &&
52 	  rowlower_[i] != rowupper_[i])
53 	 throw CoinError("Volume algorithm is unable to handle ranged rows",
54 			"checkData_", "OsiTestSolverInterface");
55    }
56 
57    for (i = getNumCols() - 1; i >= 0; --i)  {
58       if (collower_[i] < -1.0e20 || colupper_[i] > 1.0e20)
59 	 throw CoinError("Volume algorithm is unable to handle infinite bounds",
60 			"checkData_", "OsiTestSolverInterface");
61    }
62 }
63 
64 //-----------------------------------------------------------------------------
65 
66 void
compute_rc_(const double * u,double * rc) const67 OsiTestSolverInterface::compute_rc_(const double* u, double* rc) const
68 {
69   if (isZeroOneMinusOne_) {
70     rowMatrixOneMinusOne_->timesMajor(u, rc);
71   } else {
72     rowMatrix_.transposeTimes(u, rc);
73   }
74 
75   const int psize = getNumCols();
76   std::transform(rc, rc+psize, objcoeffs_, rc, std::minus<double>());
77   std::transform(rc, rc+psize, rc, std::negate<double>());
78 }
79 
80 //#############################################################################
81 
82 bool
test_zero_one_minusone_(const CoinPackedMatrix & m) const83 OsiTestSolverInterface::test_zero_one_minusone_(const CoinPackedMatrix& m) const
84 {
85   const int vecnum = m.getMajorDim();
86   const double* elem = m.getElements();
87   const int* start = m.getVectorStarts();
88   const int* length = m.getVectorLengths();
89   int i, j;
90   for (i = 0; i < vecnum; ++i) {
91     for (j = start[i] + length[i] - 1; j >= start[i]; --j) {
92       const double val = elem[j];
93       if (val != 1.0 && val != 0.0 && val != -1.0) {
94 	return false;
95       }
96     }
97   }
98   return true;
99 }
100 
101 //-----------------------------------------------------------------------------
102 
103 OsiTestSolverInterface::OsiVolMatrixOneMinusOne_::
OsiVolMatrixOneMinusOne_(const CoinPackedMatrix & m)104 OsiVolMatrixOneMinusOne_(const CoinPackedMatrix& m) {
105   const int major = m.getMajorDim();
106   const double* elem = m.getElements();
107   const int* ind = m.getIndices();
108   const int* start = m.getVectorStarts();
109   const int* length = m.getVectorLengths();
110 
111   majorDim_ = major;
112   minorDim_ = m.getMinorDim();
113 
114   plusSize_ = 0;
115   minusSize_ = 0;
116   int i, j;
117   for (i = 0; i < major; ++i) {
118     for (j = start[i] + length[i] - 1; j >= start[i]; --j) {
119       const double val = elem[j];
120       if (val == 1.0) {
121 	++plusSize_;
122       } else if (val == -1.0) {
123 	++minusSize_;
124       }
125     }
126   }
127   if (plusSize_ > 0) {
128     plusInd_ = new int[plusSize_];
129   }
130   if (minusSize_ > 0) {
131     minusInd_ = new int[minusSize_];
132   }
133   plusStart_ = new int[major];
134   plusLength_ = new int[major];
135   minusStart_ = new int[major];
136   minusLength_ = new int[major];
137 
138   plusSize_ = 0;
139   minusSize_ = 0;
140   for (i = 0; i < major; ++i) {
141     plusStart_[i] = plusSize_;
142     minusStart_[i] = minusSize_;
143     const int last = start[i] + length[i];
144     for (j = start[i]; j < last; ++j) {
145       const double val = elem[j];
146       if (val == 1.0) {
147 	plusInd_[plusSize_++] = ind[j];
148       } else if (val == -1.0) {
149 	minusInd_[minusSize_++] = ind[j];
150       }
151     }
152     plusLength_[i] = plusSize_ - plusStart_[i];
153     minusLength_[i] = minusSize_ - minusStart_[i];
154   }
155   if (plusSize_ == 0) {
156     delete[] plusStart_;    plusStart_  = NULL;
157     delete[] plusLength_;   plusLength_ = NULL;
158   }
159   if (minusSize_ == 0) {
160     delete[] minusStart_;    minusStart_  = NULL;
161     delete[] minusLength_;   minusLength_ = NULL;
162   }
163 }
164 
165 //-----------------------------------------------------------------------------
166 
167 OsiTestSolverInterface::OsiVolMatrixOneMinusOne_::
~OsiVolMatrixOneMinusOne_()168 ~OsiVolMatrixOneMinusOne_() {
169   if (plusSize_ > 0) {
170     delete[] plusInd_;      plusInd_    = NULL;
171     delete[] plusStart_;    plusStart_  = NULL;
172     delete[] plusLength_;   plusLength_ = NULL;
173   }
174   if (minusSize_ > 0) {
175     delete[] minusInd_;      minusInd_    = NULL;
176     delete[] minusStart_;    minusStart_  = NULL;
177     delete[] minusLength_;   minusLength_ = NULL;
178   }
179 }
180 
181 //-----------------------------------------------------------------------------
182 
183 void OsiTestSolverInterface::OsiVolMatrixOneMinusOne_::
timesMajor(const double * x,double * y) const184 timesMajor(const double* x, double* y) const
185 {
186   memset(y, 0, minorDim_ * sizeof(double));
187   int i;
188 
189   if (plusSize_ > 0 && minusSize_ > 0) {
190     for (i = majorDim_ - 1; i >= 0; --i) {
191       const double x_i = x[i];
192       if (x_i != 0.0) {
193 	const int* vecInd = plusInd_ + plusStart_[i];
194         int j;
195 	for ( j = plusLength_[i] - 1; j >= 0; --j)
196 	  y[vecInd[j]] += x_i;
197 	vecInd = minusInd_ + minusStart_[i];
198 	for ( j = minusLength_[i] - 1; j >= 0; --j)
199 	  y[vecInd[j]] -= x_i;
200       }
201     }
202     return;
203   }
204   if (plusSize_ > 0) {
205     for (i = majorDim_ - 1; i >= 0; --i) {
206       const double x_i = x[i];
207       if (x_i != 0.0) {
208 	const int* vecInd = plusInd_ + plusStart_[i];
209 	for (int j = plusLength_[i] - 1; j >= 0; --j)
210 	  y[vecInd[j]] += x_i;
211       }
212     }
213     return;
214   }
215   if (minusSize_ > 0) {
216     for (i = majorDim_ - 1; i >= 0; --i) {
217       const double x_i = x[i];
218       if (x_i != 0.0) {
219 	const int* vecInd = minusInd_ + minusStart_[i];
220 	for (int j = minusLength_[i] - 1; j >= 0; --j)
221 	  y[vecInd[j]] -= x_i;
222       }
223     }
224     return;
225   }
226 }
227 
228 //#############################################################################
229 
230 void
gutsOfDestructor_()231 OsiTestSolverInterface::gutsOfDestructor_()
232 {
233   rowMatrix_.clear();
234   colMatrix_.clear();
235   rowMatrixCurrent_ = true;
236   colMatrixCurrent_ = true;
237 
238   delete[] colupper_;   colupper_ = 0;
239   delete[] collower_;	collower_ = 0;
240   delete[] continuous_; continuous_ = 0;
241   delete[] rowupper_;	rowupper_ = 0;
242   delete[] rowlower_;	rowlower_ = 0;
243   delete[] rowsense_;	rowsense_ = 0;
244   delete[] rhs_;	rhs_ = 0;
245   delete[] rowrange_;	rowrange_ = 0;
246   delete[] objcoeffs_;	objcoeffs_ = 0;
247 
248   delete[] colsol_;	        colsol_ = 0;
249   delete[] rowprice_;	        rowprice_ = 0;
250   delete[] rowpriceHotStart_;	rowpriceHotStart_ = 0;
251   delete[] rc_;       	        rc_ = 0;
252   delete[] lhs_;       	        lhs_ = 0;
253 
254   lagrangeanCost_ = 0.0;
255 
256   maxNumrows_ = 0;
257   maxNumcols_ = 0;
258 }
259 
260 //#############################################################################
261 
262 void
rowRimAllocator_()263 OsiTestSolverInterface::rowRimAllocator_()
264 {
265    rowupper_ = new double[maxNumrows_];
266    rowlower_ = new double[maxNumrows_];
267    rowsense_ = new char[maxNumrows_];
268    rhs_      = new double[maxNumrows_];
269    rowrange_ = new double[maxNumrows_];
270    rowprice_ = new double[maxNumrows_];
271    lhs_      = new double[maxNumrows_];
272 }
273 
274 //-----------------------------------------------------------------------------
275 
276 void
colRimAllocator_()277 OsiTestSolverInterface::colRimAllocator_()
278 {
279    colupper_  = new double[maxNumcols_];
280    collower_  = new double[maxNumcols_];
281    continuous_ = new bool[maxNumcols_];
282    objcoeffs_ = new double[maxNumcols_];
283    colsol_    = new double[maxNumcols_];
284    rc_        = new double[maxNumcols_];
285 }
286 
287 //-----------------------------------------------------------------------------
288 
289 void
rowRimResize_(const int newSize)290 OsiTestSolverInterface::rowRimResize_(const int newSize)
291 {
292    if (newSize > maxNumrows_) {
293       double* rub   = rowupper_;
294       double* rlb   = rowlower_;
295       char*   sense = rowsense_;
296       double* right = rhs_;
297       double* range = rowrange_;
298       double* dual  = rowprice_;
299       double* left  = lhs_;
300       maxNumrows_ = CoinMax(1000, (newSize * 5) / 4);
301       rowRimAllocator_();
302       const int rownum = getNumRows();
303       CoinDisjointCopyN(rub  , rownum, rowupper_);
304       CoinDisjointCopyN(rlb  , rownum, rowlower_);
305       CoinDisjointCopyN(sense, rownum, rowsense_);
306       CoinDisjointCopyN(right, rownum, rhs_);
307       CoinDisjointCopyN(range, rownum, rowrange_);
308       CoinDisjointCopyN(dual , rownum, rowprice_);
309       CoinDisjointCopyN(left , rownum, lhs_);
310       delete[] rub;
311       delete[] rlb;
312       delete[] sense;
313       delete[] right;
314       delete[] range;
315       delete[] dual;
316       delete[] left;
317    }
318 }
319 
320 //-----------------------------------------------------------------------------
321 
322 void
colRimResize_(const int newSize)323 OsiTestSolverInterface::colRimResize_(const int newSize)
324 {
325    if (newSize > maxNumcols_) {
326       double* cub = colupper_;
327       double* clb = collower_;
328       bool* cont  = continuous_;
329       double* obj = objcoeffs_;
330       double* sol = colsol_;
331       double* rc  = rc_;
332       maxNumcols_ = CoinMax(1000, (newSize * 5) / 4);
333       colRimAllocator_();
334       const int colnum = getNumCols();
335       CoinDisjointCopyN(cub , colnum, colupper_);
336       CoinDisjointCopyN(clb , colnum, collower_);
337       CoinDisjointCopyN(cont, colnum, continuous_);
338       CoinDisjointCopyN(obj , colnum, objcoeffs_);
339       CoinDisjointCopyN(sol , colnum, colsol_);
340       CoinDisjointCopyN(rc  , colnum, rc_);
341       delete[] cub;
342       delete[] clb;
343       delete[] cont;
344       delete[] obj;
345       delete[] sol;
346       delete[] rc;
347    }
348 }
349 
350 //#############################################################################
351 
352 void
convertBoundsToSenses_()353 OsiTestSolverInterface::convertBoundsToSenses_()
354 {
355    for (int i = getNumRows() - 1; i >= 0; --i ) {
356       convertBoundToSense(rowlower_[i], rowupper_[i],
357 			  rowsense_[i], rhs_[i], rowrange_[i]);
358    }
359 }
360 
361 //-----------------------------------------------------------------------------
362 
363 void
convertSensesToBounds_()364 OsiTestSolverInterface::convertSensesToBounds_()
365 {
366    for (int i = getNumRows() - 1; i >= 0; --i) {
367       convertSenseToBound(rowsense_[i], rhs_[i], rowrange_[i],
368 			  rowlower_[i], rowupper_[i]);
369    }
370 }
371 
372 //#############################################################################
373 //  Here are the routines implementing the virtual methods inherited from
374 //  VOL_user_hooks.
375 //#############################################################################
376 
377 int
compute_rc(const VOL_dvector & u,VOL_dvector & rc)378 OsiTestSolverInterface::compute_rc(const VOL_dvector& u, VOL_dvector& rc)
379 {
380    compute_rc_(u.v, rc.v);
381    return 0;
382 }
383 
384 //-----------------------------------------------------------------------
385 
386 int
solve_subproblem(const VOL_dvector & dual,const VOL_dvector & rc,double & lcost,VOL_dvector & x,VOL_dvector & v,double & pcost)387 OsiTestSolverInterface::solve_subproblem(const VOL_dvector& dual,
388 					const VOL_dvector& rc,
389 					double& lcost,
390 					VOL_dvector& x, VOL_dvector& v,
391 					double& pcost)
392 {
393   int i;
394 
395   const int psize = x.size();
396   for (i = 0; i < psize; ++i) {
397     x[i] = (rc[i] >= 0.0) ? collower_[i] : colupper_[i];
398   }
399 
400   const int dsize = v.size();
401   lcost = (std::inner_product(rhs_, rhs_ + dsize, dual.v, 0.0) +
402 	   std::inner_product(x.v, x.v + psize, rc.v, 0.0) );
403 
404   if (isZeroOneMinusOne_) {
405     colMatrixOneMinusOne_->timesMajor(x.v, v.v);
406   } else {
407     colMatrix_.times(x.v, v.v);
408   }
409 
410   std::transform(v.v, v.v+dsize, rhs_, v.v, std::minus<double>());
411   std::transform(v.v, v.v+dsize, v.v, std::negate<double>());
412 
413   pcost = std::inner_product(x.v, x.v + psize, objcoeffs_, 0.0);
414 
415   return 0;
416 }
417 
418 //#############################################################################
419 // Solve methods
420 //#############################################################################
421 
422 void
initialSolve()423 OsiTestSolverInterface::initialSolve()
424 {
425    // set every entry to 0.0 in the dual solution
426    CoinFillN(rowprice_, getNumRows(), 0.0);
427    resolve();
428 }
429 
430 //-----------------------------------------------------------------------------
431 
432 void
resolve()433 OsiTestSolverInterface::resolve()
434 {
435   int i;
436 
437   checkData_();
438 
439   // Only one of these can do any work
440   updateRowMatrix_();
441   updateColMatrix_();
442 
443   const int dsize = getNumRows();
444   const int psize = getNumCols();
445 
446   // Negate the objective coefficients if necessary
447   if (objsense_ < 0) {
448     std::transform(objcoeffs_, objcoeffs_+psize, objcoeffs_,
449 		   std::negate<double>());
450   }
451 
452   // Set the lb/ub on the duals
453   volprob_.dual_lb.allocate(dsize);
454   volprob_.dual_ub.allocate(dsize);
455   double * dlb = volprob_.dual_lb.v;
456   double * dub = volprob_.dual_ub.v;
457   for (i = 0; i < dsize; ++i) {
458     dlb[i] = rowupper_[i] <  getInfinity() ? -1.0e31 : 0.0;
459     dub[i] = rowlower_[i] > -getInfinity() ?  1.0e31 : 0.0;
460   }
461   volprob_.dsize = dsize;
462   volprob_.psize = psize;
463 
464   // Set the dual starting point
465   VOL_dvector& dsol = volprob_.dsol;
466   dsol.allocate(dsize);
467   std::transform(rowprice_, rowprice_+dsize, dsol.v,
468 		 std::bind2nd(std::multiplies<double>(), objsense_));
469 
470   // adjust the dual vector (if necessary) to be sure it's feasible
471   double * dv = dsol.v;
472   for (i = 0; i < dsize; ++i) {
473     if (dv[i] < dlb[i]) {
474       dv[i] = dlb[i];
475     } else if (dv[i] > dub[i]) {
476       dv[i] = dub[i];
477     }
478   }
479 
480   // If requested, check whether the matrix contains anything but 0/1/-1
481 #if 0
482   isZeroOneMinusOne_ = false;
483 #else
484   isZeroOneMinusOne_ = test_zero_one_minusone_(colMatrix_);
485   if (isZeroOneMinusOne_) {
486     colMatrixOneMinusOne_ = new OsiVolMatrixOneMinusOne_(colMatrix_);
487     rowMatrixOneMinusOne_ = new OsiVolMatrixOneMinusOne_(rowMatrix_);
488   }
489 #endif
490 
491   volprob_.solve(*this, true);
492 
493   // extract the solution
494 
495   // the lower bound on the objective value
496   lagrangeanCost_ = objsense_ * volprob_.value;
497   // the primal solution
498   CoinDisjointCopyN(volprob_.psol.v, psize, colsol_);
499 
500   // Reset the objective coefficients if necessary
501   if (objsense_ < 0) {
502     std::transform(objcoeffs_, objcoeffs_ + psize, objcoeffs_,
503 		   std::negate<double>());
504     // also, multiply the dual solution by -1
505     std::transform(volprob_.dsol.v, volprob_.dsol.v+dsize, rowprice_,
506 		   std::negate<double>());
507   } else {
508     // now we just have to copy the dual
509     CoinDisjointCopyN(volprob_.dsol.v, dsize, rowprice_);
510   }
511 
512   // Compute the reduced costs
513   compute_rc_(rowprice_, rc_);
514 
515   // Compute the left hand side (row activity levels)
516   if (isZeroOneMinusOne_) {
517     colMatrixOneMinusOne_->timesMajor(colsol_, lhs_);
518   } else {
519     colMatrix_.times(colsol_, lhs_);
520   }
521 
522   if (isZeroOneMinusOne_) {
523     delete colMatrixOneMinusOne_;
524     colMatrixOneMinusOne_ = NULL;
525     delete rowMatrixOneMinusOne_;
526     rowMatrixOneMinusOne_ = NULL;
527   }
528 }
529 
530 //#############################################################################
531 // Parameter related methods
532 //#############################################################################
533 
534 bool
setIntParam(OsiIntParam key,int value)535 OsiTestSolverInterface::setIntParam(OsiIntParam key, int value)
536 {
537   switch (key) {
538   case OsiMaxNumIteration:
539     if (value < 0)
540       return false;
541     volprob_.parm.maxsgriters = value;
542     break;
543   case OsiMaxNumIterationHotStart:
544     if (value < 0)
545       return false;
546     OsiSolverInterface::setIntParam(key, value);
547     break;
548   case OsiLastIntParam:
549     return false;
550   default:
551     return false;
552   }
553   return true;
554 }
555 
556 //-----------------------------------------------------------------------------
557 
558 bool
setDblParam(OsiDblParam key,double value)559 OsiTestSolverInterface::setDblParam(OsiDblParam key, double value)
560 {
561   switch (key) {
562   case OsiDualObjectiveLimit:
563     volprob_.parm.ubinit = value;
564     break;
565   case OsiPrimalObjectiveLimit: // not applicable
566     return false;
567   case OsiDualTolerance: // only ~0 is applicable, so accept only 1e-50 ...
568     return (value == 1e-50);
569   case OsiPrimalTolerance:
570     if (value < 1e-04 || value > 1e-1)
571       return false;
572     volprob_.parm.primal_abs_precision = value;
573     break;
574   case OsiObjOffset:
575     return OsiSolverInterface::setDblParam(key, value);
576   case OsiLastDblParam:
577     return false;
578   default:
579       return false;
580   }
581   return true;
582 }
583 
584 
585 //-----------------------------------------------------------------------------
586 
587 bool
setStrParam(OsiStrParam key,const std::string & value)588 OsiTestSolverInterface::setStrParam(OsiStrParam key, const std::string & value)
589 {
590   bool retval=false;
591   switch (key) {
592   case OsiSolverName:
593     return false;
594 
595   case OsiProbName:
596     OsiSolverInterface::setStrParam(key,value);
597     return retval = true;
598 
599   case OsiLastStrParam:
600     return false;
601 
602   default:
603       return false;
604   }
605   return false;
606 }
607 
608 //-----------------------------------------------------------------------------
609 
610 bool
getIntParam(OsiIntParam key,int & value) const611 OsiTestSolverInterface::getIntParam(OsiIntParam key, int& value) const
612 {
613   switch (key) {
614   case OsiMaxNumIteration:
615     value = volprob_.parm.maxsgriters;
616     break;
617   case OsiMaxNumIterationHotStart:
618     OsiSolverInterface::getIntParam(key, value);
619     break;
620   case OsiLastIntParam:
621     return false;
622   default:
623     return false;
624   }
625   return true;
626 }
627 
628 //-----------------------------------------------------------------------------
629 
630 bool
getDblParam(OsiDblParam key,double & value) const631 OsiTestSolverInterface::getDblParam(OsiDblParam key, double& value) const
632 {
633   switch (key) {
634   case OsiDualObjectiveLimit:
635     value = volprob_.parm.ubinit;
636     break;
637   case OsiPrimalObjectiveLimit: // not applicable
638     return false;
639   case OsiDualTolerance: // not applicable, but must return almost 0
640     value = 1e-50;
641     break;
642   case OsiPrimalTolerance:
643     value = volprob_.parm.primal_abs_precision;
644     break;
645   case OsiObjOffset:
646     OsiSolverInterface::getDblParam(key, value);
647     break;
648   case OsiLastDblParam:
649     return false;
650   default:
651     return false;
652   }
653   return true;
654 }
655 
656 
657 //-----------------------------------------------------------------------------
658 
659 bool
getStrParam(OsiStrParam key,std::string & value) const660 OsiTestSolverInterface::getStrParam(OsiStrParam key, std::string & value) const
661 {
662   switch (key) {
663   case OsiProbName:
664     OsiSolverInterface::getStrParam(key, value);
665     return true;
666   case OsiSolverName:
667     value = "vol";
668     return true;
669   case OsiLastStrParam:
670     return false;
671   default:
672     return false;
673   }
674   return false;
675 }
676 //#############################################################################
677 // Methods returning info on how the solution process terminated
678 //#############################################################################
679 
680 bool
isAbandoned() const681 OsiTestSolverInterface::isAbandoned() const
682 {
683   // *THINK*: see the *THINK* in isProvenOptimal()
684   return false;
685 }
686 
687 bool
isProvenOptimal() const688 OsiTestSolverInterface::isProvenOptimal() const
689 {
690   // if exited before reaching the iteration limit it is declared optimal
691   // *THINK*: Granted, it can exit because the dual value is not improving.
692   // *THINK*: Should that be "abandoned"? But then it'll be abandoned way too
693   // *THINK*: frequently...
694   return (! isDualObjectiveLimitReached() &&
695 	  volprob_.iter() < volprob_.parm.maxsgriters);
696 }
697 
698 bool
isProvenPrimalInfeasible() const699 OsiTestSolverInterface::isProvenPrimalInfeasible() const
700 {
701   // LL: *FIXME* : at the moment the volume can't detect primal infeasibility.
702   // LL: *FIXME* : The dual will go to infinity.
703   return false;
704 }
705 
706 bool
isProvenDualInfeasible() const707 OsiTestSolverInterface::isProvenDualInfeasible() const
708 {
709   // LL: *FIXME* : at the moment the volume assumes dual feasibility...
710   return false;
711 }
712 
713 bool
isPrimalObjectiveLimitReached() const714 OsiTestSolverInterface::isPrimalObjectiveLimitReached() const
715 {
716   // The volume algorithm doesn't know anything about the primal; only the
717   // dual is monotone
718   return false;
719 }
720 
721 bool
isDualObjectiveLimitReached() const722 OsiTestSolverInterface::isDualObjectiveLimitReached() const
723 {
724   return volprob_.parm.ubinit - volprob_.value < volprob_.parm.granularity;
725 }
726 
727 bool
isIterationLimitReached() const728 OsiTestSolverInterface::isIterationLimitReached() const
729 {
730   return volprob_.iter() >= volprob_.parm.maxsgriters;
731 }
732 
733 //#############################################################################
734 // WarmStart related methods
735 //#############################################################################
736 
737 CoinWarmStart*
getEmptyWarmStart() const738 OsiTestSolverInterface::getEmptyWarmStart () const
739 { return (dynamic_cast<CoinWarmStart *>(new CoinWarmStartDual())) ; }
740 
741 CoinWarmStart*
getWarmStart() const742 OsiTestSolverInterface::getWarmStart() const
743 {
744   return new CoinWarmStartDual(getNumRows(), rowprice_);
745 }
746 
747 //-----------------------------------------------------------------------------
748 
749 bool
setWarmStart(const CoinWarmStart * warmstart)750 OsiTestSolverInterface::setWarmStart(const CoinWarmStart* warmstart)
751 {
752   const CoinWarmStartDual* ws =
753     dynamic_cast<const CoinWarmStartDual*>(warmstart);
754 
755   if (! ws)
756     return false;
757 
758   const int ws_size = ws->size();
759   if (ws_size != getNumRows() && ws_size != 0) {
760     throw CoinError("wrong dual warmstart size", "setWarmStart",
761 		   "OsiTestSolverInterface");
762   }
763 
764   CoinDisjointCopyN(ws->dual(), ws_size, rowprice_);
765   return true;
766 }
767 
768 //#############################################################################
769 // HotStart related methods
770 //#############################################################################
771 
772 void
markHotStart()773 OsiTestSolverInterface::markHotStart()
774 {
775   delete[] rowpriceHotStart_;
776   rowpriceHotStart_ = new double[getNumRows()];
777   CoinDisjointCopyN(rowprice_, getNumRows(), rowpriceHotStart_);
778 }
779 
780 void
solveFromHotStart()781 OsiTestSolverInterface::solveFromHotStart()
782 {
783    int itlimOrig = volprob_.parm.maxsgriters;
784    getIntParam(OsiMaxNumIterationHotStart, volprob_.parm.maxsgriters);
785    CoinDisjointCopyN(rowpriceHotStart_, getNumRows(), rowprice_);
786    resolve();
787    volprob_.parm.maxsgriters = itlimOrig;
788 }
789 
790 void
unmarkHotStart()791 OsiTestSolverInterface::unmarkHotStart()
792 {
793   delete[] rowpriceHotStart_;
794   rowpriceHotStart_ = NULL;
795 }
796 
797 //#############################################################################
798 // Problem information methods (original data)
799 //#############################################################################
800 
801 bool
isContinuous(int colNumber) const802 OsiTestSolverInterface::isContinuous(int colNumber) const
803 {
804   assert( continuous_!=NULL );
805   if ( continuous_[colNumber] ) return true;
806   return false;
807 }
808 
809 //-----------------------------------------------------------------------------
810 
811 const CoinPackedMatrix *
getMatrixByRow() const812 OsiTestSolverInterface::getMatrixByRow() const {
813    updateRowMatrix_();
814    return &rowMatrix_;
815 }
816 
817 //-----------------------------------------------------------------------
818 
819 const CoinPackedMatrix *
getMatrixByCol() const820 OsiTestSolverInterface::getMatrixByCol() const {
821    updateColMatrix_();
822    return &colMatrix_;
823 }
824 
825 //#############################################################################
826 // Problem information methods (results)
827 //#############################################################################
828 
getDualRays(int,bool) const829 std::vector<double*> OsiTestSolverInterface::getDualRays(int /*maxNumRays*/,
830 							 bool /*fullRay*/) const
831 {
832   // *FIXME* : must write the method -LL
833   throw CoinError("method is not yet written", "getDualRays",
834 		 "OsiTestSolverInterface");
835   return std::vector<double*>();
836 }
837 //------------------------------------------------------------------
getPrimalRays(int) const838 std::vector<double*> OsiTestSolverInterface::getPrimalRays(int /*maxNumRays*/) const
839 {
840   // *FIXME* : must write the method -LL
841   throw CoinError("method is not yet written", "getPrimalRays",
842 		 "OsiTestSolverInterface");
843   return std::vector<double*>();
844 }
845 
846 //#############################################################################
847 // Problem modifying methods (rim vectors)
848 //#############################################################################
849 
850 //-----------------------------------------------------------------------------
setColSetBounds(const int * indexFirst,const int * indexLast,const double * boundList)851 void OsiTestSolverInterface::setColSetBounds(const int* indexFirst,
852 					    const int* indexLast,
853 					    const double* boundList)
854 {
855   while (indexFirst < indexLast) {
856     const int ind = *indexFirst;
857     collower_[ind] = boundList[0];
858     colupper_[ind] = boundList[1];
859     ++indexFirst;
860     boundList += 2;
861   }
862 }
863 
864 //-----------------------------------------------------------------------------
setRowSetBounds(const int * indexFirst,const int * indexLast,const double * boundList)865 void OsiTestSolverInterface::setRowSetBounds(const int* indexFirst,
866 					    const int* indexLast,
867 					    const double* boundList)
868 {
869   if (indexLast - indexFirst < getNumRows() / 3) {
870     while (indexFirst < indexLast) {
871       setRowBounds(*indexFirst, boundList[0], boundList[1]);
872       ++indexFirst;
873       boundList += 2;
874     }
875   } else {
876     // it's better to convert everything at once
877     while (indexFirst < indexLast) {
878       const int ind = *indexFirst;
879       rowlower_[ind] = boundList[0];
880       rowupper_[ind] = boundList[1];
881       ++indexFirst;
882       boundList += 2;
883     }
884     convertBoundsToSenses_();
885   }
886 }
887 
888 //-----------------------------------------------------------------------------
setRowSetTypes(const int * indexFirst,const int * indexLast,const char * senseList,const double * rhsList,const double * rangeList)889 void OsiTestSolverInterface::setRowSetTypes(const int* indexFirst,
890 					   const int* indexLast,
891 					   const char* senseList,
892 					   const double* rhsList,
893 					   const double* rangeList)
894 {
895   if (indexLast - indexFirst < getNumRows() / 3) {
896     while (indexFirst < indexLast) {
897       setRowType(*indexFirst++, *senseList++, *rhsList++, *rangeList++);
898     }
899   } else {
900     // it's better to convert everything at once
901     while (indexFirst < indexLast) {
902       const int ind = *indexFirst++;
903       rowsense_[ind] = *senseList++;
904       rhs_[ind] = *rhsList++;
905       rowrange_[ind] = *rangeList++;
906     }
907     convertSensesToBounds_();
908   }
909 }
910 
911 //#############################################################################
912 
913 void
setContinuous(int index)914 OsiTestSolverInterface::setContinuous(int index)
915 {
916   assert(continuous_ != NULL);
917   if (index < 0 || index > getNumCols()) {
918     throw CoinError("Index out of bound.", "setContinuous",
919 		   "OsiTestSolverInterface");
920   }
921   continuous_[index] = true;
922 }
923 
924 //-----------------------------------------------------------------------
925 
926 void
setInteger(int index)927 OsiTestSolverInterface::setInteger(int index)
928 {
929   assert(continuous_ != NULL);
930   if (index < 0 || index > getNumCols()) {
931     throw CoinError("Index out of bound.", "setContinuous",
932 		   "OsiTestSolverInterface");
933   }
934   continuous_[index] = false;
935 }
936 
937 //-----------------------------------------------------------------------
938 
939 void
setContinuous(const int * indices,int len)940 OsiTestSolverInterface::setContinuous(const int* indices, int len)
941 {
942   assert(continuous_ != NULL);
943   const int colnum = getNumCols();
944   int i;
945 
946   for (i = len - 1; i >= 0; --i) {
947     if (indices[i] < 0 || indices[i] > colnum) {
948       throw CoinError("Index out of bound.", "setContinuous",
949 		     "OsiTestSolverInterface");
950     }
951   }
952 
953   for (i = len - 1; i >= 0; --i) {
954     continuous_[indices[i]] = true;
955   }
956 }
957 
958 //-----------------------------------------------------------------------
959 
960 void
setInteger(const int * indices,int len)961 OsiTestSolverInterface::setInteger(const int* indices, int len)
962 {
963   assert(continuous_ != NULL);
964   const int colnum = getNumCols();
965   int i;
966 
967   for (i = len - 1; i >= 0; --i) {
968     if (indices[i] < 0 || indices[i] > colnum) {
969       throw CoinError("Index out of bound.", "setContinuous",
970 		     "OsiTestSolverInterface");
971     }
972   }
973 
974   for (i = len - 1; i >= 0; --i) {
975     continuous_[indices[i]] = false;
976   }
977 }
978 
979 //#############################################################################
980 
981 void
setColSolution(const double * colsol)982 OsiTestSolverInterface::setColSolution(const double *colsol)
983 {
984    CoinDisjointCopyN(colsol, getNumCols(), colsol_);
985   // Compute the left hand side (row activity levels)
986   if (isZeroOneMinusOne_) {
987     colMatrixOneMinusOne_->timesMajor(colsol_, lhs_);
988   } else {
989     colMatrix_.times(colsol_, lhs_);
990   }
991 }
992 
993 //-----------------------------------------------------------------------
994 
995 void
setRowPrice(const double * rowprice)996 OsiTestSolverInterface::setRowPrice(const double *rowprice)
997 {
998    CoinDisjointCopyN(rowprice, getNumRows(), rowprice_);
999    compute_rc_(rowprice_, rc_);
1000 }
1001 
1002 //#############################################################################
1003 // Problem modifying methods (matrix)
1004 //#############################################################################
1005 
1006 void
addCol(const CoinPackedVectorBase & vec,const double collb,const double colub,const double obj)1007 OsiTestSolverInterface::addCol(const CoinPackedVectorBase& vec,
1008 			      const double collb, const double colub,
1009 			      const double obj)
1010 {
1011   const int colnum = getNumCols();
1012   colRimResize_(colnum + 1);
1013   collower_[colnum]   = collb;
1014   colupper_[colnum]   = colub;
1015   objcoeffs_[colnum]  = obj;
1016   continuous_[colnum] = true;
1017   colsol_[colnum]     = fabs(collb)<fabs(colub) ? collb : colub;
1018   rc_[colnum]         = 0.0;
1019 
1020   updateColMatrix_();
1021   colMatrix_.appendCol(vec);
1022   rowMatrixCurrent_ = false;
1023 }
1024 
1025 //-----------------------------------------------------------------------------
1026 
1027 void
addCols(const int numcols,const CoinPackedVectorBase * const * cols,const double * collb,const double * colub,const double * obj)1028 OsiTestSolverInterface::addCols(const int numcols,
1029 			       const CoinPackedVectorBase * const * cols,
1030 			       const double* collb, const double* colub,
1031 			       const double* obj)
1032 {
1033   if (numcols > 0) {
1034     const int colnum = getNumCols();
1035     colRimResize_(colnum + numcols);
1036     CoinDisjointCopyN(collb, numcols, collower_ + colnum);
1037     CoinDisjointCopyN(colub, numcols, colupper_ + colnum);
1038     CoinDisjointCopyN(obj, numcols, objcoeffs_ + colnum);
1039     CoinFillN(continuous_ + colnum, numcols, true);
1040     int c;
1041     for ( c=0; c<numcols; c++ ) {
1042       if ( fabs(collb[c]) < fabs(colub[c]) ) {
1043         colsol_[colnum+c] = collb[c];
1044       }
1045       else {
1046         colsol_[colnum+c] = colub[c];
1047       }
1048     }
1049     //CoinFillN(colsol_     + colnum, numcols, 0.0);
1050     CoinFillN(rc_         + colnum, numcols, 0.0);
1051 
1052     updateColMatrix_();
1053     colMatrix_.appendCols(numcols, cols);
1054     rowMatrixCurrent_ = false;
1055   }
1056 }
1057 
1058 //-----------------------------------------------------------------------------
1059 
1060 void
deleteCols(const int num,const int * columnIndices)1061 OsiTestSolverInterface::deleteCols(const int num, const int * columnIndices)
1062 {
1063   if (num > 0) {
1064     int * delPos = new int[num];
1065     CoinDisjointCopyN(columnIndices, num, delPos);
1066     std::sort(delPos, delPos + num);
1067     const int delNum =
1068       static_cast<int>(std::unique(delPos, delPos + num) - delPos);
1069 
1070     const int colnum = getNumCols();
1071     CoinDeleteEntriesFromArray(collower_, collower_ + colnum,
1072 			       delPos, delPos + delNum);
1073     CoinDeleteEntriesFromArray(colupper_, colupper_ + colnum,
1074 			       delPos, delPos + delNum);
1075     CoinDeleteEntriesFromArray(objcoeffs_, objcoeffs_ + colnum,
1076 			       delPos, delPos + delNum);
1077     CoinDeleteEntriesFromArray(continuous_, continuous_ + colnum,
1078 			       delPos, delPos + delNum);
1079     CoinDeleteEntriesFromArray(colsol_, colsol_ + colnum,
1080 			       delPos, delPos + delNum);
1081     CoinDeleteEntriesFromArray(rc_, rc_ + colnum,
1082 			       delPos, delPos + delNum);
1083 
1084     updateColMatrix_();
1085     colMatrix_.deleteCols(delNum, delPos);
1086     rowMatrixCurrent_ = false;
1087   }
1088 }
1089 
1090 
1091 //-----------------------------------------------------------------------------
1092 
1093 void
addRow(const CoinPackedVectorBase & vec,const double rowlb,const double rowub)1094 OsiTestSolverInterface::addRow(const CoinPackedVectorBase& vec,
1095 			      const double rowlb, const double rowub)
1096 {
1097   const int rownum = getNumRows();
1098   rowRimResize_(rownum + 1);
1099   rowlower_[rownum] = rowlb;
1100   rowupper_[rownum] = rowub;
1101   convertBoundToSense(rowlb, rowub,
1102 		      rowsense_[rownum], rhs_[rownum], rowrange_[rownum]);
1103   rowprice_[rownum] = 0.0;
1104   lhs_[rownum] = 0.0;
1105 
1106   updateRowMatrix_();
1107   rowMatrix_.appendRow(vec);
1108   colMatrixCurrent_ = false;
1109 }
1110 
1111 //-----------------------------------------------------------------------------
1112 
1113 void
addRow(const CoinPackedVectorBase & vec,const char rowsen,const double rowrhs,const double rowrng)1114 OsiTestSolverInterface::addRow(const CoinPackedVectorBase& vec,
1115 			      const char rowsen, const double rowrhs,
1116 			      const double rowrng)
1117 {
1118   const int rownum = getNumRows();
1119   rowRimResize_(rownum + 1);
1120   rowsense_[rownum] = rowsen;
1121   rhs_[rownum] = rowrhs;
1122   rowrange_[rownum] = rowrng;
1123   convertSenseToBound(rowsen, rowrhs, rowrng,
1124 		      rowlower_[rownum], rowupper_[rownum]);
1125   rowprice_[rownum] = 0.0;
1126   lhs_[rownum] = 0.0;
1127 
1128   updateRowMatrix_();
1129   rowMatrix_.appendRow(vec);
1130   colMatrixCurrent_ = false;
1131 }
1132 
1133 //-----------------------------------------------------------------------------
1134 
1135 void
addRows(const int numrows,const CoinPackedVectorBase * const * rows,const double * rowlb,const double * rowub)1136 OsiTestSolverInterface::addRows(const int numrows,
1137 			       const CoinPackedVectorBase * const * rows,
1138 			       const double* rowlb, const double* rowub)
1139 {
1140   if (numrows > 0) {
1141     const int rownum = getNumRows();
1142     rowRimResize_(rownum + numrows);
1143     CoinDisjointCopyN(rowlb, numrows, rowlower_ + rownum);
1144     CoinDisjointCopyN(rowub, numrows, rowupper_ + rownum);
1145     for (int i = rownum + numrows - 1; i >= rownum; --i) {
1146       convertBoundToSense(rowlower_[i], rowupper_[i],
1147 			  rowsense_[i], rhs_[i], rowrange_[i]);
1148     }
1149     CoinFillN(rowprice_ + rownum, numrows, 0.0);
1150     CoinFillN(lhs_      + rownum, numrows, 0.0);
1151 
1152     updateRowMatrix_();
1153     rowMatrix_.appendRows(numrows, rows);
1154     colMatrixCurrent_ = false;
1155   }
1156 }
1157 
1158 //-----------------------------------------------------------------------------
1159 
1160 void
addRows(const int numrows,const CoinPackedVectorBase * const * rows,const char * rowsen,const double * rowrhs,const double * rowrng)1161 OsiTestSolverInterface::addRows(const int numrows,
1162 			       const CoinPackedVectorBase * const * rows,
1163 			       const char* rowsen, const double* rowrhs,
1164 			       const double* rowrng)
1165 {
1166   if (numrows > 0) {
1167     const int rownum = getNumRows();
1168     rowRimResize_(rownum + numrows);
1169     CoinDisjointCopyN(rowsen, numrows, rowsense_ + rownum);
1170     CoinDisjointCopyN(rowrhs, numrows, rhs_ + rownum);
1171     CoinDisjointCopyN(rowrng, numrows, rowrange_ + rownum);
1172     for (int i = rownum + numrows - 1; i >= rownum; --i) {
1173       convertSenseToBound(rowsense_[i], rhs_[i], rowrange_[i],
1174 			  rowlower_[i], rowupper_[i]);
1175     }
1176     CoinFillN(rowprice_ + rownum, numrows, 0.0);
1177     CoinFillN(lhs_      + rownum, numrows, 0.0);
1178 
1179     updateRowMatrix_();
1180     rowMatrix_.appendRows(numrows, rows);
1181     colMatrixCurrent_ = false;
1182   }
1183 }
1184 
1185 //-----------------------------------------------------------------------------
1186 
1187 void
deleteRows(const int num,const int * rowIndices)1188 OsiTestSolverInterface::deleteRows(const int num, const int * rowIndices)
1189 {
1190   if (num > 0) {
1191     int * delPos = new int[num];
1192     CoinDisjointCopyN(rowIndices, num, delPos);
1193     std::sort(delPos, delPos + num);
1194     const int delNum =
1195         static_cast<int>(std::unique(delPos, delPos + num) - delPos);
1196 
1197     const int rownum = getNumRows();
1198     CoinDeleteEntriesFromArray(rowlower_, rowlower_ + rownum,
1199 			       delPos, delPos + delNum);
1200     CoinDeleteEntriesFromArray(rowupper_, rowupper_ + rownum,
1201 			       delPos, delPos + delNum);
1202     CoinDeleteEntriesFromArray(rowsense_, rowsense_ + rownum,
1203 			       delPos, delPos + delNum);
1204     CoinDeleteEntriesFromArray(rowrange_, rowrange_ + rownum,
1205 			       delPos, delPos + delNum);
1206     CoinDeleteEntriesFromArray(rhs_, rhs_ + rownum,
1207 			       delPos, delPos + delNum);
1208     CoinDeleteEntriesFromArray(rowprice_, rowprice_ + rownum,
1209 			       delPos, delPos + delNum);
1210     CoinDeleteEntriesFromArray(lhs_, lhs_ + rownum,
1211 			       delPos, delPos + delNum);
1212 
1213     updateRowMatrix_();
1214     rowMatrix_.deleteRows(delNum, delPos);
1215     colMatrixCurrent_ = false;
1216 
1217     delete[] delPos;
1218   }
1219 }
1220 
1221 //#############################################################################
1222 // Constructors, destructors clone and assignment
1223 //#############################################################################
1224 
OsiTestSolverInterface()1225 OsiTestSolverInterface::OsiTestSolverInterface () :
1226    rowMatrixCurrent_(true),
1227    rowMatrix_(),
1228    colMatrixCurrent_(true),
1229    colMatrix_(),
1230    isZeroOneMinusOne_(false),
1231 
1232    colupper_(0),
1233    collower_(0),
1234    continuous_(0),
1235    rowupper_(0),
1236    rowlower_(0),
1237    rowsense_(0),
1238    rhs_(0),
1239    rowrange_(0),
1240 
1241    objcoeffs_(0),
1242    objsense_(1.0),
1243 
1244    colsol_(0),
1245    rowprice_(0),
1246    rc_(0),
1247    lhs_(0),
1248    lagrangeanCost_(0.0),
1249 
1250    rowpriceHotStart_(0),
1251 
1252    maxNumrows_(0),
1253    maxNumcols_(0),
1254 
1255    volprob_()
1256 {
1257    volprob_.parm.granularity = 0.0;
1258 }
1259 
1260 //-----------------------------------------------------------------------
1261 
1262 OsiSolverInterface *
clone(bool copyData) const1263 OsiTestSolverInterface::clone(bool copyData) const {
1264   return copyData ?
1265     new OsiTestSolverInterface(*this) :
1266     new OsiTestSolverInterface();
1267 }
1268 
1269 //-----------------------------------------------------------------------
1270 
OsiTestSolverInterface(const OsiTestSolverInterface & x)1271 OsiTestSolverInterface::OsiTestSolverInterface(const OsiTestSolverInterface& x) :
1272   OsiSolverInterface(x),
1273    rowMatrixCurrent_(true),
1274    rowMatrix_(),
1275    colMatrixCurrent_(true),
1276    colMatrix_(),
1277    isZeroOneMinusOne_(false),
1278 
1279    colupper_(0),
1280    collower_(0),
1281    continuous_(0),
1282    rowupper_(0),
1283    rowlower_(0),
1284    rowsense_(0),
1285    rhs_(0),
1286    rowrange_(0),
1287 
1288    objcoeffs_(0),
1289    objsense_(1.0),
1290 
1291    colsol_(0),
1292    rowprice_(0),
1293    rc_(0),
1294    lhs_(0),
1295    lagrangeanCost_(0.0),
1296 
1297    rowpriceHotStart_(0),
1298 
1299    maxNumrows_(0),
1300    maxNumcols_(0),
1301 
1302    volprob_()
1303 {
1304    operator=(x);
1305    volprob_.parm.granularity = 0.0;
1306 }
1307 
1308 //-----------------------------------------------------------------------
1309 
1310 OsiTestSolverInterface&
operator =(const OsiTestSolverInterface & rhs)1311 OsiTestSolverInterface::operator=(const OsiTestSolverInterface& rhs)
1312 {
1313    if (&rhs == this)
1314       return *this;
1315 
1316    OsiSolverInterface::operator=(rhs);
1317    gutsOfDestructor_();
1318 
1319    rowMatrixCurrent_ = rhs.rowMatrixCurrent_;
1320    if (rowMatrixCurrent_)
1321       rowMatrix_ = rhs.rowMatrix_;
1322    colMatrixCurrent_ = rhs.colMatrixCurrent_;
1323    if (colMatrixCurrent_)
1324       colMatrix_ = rhs.colMatrix_;
1325 
1326    if (rhs.maxNumrows_) {
1327       maxNumrows_ = rhs.maxNumrows_;
1328       rowRimAllocator_();
1329       const int rownum = getNumRows();
1330       CoinDisjointCopyN(rhs.rowupper_, rownum, rowupper_);
1331       CoinDisjointCopyN(rhs.rowlower_, rownum, rowlower_);
1332       CoinDisjointCopyN(rhs.rowsense_, rownum, rowsense_);
1333       CoinDisjointCopyN(rhs.rhs_, rownum, rhs_);
1334       CoinDisjointCopyN(rhs.rowrange_, rownum, rowrange_);
1335       CoinDisjointCopyN(rhs.rowprice_, rownum, rowprice_);
1336       CoinDisjointCopyN(rhs.lhs_, rownum, lhs_);
1337    }
1338    if (rhs.maxNumcols_) {
1339       maxNumcols_ = rhs.maxNumcols_;
1340       colRimAllocator_();
1341       const int colnum = getNumCols();
1342       CoinDisjointCopyN(rhs.colupper_, colnum, colupper_);
1343       CoinDisjointCopyN(rhs.collower_, colnum, collower_);
1344       CoinDisjointCopyN(rhs.continuous_, colnum, continuous_);
1345       CoinDisjointCopyN(rhs.objcoeffs_, colnum, objcoeffs_);
1346       CoinDisjointCopyN(rhs.colsol_, colnum, colsol_);
1347       CoinDisjointCopyN(rhs.rc_, colnum, rc_);
1348    }
1349    volprob_.parm.granularity = 0.0;
1350    return *this;
1351 }
1352 
1353 //-----------------------------------------------------------------------
1354 
~OsiTestSolverInterface()1355 OsiTestSolverInterface::~OsiTestSolverInterface ()
1356 {
1357    gutsOfDestructor_();
1358 }
1359 
1360 //#############################################################################
1361 // Applying cuts
1362 //#############################################################################
1363 
1364 void
applyRowCut(const OsiRowCut & rc)1365 OsiTestSolverInterface::applyRowCut(const OsiRowCut& rc)
1366 {
1367    const int rownum = getNumRows();
1368    const double lb = rc.lb();
1369    const double ub = rc.ub();
1370    rowRimResize_(rownum + 1);
1371    rowprice_[rownum] = 0.0;
1372    rowlower_[rownum] = lb;
1373    rowupper_[rownum] = ub;
1374    convertBoundToSense(lb, ub,
1375 		       rowsense_[rownum], rhs_[rownum], rowrange_[rownum]);
1376 
1377    updateRowMatrix_();
1378    rowMatrix_.appendRow(rc.row());
1379    colMatrixCurrent_ = false;
1380 }
1381 
1382 //-----------------------------------------------------------------------
1383 
1384 void
applyColCut(const OsiColCut & cc)1385 OsiTestSolverInterface::applyColCut(const OsiColCut& cc)
1386 {
1387    int i;
1388 
1389    const double* lb_elem = cc.lbs().getElements();
1390    const int* lb_ind = cc.lbs().getIndices();
1391    for (i = cc.lbs().getNumElements() - 1; i >= 0; --i) {
1392       collower_[lb_ind[i]] = CoinMax(collower_[lb_ind[i]], lb_elem[i]);
1393    }
1394 
1395    const double* ub_elem = cc.ubs().getElements();
1396    const int* ub_ind = cc.ubs().getIndices();
1397    for (i = cc.ubs().getNumElements() - 1; i >= 0; --i) {
1398       colupper_[ub_ind[i]] = CoinMin(colupper_[ub_ind[i]], ub_elem[i]);
1399    }
1400 }
1401 
1402 //#############################################################################
1403