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

SbbMain.cpp

00001 // copyright (C) 2002, International Business Machines
00002 // Corporation and others.  All Rights Reserved.
00003 #if defined(_MSC_VER)
00004 // Turn off compiler warning about long names
00005 #  pragma warning(disable:4786)
00006 #endif
00007 
00008 #include <cassert>
00009 #include <typeinfo>
00010 #include <cstdio>
00011 #include <cmath>
00012 #include <cfloat>
00013 #include <string>
00014 #include <iostream>
00015 
00016 #define SBBVERSION "0.60"
00017 
00018 #include "CoinMpsIO.hpp"
00019 #include "CoinPackedMatrix.hpp"
00020 #include "CoinPackedVector.hpp"
00021 #include "CoinWarmStartBasis.hpp"
00022 #include "CoinTime.hpp"
00023 
00024 #include "OsiSolverInterface.hpp"
00025 #include "OsiCuts.hpp"
00026 #include "OsiRowCut.hpp"
00027 #include "OsiColCut.hpp"
00028 
00029 #include "CglCutGenerator.hpp"
00030 #include "CglGomory.hpp"
00031 #include "CglProbing.hpp"
00032 #include "CglKnapsackCover.hpp"
00033 #include "CglOddHole.hpp"
00034 
00035 #include "SbbModel.hpp"
00036 #include "SbbHeuristic.hpp"
00037 #include "SbbCompareBase.hpp"
00038 #include  "SbbParam.hpp"
00039 
00040 #ifdef COIN_USE_CLP
00041 #include "OsiClpSolverInterface.hpp"
00042 #endif
00043 #ifdef COIN_USE_DYLP
00044 #include "OsiDylpSolverInterface.hpp"
00045 #endif
00046 
00047 
00048 
00049 
00050 /* Before first solution do depth first,
00051    then it is computed to hit first solution less 2%
00052 */
00053 class SbbCompareUser  : public SbbCompareBase {
00054 public:
00055   // Weight for each infeasibility
00056   double weight_;
00057   // Number of solutions
00058   int numberSolutions_;
00059   // Default Constructor 
00060   SbbCompareUser () : weight_(-1.0), numberSolutions_(0) {test_=this;};
00061 
00062   ~SbbCompareUser() {};
00063 
00064   /* 
00065      Return true if y better than x
00066      Node y is better than node x if y has fewer unsatisfied (greater depth on tie) or
00067      after solution weighted value of y is less than weighted value of x
00068   */
00069   virtual bool test (SbbNode * x, SbbNode * y) {
00070     if (weight_<0.0) {
00071       // before solution
00072       /* printf("x %d %d %g, y %d %d %g\n",
00073              x->numberUnsatisfied(),x->depth(),x->objectiveValue(),
00074              y->numberUnsatisfied(),y->depth(),y->objectiveValue()); */
00075       if (x->numberUnsatisfied() > y->numberUnsatisfied())
00076         return true;
00077       else if (x->numberUnsatisfied() < y->numberUnsatisfied())
00078         return false;
00079       else
00080         return x->depth() < y->depth();
00081     } else {
00082       // after solution
00083       return x->objectiveValue()+ weight_*x->numberUnsatisfied() > 
00084         y->objectiveValue() + weight_*y->numberUnsatisfied();
00085     }
00086   }
00087   // This allows method to change behavior as it is called
00088   // after each solution
00089   virtual void newSolution(SbbModel * model,
00090                            double objectiveAtContinuous,
00091                            int numberInfeasibilitiesAtContinuous) 
00092   {
00093     if (model->getSolutionCount()==model->getNumberHeuristicSolutions())
00094       return; // solution was got by rounding
00095     // set to get close to this solution
00096     double costPerInteger = 
00097       (model->getObjValue()-objectiveAtContinuous)/
00098       ((double) numberInfeasibilitiesAtContinuous);
00099     weight_ = 0.98*costPerInteger;
00100     numberSolutions_++;
00101     if (numberSolutions_>5)
00102       weight_ =0.0; // this searches on objective
00103   }
00104   // This allows method to change behavior 
00105   virtual void every1000Nodes(SbbModel * model, int numberNodes)
00106   {
00107     if (numberNodes>10000)
00108       weight_ =0.0; // this searches on objective
00109   }
00110 };
00111 
00112 
00113 #define MAXPARAMETERS 100
00114 
00115 namespace {
00116 
00117 void establishParams (int &numberParameters, SbbParam *const parameters)
00118 /*
00119   Subroutine to establish the sbb parameter array. See the description of
00120   class SbbParam for details. Pulled from main() for clarity. 
00121 */
00122 { numberParameters = 0 ;
00123 
00124   parameters[numberParameters++]=
00125       SbbParam("?","For help",GENERALQUERY);
00126   parameters[numberParameters++]=
00127       SbbParam("dualT!olerance",
00128                "For an optimal solution no dual infeasibility may "
00129                "exceed this value",
00130                1.0e-20,1.0e12,DUALTOLERANCE);
00131   parameters[numberParameters++]=
00132       SbbParam("primalT!olerance",
00133                "For an optimal solution no primal infeasibility may "
00134                " exceed this value",
00135               1.0e-20,1.0e12,PRIMALTOLERANCE);
00136     parameters[numberParameters++]=
00137       SbbParam("inf!easibilityWeight","Each integer infeasibility is expected \
00138 to cost this much",
00139               0.0,1.0e20,INFEASIBILITYWEIGHT);
00140     parameters[numberParameters++]=
00141       SbbParam("integerT!olerance","For an optimal solution \
00142 no integer variable may be this away from an integer value",
00143               1.0e-20,0.5,INTEGERTOLERANCE);
00144     parameters[numberParameters++]=
00145       SbbParam("inc!rement","A valid solution must be at least this \
00146 much better than last integer solution",
00147               -1.0e20,1.0e20,INCREMENT);
00148     parameters[numberParameters++]=
00149       SbbParam("allow!ableGap","Stop when gap between best possible and \
00150 best less than this",
00151               0.0,1.0e20,ALLOWABLEGAP);
00152     parameters[numberParameters++]=
00153       SbbParam("ratio!Gap","Stop when gap between best possible and \
00154 best less than this fraction of continuous optimum",
00155               0.0,1.0e20,GAPRATIO);
00156     parameters[numberParameters++]=
00157       SbbParam("fix!OnDj","Try heuristic based on fixing variables with \
00158 reduced costs greater than this",
00159               -1.0e20,1.0e20,DJFIX);
00160     parameters[numberParameters++]=
00161       SbbParam("tighten!Factor","Tighten bounds using this times largest \
00162 activity at continuous solution",
00163               1.0,1.0e20,TIGHTENFACTOR);
00164     parameters[numberParameters++]=
00165       SbbParam("log!Level","Level of detail in BAB output",
00166               0,63,LOGLEVEL);
00167     parameters[numberParameters++]=
00168       SbbParam("slog!Level","Level of detail in Solver output",
00169               0,63,SOLVERLOGLEVEL);
00170     parameters[numberParameters++]=
00171       SbbParam("maxN!odes","Maximum number of nodes to do",
00172               1,999999,MAXNODES);
00173     parameters[numberParameters++]=
00174       SbbParam("strong!Branching","Number of variables to look at in strong branching",
00175               0,999999,STRONGBRANCHING);
00176     parameters[numberParameters++]=
00177       SbbParam("direction","Minimize or Maximize",
00178               "min!imize",DIRECTION);
00179     parameters[numberParameters-1].append("max!imize");
00180     parameters[numberParameters++]=
00181       SbbParam("error!sAllowed","Whether to allow import errors",
00182               "off",ERRORSALLOWED);
00183     parameters[numberParameters-1].append("on");
00184     parameters[numberParameters++]=
00185       SbbParam("gomory!Cuts","Whether to use Gomory cuts",
00186               "off",GOMORYCUTS);
00187     parameters[numberParameters-1].append("on");
00188     parameters[numberParameters++]=
00189       SbbParam("probing!Cuts","Whether to use Probing cuts",
00190               "off",PROBINGCUTS);
00191     parameters[numberParameters-1].append("on");
00192     parameters[numberParameters++]=
00193       SbbParam("knapsack!Cuts","Whether to use Knapsack cuts",
00194               "off",KNAPSACKCUTS);
00195     parameters[numberParameters-1].append("on");
00196     parameters[numberParameters++]=
00197       SbbParam("oddhole!Cuts","Whether to use Oddhole cuts",
00198               "off",ODDHOLECUTS);
00199     parameters[numberParameters-1].append("on");
00200     parameters[numberParameters++]=
00201       SbbParam("round!ingHeuristic","Whether to use Rounding heuristic",
00202               "off",ROUNDING);
00203     parameters[numberParameters-1].append("on");
00204     parameters[numberParameters++]=
00205       SbbParam("keepN!ames","Whether to keep names from import",
00206               "on",KEEPNAMES);
00207     parameters[numberParameters-1].append("off");
00208     parameters[numberParameters++]=
00209       SbbParam("scaling","Whether to do scaling",
00210               "on",SCALING);
00211     parameters[numberParameters-1].append("off");
00212     parameters[numberParameters++]=
00213       SbbParam("directory","Set Default import directory",
00214               DIRECTORY);
00215     parameters[numberParameters++]=
00216       SbbParam("solver!","Set the solver used by sbb",
00217                SOLVER) ;
00218     parameters[numberParameters++]=
00219       SbbParam("import","Import model from mps file",
00220               IMPORT);
00221     parameters[numberParameters++]=
00222       SbbParam("export","Export model as mps file",
00223               EXPORT);
00224     parameters[numberParameters++]=
00225       SbbParam("save!Model","Save model to binary file",
00226               SAVE);
00227     parameters[numberParameters++]=
00228       SbbParam("restore!Model","Restore model from binary file",
00229               RESTORE);
00230     parameters[numberParameters++]=
00231       SbbParam("presolve","Whether to use integer presolve - be careful",
00232               "off",PRESOLVE);
00233     parameters[numberParameters-1].append("on");
00234     parameters[numberParameters++]=
00235       SbbParam("initialS!olve","Solve to continuous",
00236               SOLVECONTINUOUS);
00237     parameters[numberParameters++]=
00238       SbbParam("branch!AndBound","Do Branch and Bound",
00239               BAB);
00240     parameters[numberParameters++]=
00241       SbbParam("sol!ution","Prints solution to file",
00242               SOLUTION);
00243     parameters[numberParameters++]=
00244       SbbParam("max!imize","Set optimization direction to maximize",
00245               MAXIMIZE);
00246     parameters[numberParameters++]=
00247       SbbParam("min!imize","Set optimization direction to minimize",
00248               MINIMIZE);
00249     parameters[numberParameters++] =
00250       SbbParam("time!Limit","Set a time limit for solving this problem",
00251               1.0,(double)(60*60*24*365*10),TIMELIMIT) ;
00252     parameters[numberParameters++]=
00253       SbbParam("exit","Stops sbb execution",
00254               EXIT);
00255     parameters[numberParameters++]=
00256       SbbParam("stop","Stops sbb execution",
00257               EXIT);
00258     parameters[numberParameters++]=
00259       SbbParam("quit","Stops sbb execution",
00260               EXIT);
00261     parameters[numberParameters++]=
00262       SbbParam("-","From stdin",
00263               STDIN);
00264     parameters[numberParameters++]=
00265       SbbParam("stdin","From stdin",
00266               STDIN);
00267     parameters[numberParameters++]=
00268       SbbParam("unitTest","Do unit test",
00269               UNITTEST);
00270     parameters[numberParameters++]=
00271       SbbParam("miplib","Do some of miplib test set",
00272               MIPLIB);
00273     parameters[numberParameters++]=
00274       SbbParam("ver!sion","Print out version",
00275               VERSION);
00276 
00277     assert(numberParameters<MAXPARAMETERS);
00278 
00279   return ; }
00280 
00281 #ifdef READLINE     
00282 #include <readline/readline.h>
00283 #include <readline/history.h>
00284 #endif
00285 
00286 // Returns next valid field
00287 
00288 int read_mode=1;
00289 char line[1000];
00290 char * where=NULL;
00291 
00292 std::string
00293 nextField()
00294 {
00295   std::string field;
00296   if (!where) {
00297     // need new line
00298 #ifdef READLINE     
00299     // Get a line from the user. 
00300     where = readline ("Sbb:");
00301      
00302     // If the line has any text in it, save it on the history.
00303     if (where) {
00304       if ( *where)
00305         add_history (where);
00306       strcpy(line,where);
00307     }
00308 #else
00309     fprintf(stdout,"Sbb:");
00310     fflush(stdout);
00311     where = fgets(line,1000,stdin);
00312 #endif
00313     if (!where)
00314       return field; // EOF
00315     where = line;
00316     // clean image
00317     char * lastNonBlank = line-1;
00318     while ( *where != '\0' ) {
00319       if ( *where != '\t' && *where < ' ' ) {
00320         break;
00321       } else if ( *where != '\t' && *where != ' ') {
00322         lastNonBlank = where;
00323       }
00324       where++;
00325     }
00326     where=line;
00327     *(lastNonBlank+1)='\0';
00328   }
00329   // munch white space
00330   while(*where==' '||*where=='\t')
00331     where++;
00332   char * saveWhere = where;
00333   while (*where!=' '&&*where!='\t'&&*where!='\0')
00334     where++;
00335   if (where!=saveWhere) {
00336     char save = *where;
00337     *where='\0';
00338     //convert to string
00339     field=saveWhere;
00340     *where=save;
00341   } else {
00342     where=NULL;
00343     field="EOL";
00344   }
00345   return field;
00346 }
00347 
00348 std::string
00349 getCommand(int argc, const char *argv[])
00350 {
00351   std::string field="EOL";
00352   while (field=="EOL") {
00353     if (read_mode>0) {
00354       if (read_mode<argc) {
00355         field = argv[read_mode++];
00356         if (field=="-") {
00357           std::cout<<"Switching to line mode"<<std::endl;
00358           read_mode=-1;
00359           field=nextField();
00360         } else if (field[0]!='-') {
00361           if (read_mode!=2) {
00362             std::cout<<"skipping non-command "<<field<<std::endl;
00363             field="EOL"; // skip
00364           } else {
00365             // special dispensation - taken as -import name
00366             read_mode--;
00367             field="import";
00368           }
00369         } else {
00370           if (field!="--") {
00371             // take off -
00372             field = field.substr(1);
00373           } else {
00374             // special dispensation - taken as -import --
00375             read_mode--;
00376             field="import";
00377           }
00378         }
00379       } else {
00380         field="";
00381       }
00382     } else {
00383       field=nextField();
00384     }
00385   }
00386   //std::cout<<field<<std::endl;
00387   return field;
00388 }
00389 std::string
00390 getString(int argc, const char *argv[])
00391 {
00392   std::string field="EOL";
00393   if (read_mode>0) {
00394     if (read_mode<argc) {
00395       if (argv[read_mode][0]!='-') { 
00396         field = argv[read_mode++];
00397       } else if (!strcmp(argv[read_mode],"--")) {
00398         field = argv[read_mode++];
00399         // -- means import from stdin
00400         field = "-";
00401       }
00402     }
00403   } else {
00404     field=nextField();
00405   }
00406   //std::cout<<field<<std::endl;
00407   return field;
00408 }
00409 
00410 // valid = 0 okay, 1 bad, 2 not there
00411 int
00412 getIntField(int argc, const char *argv[],int * valid)
00413 {
00414   std::string field="EOL";
00415   if (read_mode>0) {
00416     if (read_mode<argc) {
00417       // may be negative value so do not check for -
00418       field = argv[read_mode++];
00419     }
00420   } else {
00421     field=nextField();
00422   }
00423   int value=0;
00424   //std::cout<<field<<std::endl;
00425   if (field!="EOL") {
00426     // how do I check valid
00427     value =  atoi(field.c_str());
00428     *valid=0;
00429   } else {
00430     *valid=2;
00431   }
00432   return value;
00433 }
00434 
00435 
00436 // valid = 0 okay, 1 bad, 2 not there
00437 double
00438 getDoubleField(int argc, const char *argv[],int * valid)
00439 {
00440   std::string field="EOL";
00441   if (read_mode>0) {
00442     if (read_mode<argc) {
00443       // may be negative value so do not check for -
00444       field = argv[read_mode++];
00445     }
00446   } else {
00447     field=nextField();
00448   }
00449   double value=0.0;
00450   //std::cout<<field<<std::endl;
00451   if (field!="EOL") {
00452     // how do I check valid
00453     value = atof(field.c_str());
00454     *valid=0;
00455   } else {
00456     *valid=2;
00457   }
00458   return value;
00459 }
00460 
00462 
00463 double totalTime=0.0;
00464 
00465 }       /* end unnamed namespace */
00466 
00467 
00468 int main (int argc, const char *argv[])
00469 {
00470   // next {} is just to make sure all memory should be freed - for debug
00471   {
00472 /*
00473   Create a vector of solver prototypes and establish a default solver. After
00474   this the code is solver independent.
00475 
00476   Creating multiple solvers is moderately expensive. If you don't want to
00477   make use of this feature, best to define just one. The businesss with
00478   SBB_DEFAULT_SOLVER will select the first available solver as the default,
00479   unless overridden at compile time.
00480 */
00481     typedef std::map<std::string,OsiSolverInterface*> solverMap_t ;
00482     typedef solverMap_t::const_iterator solverMapIter_t ;
00483 
00484     solverMap_t solvers ;
00485 
00486 #   ifdef COIN_USE_CLP
00487 #     ifndef SBB_DEFAULT_SOLVER
00488 #       define SBB_DEFAULT_SOLVER "clp"
00489 #     endif
00490       solvers["clp"] = new OsiClpSolverInterface ;
00491 #   else
00492       solvers["clp"] = 0 ;
00493 #   endif
00494 #   ifdef COIN_USE_DYLP
00495 #     ifndef SBB_DEFAULT_SOLVER
00496 #       define SBB_DEFAULT_SOLVER "dylp"
00497 #     endif
00498       solvers["dylp"] = new OsiDylpSolverInterface  ;
00499 #   else
00500       solvers["dylp"] = 0 ;
00501 #   endif
00502 /*
00503   If we don't have a default solver, we're deeply confused.
00504 */
00505     OsiSolverInterface *dflt_solver = solvers[SBB_DEFAULT_SOLVER] ;
00506     if (dflt_solver)
00507     { std::cout << "Default solver is " << SBB_DEFAULT_SOLVER << std::endl ; }
00508     else
00509     { std::cerr << "No solvers! Aborting." << std::endl ;
00510       return (1) ; }
00511 /*
00512   For calculating run time.
00513 */
00514     double time1 = CoinCpuTime() ;
00515     double time2;
00516 /*
00517   Establish the command line interface: parameters, with associated info
00518   messages, ranges, defaults. See SbbParam for details. Scan the vector of
00519   solvers and add the names to the parameter object.
00520 */
00521     SbbParam parameters[MAXPARAMETERS];
00522     int numberParameters ;
00523     establishParams(numberParameters,parameters) ;
00524 
00525     { int iSolver = 0 ;
00526       for ( ; iSolver < numberParameters ; iSolver++)
00527       { int match = parameters[iSolver].matches("solver") ;
00528         if (match==1) break ; }
00529       for (solverMapIter_t solverIter = solvers.begin() ;
00530            solverIter != solvers.end() ;
00531            solverIter++)
00532       { if (solverIter->second)
00533           parameters[iSolver].append(solverIter->first) ; }
00534       int iKwd = parameters[iSolver].parameterOption(SBB_DEFAULT_SOLVER) ;
00535       parameters[iSolver].setCurrentOption(iKwd) ; }
00536 /*
00537   The rest of the default setup: establish a model, instantiate cut generators
00538   and heuristics, set various default values.
00539 */
00540     dflt_solver->messageHandler()->setLogLevel(0) ;
00541     SbbModel *model = new SbbModel(*dflt_solver) ;
00542     model->messageHandler()->setLogLevel(1);
00543     bool goodModel=false;
00544     
00545 // Set up likely cut generators and defaults
00546 
00547     CglGomory gomoryGen;
00548 
00549     CglProbing probingGen;
00550     probingGen.setUsingObjective(true);
00551     probingGen.setMaxPass(3);
00552     probingGen.setMaxProbe(100);
00553     probingGen.setMaxLook(50);
00554     probingGen.setRowCuts(3);
00555 
00556     CglKnapsackCover knapsackGen;
00557 
00558     CglOddHole oddholeGen;
00559     oddholeGen.setMinimumViolation(0.005);
00560     oddholeGen.setMinimumViolationPer(0.0002);
00561     oddholeGen.setMaximumEntries(100);
00562 
00563     bool useRounding=false;
00564    
00565     int allowImportErrors=0;
00566     int keepImportNames=1;      // not implemented
00567     int doScaling=1;
00568     int preSolve=0;
00569     double djFix=1.0e100;
00570     double gapRatio=1.0e100;
00571     double tightenFactor=0.0;
00572 
00573     std::string directory ="./";
00574     std::string field;
00575 /*
00576   The main command parsing loop.
00577 */
00578     // total number of commands read
00579     int numberGoodCommands=0;
00580     
00581     while (1) {
00582       // next command
00583       field=getCommand(argc,argv);
00584       
00585       // exit if null or similar
00586       if (!field.length()) {
00587         if (numberGoodCommands==1&&goodModel) {
00588           // we just had file name
00589           model->initialSolve();
00590           model->solver()->messageHandler()->setLogLevel(0);
00591           model->branchAndBound();
00592           time2 = CoinCpuTime();
00593           totalTime += time2-time1;
00594           std::cout<<"Result "<<model->getObjValue()<<
00595             " iterations "<<model->getIterationCount()<<
00596             " nodes "<<model->getNodeCount()<<
00597             " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
00598         } else if (!numberGoodCommands) {
00599           // let's give the sucker a hint
00600           std::cout
00601             <<"Sbb takes input from arguments ( - switches to stdin)"
00602             <<std::endl
00603             <<"Enter ? for list of commands or (-)unitTest or -miplib"
00604             <<" for tests"<<std::endl;
00605         }
00606         break;
00607       }
00608       
00609       // see if ? at end
00610       int numberQuery=0;
00611       if (field!="?") {
00612         int length = field.length();
00613         int i;
00614         for (i=length-1;i>0;i--) {
00615           if (field[i]=='?') 
00616             numberQuery++;
00617           else
00618             break;
00619         }
00620         field=field.substr(0,length-numberQuery);
00621       }
00622       // find out if valid command
00623       int iParam;
00624       int numberMatches=0;
00625       for ( iParam=0; iParam<numberParameters; iParam++ ) {
00626         int match = parameters[iParam].matches(field);
00627         if (match==1) {
00628           numberMatches = 1;
00629           break;
00630         } else {
00631           numberMatches += match>>1;
00632         }
00633       }
00634       if (iParam<numberParameters&&!numberQuery) {
00635         // found
00636         SbbParam found = parameters[iParam];
00637         SbbParameterType type = found.type();
00638         int valid;
00639         numberGoodCommands++;
00640         if (type==GENERALQUERY) {
00641           std::cout<<"In argument list keywords have leading - "
00642             ", -stdin or just - switches to stdin"<<std::endl;
00643           std::cout<<"One command per line (and no -)"<<std::endl;
00644           std::cout<<"abcd? gives list of possibilities, if only one + explanation"<<std::endl;
00645           std::cout<<"abcd?? adds explanation, if only one fuller help(LATER)"<<std::endl;
00646           std::cout<<"abcd without value (where expected) gives current value"<<std::endl;
00647           std::cout<<"abcd value or abcd = value sets value"<<std::endl;
00648           std::cout<<"Commands are:"<<std::endl;
00649           for ( iParam=0; iParam<numberParameters; iParam+=4 ) {
00650             int i;
00651             for (i=iParam;i<min(numberParameters,iParam+4);i++) 
00652               std::cout<<parameters[i].matchName()<<"  ";
00653             std::cout<<std::endl;
00654           }
00655         } else if (type<81) {
00656           // get next field as double
00657           double value = getDoubleField(argc,argv,&valid);
00658           if (!valid) {
00659             parameters[iParam].setDoubleParameter(*model,value);
00660           } else if (valid==1) {
00661             abort();
00662           } else {
00663             std::cout<<parameters[iParam].name()<<" has value "<<
00664               parameters[iParam].doubleParameter(*model)<<std::endl;
00665           }
00666         } else if (type<101) {
00667           // get next field as double for local use
00668           double value = getDoubleField(argc,argv,&valid);
00669           if (!valid) {
00670             if (!parameters[iParam].checkDoubleParameter(value)) {
00671               switch(type) {
00672               case DJFIX:
00673                 djFix=value;
00674                 preSolve=5;
00675                 break;
00676               case GAPRATIO:
00677                 gapRatio=value;
00678                 break;
00679               case TIGHTENFACTOR:
00680                 tightenFactor=value;
00681                 break;
00682               default:
00683                 abort();
00684               }
00685             }
00686           } else if (valid==1) {
00687             abort();
00688           } else {
00689             switch(type) {
00690             case DJFIX:
00691               value = djFix ;
00692               break;
00693             case GAPRATIO:
00694               value = gapRatio ;
00695               break;
00696             case TIGHTENFACTOR:
00697               value = tightenFactor ;
00698               break;
00699             default:
00700               abort();
00701             }
00702             std::cout << parameters[iParam].name() << " has value " <<
00703                          value << std::endl ;
00704           }
00705         } else if (type<201) {
00706           // get next field as int
00707           int value = getIntField(argc,argv,&valid);
00708           if (!valid) {
00709             parameters[iParam].setIntParameter(*model,value);
00710           } else if (valid==1) {
00711             abort();
00712           } else {
00713             std::cout<<parameters[iParam].name()<<" has value "<<
00714               parameters[iParam].intParameter(*model)<<std::endl;
00715           }
00716         } else if (type<301) {
00717           // one of several strings
00718           std::string value = getString(argc,argv);
00719           int action = parameters[iParam].parameterOption(value);
00720           if (action<0) {
00721             if (value!="EOL") {
00722               // no match
00723               parameters[iParam].printOptions();
00724             } else {
00725               // print current value
00726               std::cout<<parameters[iParam].name()<<" has value "<<
00727                 parameters[iParam].currentOption()<<std::endl;
00728             }
00729           } else {
00730             parameters[iParam].setCurrentOption(action);
00731             // for now hard wired
00732             switch (type) {
00733             case DIRECTION:
00734               if (action==0)
00735                 model->solver()->setObjSense(1);
00736               else
00737                 model->solver()->setObjSense(-1);
00738               break;
00739             case ERRORSALLOWED:
00740               allowImportErrors = action;
00741               break;
00742             case KEEPNAMES:
00743               keepImportNames = 1-action;
00744               break;
00745             case SCALING:
00746               doScaling = 1-action;
00747               break;
00748             case GOMORYCUTS:
00749               model->addCutGenerator(&gomoryGen,-1,"Gomory");
00750               break;
00751             case PROBINGCUTS:
00752               model->addCutGenerator(&probingGen,-1,"Probing");
00753               break;
00754             case KNAPSACKCUTS:
00755               model->addCutGenerator(&knapsackGen,-1,"Knapsack");
00756               break;
00757             case ODDHOLECUTS:
00758               model->addCutGenerator(&oddholeGen,-1,"OddHole");
00759               break;
00760             case ROUNDING:
00761               useRounding = action;
00762               break;
00763             case PRESOLVE:
00764               preSolve = action*5;
00765               break;
00766             case SOLVER:
00767             { OsiSolverInterface *newSolver = solvers[value]->clone() ;
00768               model->assignSolver(newSolver) ;
00769               break ; }
00770             default:
00771             { std::cerr << "Unrecognized action. Aborting." << std::endl ;
00772               abort(); }
00773             }
00774           }
00775         } else {
00776           // action
00777           if (type==EXIT)
00778             break; // stop all
00779           switch (type) {
00780           case SOLVECONTINUOUS:
00781             if (goodModel) {
00782               model->initialSolve();
00783               time2 = CoinCpuTime();
00784               totalTime += time2-time1;
00785               std::cout<<"Result "<<model->solver()->getObjValue()<<
00786                 " iterations "<<model->solver()->getIterationCount()<<
00787                 " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
00788               time1=time2;
00789             } else {
00790               std::cout<<"** Current model not valid"<<std::endl;
00791             }
00792             break;
00793 /*
00794   Run branch-and-cut. First set a few options -- node comparison, scaling. If
00795   the solver is Clp, consider running some presolve code (not yet converted
00796   this to generic OSI) with branch-and-cut. If presolve is disabled, or the
00797   solver is not Clp, simply run branch-and-cut. Print elapsed time at the end.
00798 */
00799           case BAB: // branchAndBound
00800           { if (goodModel)
00801             { SbbCompareUser compare; // Definition of node choice
00802               model->setNodeComparison(compare);
00803               OsiSolverInterface * solver = model->solver();
00804               if (!doScaling)
00805                 solver->setHintParam(OsiDoScale,false,OsiHintTry);
00806 #ifdef COIN_USE_CLP
00807               OsiClpSolverInterface * si =
00808                 dynamic_cast<OsiClpSolverInterface *>(solver) ;
00809               if (preSolve&&si != NULL) {
00810                 // get clp itself
00811                 ClpSimplex * modelC = si->getModelPtr();
00812                 if (si->messageHandler()->logLevel())
00813                   si->messageHandler()->setLogLevel(1);
00814                 assert (modelC->tightenPrimalBounds()==0);
00815                 model->initialSolve();
00816                 // bounds based on continuous
00817                 if (tightenFactor)
00818                   assert (modelC->tightenPrimalBounds(tightenFactor)==0);
00819                 if (gapRatio<1.0e100) {
00820                   double value = si->getObjValue();
00821                   double value2 = gapRatio*(1.0e-5+fabs(value));
00822                   model->setAllowableGap(value2);
00823                   std::cout<<"Continuous "<<value
00824                            <<", so allowable gap set to "<<value2<<std::endl;
00825                 }
00826                 if (djFix<1.0e20) {
00827                   // do some fixing
00828                   int numberColumns = modelC->numberColumns();
00829                   int i;
00830                   const char * type = modelC->integerInformation();
00831                   double * lower = modelC->columnLower();
00832                   double * upper = modelC->columnUpper();
00833                   double * solution = modelC->primalColumnSolution();
00834                   double * dj = modelC->dualColumnSolution();
00835                   for (i=0;i<numberColumns;i++) {
00836                     if (type[i]) {
00837                       double value = solution[i];
00838                       if (value<lower[i]+1.0e-5&&dj[i]>djFix) {
00839                         solution[i]=lower[i];
00840                         upper[i]=lower[i];
00841                       } else if (value>upper[i]-1.0e-5&&dj[i]<-djFix) {
00842                         solution[i]=upper[i];
00843                         lower[i]=upper[i];
00844                       }
00845                     }
00846                   }
00847                 }
00848                 {
00849                   // integer presolve
00850                   SbbModel * model2 = model->integerPresolve();
00851                   if (model2) {
00852                     // Do complete search
00853                     
00854                     SbbRounding heuristic1(*model2);
00855                     if (useRounding)
00856                       model2->addHeuristic(&heuristic1);
00857                     model2->branchAndBound();
00858                     // get back solution
00859                     model->originalModel(model2,false);
00860                   } else {
00861                     // infeasible
00862                     exit(1);
00863                   }
00864                 }
00865               } else
00866 #endif
00867               { if (model->solver()->messageHandler()->logLevel())
00868                   model->solver()->messageHandler()->setLogLevel(1) ;
00869                 model->initialSolve() ;
00870                 if (gapRatio < 1.0e100)
00871                 { double value = model->solver()->getObjValue() ;
00872                   double value2 = gapRatio*(1.0e-5+fabs(value)) ;
00873                   model->setAllowableGap(value2) ;
00874                   std::cout << "Continuous " << value
00875                             << ", so allowable gap set to "
00876                             << value2 << std::endl ; }
00877                 SbbRounding heuristic1(*model) ;
00878                 if (useRounding)
00879                   model->addHeuristic(&heuristic1) ;
00880                 model->branchAndBound() ; }
00881               if (model->bestSolution())
00882               { std::cout << "Optimal solution "
00883                           << model->solver()->getObjValue() << std::endl ; }
00884               else
00885               { std::cout << "No integer solution found." << std::endl ; }
00886                         
00887               time2 = CoinCpuTime() ;
00888               totalTime += time2-time1 ;
00889               std::cout << "Result " << model->solver()->getObjValue()
00890                         << " took " << time2-time1 << " seconds - total "
00891                         << totalTime << std::endl ;
00892               time1 = time2 ; }
00893             else
00894             { std::cout << "** Current model not valid" << std::endl ; }
00895             break ; }
00896           case IMPORT:
00897             {
00898               // get next field
00899               field = getString(argc,argv);
00900               std::string fileName;
00901               bool canOpen=false;
00902               if (field=="-") {
00903                 // stdin
00904                 canOpen=true;
00905                 fileName = "-";
00906               } else {
00907                 if (field[0]=='/'||field[0]=='~')
00908                   fileName = field;
00909                 else
00910                   fileName = directory+field;
00911                 FILE *fp=fopen(fileName.c_str(),"r");
00912                 if (fp) {
00913                   // can open - lets go for it
00914                   fclose(fp);
00915                   canOpen=true;
00916                 } else {
00917                   std::cout<<"Unable to open file "<<fileName<<std::endl;
00918                 }
00919               }
00920               if (canOpen) {
00921                 model->gutsOfDestructor();
00922                 int status =model->solver()->readMps(fileName.c_str(),"");
00923                 if (!status||(status>0&&allowImportErrors)) {
00924                   // I don't think there is any need for this but ..
00925                   //OsiWarmStartBasis allSlack;
00926                   goodModel=true;
00927                   //model->setBasis(allSlack);
00928                   time2 = CoinCpuTime();
00929                   totalTime += time2-time1;
00930                   time1=time2;
00931                 } else {
00932                   // errors
00933                   std::cout<<"There were "<<status<<
00934                     " errors on input"<<std::endl;
00935                 }
00936               }
00937             }
00938             break;
00939           case EXPORT:
00940             {
00941               // get next field
00942               field = getString(argc,argv);
00943               std::string fileName;
00944               bool canOpen=false;
00945               if (field[0]=='/'||field[0]=='~')
00946                 fileName = field;
00947               else
00948                 fileName = directory+field;
00949               FILE *fp=fopen(fileName.c_str(),"w");
00950               if (fp) {
00951                 // can open - lets go for it
00952                 fclose(fp);
00953                 canOpen=true;
00954               } else {
00955                 std::cout<<"Unable to open file "<<fileName<<std::endl;
00956               }
00957               if (canOpen) {
00958                 model->solver()->writeMps(fileName.c_str(),"");
00959                 time2 = CoinCpuTime();
00960                 totalTime += time2-time1;
00961                 time1=time2;
00962               }
00963             }
00964             break;
00965           case MAXIMIZE:
00966             model->solver()->setObjSense(-1);
00967             break;
00968           case MINIMIZE:
00969             model->solver()->setObjSense(1);
00970             break;
00971           case DIRECTORY:
00972           { directory = getString(argc,argv);
00973             if (directory[directory.length()-1] != '/')
00974               directory += '/' ;
00975             break ; }
00976           case STDIN:
00977             read_mode=-1;
00978             break;
00979           case VERSION:
00980             std::cout<<"Coin LP version "<<SBBVERSION
00981                      <<", build "<<__DATE__<<std::endl;
00982             break;
00983           case UNITTEST:
00984             {
00985               // okay so there is not a real unit test
00986 
00987               int status =model->solver()->readMps("../Mps/Sample/p0033.mps",
00988                                                    "");
00989               assert(!status);
00990               model->branchAndBound();
00991               model->solver()->resolve();
00992               std::cout<<"Optimal solution "<<model->solver()->getObjValue()<<std::endl;
00993               assert(fabs(model->solver()->getObjValue()-3089.0)<1.0e-5);
00994               fprintf(stderr,"Test was okay\n");
00995               status =model->solver()->readMps("../Mps/Sample/p0033.mps",
00996                                                    "");
00997               assert(!status);
00998               model->setCutoff(1.0e20);
00999               model->setMaximumSolutions(1);
01000               model->setSolutionCount(0);
01001               model->branchAndBound();
01002               model->solver()->resolve();
01003               std::cout<<"partial solution "<<model->solver()->getObjValue()<<std::endl;
01004               assert(model->solver()->getObjValue()>3090.0);
01005             }
01006             break;
01007           case MIPLIB:
01008             {
01009               int mainTest (int argc, const char *argv[]);
01010               // create fields for test
01011               const char * fields[3];
01012               int nFields=1;
01013               fields[0]="fake main for miplib";
01014               if (directory!="./") {
01015                 fields[1]=("-miplibDir="+directory).c_str();
01016                 nFields=2;
01017               }
01018               mainTest(nFields,fields);
01019             }
01020             break;
01021           case SOLUTION:
01022             if (goodModel) {
01023               // get next field
01024               field = getString(argc,argv);
01025               std::string fileName;
01026               FILE *fp=NULL;
01027               if (field=="-"||field=="EOL") {
01028                 // stdout
01029                 fp=stdout;
01030               } else {
01031                 if (field[0]=='/'||field[0]=='~')
01032                   fileName = field;
01033                 else
01034                   fileName = directory+field;
01035                 fp=fopen(fileName.c_str(),"w");
01036               }
01037               if (fp) {
01038                 // make fancy later on
01039                 int iRow;
01040                 int numberRows=model->solver()->getNumRows();
01041                 const double * dualRowSolution = model->getRowPrice();
01042                 const double * primalRowSolution =  model->getRowActivity();
01043                 for (iRow=0;iRow<numberRows;iRow++) {
01044                   fprintf(fp,"%7d ",iRow);
01045                   fprintf(fp,"%15.8g        %15.8g\n",primalRowSolution[iRow],
01046                           dualRowSolution[iRow]);
01047                 }
01048                 int iColumn;
01049                 int numberColumns=model->solver()->getNumCols();
01050                 const double * dualColumnSolution = 
01051                   model->getReducedCost();
01052                 const double * primalColumnSolution = 
01053                   model->getColSolution();
01054                 for (iColumn=0;iColumn<numberColumns;iColumn++) {
01055                   fprintf(fp,"%7d ",iColumn);
01056                   fprintf(fp,"%15.8g        %15.8g\n",
01057                           primalColumnSolution[iColumn],
01058                           dualColumnSolution[iColumn]);
01059                 }
01060                 if (fp!=stdout)
01061                   fclose(fp);
01062               } else {
01063                 std::cout<<"Unable to open file "<<fileName<<std::endl;
01064               }
01065             } else {
01066               std::cout<<"** Current model not valid"<<std::endl;
01067               
01068             }
01069             break;
01070           default:
01071             abort();
01072           }
01073         } 
01074       } else if (!numberMatches) {
01075         std::cout<<"No match for "<<field<<" - ? for list of commands"
01076                  <<std::endl;
01077       } else if (numberMatches==1) {
01078         if (!numberQuery) {
01079           std::cout<<"Short match for "<<field<<" possible completion:"
01080                    <<std::endl;
01081           for ( iParam=0; iParam<numberParameters; iParam++ ) {
01082             int match = parameters[iParam].matches(field);
01083             if (match) 
01084               std::cout<<parameters[iParam].matchName()<<std::endl;
01085           }
01086         } else if (numberQuery) {
01087           std::cout<<"Short match for "<<field<<" completion:"
01088                    <<std::endl;
01089           for ( iParam=0; iParam<numberParameters; iParam++ ) {
01090             int match = parameters[iParam].matches(field);
01091             if (match) {
01092               std::cout<<parameters[iParam].matchName()<<" : ";
01093               std::cout<<parameters[iParam].shortHelp()<<std::endl;
01094             }
01095           }
01096         }
01097       } else {
01098         if (!numberQuery) 
01099           std::cout<<"Multiple matches for "<<field<<" - possible completions:"
01100                    <<std::endl;
01101         else
01102           std::cout<<"Completions of "<<field<<":"<<std::endl;
01103         for ( iParam=0; iParam<numberParameters; iParam++ ) {
01104           int match = parameters[iParam].matches(field);
01105           if (match) {
01106             std::cout<<parameters[iParam].matchName();
01107             if (numberQuery>=2) 
01108               std::cout<<" : "<<parameters[iParam].shortHelp();
01109             std::cout<<std::endl;
01110           }
01111         }
01112       }
01113     }
01114 /*
01115   Final cleanup. Delete the model and the vector of available solvers.
01116 */
01117     delete model;
01118 
01119     for (solverMapIter_t solverIter = solvers.begin() ;
01120          solverIter != solvers.end() ;
01121          solverIter++)
01122     { if (solverIter->second) delete solverIter->second ; }
01123   }
01124   return 0;
01125 }    

Generated on Wed Dec 3 14:36:20 2003 for Sbb by doxygen 1.3.5