Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

OsiDylpSolverInterface.cpp

00001 
00007 #ifdef COIN_USE_DYLP
00008 
00009 #ifdef _MSC_VER
00010 
00011 /* Turn off compiler warning about long names */
00012 #  pragma warning(disable:4786)
00013 
00014 /*
00015   MS C++ doesn't want to cope with this set of templates. Since they're just
00016   paranoid checks, it's easiest to simply disable them.
00017 */
00018 
00019 #  define assert_same
00020 
00021 /*
00022   In general, templates do not seem to be a strong point for MS C++. To get
00023   around this, there are a number of macros defined below.  For Sun Workshop
00024   and Gnu programming environments, these will expand to template functions.
00025   For MS, they expand to some code plus calls to STL functions. Apparently MS
00026   C++ doesn't have trouble with the definitions of the templates, just
00027   instantiations.
00028 */
00029 
00030 #endif
00031 
00032 /* Cut name lengths for readability. */
00033 
00034 #define ODSI OsiDylpSolverInterface
00035 #define OSI OsiSolverInterface
00036 
00135 namespace {
00136   char sccsid[] = "%W%  %G%" ;
00137   char cvsid[] = "$Id: OsiDylpSolverInterface.cpp,v 1.22 2003/10/27 18:55:31 jpfasano Exp $" ;
00138 }
00139 
00140 #include <string>
00141 #include <cassert>
00142 #include <OsiColCut.hpp>
00143 #include <OsiRowCut.hpp>
00144 #include <OsiRowCutDebugger.hpp>
00145 #include "OsiDylpSolverInterface.hpp"
00146 #include "OsiDylpMessages.hpp"
00147 #include "OsiDylpWarmStartBasis.hpp"
00148 
00149 using std::string ;
00150 using std::vector ;
00151 
00152 
00153 extern "C"
00154 {
00155 
00156 #include "bonsai.h"
00157 
00158 /*
00159   Dylp uses HUGE_VAL for infinity; generally this seems to resolve to IEEE
00160   infinity but if it doesn't, you'll need to have a look at vector.h for the
00161   appropriate compile-time symbol definition. A macro seems to be necessary
00162   here because I can't figure out how to call ODSI.getInfinity() from inside
00163   a static member function without explicitly passing in the value of `this'
00164   from the context of the call. That seems like overkill.
00165 */
00166 
00167 #define DYLP_INFINITY HUGE_VAL
00168 
00169 
00170 #ifndef ERRMSGDIR
00171 # define ERRMSGDIR "."
00172 #endif
00173 
00174 
00175 extern bool dy_mpsin(const char *filename, consys_struct **consys) ;
00176 extern void dy_initbasis(int concnt, int factor_freq, double zero_tol) ;
00177 extern void dy_freebasis() ;
00178 
00179 /*
00180   These routines work with the literal tree in DylpLib (a legacy, what can I
00181   say). DO NOT MIX strings handled with stralloc/strfree with strings handled
00182   using malloc/free.  Needless to say, std::string is another beast
00183   entirely.
00184 */
00185 
00186 extern char *stralloc(const char *str) ;
00187 extern void strfree(const char *str) ;
00188 
00189 }
00190 
00233 ioid cmdchn = IOID_NOSTRM,
00234      logchn = IOID_NOSTRM ;
00235 
00236 bool cmdecho = false,
00237      gtxecho = false ;
00238 
00240 
00276 int ODSI::reference_count = 0 ;
00277 bool ODSI::basis_ready = false ;
00278 ODSI *ODSI::dylp_owner = 0 ;
00279 
00281 
00282 
00283 
00295 
00298 inline int ODSI::idx (int i) { return i+1 ; }
00299 
00306 template<class T> inline T* ODSI::idx_vec (T* vec) { return vec-1 ; }
00307 
00310 inline int ODSI::inv (int i) { return i-1 ; }
00311 
00318 template<class T> inline T* ODSI::inv_vec (T* vec) { return vec+1 ; }
00319 
00320 /*
00321   MS C++ doesn't like the template functions above. To keep it happy, wrap
00322   them in macros which will accomplish the same thing.
00323 */
00324 
00325 #ifdef _MSC_VER
00326 #  define IDX_VEC(zz_type_zz,zz_vec_zz) (zz_vec_zz-1)
00327 #  define INV_VEC(zz_type_zz,zz_vec_zz) (zz_vec_zz+1)
00328 #else
00329 #  define IDX_VEC(zz_type_zz,zz_vec_zz) idx_vec<zz_type_zz>(zz_vec_zz)
00330 #  define INV_VEC(zz_type_zz,zz_vec_zz) inv_vec<zz_type_zz>(zz_vec_zz)
00331 #endif
00332 
00342 pkvec_struct* ODSI::packed_vector (const CoinShallowPackedVector src,
00343                                    int dimension)
00344 
00345 { int n = src.getNumElements() ;
00346   pkvec_struct* dst = pkvec_new(n) ;
00347 
00348   assert(dst) ;
00349 
00350   if (n == 0) return (dst) ;
00351 
00352   packed_vector(src,dimension,dst) ;
00353 
00354   return (dst) ; }
00355 
00356 
00365 void ODSI::packed_vector (const CoinShallowPackedVector src, int dimension,
00366                           pkvec_struct *dst)
00367 
00368 { int n = src.getNumElements() ;
00369 
00370   dst->cnt = n ;
00371   dst->dim = dimension ;
00372 
00373   if (n == 0) return ;
00374 
00375   const int* indices = src.getIndices() ;
00376   const double* elements = src.getElements() ;
00377   pkcoeff_struct* coeffs = dst->coeffs ;
00378 
00379   for (int i = 0 ; i < n ; i++)
00380   { coeffs[i].ndx = idx(indices[i]) ;
00381     coeffs[i].val = elements[i] ; }
00382 
00383   return ; }
00384 
00385 
00387 
00388 
00389 
00396 
00397 /* Templates for simple copies */
00398 
00404 template<class T> inline T* ODSI::copy (const T* src)
00405 
00406 { if (!src) return 0 ;
00407   T* dst = new T ;
00408   memcpy(dst, src, sizeof(T)) ;
00409   return dst ;
00410 }
00411 
00412 #ifdef _MSC_VER
00413 #  define CLONE(zz_type_zz,zz_src_zz,zz_dst_zz) \
00414             if (zz_src_zz) \
00415             { zz_dst_zz = new zz_type_zz ; \
00416               memcpy(zz_dst_zz,zz_src_zz,sizeof(zz_type_zz)) ; } \
00417             else \
00418             { zz_dst_zz = NULL ; }
00419 #else
00420 #  define CLONE(zz_type_zz,zz_src_zz,zz_dst_zz) \
00421             zz_dst_zz = copy<zz_type_zz>(zz_src_zz) ;
00422 #endif
00423   
00424 
00430 template<class T> inline void ODSI::copy (const T* src, T* dst, int n)
00431 
00432 { if (!dst || !src || n == 0) return ;
00433   int size = sizeof(T) * n ;
00434   memcpy(dst,src,size) ;
00435 }
00436 
00437 #ifdef _MSC_VER
00438 # define COPY_VEC(zz_type_zz,zz_src_zz,zz_dst_zz,zz_n_zz) \
00439            if (zz_dst_zz && zz_src_zz && zz_n_zz > 0 ) \
00440              std::copy(zz_src_zz,zz_src_zz+zz_n_zz,zz_dst_zz)
00441 #else
00442 # define COPY_VEC(zz_type_zz,zz_src_zz,zz_dst_zz,zz_n_zz) \
00443            copy<zz_type_zz>(zz_src_zz,zz_dst_zz,zz_n_zz)
00444 #endif
00445 
00446 
00452 template<class T> inline T* ODSI::copy (const T* src, int n)
00453 
00454 { if (!src || n == 0) return 0 ;
00455   T* dst = new T[n] ;
00456   copy(src, dst, n) ;
00457   return dst ;
00458 }
00459 
00460 #ifdef _MSC_VER
00461 #  define CLONE_VEC(zz_type_zz,zz_src_zz,zz_dst_zz,zz_n_zz) \
00462             if (zz_src_zz && zz_n_zz > 0) \
00463             { zz_dst_zz = new zz_type_zz[zz_n_zz] ; \
00464               std::copy(zz_src_zz,zz_src_zz+zz_n_zz,zz_dst_zz) ; } \
00465             else \
00466             { zz_dst_zz = NULL ; }
00467 #else
00468 #  define CLONE_VEC(zz_type_zz,zz_src_zz,zz_dst_zz,zz_n_zz) \
00469             zz_dst_zz = copy<zz_type_zz>(zz_src_zz,zz_n_zz)
00470 #endif
00471 
00472 
00473 /* Specialised copy functions for complex dylp structures. */
00474 
00475 
00482 inline void ODSI::copy_basis (const basis_struct* src, basis_struct* dst)
00483 
00484 { if (!src) return ;
00485 
00486   dst->len = src->len ;
00487   if (dst->el == 0)
00488   { throw CoinError("No basis element vector",
00489                     "copy_basis","OsiDylpSolverInterface") ; }
00490   memcpy(dst->el,src->el,idx(src->len)*sizeof(basisel_struct)) ;
00491 
00492 # ifndef NDEBUG
00493   assert_same(*dst, *src, true) ;
00494 # endif
00495 
00496   return ; }
00497 
00498 
00510 inline basis_struct* ODSI::copy_basis (const basis_struct* src, int dstsze)
00511 
00512 { if (!src) return 0 ;
00513   basis_struct* dst = new basis_struct ;
00514   dst->el = (basisel_struct *) CALLOC(idx(dstsze),sizeof(basisel_struct)) ;
00515   copy_basis(src,dst) ;
00516   return dst ; }
00517 
00518 
00533 lpprob_struct* ODSI::copy_lpprob (const lpprob_struct* src)
00534 
00535 { if (!src) return 0 ;
00536 
00537   int col_count = idx(src->colsze) ;
00538   int row_count = idx(src->rowsze) ;
00539 
00540   lpprob_struct* dst = NULL;
00541   CLONE(lpprob_struct,src,dst);
00542 
00543   dst->basis = copy_basis(src->basis,row_count) ;
00544   CLONE_VEC(flags,src->status,dst->status,col_count);
00545   CLONE_VEC(double,src->x,dst->x,row_count);
00546   CLONE_VEC(double,src->y,dst->y,row_count);
00547   CLONE_VEC(bool,src->actvars,dst->actvars,col_count);
00548 
00549 # ifndef NDEBUG
00550   assert_same(*dst, *src, true) ;
00551 # endif
00552 
00553   return dst ; }
00554 
00556 
00557 
00558 
00559 /* Cache functions
00560 
00561    These properly belong in the DestructorHelpers group, but they need to be
00562    up here so that they are declared before the first use.
00563 */
00564 
00573 inline void ODSI::destruct_col_cache ()
00574 
00575 { delete [] _col_x ; _col_x = 0 ;
00576   delete [] _col_obj ; _col_obj = 0 ;
00577   delete [] _col_cbar ; _col_cbar = 0 ;
00578 }
00579 
00580 
00589 void ODSI::destruct_row_cache ()
00590 
00591 { delete [] _row_lhs ; _row_lhs = 0 ;
00592   delete [] _row_lower ; _row_lower = 0 ;
00593   delete [] _row_price ; _row_price = 0 ;
00594   delete [] _row_range ; _row_range = 0 ;
00595   delete [] _row_rhs ; _row_rhs = 0 ;
00596   delete [] _row_sense ; _row_sense = 0 ;
00597   delete [] _row_upper ; _row_upper = 0 ;
00598 }
00599 
00608 inline void ODSI::destruct_cache ()
00609 
00610 { destruct_row_cache() ;
00611   destruct_col_cache() ;
00612 
00613   delete _matrix_by_row ; _matrix_by_row = 0 ;
00614   delete _matrix_by_col ; _matrix_by_col = 0 ;
00615 
00616   return ; }
00617 
00618 
00619 
00620 
00629 
00640 inline contyp_enum ODSI::bound_to_type (double lower, double upper)
00641 
00642 { 
00643 
00644 # include <cfloat>
00645   double inf = DBL_MAX ;
00646 
00647   if (upper == lower) return contypEQ ;
00648   bool finite_low = (lower > -inf) ;
00649   bool finite_up = (upper < inf) ;
00650   if (finite_low && finite_up) return contypRNG ;
00651   if (finite_low) return contypGE ;
00652   if (finite_up) return contypLE ;
00653   return contypNB ; }
00654 
00655 
00658 inline contyp_enum ODSI::sense_to_type (char sense)
00659 
00660 { switch (sense)
00661   { case 'E': return contypEQ ;
00662     case 'G': return contypGE ;
00663     case 'L': return contypLE ;
00664     case 'N': return contypNB ;
00665     case 'R': return contypRNG ;
00666     default: { assert(0) ; return contypINV ; } } }
00667 
00668 
00671 inline char ODSI::type_to_sense (contyp_enum ctypi)
00672 
00673 { switch (ctypi)
00674   { case contypNB:
00675     { return 'N' ; }
00676     case contypGE:
00677     { return 'G' ; }
00678     case contypEQ:
00679     { return 'E' ; }
00680     case contypLE:
00681     { return 'L' ; }
00682     case contypRNG:
00683     { return 'R' ; }
00684     case contypINV:
00685     default: 
00686     { assert(0) ;
00687       return '?' ; } } }
00688 
00689 
00697 inline void
00698 ODSI::gen_rowiparms (contyp_enum* ctypi, double* rhsi, double* rhslowi,
00699                      char sensei, double rhsini, double rangei)
00700 
00701 { *ctypi = sense_to_type(sensei) ;
00702   switch (*ctypi)
00703   { case contypEQ:
00704     { *rhslowi = 0 ;
00705       *rhsi = rhsini ;
00706       break ; }
00707     case contypLE:
00708     { *rhslowi = 0 ;
00709       *rhsi = rhsini ;
00710       break ; }
00711     case contypGE:
00712     { *rhslowi = 0 ;
00713       *rhsi = rhsini ;
00714       break ; }
00715     case contypRNG:
00716     { *rhslowi = rhsini-rangei ;
00717       *rhsi = rhsini ;
00718       break ; }
00719     case contypNB:
00720     { *rhslowi = 0 ;
00721       *rhsi = 0 ;
00722       break ; }
00723     default:
00724     { assert(false) ; } }
00725 
00726   return ; }
00727 
00728 
00736 inline void
00737 ODSI::gen_rowiparms (contyp_enum* ctypi, double* rhsi, double* rhslowi,
00738                      double rowlbi, double rowubi)
00739 
00740 { *ctypi = bound_to_type(rowlbi,rowubi) ;
00741   switch (*ctypi)
00742   { case contypEQ:
00743     case contypLE:
00744     { *rhslowi = 0 ;
00745       *rhsi = rowubi ;
00746       break ; }
00747     case contypGE:
00748     { *rhslowi = 0 ;
00749       *rhsi = rowlbi ;
00750       break ; }
00751     case contypRNG:
00752     { *rhslowi = rowlbi ;
00753       *rhsi = rowubi ;
00754       break ; }
00755     case contypNB:
00756     { *rhslowi = 0 ;
00757       *rhsi = 0 ;
00758       break ; }
00759     default:
00760     { assert(false) ; } }
00761 
00762   return ; }
00763 
00764 
00775 void ODSI::add_col (const CoinPackedVectorBase& coin_colj,
00776                     vartyp_enum vtypj, double vlbj, double vubj, double objj)
00777 
00778 { pkvec_struct *pk_colj = packed_vector(coin_colj,getNumRows()) ;
00779 
00780 /*
00781   Do we need a consys?
00782 */
00783   if (!consys) construct_consys(0,0) ;
00784 /*
00785   Add the column.
00786 */
00787   bool r = consys_addcol_pk(consys,vtypj,pk_colj,objj,vlbj,vubj) ;
00788   pkvec_free(pk_colj) ;
00789   assert(r) ;
00790 /*
00791   After adding a column, the best we can do is a warm start.
00792 */
00793   resolveOptions->forcewarm = true ;
00794 
00795   destruct_cache() ; }
00796 
00797 
00807 void ODSI::add_row (const CoinPackedVectorBase &coin_rowi, char clazzi,
00808                     contyp_enum ctypi, double rhsi, double rhslowi)
00809 
00810 { pkvec_struct *pk_rowi = packed_vector(coin_rowi,getNumCols()) ;
00811 
00812 /*
00813   Do we need a consys?
00814 */
00815   if (!consys) construct_consys(0,0) ;
00816 /*
00817   Add the row.
00818 */
00819   bool r = consys_addrow_pk(consys,clazzi,ctypi,pk_rowi,rhsi,rhslowi,0,0) ;
00820   pkvec_free(pk_rowi) ;
00821   assert(r) ;
00822 /*
00823   After adding a constraint, the best we can do is a warm start.
00824 */
00825   resolveOptions->forcewarm = true ;
00826 
00827   destruct_cache() ; }
00828 
00829 
00840 void ODSI::worst_case_primal ()
00841 
00842 { 
00843 
00844 /*
00845   No columns, no solution. A non-zero value guarantees a consys structure.
00846 */
00847   int n = getNumCols() ;
00848   if (n == 0) return ;
00849   assert(consys && consys->obj && consys->vub && consys->vlb) ;
00850 
00851   double *obj = consys->obj ;
00852   double *vlb = consys->vlb ;
00853   double *vub = consys->vub ;
00854 /*
00855   We have columns. Allocate a cached primal solution vector, if it doesn't
00856   already exist.
00857 */
00858   if (!_col_x) _col_x = new double[n] ;
00859 /*
00860   Walk the objective vector, taking values for variables from the appropriate
00861   bounds vector. The objective attached to consys is always a minimisation
00862   objective.
00863 */
00864   for (int j = 1 ; j <= n ; j++)
00865   { if (obj[j] > 0)
00866     { _col_x[inv(j)] = vub[j] ; }
00867     else
00868     { _col_x[inv(j)] = vlb[j] ; } }
00869   
00870   return ; }
00871 
00881 void ODSI::calc_objval ()
00882 
00883 { int n = getNumCols() ;
00884 
00885 /*
00886   The easy case --- if we have no variables, the objective must be 0.
00887 */
00888   if (n == 0)
00889   { _objval = 0 ;
00890     return ; }
00891 /*
00892   We have variables. Grab the primal solution and objective function and
00893   calculate their dot product.
00894 */
00895   const double *obj = getObjCoefficients() ;
00896   const double *x = getColSolution() ;
00897   _objval = 0.0 ;
00898   for (int j = 0 ; j < n ; j++) _objval += x[j]*obj[j] ;
00899   setcleanzero(_objval,tolerances->cost) ;
00900 
00901   return ; }
00902 
00903 
00904 
00906 
00907 
00908 
00909 /* OsiDylpSolverInterface constructors and related subroutines. */
00910 
00911 
00914 
00921 inline void ODSI::construct_lpprob ()
00922 
00923 { lpprob = new lpprob_struct ;
00924   memset(lpprob, 0, sizeof(lpprob_struct)) ;
00925   setflg(lpprob->ctlopts,lpctlNOFREE) ;
00926   lpprob->phase = dyINV ;
00927   lpprob->consys = consys ;
00928   lpprob->rowsze = consys->rowsze ;
00929   lpprob->colsze = consys->colsze ;
00930   
00931   return ; }
00932 
00933 
00938 inline void ODSI::construct_options ()
00939 
00940 { 
00941 /*
00942   Acquire the default options and tolerances from dylp. Set the OSI options
00943   and tolerances to match. Turn dylp's printing options down to `catatonic'.
00944 */
00945   delete initialSolveOptions ;
00946   initialSolveOptions = new lpopts_struct ;
00947   delete tolerances ;
00948   tolerances = new lptols_struct ;
00949   dy_defaults(&initialSolveOptions,&tolerances) ;
00950   delete resolveOptions ;
00951   CLONE(lpopts_struct,initialSolveOptions,resolveOptions);
00952   dy_setprintopts(0,initialSolveOptions) ;
00953   dy_setprintopts(0,resolveOptions) ;
00954 
00955   setIntParam(OsiMaxNumIteration,3*initialSolveOptions->iterlim) ;
00956   setIntParam(OsiMaxNumIterationHotStart,3*initialSolveOptions->iterlim) ;
00957   setDblParam(OsiDualTolerance,tolerances->dfeas_scale*tolerances->cost) ;
00958   setDblParam(OsiPrimalTolerance,tolerances->pfeas_scale*tolerances->zero) ;
00959 /*
00960   Differentiate options for initial solution vs. reoptimising.
00961 */
00962   initialSolveOptions->forcecold = true ;
00963   initialSolveOptions->fullsys = true ;
00964   resolveOptions->forcecold = false ;
00965   resolveOptions->fullsys = false ;
00966 /*
00967   Acquire and clear a statistics structure.
00968 */
00969   delete statistics ;
00970   statistics = new lpstats_struct ;
00971   memset(statistics,0,sizeof(lpstats_struct)) ;
00972 }
00973 
00982 void ODSI::construct_consys (int cols, int rows)
00983 
00984 {
00985 /*
00986   Set parameters to specify the appropriate options and attached vectors.
00987   
00988   parts specifies (in order) an objective, variable upper bounds, variable
00989   lower bounds, constraint rhs, range constraint rhs, variable type, and
00990   constraint type.
00991 
00992   options specifies that consys should issue a warning if requested to attach
00993   a vector that's already attached.
00994 */
00995   flags parts = CONSYS_OBJ | 
00996                 CONSYS_VUB | CONSYS_VLB | CONSYS_VTYP |
00997                 CONSYS_RHS | CONSYS_RHSLOW | CONSYS_CTYP ;
00998   flags opts = CONSYS_WRNATT ;
00999 /*
01000   The first parameter to consys is the constraint system name, which is
01001   never conveniently available in the OSI frame.
01002 */
01003   consys = consys_create(0,parts,opts,rows,cols) ;
01004   assert(consys) ;
01005 
01006   return ; }
01007 
01008 
01015 void ODSI::dylp_ioinit ()
01016 
01017 { if (reference_count > 1) return ;
01018 
01019   std::string errfile = std::string(ERRMSGDIR)+std::string("/bonsaierrs.txt") ;
01020 # ifndef NDEBUG
01021   errinit(const_cast<char *>(errfile.c_str()),0,true) ;
01022 # else
01023   errinit(const_cast<char *>(errfile.c_str()),0,false) ;
01024 # endif
01025   bool r1 = ioinit() ;
01026   assert(r1) ;
01027 }
01028 
01053 void ODSI::load_problem (const CoinMpsIO &mps)
01054 
01055 { int n = mps.getNumCols() ;
01056   int m = mps.getNumRows() ;
01057 /*
01058   Unpack the operands from the CoinMpsIO object.
01059 */
01060   const CoinPackedMatrix matrix = *mps.getMatrixByCol() ;
01061   const double* col_lower = mps.getColLower() ;
01062   const double* col_upper = mps.getColUpper() ;
01063   const double* obj = mps.getObjCoefficients() ;
01064   const char *sense = mps.getRowSense() ;
01065   const double* rhsin = mps.getRightHandSide() ;
01066   const double* range = mps.getRowRange() ;
01067 
01068   double *rhs = new double[m] ;
01069   double *rhslow = new double[m] ; 
01070   contyp_enum *ctyp = new contyp_enum[m] ;
01071 
01072   gen_rowparms(m,rhs,rhslow,ctyp,sense,rhsin,range) ;
01073 /*
01074   Free the existing problem structures, preserving options and tolerances
01075   and resetting statistics.
01076 */
01077   destruct_problem(true) ;
01078 /*
01079   Create an empty consys_struct. Load the constraint system name, objective
01080   name, and objective offset.
01081 */
01082   construct_consys(n,m) ;
01083   setStrParam(OsiProbName,mps.getProblemName()) ;
01084   if (consys->objnme) strfree(consys->objnme) ;
01085   consys->objnme = stralloc(mps.getObjectiveName()) ;
01086   setDblParam(OsiObjOffset,mps.objectiveOffset()) ;
01087 /*
01088   First loop: Insert empty constraints into the new constraint system.
01089 */
01090   pkvec_struct* rowi = pkvec_new(0) ;
01091   assert(rowi) ;
01092 
01093   for (int i = 0 ; i < m ; i++)
01094   { rowi->nme = const_cast<char *>(mps.rowName(i)) ;
01095     bool r = consys_addrow_pk(consys,'a',ctyp[i],rowi,rhs[i],rhslow[i],0,0) ;
01096     assert(r) ; }
01097   
01098   if (rowi) pkvec_free(rowi) ;
01099   delete[] rhs ;
01100   delete[] rhslow ;
01101   delete[] ctyp ;
01102 /*
01103   Take a moment and set up a vector of variable types. It's a bit of a pain
01104   that CoinMpsIO doesn't distinguish binary from general integer, but we can
01105   do it here by checking bounds. The test is drawn from OSI::isBinary and
01106   will include variables fixed at 0 or 1.
01107 */
01108   const char *const intvars = mps.integerColumns() ;
01109   vartyp_enum *const vtyp = new vartyp_enum[n] ;
01110   if (intvars)
01111   { for (int j = 0 ; j < n ; j++)
01112     { if (intvars[j])
01113       { if ((col_lower[j] == 0.0 || col_lower[j] == 1.0) &&
01114             (col_upper[j] == 0.0 || col_upper[j] == 1.0))
01115         { vtyp[j] = vartypBIN ; }
01116         else
01117         { vtyp[j] = vartypINT ; } }
01118       else
01119       { vtyp[j] = vartypCON ; } } }
01120   else
01121   { for (int j = 0 ; j < n ; j++) vtyp[j] = vartypCON ; }
01122 /*
01123   Second loop. Insert the coefficients by column. If we need to create a
01124   column-ordered copy, take advantage and cache it.  The size of colj is a
01125   gross overestimate, but it saves the trouble of constantly reallocating it.
01126 */
01127   const CoinPackedMatrix *matrix2 ;
01128   if (matrix.isColOrdered())
01129   { matrix2 = &matrix ; }
01130   else
01131   { _matrix_by_col = new CoinPackedMatrix ;
01132     _matrix_by_col->reverseOrderedCopyOf(matrix) ;
01133     matrix2 = _matrix_by_col ; }
01134   
01135   pkvec_struct* colj = pkvec_new(n) ;
01136 
01137   for (int j = 0 ; j < n ; j++)
01138   { const CoinShallowPackedVector coin_col = matrix2->getVector(j) ;
01139     packed_vector(coin_col,n,colj) ;
01140     colj->nme = const_cast<char *>(mps.columnName(j)) ;
01141     bool r = consys_addcol_pk(consys,vtyp[j],colj,obj[j],
01142                               col_lower[j],col_upper[j]) ;
01143     assert(r) ; }
01144 
01145   pkvec_free(colj) ;
01146   delete[] vtyp ;
01147   assert(matrix2->isEquivalent(*getMatrixByCol())) ;
01148 
01149 /*
01150   Finish up. Establish a primal solution and an objective. The primal solution
01151   is `worst-case', in the sense that it's constructed by setting each primal
01152   variable to the bound that maximises the objective.
01153 */
01154   worst_case_primal() ;
01155   calc_objval() ;
01156 
01157   return ; }
01158 
01178 void ODSI::load_problem (const CoinPackedMatrix& matrix,
01179     const double* col_lower, const double* col_upper, const double* obj,
01180     const contyp_enum *ctyp, const double* rhs, const double* rhslow)
01181 
01182 { 
01183 /*
01184   Free the existing problem structures, preserving options and tolerances
01185   and resetting statistics.
01186 */
01187   destruct_problem(true) ;
01188 /*
01189   Create an empty consys_struct.
01190 */
01191   int m = matrix.getNumCols() ;
01192   int n = matrix.getNumRows() ;
01193 
01194   construct_consys(n,m) ;
01195 /*
01196   First loop: Insert empty constraints into the new constraint system.
01197 */
01198   pkvec_struct* rowi = pkvec_new(0) ;
01199   assert(rowi) ;
01200 
01201   for (int i = 0 ; i < n ; i++)
01202   { rowi->nme = 0 ;
01203     bool r = consys_addrow_pk(consys,'a',ctyp[i],rowi,rhs[i],rhslow[i],0,0) ;
01204     assert(r) ;
01205   }
01206 
01207   if (rowi) pkvec_free(rowi) ;
01208 /*
01209   Second loop. Insert the coefficients by column. If we need to create a
01210   column-ordered copy, take advantage and cache it.  The size of colj is a
01211   gross overestimate, but it saves the trouble of constantly reallocating it.
01212 */
01213   const CoinPackedMatrix *matrix2 ;
01214   if (matrix.isColOrdered())
01215   { matrix2 = &matrix ; }
01216   else
01217   { _matrix_by_col = new CoinPackedMatrix ;
01218     _matrix_by_col->reverseOrderedCopyOf(matrix) ;
01219     matrix2 = _matrix_by_col ; }
01220   
01221   pkvec_struct* colj = pkvec_new(n) ;
01222 
01223   for (int j = 0 ; j < m ; j++)
01224   { const CoinShallowPackedVector coin_col = matrix2->getVector(j) ;
01225     packed_vector(coin_col,n,colj) ;
01226     double objj = obj?obj[j]:0 ;
01227     double vlbj = col_lower?col_lower[j]:0 ;
01228     double vubj = col_upper?col_upper[j]:DYLP_INFINITY ;
01229     colj->nme = 0 ;
01230     bool r = consys_addcol_pk(consys,vartypCON,colj,objj,vlbj,vubj) ;
01231     assert(r) ; }
01232 
01233   pkvec_free(colj) ;
01234   assert(matrix2->isEquivalent(*getMatrixByCol())) ;
01235 
01236 /*
01237   Finish up. Establish a primal solution and an objective. The primal solution
01238   is `worst-case', in the sense that it's constructed by setting each primal
01239   variable to the bound that maximises the objective.
01240 */
01241   worst_case_primal() ;
01242   calc_objval() ;
01243 
01244   return ; }
01245 
01246 
01273 void ODSI::load_problem (const int colcnt, const int rowcnt,
01274            const int *start, const int *index, const double *value,
01275            const double* col_lower, const double* col_upper, const double* obj,
01276            const contyp_enum *ctyp, const double* rhs, const double* rhslow)
01277 
01278 { 
01279 /*
01280   Free the existing problem structures, preserving options and tolerances
01281   and resetting statistics.
01282 */
01283   destruct_problem(true) ;
01284 /*
01285   Create an empty consys_struct. Request the standard attached vectors:
01286   objective, variable upper & lower bounds, variable and constraint types,
01287   and constraint right-hand-side and range (rhslow).
01288 */
01289   construct_consys(rowcnt,colcnt) ;
01290 /*
01291   First loop: Insert empty constraints into the new constraint system.
01292 */
01293   pkvec_struct* rowi = pkvec_new(0) ;
01294   assert(rowi) ;
01295 
01296   for (int i = 0 ; i < rowcnt ; i++)
01297   { rowi->nme = 0 ;
01298     bool r = consys_addrow_pk(consys,'a',ctyp[i],rowi,rhs[i],rhslow[i],0,0) ;
01299     assert(r) ;
01300   }
01301 
01302   if (rowi) pkvec_free(rowi) ;
01303 /*
01304   Second loop. Insert the coefficients by column. The size of colj is a gross
01305   overestimate, but it saves the trouble of constantly reallocating it.
01306 */
01307   pkvec_struct *colj = pkvec_new(rowcnt) ;
01308   assert(colj) ;
01309   colj->dim = rowcnt ;
01310   pkcoeff_struct *coeffs = colj->coeffs ;
01311 
01312   for (int j = 0 ; j < colcnt ; j++)
01313   { int startj = start[j] ;
01314     int lenj = start[j+1]-startj ;
01315 
01316     for (int ndx = 0 ; ndx < lenj ; ndx++)
01317     { coeffs[ndx].ndx = idx(index[startj+ndx]) ;
01318       coeffs[ndx].val = value[startj+ndx] ; }
01319     colj->cnt = lenj ;
01320   
01321     double objj = obj?obj[j]:0 ;
01322     double vlbj = col_lower?col_lower[j]:0 ;
01323     double vubj = col_upper?col_upper[j]:DYLP_INFINITY ;
01324     colj->nme = 0 ;
01325     bool r = consys_addcol_pk(consys,vartypCON,colj,objj,vlbj,vubj) ;
01326     assert(r) ;
01327   }
01328 
01329   if (colj) pkvec_free(colj) ;
01330 /*
01331   Finish up. Establish a primal solution and an objective.
01332 */
01333   worst_case_primal() ;
01334   calc_objval() ;
01335   
01336   return ; }
01337 
01338 
01339 
01347 void ODSI::gen_rowparms (int rowcnt,
01348                          double *rhs, double *rhslow, contyp_enum *ctyp,
01349                          const double *rowlb, const double *rowub)
01350 
01351 { double inf = DYLP_INFINITY ;
01352   double rowlbi,rowubi ;
01353 
01354   for (int i = 0 ; i < rowcnt ; i++)
01355   { rowlbi = rowlb?rowlb[i]:-inf ;
01356     rowubi = rowub?rowub[i]:inf ;
01357     ctyp[i] = bound_to_type(rowlbi,rowubi) ;
01358 
01359     switch (ctyp[i])
01360     { case contypEQ:
01361       case contypLE:
01362       { rhs[i] = rowubi ; 
01363         rhslow[i] = 0 ;
01364         break ; }
01365       case contypGE:
01366       { rhs[i] = rowlbi ;
01367         rhslow[i] = 0 ;
01368         break ; }
01369       case contypRNG:
01370       { rhs[i] = rowubi ; 
01371         rhslow[i] = rowlbi ;
01372         break ; }
01373       case contypNB:
01374       { rhs[i] = inf ;
01375         rhslow[i] = -inf ;
01376         break ; }
01377       default:
01378       { assert(0) ; } } }
01379 
01380   return ; }
01381 
01382 
01390 void ODSI::gen_rowparms (int rowcnt,
01391                          double *rhs, double *rhslow, contyp_enum *ctyp,
01392                  const char *sense, const double *rhsin, const double *range)
01393 
01394 { double rhsi,rangei ;
01395   char sensei ;
01396 
01397   for (int i = 0 ; i < rowcnt ; i++)
01398   { rhsi = rhsin?rhsin[i]:0 ;
01399     rangei = range?range[i]:0 ;
01400     sensei = sense?sense[i]:'G' ;
01401     
01402     switch (sensei)
01403     { case 'E':
01404       { rhs[i] = rhsi ;
01405         rhslow[i] = 0 ;
01406         ctyp[i] = contypEQ ;
01407         break ; }
01408       case 'L':
01409       { rhs[i] = rhsi ;
01410         rhslow[i] = 0 ;
01411         ctyp[i] = contypLE ;
01412         break ; }
01413       case 'G':
01414       { rhs[i] = rhsi ;
01415         rhslow[i] = 0 ;
01416         ctyp[i] = contypGE ;
01417         break ; }
01418       case 'R':
01419       { rhs[i] = rhsi ;
01420         rhslow[i] = rhsi-rangei ;
01421         ctyp[i] = contypRNG ;
01422         break ; }
01423       case 'N':
01424       { rhs[i] = 0 ;
01425         rhslow[i] = 0 ;
01426         ctyp[i] = contypNB ;
01427         break ; }
01428       default:
01429       { assert(0) ; } } }
01430 
01431   return ; }
01432 
01434 
01435 
01436 
01444 
01454 ODSI::OsiDylpSolverInterface ()
01455 
01456   : initialSolveOptions(0),
01457     resolveOptions(0),
01458     tolerances(0),
01459     consys(0),
01460     lpprob(0),
01461     statistics(0),
01462 
01463     local_logchn(IOID_NOSTRM),
01464     initial_gtxecho(false),
01465     resolve_gtxecho(false),
01466     lp_retval(lpINV),
01467     obj_sense(1.0),
01468 
01469     solvername("dylp"),
01470     mps_debug(0),
01471     hotstart_fallback(0),
01472     activeBasis(0),
01473     activeIsModified(false),
01474 
01475     _objval(0),
01476     _col_x(0),
01477     _col_obj(0),
01478     _col_cbar(0),
01479     _row_lhs(0),
01480     _row_lower(0),
01481     _row_price(0),
01482     _row_range(0),
01483     _row_rhs(0),
01484     _row_sense(0),
01485     _row_upper(0),
01486     _matrix_by_row(0),
01487     _matrix_by_col(0)
01488 
01489 {
01490 /*
01491   Replace the OSI default messages with ODSI messages.
01492 */
01493   setOsiDylpMessages(CoinMessages::us_en) ;
01494 /*
01495   Clear the hint info_ array.
01496 */
01497   for (int i = 0 ; i < OsiLastHintParam ; i++) info_[i] = 0 ;
01498 /*
01499   Acquire the default options and tolerances.
01500 */
01501   construct_options() ;
01502 /*
01503   Increment the ODSI existence count. If this is the first interface in
01504   existence, initialise the i/o package.
01505 */
01506   reference_count++ ;
01507 
01508   if (reference_count == 1)
01509   { dylp_ioinit() ;
01510     CoinRelFltEq eq ;
01511     assert(eq(DYLP_INFINITY, DYLP_INFINITY)) ; }
01512   
01513   return ; }
01514 
01515 
01521 ODSI::OsiDylpSolverInterface (const OsiDylpSolverInterface& src)
01522 
01523   : OsiSolverInterface(src),
01524     initial_gtxecho(src.initial_gtxecho),
01525     resolve_gtxecho(src.resolve_gtxecho),
01526     lp_retval(src.lp_retval),
01527     obj_sense(src.obj_sense),
01528 
01529     solvername(src.solvername),
01530     mps_debug(src.mps_debug),
01531     hotstart_fallback(0),       // do not copy hot start information
01532     activeBasis(0),
01533     activeIsModified(false),
01534   
01535     _objval(src._objval),
01536     _matrix_by_row(0),
01537     _matrix_by_col(0)
01538 
01539 { if (src.consys)
01540   { bool r = consys_dupsys(src.consys,&consys,src.consys->parts) ;
01541     assert(r) ; }
01542   else
01543   { consys = 0 ; }
01544   if (src.lpprob)
01545   { lpprob = copy_lpprob(src.lpprob) ;
01546     lpprob->consys = consys ; }
01547   else
01548   { lpprob = 0 ; }
01549 
01550   CLONE(lpopts_struct,src.initialSolveOptions,initialSolveOptions) ;
01551   CLONE(lpopts_struct,src.resolveOptions,resolveOptions) ;
01552   CLONE(lpstats_struct,src.statistics,statistics) ;
01553   CLONE(lptols_struct,src.tolerances,tolerances) ;
01554 
01555   if (src.local_logchn != IOID_NOSTRM)
01556   { local_logchn = openfile(idtopath(src.local_logchn),
01557                             const_cast<char *>("w")) ; }
01558   else
01559   { local_logchn = IOID_NOSTRM ; }
01560   assert(local_logchn == src.local_logchn) ;
01561 
01562   if (src.activeBasis)
01563   { activeBasis = src.activeBasis->clone() ;
01564     activeIsModified = src.activeIsModified ; }
01565 
01566   int col_count = src.getNumCols() ;
01567   int row_count = src.getNumRows() ;
01568 
01569   CLONE_VEC(double,src._col_x,_col_x,col_count) ;
01570   CLONE_VEC(double,src._col_obj,_col_obj,col_count) ;
01571   CLONE_VEC(double,src._col_cbar,_col_cbar,col_count) ;
01572   CLONE_VEC(double,src._row_lhs,_row_lhs,row_count) ;
01573   CLONE_VEC(double,src._row_lower,_row_lower,row_count) ;
01574   CLONE_VEC(double,src._row_price,_row_price,row_count) ;
01575   CLONE_VEC(double,src._row_range,_row_range,row_count) ;
01576   CLONE_VEC(double,src._row_rhs,_row_rhs,row_count) ;
01577   CLONE_VEC(char,src._row_sense,_row_sense,row_count) ;
01578   CLONE_VEC(double,src._row_upper,_row_upper,row_count) ;
01579 
01580   if (src._matrix_by_row) 
01581     _matrix_by_row = new CoinPackedMatrix(*src._matrix_by_row) ;
01582   if (src._matrix_by_col) 
01583     _matrix_by_col = new CoinPackedMatrix(*src._matrix_by_col) ;
01584 
01585   COPY_VEC(void *,&src.info_[0],&info_[0],OsiLastHintParam) ;
01586 
01587   reference_count++ ;
01588 
01589 # ifndef NDEBUG
01590   assert_same(*this, src, true) ;
01591 # endif
01592 
01593 }
01594 
01595 
01600 inline OsiSolverInterface* ODSI::clone (bool copyData) const
01601 
01602 { if (copyData)
01603   { return new OsiDylpSolverInterface(*this) ; }
01604   else
01605   { return new OsiDylpSolverInterface() ; }
01606 }
01607 
01608 
01616 OsiDylpSolverInterface &ODSI::operator= (const OsiDylpSolverInterface &rhs)
01617 
01618 { if (this != &rhs)
01619   { destruct_problem(false) ;
01620   
01621     OSI::operator=(rhs) ;
01622 
01623     if (rhs.consys)
01624     { bool r = consys_dupsys(rhs.consys,&consys,rhs.consys->parts) ;
01625       assert(r) ; }
01626     else
01627     { consys = 0 ; }
01628     if (rhs.lpprob)
01629     { lpprob = copy_lpprob(rhs.lpprob) ;
01630       lpprob->consys = consys ; }
01631     else
01632     { lpprob = 0 ; }
01633 
01634     CLONE(lpopts_struct,rhs.initialSolveOptions,initialSolveOptions) ;
01635     CLONE(lpopts_struct,rhs.resolveOptions,resolveOptions) ;
01636     CLONE(lpstats_struct,rhs.statistics,statistics) ;
01637     CLONE(lptols_struct,rhs.tolerances,tolerances) ;
01638 
01639     if (rhs.local_logchn != IOID_NOSTRM)
01640     { local_logchn = openfile(idtopath(rhs.local_logchn),
01641                               const_cast<char *>("w")) ; }
01642     else
01643     { local_logchn = IOID_NOSTRM ; }
01644     assert(local_logchn == rhs.local_logchn) ;
01645 
01646     if (rhs.activeBasis)
01647     { activeBasis = rhs.activeBasis->clone() ;
01648       activeIsModified = rhs.activeIsModified ; }
01649 
01650     int col_count = rhs.getNumCols() ;
01651     int row_count = rhs.getNumRows() ;
01652 
01653     CLONE_VEC(double,rhs._col_x,_col_x,col_count) ;
01654     CLONE_VEC(double,rhs._col_obj,_col_obj,col_count) ;
01655     CLONE_VEC(double,rhs._col_cbar,_col_cbar,col_count) ;
01656     CLONE_VEC(double,rhs._row_lhs,_row_lhs,row_count) ;
01657     CLONE_VEC(double,rhs._row_lower,_row_lower,row_count) ;
01658     CLONE_VEC(double,rhs._row_price,_row_price,row_count) ;
01659     CLONE_VEC(double,rhs._row_range,_row_range,row_count) ;
01660     CLONE_VEC(double,rhs._row_rhs,_row_rhs,row_count) ;
01661     CLONE_VEC(char,rhs._row_sense,_row_sense,row_count) ;
01662     CLONE_VEC(double,rhs._row_upper,_row_upper,row_count) ;
01663 
01664     if (rhs._matrix_by_row) 
01665       _matrix_by_row = new CoinPackedMatrix(*rhs._matrix_by_row) ;
01666     if (rhs._matrix_by_col) 
01667       _matrix_by_col = new CoinPackedMatrix(*rhs._matrix_by_col) ;
01668 
01669     COPY_VEC(void *,&rhs.info_[0],&info_[0],OsiLastHintParam) ;
01670 
01671     reference_count++ ;
01672 
01673 #   ifndef NDEBUG
01674     assert_same(*this, rhs, true) ;
01675 #   endif
01676   }
01677 
01678   return (*this) ; }
01679 
01680 
01682 
01683 
01684 
01685 /* OsiDylpSolverInterface destructor and related subroutines. */
01686 
01689 
01709 void ODSI::destruct_problem (bool preserve_interface)
01710 
01711 { 
01712 /*
01713   If this object claims ownership of the solver, it should possess an lpprob
01714   structure created when the solver was called.
01715 */
01716   assert((dylp_owner != this) || (dylp_owner == this && lpprob)) ;
01717 
01718   if (dylp_owner == this) detach_dylp() ;
01719 
01720   if (lpprob)
01721   { assert(lpprob->consys == consys) ;
01722     consys_free(consys) ;
01723     consys = 0 ;
01724     dy_freesoln(lpprob) ;
01725     delete lpprob ;
01726     lpprob = 0 ; }
01727   else
01728   if (consys)
01729   { consys_free(consys) ;
01730     consys = 0 ; }
01731  
01732   if (hotstart_fallback)
01733   { delete hotstart_fallback ;
01734     hotstart_fallback = 0 ; }
01735   if (activeBasis)
01736   { delete activeBasis ;
01737     activeBasis = 0 ;
01738     activeIsModified = false ; }
01739 
01740   destruct_cache() ;
01741 
01742   if (preserve_interface == false)
01743   { if (initialSolveOptions)
01744     { delete initialSolveOptions ;
01745       initialSolveOptions = 0 ; }
01746     if (resolveOptions)
01747     { delete resolveOptions ;
01748       resolveOptions = 0 ; }
01749     if (tolerances)
01750     { delete tolerances ;
01751       tolerances = 0 ; } }
01752   
01753   if (statistics)
01754   { if (preserve_interface == true)
01755     { memset(statistics,0,sizeof(lpstats_struct)) ; }
01756     else
01757     { delete statistics ;
01758       statistics = 0 ; } }
01759   
01760   return ; }
01761 
01762 
01776 void ODSI::detach_dylp ()
01777 
01778 { assert(dylp_owner == this && lpprob && lpprob->consys) ;
01779   assert(flgon(lpprob->ctlopts,lpctlDYVALID)) ;
01780   flags save_flags = getflg(lpprob->ctlopts,lpctlNOFREE|lpctlONLYFREE) ;
01781   clrflg(lpprob->ctlopts,lpctlNOFREE) ;
01782   setflg(lpprob->ctlopts,lpctlONLYFREE) ;
01783   lpprob->phase = dyDONE ;
01784 /*
01785   Either of the initialSolve or resolve option blocks are ok here; dylp does
01786   not look.
01787 */
01788   dylp(lpprob,initialSolveOptions,tolerances,statistics) ;
01789   clrflg(lpprob->ctlopts,lpctlONLYFREE) ;
01790   setflg(lpprob->ctlopts,save_flags) ;
01791   dylp_owner = 0 ; }
01792 
01794 
01803 ODSI::~OsiDylpSolverInterface ()
01804 
01805 {
01806 /*
01807   Destroy the problem-specific structures used by dylp, and close the log
01808   file, if open.
01809 */
01810   destruct_problem(false) ;
01811   if (local_logchn != IOID_INV && local_logchn != IOID_NOSTRM)
01812     (void) closefile(local_logchn) ;
01813 
01814   reference_count-- ;
01815   if (reference_count == 0)
01816   { if (basis_ready == true)
01817     { dy_freebasis() ;
01818       basis_ready = false ; }
01819     ioterm() ;
01820     errterm() ; }
01821   
01822   return ; }
01823 
01832 void ODSI::reset ()
01833 
01834 { 
01835 /*
01836   Destroy the problem-specific structures used by dylp, and close the log
01837   file, if open.
01838 */
01839   destruct_problem(false) ;
01840   if (local_logchn != IOID_INV && local_logchn != IOID_NOSTRM)
01841   { (void) closefile(local_logchn) ;
01842     local_logchn = IOID_NOSTRM ; }
01843 /*
01844   That takes care of cleaning out the ODSI object. Call setInitialData to
01845   reset the underlying OSI object.
01846 */
01847   setInitialData() ;
01848 /*
01849   Now the equivalent for ODSI: ensure default values for various fields in the
01850   object. Regrettably, messages_ is not a pointer, so we can't preserve the
01851   CoinMessages structure over the reset.
01852 */
01853   initial_gtxecho = false ;
01854   resolve_gtxecho = false ;
01855   lp_retval = lpINV ;
01856   setObjSense(1.0) ;
01857   mps_debug = false ;
01858   construct_options() ;
01859   setOsiDylpMessages(CoinMessages::us_en) ;
01860   for (int i = 0 ; i < OsiLastHintParam ; i++) info_[i] = 0 ;
01861 
01862   return ; }
01863 
01864 
01865 
01873 
01874 inline void ODSI::setContinuous (int j)
01875 
01876 { if (!consys->vtyp)
01877   { bool r = consys_attach(consys,CONSYS_VTYP,sizeof(vartyp_enum),
01878                            reinterpret_cast<void **>(&consys->vtyp)) ;
01879     assert(r) ; }
01880 
01881   consys->vtyp[idx(j)] = vartypCON ; }
01882 
01883 
01884 inline void ODSI::setContinuous (const int* indices, int len)
01885 
01886 { if (!consys->vtyp)
01887   { bool r = consys_attach(consys,CONSYS_VTYP,sizeof(vartyp_enum),
01888                            reinterpret_cast<void **>(&consys->vtyp)) ;
01889     assert(r) ; }
01890 
01891   for (int i = 0 ; i < len ; i++)
01892     consys->vtyp[idx(indices[i])] = vartypCON ; }
01893 
01894 
01895 inline void ODSI::setInteger (int j)
01896 
01897 { if (!consys->vtyp)
01898   { bool r = consys_attach(consys,CONSYS_VTYP,sizeof(vartyp_enum),
01899                            reinterpret_cast<void **>(&consys->vtyp)) ;
01900     assert(r) ; }
01901 
01902   if (getColLower()[j] == 0.0 && getColUpper()[j] == 1.0)
01903     consys->vtyp[idx(j)] = vartypBIN ;
01904   else
01905     consys->vtyp[idx(j)] = vartypINT ; }
01906 
01907 
01908 inline void ODSI::setInteger (const int* indices, int len)
01909 
01910 { if (!consys->vtyp)
01911   { bool r = consys_attach(consys,CONSYS_VTYP,sizeof(vartyp_enum),
01912                            reinterpret_cast<void **>(&consys->vtyp)) ;
01913     assert(r) ; }
01914 
01915   for (int i = 0 ; i < len ; i++) setInteger(indices[i]) ; }
01916 
01917 
01930 inline void ODSI::setColLower (int i, double val)
01931 
01932 { if (!consys->vlb)
01933   { bool r = consys_attach(consys,CONSYS_VLB,sizeof(double),
01934                            reinterpret_cast<void **>(&consys->vlb)) ;
01935     assert(r) ; }
01936 
01937   consys->vlb[idx(i)] = val ;
01938   if (lpprob) setflg(lpprob->ctlopts,lpctlLBNDCHG) ;
01939 
01940   if (isInteger(i))
01941   { if (floor(val) != val)
01942       setContinuous(i) ;
01943     else
01944     if (isBinary(i) && !(val == 0.0 || val == 1.0))
01945       setInteger(i) ; } }
01946 
01951 inline void ODSI::setColUpper (int i, double val)
01952 
01953 { if (!consys->vub)
01954   { bool r = consys_attach(consys,CONSYS_VUB,sizeof(double),
01955                            reinterpret_cast<void **>(&consys->vub)) ;
01956     assert(r) ; }
01957 
01958   consys->vub[idx(i)] = val ;
01959   if (lpprob) setflg(lpprob->ctlopts,lpctlUBNDCHG) ;
01960 
01961   if (isInteger(i))
01962   { if (floor(val) != val)
01963       setContinuous(i) ;
01964     else
01965     if (isBinary(i) && !(val == 0.0 || val == 1.0))
01966       setInteger(i) ; } }
01967 
01968 
01973 void ODSI::setRowType (int i, char sense, double rhs, double range)
01974 
01975 { int k = idx(i) ;
01976 
01977   gen_rowiparms(&consys->ctyp[k],&consys->rhs[k],&consys->rhslow[k],
01978                 sense,rhs,range) ;
01979   if (resolveOptions) resolveOptions->forcewarm = true ;
01980 
01981   destruct_row_cache() ; }
01982 
01983 
01988 void ODSI::setRowUpper (int i, double val)
01989 
01990 { int k = idx(i) ;
01991   double clbi ;
01992 
01993   switch (consys->ctyp[k])
01994   { case contypEQ:
01995     case contypGE:
01996     { clbi = consys->rhs[k] ;
01997       break ; }
01998     case contypRNG:
01999     { clbi = consys->rhslow[k] ;
02000       break ; }
02001     case contypLE:
02002     case contypNB:
02003     { clbi = -DYLP_INFINITY ;
02004       break ; }
02005     default:
02006     { assert(false) ; } }
02007   
02008   gen_rowiparms(&consys->ctyp[k],&consys->rhs[k],&consys->rhslow[k],
02009                 clbi,val) ;
02010   if (lpprob) setflg(lpprob->ctlopts,lpctlRHSCHG) ;
02011 
02012   destruct_row_cache() ; }
02013 
02014 
02019 void ODSI::setRowLower (int i, double val)
02020 
02021 { int k = idx(i) ;
02022   double cubi ;
02023   contyp_enum ctypi = consys->ctyp[k] ;
02024 
02025   if (ctypi == contypGE || ctypi == contypNB)
02026     cubi = DYLP_INFINITY ;
02027   else
02028     cubi = consys->rhs[k] ;
02029 
02030   gen_rowiparms(&consys->ctyp[k],&consys->rhs[k],&consys->rhslow[k],
02031                 val,cubi) ;
02032   if (lpprob) setflg(lpprob->ctlopts,lpctlRHSCHG) ;
02033 
02034   destruct_row_cache() ; }
02035 
02036 
02044 inline void ODSI::addRow (const CoinPackedVectorBase &row,
02045                           double rlb, double rub)
02046 
02047 { contyp_enum ctypi ;
02048   double rhsi,rhslowi ;
02049 
02050   gen_rowiparms(&ctypi,&rhsi,&rhslowi,rlb,rub) ;
02051   add_row(row,'a',ctypi,rhsi,rhslowi) ;
02052 
02053   return ; }
02054 
02055 
02063 inline void ODSI::addRow (const CoinPackedVectorBase &coin_row, 
02064                           char sense, double rhs, double range)
02065 
02066 { contyp_enum ctypi ;
02067   double rhsi,rhslowi ;
02068 
02069   gen_rowiparms(&ctypi,&rhsi,&rhslowi,sense,rhs,range) ;
02070   add_row(coin_row,'a',ctypi,rhsi,rhslowi) ;
02071 
02072   return ; }
02073 
02074 
02081 void ODSI::applyRowCut (const OsiRowCut &cut)
02082 
02083 { contyp_enum ctypi ;
02084   double rhsi,rhslowi ;
02085 
02086   gen_rowiparms(&ctypi,&rhsi,&rhslowi,cut.lb(),cut.ub()) ;
02087   add_row(cut.row(),'c',ctypi,rhsi,rhslowi) ;
02088   
02089   return ; }
02090 
02091 
02104 void ODSI::deleteRows (int count, const int* rows)
02105 
02106 { if (count <= 0) return ;
02107 /*
02108   Sort the indices and do the deletions, one by one.
02109 */
02110   vector<int> lclrows = vector<int>(&rows[0],&rows[count]) ;
02111 
02112   if (count > 1) std::sort(lclrows.begin(),lclrows.end()) ;
02113 
02114   for (int k = count-1 ; k >= 0 ; k--)
02115   { int i = idx(lclrows[k]) ;
02116     bool r = consys_delrow_stable(consys,i) ;
02117     assert(r) ; }
02118 /*
02119   Now, see if there's an active basis. If so, check that all the constraints
02120   to be deleted are slack. If they are, we can delete them from activeBasis
02121   and still guarantee a valid basis. If not, throw away activeBasis.
02122 */
02123   if (activeBasis)
02124   { bool allslack = true ;
02125     OsiDylpWarmStartBasis *odwsb =
02126       dynamic_cast<OsiDylpWarmStartBasis *>(activeBasis) ;
02127     for (int k = count-1 ; k >= 0 ; k--)
02128     { int i = lclrows[k] ;
02129       if (odwsb->getArtifStatus(i) != CoinWarmStartBasis::basic)
02130       { allslack = false ;
02131         break ; } }
02132     if (allslack == true)
02133     { odwsb->deleteRows(count,rows) ;
02134       activeIsModified = true ;
02135       resolveOptions->forcewarm = true ; }
02136     else
02137     { delete activeBasis ;
02138       activeBasis = 0 ;
02139       activeIsModified = false ;
02140       resolveOptions->forcecold = true ; } }
02141 
02142   destruct_cache() ; }
02143 
02144 
02145 
02150 void ODSI::setObjCoeff (int j, double objj)
02151 
02152 { if (j >= getNumCols()) return ;
02153 
02154   consys->obj[idx(j)] = getObjSense()*objj ;
02155   if (_col_obj) _col_obj[j] = objj ;
02156   if (lpprob) setflg(lpprob->ctlopts,lpctlOBJCHG) ;
02157   calc_objval() ; }
02158   
02159 
02165 void ODSI::setObjSense (double val)
02166 /*
02167   The `natural' action of OSI (and dylp) is minimisation. Maximisation is
02168   accomplished as min -cx. So using -1 for maximisation is more natural
02169   than you'd think at first glance.
02170 */
02171 
02172 { int n = getNumCols() ;
02173 
02174   if (n > 0 && val != obj_sense)
02175   { double *tmpobj = INV_VEC(double,consys->obj) ;
02176     std::transform(tmpobj,tmpobj+n,tmpobj,std::negate<double>()) ;
02177     if (lpprob) setflg(lpprob->ctlopts,lpctlOBJCHG) ; }
02178   
02179   obj_sense = val ;
02180   
02181   return ; }
02182 
02183 
02192 inline void ODSI::addCol (const CoinPackedVectorBase& coin_col,
02193                           double vlb, double vub, double obj)
02194 
02195 { add_col(coin_col,vartypCON,vlb,vub,obj) ; }
02196 
02197 
02205 void ODSI::applyColCut (const OsiColCut &cut)
02206 
02207 { const double* old_lower = getColLower() ;
02208   const double* old_upper = getColUpper() ;
02209   const CoinPackedVector& new_lower = cut.lbs() ;
02210   const CoinPackedVector& new_upper = cut.ubs() ;
02211 
02212   int i ;
02213   int n1 = new_lower.getNumElements() ;
02214   int n2 = new_upper.getNumElements() ;
02215 
02216   for (i = 0 ; i < n1 ; i++)
02217   { int j = new_lower.getIndices()[i] ;
02218     double x = new_lower.getElements()[i] ;
02219     if (x > old_lower[j]) setColLower(j,x) ; }
02220 
02221   for (i = 0 ; i < n2 ; i++)
02222   { int j = new_upper.getIndices()[i] ;
02223     double x = new_upper.getElements()[i] ;
02224     if (x < old_upper[j]) setColUpper(j,x) ; }
02225 }
02226 
02227 
02240 void ODSI::deleteCols (int count, const int* cols)
02241 
02242 { if (count <= 0) return ;
02243 /*
02244   Sort the indices and do the deletions, one by one.
02245 */
02246   vector<int> lclcols = vector<int>(&cols[0],&cols[count]) ;
02247 
02248   if (count > 1) std::sort(lclcols.begin(),lclcols.end()) ;
02249 
02250   for (int k = 0 ; k < count ; k++)
02251   { int j = idx(lclcols[k]) ;
02252     bool r = consys_delcol(consys, j) ;
02253     assert(r) ; }
02254 /*
02255   Now, see if there's an active basis. If so, check that all the variables to
02256   be deleted are nonbasic. If they are, we can delete them from activeBasis
02257   and still guarantee a valid basis. If not, throw away activeBasis.
02258 */
02259   if (activeBasis)
02260   { bool allnonbasic = true ;
02261     OsiDylpWarmStartBasis *odwsb =
02262       dynamic_cast<OsiDylpWarmStartBasis *>(activeBasis) ;
02263     for (int k = count-1 ; k >= 0 ; k--)
02264     { int j = lclcols[k] ;
02265       if (odwsb->getStructStatus(j) == CoinWarmStartBasis::basic)
02266       { allnonbasic = false ;
02267         break ; } }
02268     if (allnonbasic == true)
02269     { odwsb->deleteColumns(count,cols) ;
02270       activeIsModified = true ;
02271       resolveOptions->forcewarm = true ; }
02272     else
02273     { delete activeBasis ;
02274       activeBasis = 0 ;
02275       activeIsModified = false ;
02276       resolveOptions->forcecold = true ; } }
02277 
02278   destruct_cache() ; }
02279 
02280 
02290 void ODSI::setColSolution (const double* solution)
02291 
02292 { int n = getNumCols() ;
02293 /*
02294   You can't set what you don't have. Otherwise, replace the current solution.
02295 */
02296   if (n == 0) return ;
02297 
02298   if (_col_x) delete[] _col_x ;
02299   _col_x = new double[n] ;
02300   
02301   COPY_VEC(double,solution,_col_x,n) ;
02302   calc_objval() ;
02303 
02304   return ; }
02305 
02306 
02316 void ODSI::setRowPrice (const double* price)
02317 
02318 { int m = getNumRows() ;
02319 
02320 /*
02321   You can't set what you don't have. Otherwise, replace the current solution.
02322 */
02323   if (m == 0) return ;
02324 
02325   if (_row_price) delete[] _row_price ;
02326   _row_price = new double[m] ;
02327   
02328   COPY_VEC(double,price,_row_price,m) ;
02329 
02330   return ; }
02331 
02333 
02334 
02335 
02336 #ifndef _MSC_VER
02337 
02346 
02347 
02356 void ODSI::assert_same (double d1, double d2, bool exact)
02357 
02358 { if (d1 == d2) return ;
02359 
02360   assert(!exact && finite(d1) && finite(d2)) ;
02361 
02362   static const double epsilon = 1.e-10 ;
02363   double tol = std::max(fabs(d1),fabs(d2))+1 ;
02364   double diff = fabs(d1 - d2) ;
02365 
02366   assert(diff <= tol*epsilon) ; }
02367 
02368 
02374 template<class T>
02375   void ODSI::assert_same (const T& t1, const T& t2, bool exact)
02376 
02377 
02378 { if (&t1 == &t2) return ;
02379   assert(memcmp(&t1,&t2,sizeof(T)) == 0) ; }
02380 
02381 
02384 template<class T>
02385   void ODSI::assert_same (const T* t1, const T* t2, int n, bool exact)
02386 
02387 { if (t1 == t2) return ;
02388   for (int i=0 ; i<n ; i++) assert_same(t1[i],t2[i],exact) ; }
02389 
02390 
02398 void ODSI::assert_same (const basis_struct& b1, const basis_struct& b2,
02399                         bool exact)
02400 { assert(exact) ;                // be explicit
02401   if (&b1 == &b2) return ;
02402   assert(b1.len == b2.len) ;
02403 
02404   int size = b1.len*sizeof(basisel_struct) ;
02405   assert(memcmp(inv_vec<basisel_struct>(b1.el),
02406                 inv_vec<basisel_struct>(b2.el),size) == 0) ; }
02407 
02408 
02416 void ODSI::assert_same (const conbnd_struct& c1, const conbnd_struct& c2,
02417                         bool exact)
02418 
02419 { assert(exact) ;                // be explicit
02420   if (&c1 == &c2) return ;
02421 
02422   //-- consys.h::conbnd_struct
02423   assert(c1.revs == c2.revs) ;
02424   assert(c1.inf == c2.inf) ;
02425   assert(c1.bnd == c2.bnd) ; }
02426 
02427 
02437 void ODSI::assert_same (const consys_struct& c1, const consys_struct& c2,
02438                         bool exact)
02439 
02440 { if (&c1 == &c2) return ;
02441 /*
02442   Simple fields: flags, counts, indices.
02443 */
02444   assert(c1.parts == c2.parts) ;
02445   assert(c1.opts == c2.opts) ;
02446   assert(c1.varcnt == c2.varcnt) ;
02447   assert(c1.archvcnt == c2.archvcnt) ;
02448   assert(c1.logvcnt == c2.logvcnt) ;
02449   assert(c1.intvcnt == c2.intvcnt) ;
02450   assert(c1.binvcnt == c2.binvcnt) ;
02451   assert(c1.maxcollen == c2.maxcollen) ;
02452   assert(!exact || (c1.maxcolndx == c2.maxcolndx)) ;
02453   assert(c1.concnt == c2.concnt) ;
02454   assert(c1.archccnt == c2.archccnt) ;
02455   assert(c1.cutccnt == c2.cutccnt) ;
02456   assert(c1.maxrowlen == c2.maxrowlen) ;
02457   assert(!exact || (c1.maxrowndx == c2.maxrowndx)) ;
02458   assert(c1.objndx == c2.objndx) ;
02459   assert(c1.xzndx == c2.xzndx) ;
02460 /*
02461   Associated vectors.
02462 */
02463   int var_count = ODSI::idx(c1.varcnt) ;
02464   int con_count = ODSI::idx(c1.concnt) ;
02465 
02466   assert_same(c1.obj, c2.obj, var_count, exact) ;
02467   assert_same(c1.vtyp, c2.vtyp, var_count, true) ;
02468   assert_same(c1.vub, c2.vub, var_count, exact) ;
02469   assert_same(c1.vlb, c2.vlb, var_count, exact) ;
02470   assert_same(c1.colscale, c2.colscale, var_count, exact) ;
02471 
02472   assert_same(c1.rhs, c2.rhs, con_count, exact) ;
02473   assert_same(c1.rhslow, c2.rhslow, con_count, exact) ;
02474   assert_same(c1.ctyp, c2.ctyp, con_count, true) ;
02475   assert_same(c1.cub, c2.cub, con_count, exact) ;
02476   assert_same(c1.clb, c2.clb, con_count, exact) ;
02477   assert_same(c1.rowscale, c2.rowscale, con_count, exact) ;
02478 /*
02479   These can differ and have no mathematical effect. Test them only if the
02480   client has requested exact equality.
02481 */
02482   if (exact)
02483   { assert(c1.nme == c2.nme) ;
02484     assert(c1.colsze == c2.colsze) ;
02485     assert(c1.rowsze == c2.rowsze) ;
02486     assert(c1.objnme == c2.objnme) ; } }
02487 
02488 
02496 void ODSI::assert_same (const lpprob_struct& l1, const lpprob_struct& l2,
02497                         bool exact)
02498 
02499 { if (&l1 == &l2) return ;
02500 /*
02501   Simple fields: flags, LP phase & return code, objective value, iteration
02502   count.
02503 */
02504   assert(l1.ctlopts == l2.ctlopts) ;
02505   assert(l1.phase == l2.phase) ;
02506   assert(l1.lpret == l2.lpret) ;
02507   assert_same(l1.obj,l2.obj,exact) ;
02508   assert(l1.iters == l2.iters) ;
02509 /*
02510   The allocated capacity can differ unless the client requires exact
02511   equivalence.
02512 */
02513   if (exact)
02514   { assert(l1.colsze == l2.colsze) ;
02515     assert(l1.rowsze == l2.rowsze) ; }
02516 /*
02517   Vectors: x, y, status
02518 */
02519   int min_col = idx(std::min(l1.colsze, l2.colsze)) ;
02520   int min_row = idx(std::min(l1.rowsze, l2.rowsze)) ;
02521 
02522   assert_same(l1.status,l2.status,min_col,exact) ;
02523   assert_same(l1.x,l2.x,min_row, exact) ;
02524   assert_same(l1.y,l2.y,min_row, exact) ;
02525 /*
02526   Complex structures: the constraint system and basis.
02527 */
02528   assert_same(*l1.consys,*l2.consys,exact) ;
02529   assert_same(*l1.basis,*l2.basis,exact) ; }
02530 
02531 
02539 void ODSI::assert_same (const OsiDylpSolverInterface& o1,
02540                         const OsiDylpSolverInterface& o2, bool exact)
02541 
02542 { 
02543 /*
02544   The same chunk of memory?
02545 */
02546   if (&o1 == &o2) return ;
02547 /*
02548   These three fields are static. If they don't match, we're really
02549   confused.
02550 */
02551   assert(o1.reference_count == o2.reference_count) ;
02552   assert(o1.basis_ready == o2.basis_ready) ;
02553   assert(o1.dylp_owner == o2.dylp_owner) ;
02554 /*
02555   Test the rest of the simple data fields.
02556 */
02557   assert(o1.local_logchn == o2.local_logchn) ;
02558   assert(o1.initial_gtxecho == o2.initial_gtxecho) ;
02559   assert(o1.resolve_gtxecho == o2.resolve_gtxecho) ;
02560   assert(o1.lp_retval == o2.lp_retval) ;
02561   assert(o1.obj_sense == o2.obj_sense) ;
02562   assert(o1.solvername == o2.solvername) ;
02563   assert(o1.mps_debug == o2.mps_debug) ;
02564 /*
02565   Options, tolerances, and statistics should be byte-for-byte identical.
02566 */
02567   assert_same(*o1.initialSolveOptions, *o2.initialSolveOptions, true) ;
02568   assert_same(*o1.resolveOptions, *o2.resolveOptions, true) ;
02569   assert_same(*o1.statistics, *o2.statistics, true) ;
02570   assert_same(*o1.tolerances, *o2.tolerances, true) ;
02571 /*
02572   The info_ array. The best we can do here is entry by entry equality.
02573 */
02574   assert_same(o1.info_,o2.info_,OsiLastHintParam,exact) ;
02575 /*
02576   Now the more complicated structures. If the lpprob exists, it should
02577   reference a constraint system, and it should be the same constraint system
02578   as the consys field. The call to assert_same will check both the lpprob and
02579   the consys structures.
02580 */
02581   if (o1.lpprob)
02582   { assert(o2.lpprob) ;
02583     assert(o1.lpprob->consys && (o1.consys == o1.lpprob->consys)) ;
02584     assert(o2.lpprob->consys && (o2.consys == o2.lpprob->consys)) ;
02585     assert_same(*o1.lpprob,*o2.lpprob,exact) ; }
02586   else
02587   { assert(!o2.lpprob) ;
02588     assert_same(*o1.consys,*o2.consys,exact) ; }
02589 /*
02590   A belt & suspenders check: retrieve the matrix as a COINPackedMatrix and
02591   use the COIN isEquivalent routine to check for equality.
02592 */
02593   const CoinPackedMatrix* m1 = o1.getMatrixByCol() ;
02594   const CoinPackedMatrix* m2 = o2.getMatrixByCol() ;
02595   if (m1)
02596   { assert(m2 || m1->isEquivalent(*m2)) ; }
02597   else
02598   { assert(!m2) ; }
02599 }
02600 
02602 
02603 #endif /* !_MSC_VER */
02604 
02605 
02606 
02607 /*
02608   Problem specification routines: MPS and control files, and loading a problem
02609   from OSI data structures.
02610 */
02611 
02621 
02629 lpopts_struct* main_lpopts ;     // just for cmdint.c::process_cmds
02630 lptols_struct* main_lptols ;     // just for cmdint.c::process_cmds
02631 
02633 
02636 
02646 std::string ODSI::make_filename (const char *filename,
02647                                  const char *ext1, const char *ext2)
02648 
02649 { std::string basename(filename) ;
02650   std::string ext1str(ext1), ext2str(ext2) ;
02651 
02652 /*
02653   Extensions must start with ".", so fix if necessary.
02654 */
02655   if (ext1 && strlen(ext1) > 0 && ext1[0] != '.')
02656     ext1str.insert(ext1str.begin(),'.') ;
02657   if (ext2 && strlen(ext2) > 0 && ext2[0] != '.')
02658     ext2str.insert(ext2str.begin(),'.') ;
02659 /*
02660   Strip ext1 from filename, if it exists, leaving the base name.
02661 */
02662   if (ext1 && strlen(ext1) > 0)
02663   { string tmpname(filename) ;
02664     string::size_type ext1pos = tmpname.rfind(ext1str) ;
02665     if (ext1pos < tmpname.npos)
02666     { basename = tmpname.substr(0,ext1pos) ; } }
02667 /*
02668   Add ext2, if it exists.
02669 */
02670   if (ext2 && strlen(ext2) > 0) basename += ext2str ;
02671 
02672   return (basename) ; }
02673 
02674 
02676 
02677 
02678 
02707 
02708 
02709 
02723 int ODSI::readMps (const char* basename, const char* ext)
02724 
02725 /*
02726   This routine uses the COIN MPS input code, which allows me to sidestep
02727   the issues that dylp's MPS reader has when confronted with an MPS file
02728   that requires fixed-field processing or contains a constant objective
02729   function offset.
02730 
02731   Parameters:
02732     basename:   base name for mps file
02733     ext:        file extension; defaults to "mps"
02734 
02735   Returns: -1 if the MPS file could not be opened, otherwise the number of
02736            errors encountered while reading the file.
02737 */
02738 
02739 { int errcnt ;
02740   CoinMpsIO mps ;
02741   CoinMessageHandler *mps_handler = mps.messageHandler() ;
02742 
02743   if (mps_debug)
02744   { mps_handler->setLogLevel(handler_->logLevel()) ; }
02745   else
02746   { mps_handler->setLogLevel(0) ; }
02747 
02748 /*
02749   See if there's an associated .spc file and read it first, if present.
02750 */
02751   std::string filename = make_filename(basename,ext,"spc") ;
02752   dylp_controlfile(filename.c_str(),true,false) ;
02753 /*
02754   Make sure the MPS reader has the same idea of infinity as dylp, then
02755   attempt to read the MPS file.
02756 */
02757   mps.setInfinity(DYLP_INFINITY) ;
02758   filename = make_filename(basename,ext,ext) ;
02759   errcnt = mps.readMps(filename.c_str(),0) ;
02760   handler_->message(ODSI_MPSFILEIO,messages_)
02761     << filename << "read" << errcnt << CoinMessageEol ;
02762   if (errcnt != 0) return (errcnt) ;
02763 /*
02764   Load the problem and build a worst-case solution. To take full advantage
02765   of information in the MPS file, it's easiest to pass the mps object to
02766   load_problem.
02767 */
02768   load_problem(mps) ;
02769 /*
02770   Done!
02771 */
02772   return (0) ; }
02773 
02774 
02782 void ODSI::writeMps (const char *basename,
02783                      const char *ext, double objsense) const
02784 
02785 { string filename = make_filename(basename,ext,ext) ;
02786   
02787   CoinMpsIO mps ;
02788   CoinMessageHandler *mps_handler = mps.messageHandler() ;
02789 
02790   if (mps_debug)
02791   { mps_handler->setLogLevel(handler_->logLevel()) ; }
02792   else
02793   { mps_handler->setLogLevel(0) ; }
02794 
02795   double *outputobj ;
02796   const double *const solverobj = getObjCoefficients() ;
02797   
02798   int n = getNumCols(),
02799       m = getNumRows() ;
02800 
02801   if (objsense == getObjSense())
02802   { outputobj = const_cast<double *>(solverobj) ; }
02803   else
02804   { outputobj = new double[n] ;
02805     std::transform(solverobj,solverobj+n,outputobj,std::negate<double>()) ; }
02806 
02807   char *vartyp = new char[n] ;
02808   typedef char *charp ;
02809   char **colnames = new charp[n],
02810        **rownames = new charp[m] ;
02811   int i,j ;
02812 
02813   for (j = 0 ; j < n ; j++) vartyp[j] = isInteger(j) ;
02814 
02815   for (i = 0 ; i < m ; i++)
02816     rownames[i] = consys_nme(consys,'c',idx(i),false,0) ;
02817   
02818   for (j = 0 ; j < n ; j++)
02819     colnames[j] = consys_nme(consys,'v',idx(j),false,0) ;
02820 
02821   mps.setMpsData(*getMatrixByRow(),DYLP_INFINITY,
02822                  getColLower(),getColUpper(),outputobj,vartyp,
02823                  getRowLower(),getRowUpper(),colnames,rownames) ;
02824 /*
02825   We really need to work on symbolic names for these magic numbers.
02826 */
02827   int errcnt = mps.writeMps(filename.c_str(),0,4,2) ;
02828   handler_->message(ODSI_MPSFILEIO,messages_)
02829     << filename << "read" << errcnt << CoinMessageEol ;
02830 /*
02831   Free up the arrays we allocated.
02832 */
02833   delete[] vartyp ;
02834   delete[] colnames ;
02835   delete[] rownames ;
02836   if (outputobj != solverobj) delete[] outputobj ;
02837 
02838   return ; }
02839 
02840 
02848 inline void
02849 ODSI::assignProblem (CoinPackedMatrix*& matrix,
02850                      double*& col_lower, double*& col_upper, double*& obj, 
02851                      double*& row_lower, double*& row_upper)
02852 
02853 { loadProblem(*matrix,col_lower,col_upper,obj,row_lower,row_upper) ;
02854   delete matrix ; matrix = 0 ;
02855   delete [] col_lower ; col_lower = 0 ;
02856   delete [] col_upper ; col_upper = 0 ;
02857   delete [] obj ; obj = 0 ;
02858   delete [] row_lower ; row_lower = 0 ;
02859   delete [] row_upper ; row_upper = 0 ;
02860 }
02861 
02862 
02870 inline void
02871 ODSI::assignProblem (CoinPackedMatrix*& matrix, 
02872                      double*& lower, double*& upper, double*& obj, 
02873                      char*& sense, double*& rhs, double*& range)
02874 
02875 { loadProblem(*matrix, lower, upper, obj, sense, rhs, range) ;
02876   delete matrix ; matrix = 0 ;
02877   delete [] lower ; lower = 0 ;
02878   delete [] upper ; upper = 0 ;
02879   delete [] obj ; obj = 0 ;
02880   delete [] sense ; sense = 0 ;
02881   delete [] rhs ; rhs = 0 ;
02882   delete [] range ; range = 0 ;
02883 }
02884 
02885 
02892 inline void
02893 ODSI::loadProblem (const CoinPackedMatrix& matrix,
02894                    const double* col_lower, const double* col_upper,
02895                    const double* obj,
02896                    const double* row_lower, const double* row_upper)
02897 
02898 { int rowcnt = matrix.getNumRows() ;
02899   double *rhs = new double[rowcnt] ;
02900   double *rhslow = new double[rowcnt] ;
02901   contyp_enum *ctyp = new contyp_enum[rowcnt] ;
02902 
02903   gen_rowparms(rowcnt,rhs,rhslow,ctyp,row_lower,row_upper) ;
02904   load_problem(matrix,col_lower,col_upper,obj,ctyp,rhs,rhslow) ;
02905 
02906   delete[] rhs ;
02907   delete[] rhslow ;
02908   delete[] ctyp ; }
02909 
02910 
02917 inline void
02918 ODSI::loadProblem (const CoinPackedMatrix& matrix, 
02919                    const double* col_lower, const double* col_upper,
02920                    const double* obj,
02921                    const char* sense, const double* rhsin, const double* range)
02922 
02923 { int rowcnt = matrix.getNumRows() ;
02924   double *rhs = new double[rowcnt] ;
02925   double *rhslow = new double[rowcnt] ;
02926   contyp_enum *ctyp = new contyp_enum[rowcnt] ;
02927 
02928   gen_rowparms(rowcnt,rhs,rhslow,ctyp,sense,rhsin,range) ;
02929   load_problem(matrix,col_lower,col_upper,obj,ctyp,rhs,rhslow) ;
02930 
02931   delete[] rhs ;
02932   delete[] rhslow ;
02933   delete[] ctyp ; }
02934 
02942 inline void
02943 ODSI::loadProblem (const int colcnt, const int rowcnt,
02944                    const int *start, const int *index, const double *value,
02945                    const double* col_lower, const double* col_upper,
02946                    const double* obj,
02947                    const double* row_lower, const double* row_upper)
02948 
02949 { double *rhs = new double[rowcnt] ;
02950   double *rhslow = new double[rowcnt] ;
02951   contyp_enum *ctyp = new contyp_enum[rowcnt] ;
02952 
02953   gen_rowparms(rowcnt,rhs,rhslow,ctyp,row_lower,row_upper) ;
02954   load_problem(colcnt,rowcnt,start,index,value,
02955                col_lower,col_upper,obj,ctyp,rhs,rhslow) ;
02956 
02957   delete[] rhs ;
02958   delete[] rhslow ;
02959   delete[] ctyp ; }
02960 
02961 
02969 inline void
02970 ODSI::loadProblem (const int colcnt, const int rowcnt,
02971                    const int *start, const int *index, const double *value,
02972                    const double* col_lower, const double* col_upper,
02973                    const double* obj,
02974                    const char* sense, const double* rhsin, const double* range)
02975 
02976 { double *rhs = new double[rowcnt] ;
02977   double *rhslow = new double[rowcnt] ;
02978   contyp_enum *ctyp = new contyp_enum[rowcnt] ;
02979 
02980   gen_rowparms(rowcnt,rhs,rhslow,ctyp,sense,rhsin,range) ;
02981   load_problem(colcnt,rowcnt,start,index,value,
02982                col_lower,col_upper,obj,ctyp,rhs,rhslow) ;
02983 
02984   delete[] rhs ;
02985   delete[] rhslow ;
02986   delete[] ctyp ; }
02987 
02989 
02990 
02991 
02992 
02993 
03052 
03053 inline double ODSI::getInfinity () const { return DYLP_INFINITY ; }
03054 
03055 
03056 bool ODSI::setDblParam (OsiDblParam key, double value)
03057 /*
03058   Aside from simply setting the relevant ODSI field, the work here is making
03059   sure the dylp tolerance values are consistent.
03060 
03061   OsiDualTolerance and OsiPrimalTolerance are both feasibility tolerances.
03062   dylp actually maintains feasibility tolerances scaled off the respective
03063   zero tolerances. dfeas_scale and pfeas_scale allow the scaled tolerances to
03064   be relaxed (or tightened, for that matter) with respect to the zero
03065   tolerances. Hence the best approach to consistency is to set *_scale based
03066   on the ratio of osi and dylp tolerances. This is, at best, imperfect, as it
03067   doesn't take into account dylp's internal scaling. Nor can it, really, as
03068   this information isn't guaranteed to be valid.
03069 
03070   Support for Osi[Dual,Primal]ObjectiveLimit is a facade at the moment. The
03071   values are stored, and used by is[Dual,Primal]ObjectiveLimitReached, but
03072   dylp knows nothing of them.
03073 */
03074 { if (key == OsiLastDblParam) return (false) ;
03075 
03076   bool retval = OSI::setDblParam(key,value) ;
03077 
03078   switch (key)
03079   { case OsiDualTolerance:
03080     { tolerances->dfeas_scale = value/tolerances->cost ;
03081       break ; }
03082     case OsiPrimalTolerance:
03083     { tolerances->pfeas_scale = value/tolerances->zero ;
03084       break ; }
03085     case OsiObjOffset:
03086     { break ; }
03087     case OsiDualObjectiveLimit:
03088     case OsiPrimalObjectiveLimit:
03089     { break ; }
03090     default:
03091     { retval = false ;
03092       break ; } }
03093   
03094   return (retval) ; }
03095 
03096 
03097 bool ODSI::getDblParam (OsiDblParam key, double& value) const
03098 /*
03099   This simply duplicates OSI::getDblParam. I've kept it here until I decide
03100   what to do with the parameters Osi[Primal,Dual]ObjectiveLimit.
03101 */
03102 { if (key == OsiLastDblParam) return (false) ;
03103 
03104   bool retval ;
03105 
03106   switch (key)
03107   { case OsiDualTolerance:
03108     case OsiPrimalTolerance:
03109     case OsiObjOffset:
03110     { retval = OSI::getDblParam(key,value) ;
03111       break ; }
03112     case OsiDualObjectiveLimit:
03113     case OsiPrimalObjectiveLimit:
03114     { retval = OSI::getDblParam(key,value) ;
03115       break ; }
03116     default:
03117     { OSI::getDblParam(key,value) ;
03118       retval = false ;
03119       break ; } }
03120 
03121   return (retval) ; }
03122 
03123 
03124 bool ODSI::setIntParam (OsiIntParam key, int value)
03125 /*
03126   Dylp's iteration limit is normally enforced on a per-phase basis, with an
03127   overall limit of 3*(per-phase limit). OsiMaxNumIterationHotStart is handled
03128   in solveFromHotStart.
03129 */
03130 { if (key == OsiLastIntParam) return (false) ;
03131 
03132   bool retval = OSI::setIntParam(key,value) ;
03133 
03134   switch (key)
03135   { case OsiMaxNumIteration:
03136     { initialSolveOptions->iterlim = value/3 ;
03137       resolveOptions->iterlim = initialSolveOptions->iterlim ;
03138       break ; }
03139     case OsiMaxNumIterationHotStart:
03140     { break ; }
03141     default:
03142     { retval = false ;
03143       break ; } }
03144   
03145   return (retval) ; }
03146 
03147 
03148 inline bool ODSI::getIntParam (OsiIntParam key, int& value) const
03149 /*
03150   This simply duplicates OSI::getIntParam. Retained here in anticipation of
03151   future extensions.
03152 */
03153 { bool retval ;
03154 
03155   if (key == OsiLastIntParam) return (false) ;
03156 
03157   switch (key)
03158   { case OsiMaxNumIteration:
03159     case OsiMaxNumIterationHotStart:
03160     { retval = OSI::getIntParam(key,value) ;
03161       break ; }
03162     default:
03163     { retval = false ;
03164       break ; } }
03165   
03166   return (retval) ; }
03167 
03168 
03169 bool ODSI::setStrParam (OsiStrParam key, const std::string& value)
03170 /*
03171   Set string paramaters. Note that OsiSolverName is, by definition, a
03172   constant. You can set it all you like, however :-).
03173 
03174   The problem name is pushed to the constraint system, if it exists.
03175 */
03176 
03177 { if (key == OsiLastStrParam) return (false) ;
03178 
03179   bool retval = OSI::setStrParam(key,value) ;
03180 
03181   switch (key)
03182   { case OsiProbName:
03183     { if (consys)
03184       { if (consys->nme) strfree(consys->nme) ;
03185         consys->nme = stralloc(value.c_str()) ; }
03186       break ; }
03187     case OsiSolverName:
03188     { break ; }
03189     default:
03190     { retval = false ;
03191       break ; } }
03192   
03193   return (retval) ; }
03194 
03195 bool ODSI::getStrParam (OsiStrParam key, std::string& value) const
03196 /*
03197   This mostly duplicates OSI::getStrParam. It enforces the notion that you
03198   can't set the solver name, which the default OSI routine does not.
03199 */
03200 { if (key == OsiLastStrParam) return (false) ;
03201 
03202   bool retval = true ;
03203 
03204   switch (key)
03205   { case OsiProbName:
03206     { retval = OSI::getStrParam(key,value) ;
03207       break ; }
03208     case OsiSolverName:
03209     { value = solvername ;
03210       break ; }
03211     default:
03212     { retval = false ;
03213       break ; } }
03214 
03215   return (retval) ; }
03216 
03217 
03226 void ODSI::unimp_hint (bool dylpSense, bool hintSense,
03227                        OsiHintStrength hintStrength, const char *msgString)
03228 
03229 { if (dylpSense != hintSense)
03230   { std::string message("Dylp ") ;
03231     if (dylpSense == true)
03232     { message += "cannot disable " ; }
03233     else
03234     { message += "does not support " ; }
03235     message += msgString ;
03236     if (hintStrength == OsiForceDo)
03237     { handler_->message(ODSI_UNSUPFORCEDO,messages_)
03238         << message << CoinMessageEol ;
03239       throw CoinError(message,"setHintParam","OsiDylpSolverInterface") ; }
03240     else
03241     { handler_->message(ODSI_IGNORED,messages_)
03242         << message << CoinMessageEol ; } }
03243   
03244   return ; }
03245 
03246 
03259 bool ODSI::setHintParam (OsiHintParam key, bool sense,
03260                          OsiHintStrength strength, void *info)
03261 /*
03262   OSI provides arrays for the sense and strength. ODSI provides the array for
03263   info.
03264 */
03265 
03266 { bool retval = false ;
03267 /*
03268   Set the hint in the OSI structures. Unlike the other set*Param routines,
03269   setHintParam will return false for key == OsiLastHintParam. Unfortunately,
03270   it'll also throw for strength = OsiForceDo, without setting a return value.
03271   We need to catch that throw.
03272 */
03273   try
03274   { retval = OSI::setHintParam(key,sense,strength) ; }
03275   catch (CoinError)
03276   { retval = (strength == OsiForceDo) ; }
03277     
03278   if (retval == false) return (false) ;
03279   info_[key] = info ;
03280 /*
03281   Did the client say `ignore this'? Who are we to argue.
03282 */
03283   if (strength == OsiHintIgnore) return (true) ;
03284 /*
03285   We have a valid hint which would be impolite to simply ignore. Deal with
03286   it as best we can.
03287 */
03288   switch (key)
03289   {
03290 /*
03291   Dylp has no presolve capabilities.
03292 */
03293     case OsiDoPresolveInInitial:
03294     case OsiDoPresolveInResolve:
03295     { unimp_hint(false,sense,strength,"presolve") ;
03296       retval = true ;
03297       break ; }
03298 /*
03299   Dylp can suppress the dual, but cannot suppress the primal. Requesting
03300   OsiDoDual* with (true, OsiHint*) is ignored; (true,OsiForceDo) will throw
03301   an exception. On the other hand, suppressing the dual is generally not a
03302   good idea, so the hint is ignored at (true,OsiHintTry).
03303 */
03304     case OsiDoDualInInitial:
03305     case OsiDoDualInResolve:
03306     { unimp_hint(false,sense,strength,"exclusive use of dual simplex") ;
03307       retval = true ;
03308       lpopts_struct *opts =
03309         (key == OsiDoDualInInitial)?initialSolveOptions:resolveOptions ;
03310       if (sense == false)
03311       { if (strength >= OsiHintDo) opts->usedual = false ; }
03312       else
03313       { opts->usedual = true ; }
03314       break ; }
03315 /*
03316   No issues here, dylp can go either way.
03317 */
03318     case OsiDoScale:
03319     { if (sense == false)
03320       { if (strength >= OsiHintTry) initialSolveOptions->scaling = 0 ; }
03321       else
03322       { initialSolveOptions->scaling = 2 ; }
03323       resolveOptions->scaling = initialSolveOptions->scaling ;
03324       break ; }
03325 /*
03326   Dylp knows only one crash, which preferably uses slacks, then architecturals,
03327   and artificials as a last resort.
03328 */
03329     case OsiDoCrash:
03330     { unimp_hint(true,sense,strength,"basis crash") ;
03331       retval = true ;
03332       break ; }
03333 /*
03334   An unadorned hint changes the level by +/- 1, 2, or 3, depending on sense
03335   and strength (abusing the equivalence of enums and integers).  If info is
03336   non-zero, it is taken as a pointer to an integer which is the absolute
03337   value for the log level. In this case, sense is irrelevant. Note that
03338   CoinMessageHandler recognizes levels 0 -- 4 as generic levels.
03339   Conveniently, dylp has a similar set of generic levels. The larger powers
03340   of 2 (8, 16, 32, etc.) left to trigger specific classes of debugging
03341   printout. These must be set using info. Currently:
03342     0x08        CoinMpsIO messages
03343 */
03344     case OsiDoReducePrint:
03345     { int verbosity = messageHandler()->logLevel() ;
03346       mps_debug = false ;
03347       if (info)
03348       { verbosity = *reinterpret_cast<int *>(info) ;
03349         if (verbosity&0x8) mps_debug = true ; }
03350       else
03351       { if (sense == true)
03352         { verbosity -= strength ;
03353           verbosity = max(verbosity,0) ; }
03354         else
03355         { verbosity += strength ;
03356           verbosity = min(verbosity,4) ; } } 
03357 
03358       dy_setprintopts(0,initialSolveOptions) ;
03359       dy_setprintopts(0,resolveOptions) ;
03360       if (verbosity == 0)
03361       { initial_gtxecho = false ;
03362         resolve_gtxecho = false ; }
03363       else
03364       { initial_gtxecho = true ;
03365         resolve_gtxecho = true ; }
03366       messageHandler()->setLogLevel(verbosity) ;
03367       dy_setprintopts((verbosity&0x7),initialSolveOptions) ;
03368       dy_setprintopts((verbosity&0x7),resolveOptions) ;
03369       retval = true ;
03370       break ; }
03371 /*
03372   The OSI spec says that unimplemented options (and, by implication, hints)
03373   should return false. In the case of a hint, however, we can ignore anything
03374   except OsiForceDo, so usability says we should anticipate new hints and set
03375   this up so the solver doesn't break. So return true.
03376 */
03377     default:
03378     { unimp_hint(!sense,sense,strength,"unrecognized hint") ;
03379       retval = true ;
03380       break ; } }
03381 
03382   return (retval) ; }
03383 
03384 
03385 inline bool ODSI::getHintParam (OsiHintParam key, bool &sense,
03386                                 OsiHintStrength &strength, void *&info) const
03387 /*
03388   OSI provides the arrays for the sense and strength. ODSI provides the array
03389   for info.
03390 */
03391 
03392 { bool retval = OSI::getHintParam(key,sense,strength) ;
03393 
03394   if (retval == false) return (false) ;
03395 
03396   info = info_[key] ;
03397 
03398   return (true) ; }
03399 
03400 
03402 
03403 
03404 
03414 
03424 void ODSI::initialSolve ()
03425 
03426 { 
03427 /*
03428   The minimum requirement is a constraint system. Options and tolerances should
03429   also be present --- they're established when the ODSI object is created.
03430 */
03431   assert(consys && initialSolveOptions && tolerances) ;
03432 /*
03433   Do we have an lpprob structure yet?
03434 */
03435   if (!lpprob) construct_lpprob() ;
03436 /*
03437   Is the basis package initialised?
03438 */
03439   if (basis_ready == false)
03440   { int count = static_cast<int>((1.5*getNumRows()) + 2*getNumCols()) ;
03441     dy_initbasis(count,initialSolveOptions->factor,0) ;
03442     basis_ready = true ; }
03443 /*
03444   Does some other ODSI object own the solver? If so, detach it.
03445 */
03446   if (dylp_owner != 0 && dylp_owner != this) dylp_owner->detach_dylp() ;
03447 /*
03448   Choose options appropriate for the initial solution of the lp and go to it.
03449 */
03450   lpopts_struct lclopts = *initialSolveOptions ;
03451   lptols_struct lcltols = *tolerances ;
03452   dy_checkdefaults(consys,&lclopts,&lcltols) ;
03453   if (isactive(local_logchn)) logchn = local_logchn ;
03454   gtxecho = initial_gtxecho ;
03455   lpprob->phase = dyINV ;
03456   lp_retval = dylp_dolp(lpprob,&lclopts,&lcltols,statistics) ;
03457   if (!(lp_retval == lpOPTIMAL || lp_retval == lpINFEAS ||
03458         lp_retval == lpUNBOUNDED))
03459   { throw CoinError("Call to dylp failed.",
03460                     "initialSolve","OsiDylpSolverInterface") ; }
03461 /*
03462   Trash the cached solution. This needs to happen regardless of how the lp
03463   turned out. It needs to be done ahead of getWarmStart, which will try to
03464   access reduced costs.
03465 */
03466     destruct_col_cache() ;
03467     destruct_row_cache() ;
03468 /*
03469   Tidy up. If all went well, indicate this object owns the solver, set the
03470   objective, and set the active basis. If we've failed, do the opposite.
03471   Note that we have to remove any current active basis first, or getWarmStart
03472   will hand it back to us.
03473 
03474   Any of lpOPTIMAL, lpINFEAS, or lpUNBOUNDED can (in theory) be hot started
03475   after allowable problem modifications, hence can be flagged lpctlDYVALID.
03476   dylp overloads lpprob->obj with the index of the unbounded variable when
03477   returning lpUNBOUNDED, so we need to fake the objective.
03478 */
03479   delete activeBasis ;
03480   activeBasis = 0 ;
03481   activeIsModified = false ;
03482   if (flgon(lpprob->ctlopts,lpctlDYVALID))
03483   { dylp_owner = this ;
03484     if (lpprob->lpret == lpUNBOUNDED)
03485     { _objval = -getObjSense()*getInfinity() ; }
03486     else
03487     { _objval = getObjSense()*lpprob->obj ; }
03488     activeBasis = this->getWarmStart() ; }
03489   else
03490   { dylp_owner = 0 ; }
03491 
03492   return ; }
03493 
03495 
03496 
03497 
03500 
03501 
03502 inline int ODSI::getIterationCount () const
03503 
03504 { return ((lpprob)?lpprob->iters:0) ; }
03505 
03506 
03507 inline bool ODSI::isIterationLimitReached () const
03508 
03509 { return (lp_retval == lpITERLIM) ; }
03510 
03511 
03512 inline bool ODSI::isProvenOptimal () const
03513 
03514 { return (lp_retval == lpOPTIMAL) ; }
03515 
03516 
03517 inline bool ODSI::isProvenPrimalInfeasible () const
03518 
03519 { return (lp_retval == lpINFEAS) ; }
03520 
03521 
03526 inline bool ODSI::isProvenDualInfeasible () const
03527 
03528 { return (lp_retval == lpUNBOUNDED) ; }
03529 
03530 
03537 inline bool ODSI::isAbandoned () const
03538 
03539 { if (lp_retval == lpACCCHK || lp_retval == lpSINGULAR ||
03540       lp_retval == lpSTALLED || lp_retval == lpNOSPACE ||
03541       lp_retval == lpLOSTFEAS || lp_retval == lpPUNT || lp_retval == lpFATAL)
03542     return (true) ;
03543   else
03544     return (false) ; }
03545 
03546 
03548 
03549 
03550 
03553 
03562 inline double ODSI::getObjValue () const
03563 /*
03564   _objval is kept up-to-date and corrected for obj_sense. All we need to do
03565   here is deal with the offset.
03566 */
03567 { double objoffset ;
03568 
03569   getDblParam(OsiObjOffset,objoffset) ;
03570 
03571   return (_objval-objoffset) ; }
03572   
03573 
03574 
03587 const double* ODSI::getColSolution () const
03588 /*
03589   We could have a cached solution, either supplied by the client or a
03590   previous solution from dylp. If not, we have to build one.  Dylp returns a
03591   vector x of basic variables, in basis order, and a status vector. To
03592   assemble a complete primal solution, it's necessary to construct one vector
03593   that merges the two sources. The result is cached.
03594 
03595   NOTE the caution above about superbasic (vstatSB) variables. Nonbasic free
03596   variables (vstatNBFR) occur under the same termination conditions, but are
03597   legitimately zero. We really should return NaN for superbasics, using the
03598   function <limits>:std::numeric_limits::signaling_NaN(), but it's just not
03599   worth the hassle. Sun Workshop C++ (Rogue Wave Software) has it, but Gnu C++
03600   prior to v3 doesn't even have <limits>, and the local v3 installation's
03601   <limits> points to another, non-existent header.
03602 */
03603 { if (_col_x) return _col_x ;
03604 
03605   if (lpprob)
03606   { assert(lpprob->status && lpprob->x) ;
03607 
03608     int n = getNumCols() ;
03609     flags statj ;
03610     _col_x = new double[n] ;
03611 
03612 /*
03613   Walk the status vector, taking values for basic variables from lpprob.x and
03614   values for nonbasic variables from the appropriate bounds vector.
03615 */
03616     for (int j = 0 ; j < n ; j++)
03617     { statj = lpprob->status[idx(j)] ;
03618       if (((int) statj) < 0)
03619       { int k = -((int) statj) ;
03620         _col_x[j] = lpprob->x[k] ; }
03621       else
03622       { switch (statj)
03623         { case vstatNBLB:
03624           case vstatNBFX:
03625           { _col_x[j] = consys->vlb[idx(j)] ;
03626             break ; }
03627           case vstatNBUB:
03628           { _col_x[j] = consys->vub[idx(j)] ;
03629             break ; }
03630           case vstatNBFR:
03631           { _col_x[j] = 0 ;
03632             break ; }
03633           case vstatSB:
03634           { _col_x[j] = -DYLP_INFINITY ;
03635             break ; } } } } }
03636 
03637   return (_col_x) ; }
03638 
03639 
03645 const double* ODSI::getRowPrice () const
03646 /*
03647   Dylp reports dual variables in basis order, so we need to write a vector
03648   with the duals dropped into position by row index.
03649 */
03650 
03651 { if (_row_price) return (_row_price) ;
03652 
03653   if (lpprob)
03654   { assert(lpprob->basis && lpprob->y) ;
03655 
03656     int m = getNumRows() ;
03657     _row_price = new double[m] ;
03658     basis_struct* basis = lpprob->basis ;
03659 
03660     memset(_row_price,0,m*sizeof(double)) ;
03661 
03662     for (int k = 1 ; k <= basis->len ; k++)
03663     { int i = inv(basis->el[k].cndx) ;
03664       _row_price[i] = lpprob->y[k]*getObjSense() ; } }
03665 
03666   return (_row_price) ; }
03667 
03668 
03675 const double *ODSI::getRowActivity () const
03676 /*
03677   This routine calculates the value of the left-hand-side of a constraint. The
03678   algorithm is straightforward: Retrieve the primal solution, then walk the
03679   variables, adding the contribution of each non-zero variable.
03680 */
03681 { 
03682 /*
03683   If we have a cached copy, we're done.
03684 */
03685   if (_row_lhs) return (_row_lhs) ;
03686 /*
03687   In order to go further, we'll need a primal solution and some rows.
03688 */
03689   int m = getNumRows() ;
03690   const double *x = getColSolution() ;
03691 
03692   if (m > 0 && x)
03693 /*
03694   Create a vector to hold ax and clear it to 0.
03695 */
03696   { _row_lhs = new double[consys->concnt] ;
03697     memset(_row_lhs,0,m*sizeof(double)) ;
03698 /*
03699   Walk the primal solution vector, adding in the contribution from non-zero
03700   variables.
03701 */
03702     pkvec_struct *aj = pkvec_new(m) ;
03703     for (int j = 0 ; j < consys->varcnt ; j++)
03704     { if (x[j] != 0)
03705       { bool r = consys_getcol_pk(consys,idx(j),&aj) ;
03706         if (!r)
03707         { delete[] _row_lhs ;
03708           if (aj) pkvec_free(aj) ;
03709           return (0) ; }
03710         for (int l = 0 ; l < aj->cnt ; l++)
03711         { int i = inv(aj->coeffs[l].ndx) ;
03712           _row_lhs[i] += x[j]*aj->coeffs[l].val ; } } }
03713     if (aj) pkvec_free(aj) ;
03714 /*
03715   Groom the vector to eliminate tiny values.
03716 */
03717     for (int i = 0 ; i < consys->concnt ; i++)
03718       setcleanzero(_row_lhs[i],tolerances->zero) ; }
03719 /*
03720   Cache the result and return.
03721 */
03722 
03723   return (_row_lhs) ; }
03724 
03725 
03730 const double *ODSI::getReducedCost () const
03731 /*
03732   Calculate the reduced cost as cbar = c - yA.
03733 
03734   It's tempting to want to dive into dylp for this calculation, but there are
03735   problems: First, some other ODSI object may own the solver. Second, we
03736   can't be sure where the duals are coming from --- they could be part of a
03737   solution from dylp, or they could be a vector supplied by the client.
03738   Third, both the objective coefficients and the duals are subject to sign
03739   change for maximisation. In the end, it seems best to rely on
03740   getObjCoefficients and getRowPrice to provide the objective and duals,
03741 */
03742 
03743 { 
03744 /*
03745   Check for a cached value.
03746 */
03747   if (_col_cbar) return (_col_cbar) ;
03748 /*
03749   Do we have columns to to work with? If yes, then we have a valid constraint
03750   system data structure. Initialize cbar with the objective coefficients.
03751 */
03752   int n = getNumCols() ;
03753   if (n == 0) return (0) ;
03754   _col_cbar = new double[n] ;
03755   COPY_VEC(double,getObjCoefficients(),_col_cbar,n) ;  
03756 /*
03757   Do we have rows? Dual variables? If not, we're done. The presence of rows
03758   does not necessarily mean we have valid duals.
03759 */
03760   int m = getNumRows() ;
03761   const double *y = getRowPrice() ;
03762   if (!y) return (_col_cbar) ;
03763 /*
03764   We have a constraint system, objective coefficients, and dual variables.
03765   Grind out the calculation, row by row.
03766 */
03767   pkvec_struct *ai = pkvec_new(n) ;
03768   for (int i = 0 ; i < m ; i++)
03769   { if (y[i] != 0)
03770     { bool r = consys_getrow_pk(consys,idx(i),&ai) ;
03771       if (!r)
03772       { delete[] _col_cbar ;
03773         _col_cbar = 0 ;
03774         if (ai) pkvec_free(ai) ;
03775         return (0) ; }
03776       for (int l = 0 ; l < ai->cnt ; l++)
03777       { int j = inv(ai->coeffs[l].ndx) ;
03778         _col_cbar[j] -= y[i]*ai->coeffs[l].val ; } } }
03779   if (ai) pkvec_free(ai) ;
03780 /*
03781   Groom the vector to eliminate tiny values and we're done.
03782 */
03783   for (int j = 0 ; j < n ; j++) setcleanzero(_col_cbar[j],tolerances->cost) ;
03784 
03785   return (_col_cbar) ; }
03786 
03787 
03789 
03790 
03791 
03794 
03800 inline bool ODSI::isBinary (int i) const
03801 
03802 { if (!consys || i < 0 || i > consys->varcnt-1)
03803     return (false) ;
03804   else
03805   if (!consys->vtyp)
03806     return (false) ;
03807   else
03808     return (consys->vtyp[idx(i)] == vartypBIN) ; }
03809 
03810 
03816 inline bool ODSI::isIntegerNonBinary (int i) const
03817 
03818 { if (!consys || i < 0 || i > consys->varcnt-1)
03819     return (false) ;
03820   else
03821   if (!consys->vtyp)
03822     return (false) ;
03823   else
03824     return (consys->vtyp[idx(i)] == vartypINT) ; }
03825 
03826 
03832 inline bool ODSI::isInteger (int i) const
03833 
03834 { if (!consys || i < 0 || i > consys->varcnt-1)
03835     return (false) ;
03836   else
03837   if (!consys->vtyp)
03838     return (false) ;
03839   else
03840     return (consys->vtyp[idx(i)] == vartypINT ||
03841             consys->vtyp[idx(i)] == vartypBIN) ; }
03842 
03843 
03844 
03850 inline bool ODSI::isContinuous (int i) const
03851 
03852 { if (!consys || i < 0 || i > consys->varcnt-1)
03853     return (false) ;
03854   else
03855   if (!consys->vtyp)
03856     return (true) ;
03857   else
03858     return (consys->vtyp[idx(i)] == vartypCON) ; }
03859 
03860 
03863 inline const double* ODSI::getColLower () const
03864 
03865 { if (!consys || !consys->vlb)
03866     return (0) ;
03867   else
03868     return (INV_VEC(double,consys->vlb)) ; }
03869 
03870 
03873 inline const double* ODSI::getColUpper () const
03874 
03875 { if (!consys || !consys->vub)
03876     return (0) ;
03877   else
03878     return (INV_VEC(double,consys->vub)) ; }
03879 
03880 
03881 inline int ODSI::getNumCols () const
03882 
03883 { if (!consys)
03884     return (0) ;
03885   else
03886     return (consys->varcnt) ; }
03887 
03888 
03889 inline int ODSI::getNumElements () const
03890 
03891 { if (!consys)
03892     return (0) ; 
03893   else
03894     return (consys->mtx.coeffcnt) ; }
03895 
03896 
03897 inline int ODSI::getNumRows () const
03898 
03899 { if (!consys)
03900     return (0) ;
03901   else
03902     return (consys->concnt) ; }
03903 
03904 
03910 inline const double* ODSI::getObjCoefficients () const
03911 
03912 { if (!consys || !consys->obj) return (0) ;
03913 
03914   if (_col_obj) return _col_obj ;
03915 
03916   int n = getNumCols() ;
03917   _col_obj = new double[n] ;
03918   double *obj_0base = INV_VEC(double,consys->obj) ;
03919 
03920   if (getObjSense() < 0)
03921   { std::transform(obj_0base,obj_0base+n,_col_obj,std::negate<double>()) ; }
03922   else
03923   { COPY_VEC(double,obj_0base,_col_obj,n) ; }
03924 
03925   return (_col_obj) ; }
03926 
03927 
03928 inline double ODSI::getObjSense () const
03929 
03930 { return (obj_sense) ; }
03931 
03932 
03939 const CoinPackedMatrix* ODSI::getMatrixByRow () const
03940 
03941 { if (!consys) return 0 ;
03942   if (_matrix_by_row) return _matrix_by_row ;
03943 
03944   _matrix_by_row = new CoinPackedMatrix ;
03945   _matrix_by_row->reverseOrderedCopyOf(*getMatrixByCol()) ;
03946 
03947   return _matrix_by_row ; }
03948 
03949 
03965 const CoinPackedMatrix* ODSI::getMatrixByCol () const
03966 
03967 { if (!consys) return 0 ;
03968   if (_matrix_by_col) return _matrix_by_col ;
03969 
03970 /*
03971   Get the column and coefficient counts and create the OSI core vectors.
03972 */
03973   int col_count = getNumCols() ;
03974   assert(col_count > 0) ;
03975   int coeff_count = consys->mtx.coeffcnt ;
03976   assert(coeff_count > 0) ;
03977 
03978   int* start = new int[col_count+1] ;
03979   int* len = new int[col_count] ;
03980   double* values = new double[coeff_count] ;
03981   int* indices = new int[coeff_count] ;
03982   CoinPackedMatrix* matrix = new CoinPackedMatrix ;
03983 /*
03984   Scan out the coefficients from the consys_struct column by column.
03985 */
03986   colhdr_struct** cols = consys->mtx.cols ;
03987   int coeff_ndx = 0 ;
03988   for (int i = 0 ; i < col_count ; i++)
03989   { start[i] = coeff_ndx ;
03990     len[i] = cols[idx(i)]->len ;
03991 
03992     coeff_struct* c = cols[idx(i)]->coeffs ;
03993     for (int j = 0 ; j < len[i] ; j++, c = c->colnxt, coeff_ndx++)
03994     { values[coeff_ndx] = c->val ;
03995       indices[coeff_ndx] = inv(c->rowhdr->ndx) ; }
03996     assert(c == 0) ; }
03997   assert(coeff_ndx == coeff_count) ;
03998 /*
03999   Create the OSI sparse matrix structure.
04000 */
04001   start[col_count] = coeff_ndx ;
04002   int row_count = getNumRows() ;
04003   matrix->assignMatrix(true, row_count, col_count, coeff_count, 
04004     values, indices, start, len) ;
04005 /*
04006   Make a cached copy and return a pointer to it.
04007 */
04008   _matrix_by_col = matrix ;
04009   return matrix ; }
04010 
04011 
04022 const double* ODSI::getRowLower () const
04023 
04024 { if (!consys) return (0) ;
04025   if (_row_lower) return _row_lower ;
04026 
04027   int n = getNumRows() ;
04028   double* lower = new double[n] ;
04029 
04030   for (int i = 0 ; i < n ; i++)
04031   { contyp_enum ctypi = consys->ctyp[idx(i)] ;
04032     switch (ctypi)
04033     { case contypEQ:
04034       case contypGE:
04035       { lower[i] = consys->rhs[idx(i)] ;
04036         break ; }
04037       case contypRNG:
04038       { lower[i] = consys->rhslow[idx(i)] ;
04039         break ; }
04040       case contypLE:
04041       case contypNB:
04042       { lower[i] = -DYLP_INFINITY ;
04043         break ; }
04044       default:
04045       { assert(0) ; } } }
04046 
04047   _row_lower = lower ;
04048   return (lower) ; }
04049 
04050 
04061 const double* ODSI::getRowUpper () const
04062 
04063 { if (!consys) return (0) ;
04064   if (_row_upper) return _row_upper ;
04065 
04066   int n = getNumRows() ;
04067   double* upper = new double[n] ;
04068 
04069   for (int i = 0 ; i < n ; i++)
04070   { if (consys->ctyp[idx(i)] == contypGE || consys->ctyp[idx(i)] == contypNB)
04071       upper[i] = DYLP_INFINITY ;
04072     else
04073       upper[i] = consys->rhs[idx(i)] ; }
04074 
04075   _row_upper = upper ;
04076   return upper ; }
04077 
04078 
04087 const char* ODSI::getRowSense () const
04088 
04089 { if (!consys) return (0) ;
04090   if (_row_sense) return _row_sense ;
04091   
04092   int n = getNumRows() ;
04093   char* sense = new char[n] ;
04094   const contyp_enum* ctyp = INV_VEC(contyp_enum,consys->ctyp) ;
04095 
04096   std::transform(ctyp,ctyp+n,sense,type_to_sense) ;
04097 
04098   _row_sense = sense ;
04099   return sense ; }
04100 
04101 
04112 const double* ODSI::getRowRange () const
04113 
04114 { if (!consys) return (0) ;
04115   if (_row_range) return _row_range ;
04116   
04117   int n = getNumRows() ;  
04118   double* range = new double[n] ;
04119   const double* lower = getRowLower() ;
04120   const double* upper = getRowUpper() ;
04121   const char* sense = getRowSense() ;
04122 
04123   for (int i=0 ; i<n ; i++)
04124     if (sense[i] != 'R')
04125       range[i] = 0.0 ;
04126     else
04127       range[i] = upper[i] - lower[i] ;
04128   
04129   _row_range = range ;
04130   return range ; }
04131 
04132 
04143 const double* ODSI::getRightHandSide () const
04144 
04145 { if (!consys) return (0) ;
04146   if (_row_rhs) return _row_rhs ;
04147   
04148   int n = getNumRows() ;  
04149   double* rhs = new double[n] ;
04150   const double* lower = getRowLower() ;
04151   const double* upper = getRowUpper() ;
04152   const char* sense = getRowSense() ;
04153 
04154   for (int i = 0 ; i < n ; i++)
04155   { switch (sense[i])
04156     { case 'N':
04157       { rhs[i] = 0.0 ;
04158         break ; }
04159       case 'G':
04160       { rhs[i] = lower[i] ;
04161         break ; }
04162       case 'E':
04163       { rhs[i] = upper[i] ;
04164         break ; }
04165       case 'L':
04166       { rhs[i] = upper[i] ;
04167         break ; }
04168       case 'R':
04169       { rhs[i] = upper[i] ;
04170         break ; }
04171       default:
04172       { assert(0) ; } } }
04173 
04174   _row_rhs = rhs ;
04175   return (rhs) ; }
04176 
04177 
04179 
04180 
04181 
04184 
04185 
04196 bool ODSI::isDualObjectiveLimitReached () const
04197 
04198 { double objlim ;
04199   double objval = getObjValue() ;
04200 
04201   getDblParam(OsiDualObjectiveLimit,objlim) ;
04202   objlim *= getObjSense() ;
04203 
04204   if (getObjSense() > 0)
04205     return (objval > objlim) ;
04206   else
04207     return (objval < objlim) ; }
04208 
04209 
04216 bool ODSI::isPrimalObjectiveLimitReached () const
04217 
04218 { double objlim ;
04219   double objval = getObjValue() ;
04220 
04221   getDblParam(OsiDualObjectiveLimit,objlim) ;
04222   objlim *= getObjSense() ;
04223 
04224   if (getObjSense() > 0)
04225     return (objval < objlim) ;
04226   else
04227     return (objval > objlim) ; }
04228 
04229 
04235 vector<double*> ODSI::getDualRays (int) const
04236 
04237 { throw CoinError("Unimplemented method.",
04238                   "getDualRays","OsiDylpSolverInterface") ;
04239 
04240   return (vector<double*>(0)) ; }
04241 
04242 
04248 vector<double*> ODSI::getPrimalRays (int) const
04249 
04250 { throw CoinError("Unimplemented method.",
04251                   "getPrimalRays","OsiDylpSolverInterface") ;
04252 
04253   return (vector<double*>(0)) ; }
04254 
04255 
04260 void ODSI::branchAndBound ()
04261 
04262 { throw CoinError("Unimplemented method.",
04263                   "branchAndBound","OsiDylpSolverInterface") ;
04264 
04265   return ; }
04266 
04267 
04269 
04270 
04271 
04298 
04305 CoinWarmStart *ODSI::getEmptyWarmStart () const
04306 { return (dynamic_cast<CoinWarmStart *>(new OsiDylpWarmStartBasis())) ; }
04307 
04314 CoinWarmStart* ODSI::getWarmStart () const
04315 
04316 /*
04317   This routine constructs an OsiDylpWarmStartBasis structure from the basis
04318   returned by dylp.
04319 
04320   Dylp takes the atttitude that in so far as it is possible, logicals should
04321   be invisible outside the solver. The status of nonbasic logicals is not
04322   reported, nor does dylp expect to receive it. For completeness, however,
04323   getWarmStart will synthesize status information for nonbasic logicals.
04324 */
04325 
04326 { int i,j,k ;
04327   flags statj ;
04328 
04329 /*
04330   If we have an active basis, return a clone.
04331 */
04332   if (activeBasis) { return (activeBasis->clone()) ; }
04333 /*
04334   Create an empty ODWSB object. If no solution exists, we can return
04335   immediately.
04336 */
04337   OsiDylpWarmStartBasis *wsb = new OsiDylpWarmStartBasis ;
04338   assert(wsb) ;
04339   if (!lpprob) return (wsb) ;
04340 /*
04341   Size the ODWSB object. setSize initialises all status entries to isFree.
04342   Then grab pointers to the status vectors and the dylp basis vector.
04343 */
04344   wsb->setSize(consys->varcnt,consys->concnt) ;
04345 
04346   char *const strucStatus = wsb->getStructuralStatus() ;
04347   char *const artifStatus = wsb->getArtificialStatus() ;
04348   char *const conStatus = wsb->getConstraintStatus() ;
04349   basis_struct *basis = lpprob->basis ;
04350 
04351   if (lpprob->lpret == lpOPTIMAL)
04352     wsb->setPhase(dyPRIMAL2) ;
04353   else
04354     wsb->setPhase(dyPRIMAL1) ;
04355 /*
04356   Walk the basis and mark the active constraints and basic variables. Basic
04357   logical variables are entered as the negative of the constraint index.
04358 */
04359   for (k = 1 ; k <= basis->len ; k++)
04360   { i = inv(basis->el[k].cndx) ; 
04361     setStatus(conStatus,i,CoinWarmStartBasis::atLowerBound) ;
04362     j = basis->el[k].vndx ;
04363     if (j < 0)
04364     { j = inv(-j) ;
04365       setStatus(artifStatus,j,CoinWarmStartBasis::basic) ; }
04366     else
04367     { j = inv(j) ;
04368       setStatus(strucStatus,j,CoinWarmStartBasis::basic) ; } }
04369 /*
04370   Next, scan the conStatus array. For each inactive (loose => isFree)
04371   constraint, indicate that the logical is basic. For active (tight =>
04372   atLowerBound) constraints, if the corresponding logical isn't already
04373   marked as basic, use the value of the dual to select one of atLowerBound
04374   (negative dual) or (for range constraints) atUpperBound (positive dual).
04375 */
04376   const double *y = getRowPrice() ;
04377   for (i = 0 ; i < consys->concnt ; i++)
04378   { if (getStatus(conStatus,i) == CoinWarmStartBasis::isFree)
04379     { setStatus(artifStatus,i,CoinWarmStartBasis::basic) ; }
04380     else
04381     if (getStatus(artifStatus,i) == CoinWarmStartBasis::isFree)
04382     { if (y[i] > 0)
04383       { setStatus(artifStatus,i,CoinWarmStartBasis::atUpperBound) ; }
04384       else
04385       { setStatus(artifStatus,i,CoinWarmStartBasis::atLowerBound) ; } } }
04386 /*
04387   Now scan the status vector and record the status of nonbasic structural
04388   variables. Some information is lost here --- CoinWarmStartBasis::Status
04389   doesn't encode NBFX.
04390 */
04391   for (j = 1 ; j <= consys->varcnt ; j++)
04392   { statj = lpprob->status[j] ;
04393     if (((int) statj) > 0)
04394     { switch (statj)
04395       { case vstatNBLB:
04396         case vstatNBFX:
04397         { setStatus(strucStatus,inv(j), CoinWarmStartBasis::atLowerBound) ;
04398           break ; }
04399         case vstatNBUB:
04400         { setStatus(strucStatus,inv(j), CoinWarmStartBasis::atUpperBound) ;
04401           break ; }
04402         case vstatNBFR:
04403         { setStatus(strucStatus,inv(j), CoinWarmStartBasis::isFree) ;
04404           break ; }
04405         default:
04406         { delete wsb ;
04407           wsb = 0 ; } } } }
04408 
04409   return (wsb) ; }
04410 
04411 
04420 bool ODSI::setWarmStart (const CoinWarmStart *ws)
04421 
04422 { int i,j,k ;
04423   CoinWarmStartBasis::Status osi_statlogi,osi_statconi,osi_statvarj ;
04424 
04425 /*
04426   Use a dynamic cast to make sure we have an OsiDylpWarmStartBasis. Then check
04427   for an empty basis.
04428 */
04429   const OsiDylpWarmStartBasis *wsb =
04430                         dynamic_cast<const OsiDylpWarmStartBasis *>(ws) ;
04431   if (!wsb)
04432   { handler_->message(ODSI_NOTODWSB,messages_) ;
04433     return (false) ; }
04434   int varcnt = wsb->getNumStructural() ;
04435   int concnt = wsb->getNumArtificial() ;
04436   if (!(varcnt > 0 && concnt > 0))
04437   { handler_->message(ODSI_EMPTYODWSB,messages_) ;
04438     return (false) ; }
04439 /*
04440   Do we have an lpprob structure yet? If not, construct one.
04441 */
04442   assert(consys && consys->vlb && consys->vub) ;
04443   if (!lpprob) construct_lpprob() ;
04444   assert(resolveOptions) ;
04445 
04446 /*
04447   Extract the info in the warm start object --- size and status vectors.  The
04448   number of variables and constraints in the warm start object should match
04449   the full size of the constraint system. Note that getWarmStart can create
04450   an empty ODWSB object (see comments with getWarmStart).
04451 
04452   Create a dylp basis_struct and status vector of sufficient size to hold the
04453   information in the OsiDylpWarmStartBasis. This space may well be freed or
04454   realloc'd by dylp, so use standard calloc to acquire it.  We'll only use as
04455   much of the basis as is needed for the active constraints.
04456 */
04457   if (!(varcnt == getNumCols() && concnt == getNumRows()))
04458   { handler_->message(ODSI_ODWSBBADSIZE,messages_) <<
04459       concnt << varcnt << getNumRows() << getNumCols() ;
04460     return (false) ; }
04461 
04462   const char *const strucStatus = wsb->getStructuralStatus() ;
04463   const char *const artifStatus = wsb->getArtificialStatus() ;
04464   const char *const conStatus = wsb->getConstraintStatus() ;
04465 
04466   flags *status = new flags[idx(varcnt)] ;
04467   basis_struct basis ;
04468   basis.el = new basisel_struct[idx(concnt)] ;
04469 /*
04470   We never use these entries, but we need to initialise them to squash a
04471   `read from uninitialised memory' error during block copies.
04472 */
04473   basis.el[0].cndx = 0 ;
04474   basis.el[0].vndx = 0 ;
04475   status[0] = 0 ;
04476 /*
04477   Walk the constraint status vector and build the set of active constraints.
04478 */
04479   int actcons = 0 ;
04480   for (i = 1 ; i <= concnt ; i++)
04481   { osi_statconi = getStatus(conStatus,inv(i)) ;
04482     if (osi_statconi == CoinWarmStartBasis::atLowerBound)
04483     { actcons++ ;
04484       basis.el[actcons].cndx = i ;
04485       basis.el[actcons].vndx = 0 ; } }
04486   basis.len = actcons ;
04487 /*
04488   Now walk the structural status vector. For each basic variable, drop it into
04489   a basis entry and note the position in the status vector. For each nonbasic
04490   variable, set the proper status flag. We need to check bounds to see if the
04491   variable should be fixed.
04492 */
04493   k = 0 ;
04494   for (j = 1 ; j <= varcnt ; j++)
04495   { osi_statvarj = getStatus(strucStatus,inv(j)) ;
04496     switch (osi_statvarj)
04497     { case CoinWarmStartBasis::basic:
04498       { k++ ;
04499         assert(k <= actcons) ;
04500         basis.el[k].vndx = j ;
04501         status[j] = (flags) (-k) ;
04502         break ; }
04503       case CoinWarmStartBasis::atLowerBound:
04504       { if (consys->vlb[j] == consys->vub[j])
04505         { status[j] = vstatNBFX ; }
04506         else
04507         { status[j] = vstatNBLB ; }
04508         break ; }
04509       case CoinWarmStartBasis::atUpperBound:
04510       { status[j] = vstatNBUB ;
04511         break ; }
04512       case CoinWarmStartBasis::isFree:
04513       { status[j] = vstatNBFR ;
04514         break ; } } }
04515 /*
04516   Now we need to finish out the basis by adding the basic logicals.  The
04517   convention is to represent this with the negative of the index of the
04518   constraint which spawns the logical. Note that we do this only if the
04519   constraint is active. When running in fullsys mode, this is the common
04520   case. If we're running dynamic simplex, then all we're picking up here
04521   is the occasional logical that's basic at bound.
04522 */
04523   for (i = 1 ; i <= concnt ; i++)
04524   { osi_statlogi = getStatus(artifStatus,inv(i)) ;
04525     osi_statconi = getStatus(conStatus,inv(i)) ;
04526     if (osi_statlogi == CoinWarmStartBasis::basic &&
04527         osi_statconi == CoinWarmStartBasis::atLowerBound)
04528     { k++ ;
04529       assert(k <= actcons) ;
04530       basis.el[k].vndx = -i ; } }
04531 /*
04532   Now install the new basis in the lpprob_struct. If the present allocated
04533   capacity is sufficient, we can just copy over the existing information. If
04534   the capacity is insufficient, we'll free the existing space and allocate
04535   new. There's also the possibility that this WarmStartBasis came from some
04536   other object, and there are no vectors here at all. Because dylp relies on
04537   lpprob->colsze and lpprob->rowsze for the allocated capacity of actvars, x,
04538   and y, we need to reallocate them too.
04539 */
04540   if (lpprob->colsze < varcnt)
04541   { if (lpprob->status)
04542     { FREE(lpprob->status) ;
04543       lpprob->status = 0 ; }
04544     if (lpprob->actvars)
04545     { lpprob->actvars =
04546         (bool *) REALLOC(lpprob->actvars,idx(varcnt)*sizeof(bool)) ; }
04547     lpprob->colsze = varcnt ; }
04548   if (!lpprob->status)
04549   { lpprob->status = (flags *) CALLOC(idx(lpprob->colsze),sizeof(flags)) ; }
04550   if (!lpprob->actvars)
04551   { lpprob->actvars = (bool *) CALLOC(idx(lpprob->colsze),sizeof(bool)) ; }
04552 
04553   if (lpprob->rowsze < actcons)
04554   { if (lpprob->x)
04555     { lpprob->x =
04556         (double *) REALLOC(lpprob->x,idx(actcons)*sizeof(double)) ; }
04557     if (lpprob->y)
04558     { lpprob->y =
04559         (double *) REALLOC(lpprob->y,idx(actcons)*sizeof(double)) ; }
04560     if (lpprob->basis && lpprob->basis->el)
04561     { FREE(lpprob->basis->el) ;
04562       lpprob->basis->el = 0 ; }
04563     lpprob->rowsze = actcons ; }
04564   if (!lpprob->x)
04565   { lpprob->x = (double *) CALLOC(idx(lpprob->rowsze),sizeof(double)) ; }
04566   if (!lpprob->y)
04567   { lpprob->y = (double *) CALLOC(idx(lpprob->rowsze),sizeof(double)) ; }
04568   if (!lpprob->basis)
04569   { lpprob->basis =  (basis_struct *) CALLOC(1,sizeof(basis_struct)) ; }
04570   if (!lpprob->basis->el)
04571   { lpprob->basis->el =
04572       (basisel_struct *) CALLOC(idx(lpprob->rowsze),sizeof(basisel_struct)) ; }
04573 /*
04574   Whew. The actual copy is dead easy.
04575 */
04576   copy_basis(&basis,lpprob->basis) ;
04577   COPY_VEC(flags,status,lpprob->status,idx(varcnt)) ;
04578   delete[] basis.el ;
04579   delete[] status ;
04580 /*
04581   And we're done. The new status and basis are installed in lpprob, and the
04582   x, y, and actvars arrays have been resized if needed. Set the phase, signal
04583   a warm start, and then we're done.
04584 */
04585   lpprob->phase = wsb->getPhase() ;
04586   resolveOptions->forcecold = false ;
04587   resolveOptions->forcewarm = true ;
04588 /*
04589   One last thing --- make a copy of wsb to be the active basis (that is, unless
04590   wsb is the active basis, and we're simply installing it in lpprob).
04591 */
04592   if (wsb != static_cast<const CoinWarmStart *>(activeBasis) )
04593   { delete activeBasis ;
04594     activeBasis = wsb->clone() ;
04595     activeIsModified = false ; }
04596   
04597   return (true) ; }
04598 
04599 
04600 void ODSI::resolve ()
04601 /*
04602   Grossly oversimplified, this routine calls dylp after making sure that the
04603   forcecold option is turned off.  But we do need to make sure the solver is
04604   ours to use, and there's some state to maintain.
04605 
04606   If we're reoptimising, then the basis should be ready and we should have
04607   warm start information. For our purposes here, that boils down to the
04608   presence of an activeBasis object (created by setWarmStart() or a recent call
04609   to the solver).
04610 
04611   Note that we don't actually force a warm start unless we install the active
04612   basis here. Similarly, setWarmStart will force a warm start. But if we have
04613   an unmodified active basis, dylp should be able to manage a hot start.
04614 */
04615 { assert(lpprob && lpprob->basis && lpprob->status && consys &&
04616          resolveOptions && tolerances && statistics) ;
04617 
04618   if (dylp_owner != 0 && dylp_owner != this) dylp_owner->detach_dylp() ;
04619 /*
04620   Is the basis package initialised?
04621 */
04622   if (basis_ready == false)
04623   { int count = static_cast<int>((1.5*getNumRows()) + 2*getNumCols()) ;
04624     dy_initbasis(count,initialSolveOptions->factor,0) ;
04625     basis_ready = true ; }
04626 /*
04627   We can hope that activeBasis is already installed in the lpprob, but there
04628   are several circumstances to trap for here:
04629     * The user has been playing with cuts since the last call to dylp, but
04630       kept within the rules for modifying the active basis. In this case
04631       activeIsModified will be true, and we need to install it.
04632     * The solver has been used by some other ODSI object since the last
04633       call by this object. In this case, we've just done a detach_dylp()
04634       and dylp_owner will be null. Again, we need to install activeBasis.
04635   If we have an active basis, install it. If that fails, remove activeBasis.
04636 */
04637   if (activeBasis && (activeIsModified == true || dylp_owner == 0))
04638   { if (setWarmStart(activeBasis) == false)
04639     { throw CoinError("Warm start failed --- invalid active basis.",
04640                       "resolve","OsiDylpSolverInterface") ; }
04641     delete activeBasis ;
04642     activeBasis = 0 ;
04643     activeIsModified = false ;
04644     resolveOptions->forcewarm = true ; }
04645 /*
04646   Choose options appropriate for reoptimising and go to it. Phase is not
04647   crucial here --- dylp will sort it out as it starts.
04648 */
04649   lpopts_struct lclopts = *resolveOptions ;
04650   lptols_struct lcltols = *tolerances ;
04651   dy_checkdefaults(consys,&lclopts,&lcltols) ;
04652   assert(lclopts.forcecold == false) ;
04653   if (isactive(local_logchn)) logchn = local_logchn ;
04654   gtxecho = resolve_gtxecho ;
04655   dyphase_enum phase = lpprob->phase ;
04656   if (!(phase == dyPRIMAL1 || phase == dyPRIMAL2 || phase == dyDUAL))
04657     lpprob->phase = dyINV ;
04658   lp_retval = dylp_dolp(lpprob,&lclopts,&lcltols,statistics) ;
04659   if (!(lp_retval == lpOPTIMAL || lp_retval == lpINFEAS ||
04660         lp_retval == lpUNBOUNDED))
04661   { throw CoinError("Call to dylp failed.",
04662                     "resolve","OsiDylpSolverInterface") ; }
04663 /*
04664   Trash the cached solution. This needs to happen regardless of how the lp
04665   turned out. It needs to be done ahead of getWarmStart, which will try to
04666   access reduced costs.
04667 */
04668   destruct_col_cache() ;
04669   destruct_row_cache() ;
04670 /*
04671   Tidy up. If all went well, indicate this object owns the solver, set the
04672   objective, and set the active basis. If we've failed, do the opposite.
04673   Note that we have to remove any current active basis first, or getWarmStart
04674   will hand it back to us.
04675 
04676   Any of lpOPTIMAL, lpINFEAS, or lpUNBOUNDED can (in theory) be hot started
04677   after allowable problem modifications, hence can be flagged lpctlDYVALID.
04678   dylp overloads lpprob->obj with the index of the unbounded variable when
04679   returning lpUNBOUNDED, so we need to fake the objective.
04680 */
04681   delete activeBasis ;
04682   activeBasis = 0 ;
04683   activeIsModified = false ;
04684   if (flgon(lpprob->ctlopts,lpctlDYVALID))
04685   { dylp_owner = this ;
04686     if (lpprob->lpret == lpUNBOUNDED)
04687     { _objval = -getObjSense()*getInfinity() ; }
04688     else
04689     { _objval = getObjSense()*lpprob->obj ; }
04690     activeBasis = this->getWarmStart() ;
04691     resolveOptions->forcewarm = false ; }
04692   else
04693   { dylp_owner = 0 ; }
04694   
04695   return ; }
04696 
04698 
04699 
04700 
04733 
04741 inline void ODSI::markHotStart ()
04742 { 
04743 /*
04744   If we're attempting this, then it should be true that this OSI object
04745   owns the solver, has successfully solved an lp, and has left dylp's data
04746   structures intact.
04747 */
04748   assert(dylp_owner == this) ;
04749   assert(lpprob && resolveOptions) ;
04750   assert(flgon(lpprob->ctlopts,lpctlDYVALID)) ;
04751 /*
04752   Turn off the forcecold and forcewarm options, allowing a hot start.
04753 */
04754   resolveOptions->forcecold = false ;
04755   resolveOptions->forcewarm = false ;
04756 /*
04757   Capture a warm start object, in case some other ODSI object uses the solver
04758   between hot starts by this ODSI object.
04759 */
04760   if (hotstart_fallback) delete hotstart_fallback ;
04761   hotstart_fallback = getWarmStart() ;
04762 
04763   return ; }
04764 
04772 void ODSI::solveFromHotStart ()
04773 
04774 { 
04775 /*
04776   If some other ODSI object has used the solver, then fall back to a warm
04777   start. Throw an error if there's no warm start object to fall back on.
04778   (The throw message lies a little, for the benefit of users who haven't
04779   checked the details of the code.)
04780 */
04781 
04782   if (dylp_owner != this)
04783   { if (hotstart_fallback && setWarmStart(hotstart_fallback))
04784     { resolve() ; }
04785     else
04786     { throw CoinError("Hot start failed --- invalid/missing hot start object.",
04787                       "solveFromHotStart","OsiDylpSolverInterface") ; } }
04788 /*
04789   If no other ODSI object has used the solver, all we need to do is
04790   make sure forcecold and forcewarm are off. The basis should be ready.
04791   Note that dylp does need to know what's changed: any of bounds, rhs &
04792   rhslow, or objective. The various routines that make these changes
04793   set the flags.
04794 */
04795   else
04796   { int tmp_iterlim = -1 ;
04797     int hotlim ;
04798 
04799     assert(lpprob && lpprob->basis && lpprob->status && basis_ready &&
04800            consys && resolveOptions && tolerances && statistics) ;
04801 
04802     if (isactive(local_logchn)) logchn = local_logchn ;
04803     gtxecho = resolve_gtxecho ;
04804 /*
04805   Setting the phase to dyPRIMAL1 is overly cautious, but the only practical
04806   solution (dylp expects the client to set this, but exposing this would
04807   violates the generic OSI interface). In any event, dylp will sort it out.
04808 */
04809     lpopts_struct lclopts = *resolveOptions ;
04810     lptols_struct lcltols = *tolerances ;
04811     dy_checkdefaults(consys,&lclopts,&lcltols) ;
04812     lpprob->phase = dyPRIMAL1 ;
04813     assert(lclopts.forcecold == false) ;
04814     lclopts.forcewarm = false ;
04815     getIntParam(OsiMaxNumIterationHotStart,hotlim) ;
04816     if (hotlim > 0)
04817     { tmp_iterlim = resolveOptions->iterlim ;
04818       resolveOptions->iterlim = (hotlim/3 > 0)?hotlim/3:1 ; }
04819 
04820     lp_retval = dylp_dolp(lpprob,&lclopts,&lcltols,statistics) ;
04821     if (!(lp_retval == lpOPTIMAL || lp_retval == lpINFEAS ||
04822           lp_retval == lpUNBOUNDED))
04823     { throw CoinError("Call to dylp failed.",
04824                       "solveFromHotStart","OsiDylpSolverInterface") ; }
04825 /*
04826   Trash the cached solution. This needs to happen regardless of how the lp
04827   turned out. It needs to be done ahead of getWarmStart, which will try to
04828   access reduced costs.
04829 */
04830     destruct_col_cache() ;
04831     destruct_row_cache() ;
04832 /*
04833   Tidy up. If all went well, indicate this object owns the solver, set the
04834   objective, and set the active basis. If we've failed, do the opposite.
04835   Note that we have to remove any current active basis first, or getWarmStart
04836   will hand it back to us.
04837 
04838   Any of lpOPTIMAL, lpINFEAS, or lpUNBOUNDED can (in theory) be hot started
04839   after allowable problem modifications, hence can be flagged lpctlDYVALID.
04840   dylp overloads lpprob->obj with the index of the unbounded variable when
04841   returning lpUNBOUNDED, so we need to fake the objective.
04842 */
04843     delete activeBasis ;
04844     activeBasis = 0 ;
04845     activeIsModified = false ;
04846     if (flgon(lpprob->ctlopts,lpctlDYVALID))
04847     { if (lpprob->lpret == lpUNBOUNDED)
04848       { _objval = -getObjSense()*getInfinity() ; }
04849       else
04850       { _objval = getObjSense()*lpprob->obj ; }
04851       activeBasis = this->getWarmStart() ; }
04852     else
04853     { dylp_owner = 0 ; }
04854     if (tmp_iterlim > 0) resolveOptions->iterlim = tmp_iterlim ; }
04855 
04856   return ; }
04857 
04858 
04859 inline void ODSI::unmarkHotStart ()
04860 /*
04861   Nothing to do here but to destroy the fall back warm start object.
04862 */
04863 
04864 { if (hotstart_fallback)
04865   { delete hotstart_fallback ;
04866     hotstart_fallback = 0 ; }
04867 
04868   return ; }
04869 
04871 
04872 
04873 
04876 
04897 void ODSI::activateRowCutDebugger (const char * modelName)
04898 
04899 { delete rowCutDebugger_ ;
04900 
04901   if (dylp_owner && dylp_owner->lpprob &&
04902       flgon(dylp_owner->lpprob->ctlopts,lpctlDYVALID))
04903   { CoinWarmStart *ws = dylp_owner->getWarmStart() ;
04904     ODSI *prev_owner = dylp_owner ;
04905     prev_owner->detach_dylp() ;
04906     rowCutDebugger_ = new OsiRowCutDebugger(*this,modelName) ;
04907     prev_owner->setWarmStart(ws) ;
04908     prev_owner->resolve() ;
04909     delete ws ; }
04910   else
04911   { rowCutDebugger_ = new OsiRowCutDebugger(*this,modelName) ; }
04912 
04913   return ; }
04914 
04916 
04917 
04918 
04921 
04933 void ODSI::dylp_controlfile (const char *name,
04934                              const bool silent, const bool mustexist)
04935 
04936 { if (name == 0 || *name == 0) return ;
04937   string mode = (mustexist)?"r":"q" ;
04938   cmdchn = openfile(const_cast<char *>(name),const_cast<char *>(mode.c_str())) ;
04939   if (!(cmdchn == IOID_INV || cmdchn == IOID_NOSTRM))
04940   { setmode (cmdchn, 'l') ;  
04941     main_lpopts = initialSolveOptions ;
04942     main_lptols = tolerances ;
04943     bool r = (process_cmds(silent) != 0) ;
04944     (void) closefile(cmdchn) ;
04945     assert(r == cmdOK) ;
04946 /*
04947   Copy user settings into resolveOptions, except for forcecold and fullsys.
04948 */
04949     lpopts_struct saveOptions = *resolveOptions ;
04950     memcpy(resolveOptions,initialSolveOptions,sizeof(lpopts_struct));
04951     resolveOptions->forcecold = saveOptions.forcecold ;
04952     resolveOptions->fullsys = saveOptions.fullsys ; }
04953 
04954   cmdchn = IOID_NOSTRM ;
04955 
04956   return ; }
04957   
04958 
04966 void ODSI::dylp_logfile (const char *name, bool echo)
04967 
04968 { if (name == 0 || *name == 0) return ;
04969 
04970   string log = make_filename(name,".mps",".log") ;
04971   local_logchn = openfile(const_cast<char *>(log.c_str()),
04972                           const_cast<char *>("w")) ;
04973   if (local_logchn == IOID_INV) local_logchn = IOID_NOSTRM ;
04974   initial_gtxecho = echo ;
04975   resolve_gtxecho = echo ; }
04976 
04978 
04979 #endif /* COIN_USE_DYLP */

Generated on Wed Dec 3 14:35:31 2003 for Osi by doxygen 1.3.5