source: trunk/Test/CbcMain.cpp @ 246

Last change on this file since 246 was 246, checked in by forrest, 14 years ago

for HAS vs USE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.4 KB
Line 
1// copyright (C) 2002, International Business Machines
2// Corporation and others.  All Rights Reserved.
3#if defined(_MSC_VER)
4// Turn off compiler warning about long names
5#  pragma warning(disable:4786)
6#endif
7
8#include <cassert>
9#include <typeinfo>
10#include <cstdio>
11#include <cmath>
12#include <cfloat>
13#include <string>
14#include <iostream>
15
16#define CBCVERSION "1.00.00"
17
18#include "CoinMpsIO.hpp"
19#include "CoinPackedMatrix.hpp"
20#include "CoinPackedVector.hpp"
21#include "CoinWarmStartBasis.hpp"
22#include "CoinTime.hpp"
23#include "OsiSolverInterface.hpp"
24#include "OsiCuts.hpp"
25#include "OsiRowCut.hpp"
26#include "OsiColCut.hpp"
27
28#include "CglCutGenerator.hpp"
29#include "CglGomory.hpp"
30#include "CglProbing.hpp"
31#include "CglKnapsackCover.hpp"
32#include "CglOddHole.hpp"
33#include "CglClique.hpp"
34#include "CglFlowCover.hpp"
35#include "CglMixedIntegerRounding.hpp"
36#include "CglTwomir.hpp"
37#include "CglPreProcess.hpp"
38
39#include "CbcModel.hpp"
40#include "CbcTree.hpp"
41#include "CbcCutGenerator.hpp"
42#include "CbcHeuristic.hpp"
43#include "CbcCompareActual.hpp"
44#include  "CbcParam.hpp"
45
46#ifdef COIN_USE_CLP
47#include "OsiClpSolverInterface.hpp"
48#endif
49#ifdef COIN_USE_DYLP
50#include "OsiDylpSolverInterface.hpp"
51#endif
52#ifdef COIN_USE_OSL
53#include "OsiOslSolverInterface.hpp"
54#endif
55
56
57
58
59/* Before first solution do depth first,
60   then it is computed to hit first solution less 2%
61*/
62class CbcCompareUser  : public CbcCompareBase {
63public:
64  // Weight for each infeasibility
65  double weight_;
66  // Weight for each infeasibility - computed from solution
67  double saveWeight_;
68  // Number of solutions
69  int numberSolutions_;
70  // Tree size (at last check)
71  int treeSize_;
72  // Default Constructor
73  CbcCompareUser () : CbcCompareBase(),
74                      weight_(-1.0),saveWeight_(0.0),numberSolutions_(0),
75                      treeSize_(0)
76  { test_=this;};
77
78  // Copy constructor
79  CbcCompareUser ( const CbcCompareUser &rhs)
80    : CbcCompareBase(rhs)
81  {
82    weight_=rhs.weight_;
83    saveWeight_ = rhs.saveWeight_;
84    numberSolutions_=rhs.numberSolutions_;
85    treeSize_ = rhs.treeSize_;
86  };
87   
88  // Assignment operator
89  CbcCompareUser & operator=( const CbcCompareUser& rhs)
90  {
91    if (this!=&rhs) { 
92      CbcCompareBase::operator=(rhs);
93      weight_=rhs.weight_;
94      saveWeight_ = rhs.saveWeight_;
95      numberSolutions_=rhs.numberSolutions_;
96      treeSize_ = rhs.treeSize_;
97    }
98    return *this;
99  };
100
101  /// Clone
102  virtual CbcCompareBase * clone() const
103  { 
104    return new CbcCompareUser (*this);
105  };
106
107  ~CbcCompareUser() {};
108
109  /*
110     Return true if y better than x
111     Node y is better than node x if y has fewer unsatisfied (greater depth on tie) or
112     after solution weighted value of y is less than weighted value of x
113  */
114  virtual bool test (CbcNode * x, CbcNode * y) {
115    if (weight_==-1.0) {
116      // before solution
117      if (x->numberUnsatisfied() > y->numberUnsatisfied())
118        return true;
119      else if (x->numberUnsatisfied() < y->numberUnsatisfied())
120        return false;
121      else
122        return x->depth() < y->depth();
123    } else {
124      // after solution
125      double weight = CoinMax(weight_,0.0);
126      return x->objectiveValue()+ weight*x->numberUnsatisfied() > 
127        y->objectiveValue() + weight*y->numberUnsatisfied();
128    }
129  }
130  // This allows method to change behavior as it is called
131  // after each solution
132  virtual void newSolution(CbcModel * model,
133                           double objectiveAtContinuous,
134                           int numberInfeasibilitiesAtContinuous) 
135  {
136    if (model->getSolutionCount()==model->getNumberHeuristicSolutions())
137      return; // solution was got by rounding
138    // set to get close to this solution
139    double costPerInteger = 
140      (model->getObjValue()-objectiveAtContinuous)/
141      ((double) numberInfeasibilitiesAtContinuous);
142    weight_ = 0.98*costPerInteger;
143    saveWeight_=weight_;
144    numberSolutions_++;
145    if (numberSolutions_>5)
146      weight_ =0.0; // this searches on objective
147  }
148  // This allows method to change behavior
149  virtual bool every1000Nodes(CbcModel * model, int numberNodes)
150  {
151    if (numberNodes>10000)
152      weight_ =0.0; // this searches on objective
153    else if (numberNodes==1000&&weight_==-2.0)
154      weight_=-1.0; // Go to depth first
155    // get size of tree
156    treeSize_ = model->tree()->size();
157    if (treeSize_>10000) {
158      // set weight to reduce size most of time
159      if (treeSize_>20000)
160        weight_=-1.0;
161      else if ((numberNodes%4000)!=0)
162        weight_=-1.0;
163      else
164        weight_=saveWeight_;
165    }
166    return numberNodes==11000; // resort if first time
167  }
168};
169
170
171#define MAXPARAMETERS 100
172
173namespace {
174
175void establishParams (int &numberParameters, CbcParam *const parameters)
176/*
177  Subroutine to establish the cbc parameter array. See the description of
178  class CbcParam for details. Pulled from main() for clarity.
179*/
180{ numberParameters = 0 ;
181
182  parameters[numberParameters++]=
183      CbcParam("?","For help",GENERALQUERY);
184  parameters[numberParameters++]=
185      CbcParam("dualT!olerance",
186               "For an optimal solution no dual infeasibility may "
187               "exceed this value",
188               1.0e-20,1.0e12,DUALTOLERANCE);
189  parameters[numberParameters++]=
190      CbcParam("primalT!olerance",
191               "For an optimal solution no primal infeasibility may "
192               " exceed this value",
193              1.0e-20,1.0e12,PRIMALTOLERANCE);
194    parameters[numberParameters++]=
195      CbcParam("inf!easibilityWeight","Each integer infeasibility is expected \
196to cost this much",
197              0.0,1.0e20,INFEASIBILITYWEIGHT);
198    parameters[numberParameters++]=
199      CbcParam("integerT!olerance","For an optimal solution \
200no integer variable may be this away from an integer value",
201              1.0e-20,0.5,INTEGERTOLERANCE);
202    parameters[numberParameters++]=
203      CbcParam("inc!rement","A valid solution must be at least this \
204much better than last integer solution",
205              -1.0e20,1.0e20,INCREMENT);
206    parameters[numberParameters++]=
207      CbcParam("allow!ableGap","Stop when gap between best possible and \
208best less than this",
209              0.0,1.0e20,ALLOWABLEGAP);
210    parameters[numberParameters++]=
211      CbcParam("ratio!Gap","Stop when gap between best possible and \
212best less than this fraction of larger of two",
213              0.0,1.0e20,GAPRATIO);
214    parameters[numberParameters++]=
215      CbcParam("fix!OnDj","Try heuristic based on fixing variables with \
216reduced costs greater than this",
217              -1.0e20,1.0e20,DJFIX);
218    parameters[numberParameters++]=
219      CbcParam("tighten!Factor","Tighten bounds using this times largest \
220activity at continuous solution",
221              1.0,1.0e20,TIGHTENFACTOR);
222    parameters[numberParameters++]=
223      CbcParam("log!Level","Level of detail in BAB output",
224              0,63,LOGLEVEL);
225    parameters[numberParameters++]=
226      CbcParam("slog!Level","Level of detail in Solver output",
227              0,63,SOLVERLOGLEVEL);
228    parameters[numberParameters++]=
229      CbcParam("maxN!odes","Maximum number of nodes to do",
230              1,999999,MAXNODES);
231    parameters[numberParameters++]=
232      CbcParam("strong!Branching","Number of variables to look at in strong branching",
233              0,999999,STRONGBRANCHING);
234    parameters[numberParameters++]=
235      CbcParam("direction","Minimize or Maximize",
236              "min!imize",DIRECTION);
237    parameters[numberParameters-1].append("max!imize");
238    parameters[numberParameters++]=
239      CbcParam("error!sAllowed","Whether to allow import errors",
240              "off",ERRORSALLOWED);
241    parameters[numberParameters-1].append("on");
242    parameters[numberParameters++]=
243      CbcParam("gomory!Cuts","Whether to use Gomory cuts",
244              "off",GOMORYCUTS);
245    parameters[numberParameters-1].append("on");
246    parameters[numberParameters-1].append("root");
247    parameters[numberParameters++]=
248      CbcParam("probing!Cuts","Whether to use Probing cuts",
249              "off",PROBINGCUTS);
250    parameters[numberParameters-1].append("on");
251    parameters[numberParameters-1].append("root");
252    parameters[numberParameters++]=
253      CbcParam("knapsack!Cuts","Whether to use Knapsack cuts",
254              "off",KNAPSACKCUTS);
255    parameters[numberParameters-1].append("on");
256    parameters[numberParameters-1].append("root");
257    parameters[numberParameters++]=
258      CbcParam("oddhole!Cuts","Whether to use Oddhole cuts",
259              "off",ODDHOLECUTS);
260    parameters[numberParameters-1].append("on");
261    parameters[numberParameters-1].append("root");
262    parameters[numberParameters++]=
263      CbcParam("clique!Cuts","Whether to use Clique cuts",
264              "off",CLIQUECUTS);
265    parameters[numberParameters-1].append("on");
266    parameters[numberParameters-1].append("root");
267    parameters[numberParameters++]=
268      CbcParam("mixed!IntegerRoundingCuts","Whether to use Mixed Integer Rounding cuts",
269              "off",MIXEDCUTS);
270    parameters[numberParameters-1].append("on");
271    parameters[numberParameters-1].append("root");
272    parameters[numberParameters++]=
273      CbcParam("flow!CoverCuts","Whether to use Flow Cover cuts",
274              "off",FLOWCUTS);
275    parameters[numberParameters-1].append("on");
276    parameters[numberParameters-1].append("root");
277    parameters[numberParameters++]=
278      CbcParam("two!MirCuts","Whether to use Two phase Mixed Integer Rounding cuts",
279              "off",TWOMIRCUTS);
280    parameters[numberParameters-1].append("on");
281    parameters[numberParameters-1].append("root");
282    parameters[numberParameters++]=
283      CbcParam("round!ingHeuristic","Whether to use Rounding heuristic",
284              "off",ROUNDING);
285    parameters[numberParameters-1].append("on");
286    parameters[numberParameters++]=
287      CbcParam("cost!Strategy","How to use costs",
288              "off",COSTSTRATEGY);
289    parameters[numberParameters-1].append("pri!orities");
290    parameters[numberParameters-1].append("pseudo!costs(not implemented yet)");
291    parameters[numberParameters++]=
292      CbcParam("keepN!ames","Whether to keep names from import",
293              "on",KEEPNAMES);
294    parameters[numberParameters-1].append("off");
295    parameters[numberParameters++]=
296      CbcParam("scaling","Whether to do scaling",
297              "on",SCALING);
298    parameters[numberParameters-1].append("off");
299    parameters[numberParameters++]=
300      CbcParam("directory","Set Default import directory",
301              DIRECTORY);
302    parameters[numberParameters++]=
303      CbcParam("solver!","Set the solver used by cbc",
304               SOLVER) ;
305    parameters[numberParameters++]=
306      CbcParam("import","Import model from mps file",
307              IMPORT);
308    parameters[numberParameters++]=
309      CbcParam("export","Export model as mps file",
310              EXPORT);
311    parameters[numberParameters++]=
312      CbcParam("save!Model","Save model to binary file",
313              SAVE);
314    parameters[numberParameters++]=
315      CbcParam("restore!Model","Restore model from binary file",
316              RESTORE);
317    parameters[numberParameters++]=
318      CbcParam("presolve","Whether to use integer presolve - be careful",
319              "off",PRESOLVE);
320    parameters[numberParameters-1].append("on");
321    parameters[numberParameters++]=
322      CbcParam("preprocess","Whether to use integer preprocessing",
323              "off",PREPROCESS);
324    parameters[numberParameters-1].append("on");
325    parameters[numberParameters++]=
326      CbcParam("initialS!olve","Solve to continuous",
327              SOLVECONTINUOUS);
328    parameters[numberParameters++]=
329      CbcParam("branch!AndBound","Do Branch and Bound",
330              BAB);
331    parameters[numberParameters++]=
332      CbcParam("sol!ution","Prints solution to file",
333              SOLUTION);
334    parameters[numberParameters++]=
335      CbcParam("max!imize","Set optimization direction to maximize",
336              MAXIMIZE);
337    parameters[numberParameters++]=
338      CbcParam("min!imize","Set optimization direction to minimize",
339              MINIMIZE);
340    parameters[numberParameters++] =
341      CbcParam("time!Limit","Set a time limit for solving this problem",
342              1.0,(double)(60*60*24*365*10),TIMELIMIT) ;
343    parameters[numberParameters++]=
344      CbcParam("exit","Stops cbc execution",
345              EXIT);
346    parameters[numberParameters++]=
347      CbcParam("stop","Stops cbc execution",
348              EXIT);
349    parameters[numberParameters++]=
350      CbcParam("quit","Stops cbc execution",
351              EXIT);
352    parameters[numberParameters++]=
353      CbcParam("-","From stdin",
354              STDIN);
355    parameters[numberParameters++]=
356      CbcParam("stdin","From stdin",
357              STDIN);
358    parameters[numberParameters++]=
359      CbcParam("unitTest","Do unit test",
360              UNITTEST);
361    parameters[numberParameters++]=
362      CbcParam("miplib","Do some of miplib test set",
363              MIPLIB);
364    parameters[numberParameters++]=
365      CbcParam("ver!sion","Print out version",
366              VERSION);
367    parameters[numberParameters++]=
368      CbcParam("alg!orithm","Whether to use dual or primal",
369              "dual",ALGORITHM);
370    parameters[numberParameters-1].append("primal");
371
372    assert(numberParameters<MAXPARAMETERS);
373
374  return ; }
375
376#ifdef COIN_USE_READLINE     
377#include <readline/readline.h>
378#include <readline/history.h>
379#endif
380
381// Returns next valid field
382
383int read_mode=1;
384char line[1000];
385char * where=NULL;
386
387std::string
388nextField()
389{
390  std::string field;
391  if (!where) {
392    // need new line
393#ifdef COIN_USE_READLINE     
394    // Get a line from the user.
395    where = readline ("Cbc:");
396     
397    // If the line has any text in it, save it on the history.
398    if (where) {
399      if ( *where)
400        add_history (where);
401      strcpy(line,where);
402    }
403#else
404    fprintf(stdout,"Cbc:");
405    fflush(stdout);
406    where = fgets(line,1000,stdin);
407#endif
408    if (!where)
409      return field; // EOF
410    where = line;
411    // clean image
412    char * lastNonBlank = line-1;
413    while ( *where != '\0' ) {
414      if ( *where != '\t' && *where < ' ' ) {
415        break;
416      } else if ( *where != '\t' && *where != ' ') {
417        lastNonBlank = where;
418      }
419      where++;
420    }
421    where=line;
422    *(lastNonBlank+1)='\0';
423  }
424  // munch white space
425  while(*where==' '||*where=='\t')
426    where++;
427  char * saveWhere = where;
428  while (*where!=' '&&*where!='\t'&&*where!='\0')
429    where++;
430  if (where!=saveWhere) {
431    char save = *where;
432    *where='\0';
433    //convert to string
434    field=saveWhere;
435    *where=save;
436  } else {
437    where=NULL;
438    field="EOL";
439  }
440  return field;
441}
442
443std::string
444getCommand(int argc, const char *argv[])
445{
446  std::string field="EOL";
447  while (field=="EOL") {
448    if (read_mode>0) {
449      if (read_mode<argc) {
450        field = argv[read_mode++];
451        if (field=="-") {
452          std::cout<<"Switching to line mode"<<std::endl;
453          read_mode=-1;
454          field=nextField();
455        } else if (field[0]!='-') {
456          if (read_mode!=2) {
457            std::cout<<"skipping non-command "<<field<<std::endl;
458            field="EOL"; // skip
459          } else {
460            // special dispensation - taken as -import name
461            read_mode--;
462            field="import";
463          }
464        } else {
465          if (field!="--") {
466            // take off -
467            field = field.substr(1);
468          } else {
469            // special dispensation - taken as -import --
470            read_mode--;
471            field="import";
472          }
473        }
474      } else {
475        field="";
476      }
477    } else {
478      field=nextField();
479    }
480  }
481  //std::cout<<field<<std::endl;
482  return field;
483}
484std::string
485getString(int argc, const char *argv[])
486{
487  std::string field="EOL";
488  if (read_mode>0) {
489    if (read_mode<argc) {
490      if (argv[read_mode][0]!='-') { 
491        field = argv[read_mode++];
492      } else if (!strcmp(argv[read_mode],"--")) {
493        field = argv[read_mode++];
494        // -- means import from stdin
495        field = "-";
496      }
497    }
498  } else {
499    field=nextField();
500  }
501  //std::cout<<field<<std::endl;
502  return field;
503}
504
505// valid = 0 okay, 1 bad, 2 not there
506int
507getIntField(int argc, const char *argv[],int * valid)
508{
509  std::string field="EOL";
510  if (read_mode>0) {
511    if (read_mode<argc) {
512      // may be negative value so do not check for -
513      field = argv[read_mode++];
514    }
515  } else {
516    field=nextField();
517  }
518  int value=0;
519  //std::cout<<field<<std::endl;
520  if (field!="EOL") {
521    // how do I check valid
522    value =  atoi(field.c_str());
523    *valid=0;
524  } else {
525    *valid=2;
526  }
527  return value;
528}
529
530
531// valid = 0 okay, 1 bad, 2 not there
532double
533getDoubleField(int argc, const char *argv[],int * valid)
534{
535  std::string field="EOL";
536  if (read_mode>0) {
537    if (read_mode<argc) {
538      // may be negative value so do not check for -
539      field = argv[read_mode++];
540    }
541  } else {
542    field=nextField();
543  }
544  double value=0.0;
545  //std::cout<<field<<std::endl;
546  if (field!="EOL") {
547    // how do I check valid
548    value = atof(field.c_str());
549    *valid=0;
550  } else {
551    *valid=2;
552  }
553  return value;
554}
555
556/// For run timing
557
558double totalTime=0.0;
559
560}       /* end unnamed namespace */
561
562
563int main (int argc, const char *argv[])
564{
565  // next {} is just to make sure all memory should be freed - for debug
566  {
567    std::ios::sync_with_stdio() ;
568/*
569  Create a vector of solver prototypes and establish a default solver. After
570  this the code is solver independent.
571
572  Creating multiple solvers is moderately expensive. If you don't want to
573  make use of this feature, best to define just one. The businesss with
574  CBC_DEFAULT_SOLVER will select the first available solver as the default,
575  unless overridden at compile time.
576
577  NOTE that processing of string parameters is case-independent, but maps are
578       case-sensitive. The solver name given here must contain only lower case
579       letters.
580*/
581    typedef std::map<std::string,OsiSolverInterface*> solverMap_t ;
582    typedef solverMap_t::const_iterator solverMapIter_t ;
583
584    solverMap_t solvers ;
585
586#   ifdef COIN_USE_CLP
587#     ifndef CBC_DEFAULT_SOLVER
588#       define CBC_DEFAULT_SOLVER "clp"
589#     endif
590      solvers["clp"] = new OsiClpSolverInterface ;
591#   else
592      solvers["clp"] = 0 ;
593#   endif
594#   ifdef COIN_USE_DYLP
595#     ifndef CBC_DEFAULT_SOLVER
596#       define CBC_DEFAULT_SOLVER "dylp"
597#     endif
598      solvers["dylp"] = new OsiDylpSolverInterface  ;
599#   else
600      solvers["dylp"] = 0 ;
601#   endif
602#   ifdef COIN_USE_OSL
603#     ifndef CBC_DEFAULT_SOLVER
604#       define CBC_DEFAULT_SOLVER "osl"
605#     endif
606      solvers["osl"] = new OsiOslSolverInterface  ;
607#   else
608      solvers["osl"] = 0 ;
609#   endif
610/*
611  If we don't have a default solver, we're deeply confused.
612*/
613    OsiSolverInterface *dflt_solver = solvers[CBC_DEFAULT_SOLVER] ;
614    if (dflt_solver)
615    { std::cout << "Default solver is " << CBC_DEFAULT_SOLVER << std::endl ; }
616    else
617    { std::cerr << "No solvers! Aborting." << std::endl ;
618      return (1) ; }
619/*
620  For calculating run time.
621*/
622    double time1 = CoinCpuTime() ;
623    double time2;
624/*
625  Establish the command line interface: parameters, with associated info
626  messages, ranges, defaults. See CbcParam for details. Scan the vector of
627  solvers and add the names to the parameter object.
628*/
629    CbcParam parameters[MAXPARAMETERS];
630    int numberParameters ;
631    establishParams(numberParameters,parameters) ;
632
633    { int iSolver = 0 ;
634      for ( ; iSolver < numberParameters ; iSolver++)
635      { int match = parameters[iSolver].matches("solver") ;
636        if (match==1) break ; }
637      for (solverMapIter_t solverIter = solvers.begin() ;
638           solverIter != solvers.end() ;
639           solverIter++)
640      { if (solverIter->second)
641          parameters[iSolver].append(solverIter->first) ; }
642      int iKwd = parameters[iSolver].parameterOption(CBC_DEFAULT_SOLVER) ;
643      parameters[iSolver].setCurrentOption(iKwd) ; }
644/*
645  The rest of the default setup: establish a model, instantiate cut generators
646  and heuristics, set various default values.
647*/
648    dflt_solver->messageHandler()->setLogLevel(0) ;
649    CbcModel *model = new CbcModel(*dflt_solver) ;
650    model->messageHandler()->setLogLevel(1);
651    bool goodModel=false;
652   
653// Set up likely cut generators and defaults
654
655    CglGomory gomoryGen;
656    // try larger limit
657    gomoryGen.setLimit(300);
658    // set default action (0=off,1=on,2=root)
659    int gomoryAction=1;
660
661    CglProbing probingGen;
662    probingGen.setUsingObjective(true);
663    probingGen.setMaxPass(3);
664    probingGen.setMaxPassRoot(3);
665    // Number of unsatisfied variables to look at
666    probingGen.setMaxProbe(10);
667    probingGen.setMaxProbeRoot(50);
668    // How far to follow the consequences
669    probingGen.setMaxLook(10);
670    probingGen.setMaxLookRoot(50);
671    // Only look at rows with fewer than this number of elements
672    probingGen.setMaxElements(200);
673    probingGen.setRowCuts(3);
674    // set default action (0=off,1=on,2=root)
675    int probingAction=1;
676
677    CglKnapsackCover knapsackGen;
678    // set default action (0=off,1=on,2=root)
679    int knapsackAction=1;
680
681    CglOddHole oddholeGen;
682    oddholeGen.setMinimumViolation(0.005);
683    oddholeGen.setMinimumViolationPer(0.0002);
684    oddholeGen.setMaximumEntries(100);
685    // set default action (0=off,1=on,2=root)
686    int oddholeAction=0;
687
688    CglClique cliqueGen;
689    cliqueGen.setStarCliqueReport(false);
690    cliqueGen.setRowCliqueReport(false);
691    // set default action (0=off,1=on,2=root)
692    int cliqueAction=1;
693
694    CglMixedIntegerRounding mixedGen;
695    // set default action (0=off,1=on,2=root)
696    int mixedAction=1;
697
698    CglFlowCover flowGen;
699    // set default action (0=off,1=on,2=root)
700    int flowAction=1;
701
702    CglTwomir twomirGen;
703    // set default action (0=off,1=on,2=root)
704    int twomirAction=0;
705
706    bool useRounding=true;
707   
708    int allowImportErrors=0;
709    int algorithm=0; // dual
710    int keepImportNames=1;      // not implemented
711    int doScaling=1;
712    int preSolve=0;
713    int preProcess=1;
714    double djFix=1.0e100;
715    double gapRatio=1.0e100;
716    double tightenFactor=0.0;
717
718    // Set false if user does anything advanced
719    bool defaultSettings=true;
720
721    const char dirsep =  CoinFindDirSeparator();
722    std::string directory = (dirsep == '/' ? "./" : ".\\");
723    std::string field;
724/*
725  The main command parsing loop.
726*/
727    // total number of commands read
728    int numberGoodCommands=0;
729   
730    while (1) {
731      // next command
732      field=getCommand(argc,argv);
733     
734      // exit if null or similar
735      if (!field.length()) {
736        if (numberGoodCommands==1&&goodModel) {
737          // we just had file name
738          field="branchAndBound";
739        } else if (!numberGoodCommands) {
740          // let's give the sucker a hint
741          std::cout
742            <<"Cbc takes input from arguments ( - switches to stdin)"
743            <<std::endl
744            <<"Enter ? for list of commands or (-)unitTest or -miplib"
745            <<" for tests"<<std::endl;
746          break;
747        } else {
748          break;
749        }
750      }
751     
752      // see if ? at end
753      int numberQuery=0;
754      if (field!="?") {
755        int length = field.length();
756        int i;
757        for (i=length-1;i>0;i--) {
758          if (field[i]=='?') 
759            numberQuery++;
760          else
761            break;
762        }
763        field=field.substr(0,length-numberQuery);
764      }
765      // find out if valid command
766      int iParam;
767      int numberMatches=0;
768      for ( iParam=0; iParam<numberParameters; iParam++ ) {
769        int match = parameters[iParam].matches(field);
770        if (match==1) {
771          numberMatches = 1;
772          break;
773        } else {
774          numberMatches += match>>1;
775        }
776      }
777      if (iParam<numberParameters&&!numberQuery) {
778        // found
779        CbcParam found = parameters[iParam];
780        CbcParameterType type = found.type();
781        int valid;
782        numberGoodCommands++;
783        if (type==GENERALQUERY) {
784          std::cout<<"In argument list keywords have leading - "
785            ", -stdin or just - switches to stdin"<<std::endl;
786          std::cout<<"One command per line (and no -)"<<std::endl;
787          std::cout<<"abcd? gives list of possibilities, if only one + explanation"<<std::endl;
788          std::cout<<"abcd?? adds explanation, if only one fuller help(LATER)"<<std::endl;
789          std::cout<<"abcd without value (where expected) gives current value"<<std::endl;
790          std::cout<<"abcd value or abcd = value sets value"<<std::endl;
791          std::cout<<"Commands are:"<<std::endl;
792          for ( iParam=0; iParam<numberParameters; iParam+=4 ) {
793            int i;
794            for (i=iParam;i<min(numberParameters,iParam+4);i++) 
795              std::cout<<parameters[i].matchName()<<"  ";
796            std::cout<<std::endl;
797          }
798        } else if (type<81) {
799          // get next field as double
800          double value = getDoubleField(argc,argv,&valid);
801          if (!valid) {
802            parameters[iParam].setDoubleParameter(*model,value);
803          } else if (valid==1) {
804            abort();
805          } else {
806            std::cout<<parameters[iParam].name()<<" has value "<<
807              parameters[iParam].doubleParameter(*model)<<std::endl;
808          }
809        } else if (type<101) {
810          // get next field as double for local use
811          double value = getDoubleField(argc,argv,&valid);
812          if (!valid) {
813            if (!parameters[iParam].checkDoubleParameter(value)) {
814              switch(type) {
815              case DJFIX:
816                djFix=value;
817                preSolve=5;
818                defaultSettings=false; // user knows what she is doing
819                break;
820              case GAPRATIO:
821                gapRatio=value;
822                break;
823              case TIGHTENFACTOR:
824                tightenFactor=value;
825                defaultSettings=false; // user knows what she is doing
826                break;
827              default:
828                abort();
829              }
830            }
831          } else if (valid==1) {
832            abort();
833          } else {
834            switch(type) {
835            case DJFIX:
836              value = djFix ;
837              break;
838            case GAPRATIO:
839              value = gapRatio ;
840              break;
841            case TIGHTENFACTOR:
842              value = tightenFactor ;
843              break;
844            default:
845              abort();
846            }
847            std::cout << parameters[iParam].name() << " has value " <<
848                         value << std::endl ;
849          }
850        } else if (type<201) {
851          // get next field as int
852          int value = getIntField(argc,argv,&valid);
853          if (!valid) {
854            parameters[iParam].setIntParameter(*model,value);
855          } else if (valid==1) {
856            abort();
857          } else {
858            std::cout<<parameters[iParam].name()<<" has value "<<
859              parameters[iParam].intParameter(*model)<<std::endl;
860          }
861        } else if (type<301) {
862          // one of several strings
863          std::string value = getString(argc,argv);
864          int action = parameters[iParam].parameterOption(value);
865          if (action<0) {
866            if (value!="EOL") {
867              // no match
868              parameters[iParam].printOptions();
869            } else {
870              // print current value
871              std::cout<<parameters[iParam].name()<<" has value "<<
872                parameters[iParam].currentOption()<<std::endl;
873            }
874          } else {
875            parameters[iParam].setCurrentOption(action);
876            // for now hard wired
877            switch (type) {
878            case DIRECTION:
879              if (action==0)
880                model->solver()->setObjSense(1);
881              else
882                model->solver()->setObjSense(-1);
883              break;
884            case ERRORSALLOWED:
885              allowImportErrors = action;
886              break;
887            case ALGORITHM:
888              algorithm  = action;
889              defaultSettings=false; // user knows what she is doing
890              break;
891            case KEEPNAMES:
892              keepImportNames = 1-action;
893              break;
894            case SCALING:
895              doScaling = 1-action;
896              break;
897            case GOMORYCUTS:
898              defaultSettings=false; // user knows what she is doing
899              gomoryAction = action;
900              break;
901            case PROBINGCUTS:
902              defaultSettings=false; // user knows what she is doing
903              probingAction = action;
904              break;
905            case KNAPSACKCUTS:
906              defaultSettings=false; // user knows what she is doing
907              knapsackAction = action;
908              break;
909            case ODDHOLECUTS:
910              defaultSettings=false; // user knows what she is doing
911              oddholeAction = action;
912              break;
913            case CLIQUECUTS:
914              defaultSettings=false; // user knows what she is doing
915              cliqueAction = action;
916              break;
917            case FLOWCUTS:
918              defaultSettings=false; // user knows what she is doing
919              flowAction = action;
920              break;
921            case MIXEDCUTS:
922              defaultSettings=false; // user knows what she is doing
923              mixedAction = action;
924              break;
925            case TWOMIRCUTS:
926              defaultSettings=false; // user knows what she is doing
927              twomirAction = action;
928              break;
929            case ROUNDING:
930              defaultSettings=false; // user knows what she is doing
931              useRounding = action;
932              break;
933            case COSTSTRATEGY:
934              if (action!=1) {
935                printf("Pseudo costs not implemented yet\n");
936              } else {
937                int numberColumns = model->getNumCols();
938                int * sort = new int[numberColumns];
939                double * dsort = new double[numberColumns];
940                int * priority = new int [numberColumns];
941                const double * objective = model->getObjCoefficients();
942                int iColumn;
943                int n=0;
944                for (iColumn=0;iColumn<numberColumns;iColumn++) {
945                  if (model->isInteger(iColumn)) {
946                    sort[n]=n;
947                    dsort[n++]=-objective[iColumn];
948                  }
949                }
950                CoinSort_2(dsort,dsort+n,sort);
951                int level=0;
952                double last = -1.0e100;
953                for (int i=0;i<n;i++) {
954                  int iPut=sort[i];
955                  if (dsort[i]!=last) {
956                    level++;
957                    last=dsort[i];
958                  }
959                  priority[iPut]=level;
960                }
961                model->passInPriorities( priority,false);
962                delete [] priority;
963                delete [] sort;
964                delete [] dsort;
965              }
966              break;
967            case PRESOLVE:
968                defaultSettings=false; // user knows what she is doing
969              preSolve = action*5;
970              break;
971            case PREPROCESS:
972              preProcess = action;
973              break;
974            case SOLVER:
975            { for (int i = 0 ; i < (int) value.length() ; i++)
976                value[i] = tolower(value[i]) ;
977              OsiSolverInterface *newSolver = solvers[value]->clone() ;
978              model->assignSolver(newSolver) ;
979              std::cout << "Solver set to " << value << "." << std::endl ;
980              break ; }
981            default:
982            { std::cerr << "Unrecognized action. Aborting." << std::endl ;
983              abort(); }
984            }
985          }
986        } else {
987          // action
988          if (type==EXIT)
989            break; // stop all
990          switch (type) {
991          case SOLVECONTINUOUS:
992            if (goodModel) {
993              model->initialSolve();
994              time2 = CoinCpuTime();
995              totalTime += time2-time1;
996              std::cout<<"Result "<<model->solver()->getObjValue()<<
997                " iterations "<<model->solver()->getIterationCount()<<
998                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
999              time1=time2;
1000            } else {
1001              std::cout<<"** Current model not valid"<<std::endl;
1002            }
1003            break;
1004/*
1005  Run branch-and-cut. First set a few options -- node comparison, scaling. If
1006  the solver is Clp, consider running some presolve code (not yet converted
1007  this to generic OSI) with branch-and-cut. If presolve is disabled, or the
1008  solver is not Clp, simply run branch-and-cut. Print elapsed time at the end.
1009*/
1010          case BAB: // branchAndBound
1011          { if (goodModel)
1012            { CbcCompareUser compare; // Definition of node choice
1013            // If user made settings then use them
1014            if (!defaultSettings) {
1015              model->setNodeComparison(compare);
1016              OsiSolverInterface * solver = model->solver();
1017              if (!doScaling)
1018                solver->setHintParam(OsiDoScale,false,OsiHintTry);
1019#ifdef COIN_USE_CLP
1020              OsiClpSolverInterface * si =
1021                dynamic_cast<OsiClpSolverInterface *>(solver) ;
1022              if (preSolve&&si != NULL) {
1023                // get clp itself
1024                ClpSimplex * modelC = si->getModelPtr();
1025                if (si->messageHandler()->logLevel())
1026                  si->messageHandler()->setLogLevel(1);
1027                if (modelC->tightenPrimalBounds()!=0) {
1028                  std::cout<<"Problem is infeasible!"<<std::endl;
1029                  break;
1030                }
1031                model->initialSolve();
1032                // bounds based on continuous
1033                if (tightenFactor) {
1034                  if (modelC->tightenPrimalBounds(tightenFactor)!=0) {
1035                    std::cout<<"Problem is infeasible!"<<std::endl;
1036                    break;
1037                  }
1038                }
1039                if (gapRatio<1.0e100) {
1040                  double value = si->getObjValue();
1041                  double value2 = gapRatio*(1.0e-5+fabs(value));
1042                  model->setAllowableGap(value2);
1043                  model->setAllowableFractionGap(gapRatio);
1044                  std::cout<<"Continuous "<<value
1045                           <<", so allowable gap set to "<<value2<<std::endl;
1046                }
1047                if (djFix<1.0e20) {
1048                  // do some fixing
1049                  int numberColumns = modelC->numberColumns();
1050                  int i;
1051                  const char * type = modelC->integerInformation();
1052                  double * lower = modelC->columnLower();
1053                  double * upper = modelC->columnUpper();
1054                  double * solution = modelC->primalColumnSolution();
1055                  double * dj = modelC->dualColumnSolution();
1056                  int numberFixed=0;
1057                  for (i=0;i<numberColumns;i++) {
1058                    if (type[i]) {
1059                      double value = solution[i];
1060                      if (value<lower[i]+1.0e-5&&dj[i]>djFix) {
1061                        solution[i]=lower[i];
1062                        upper[i]=lower[i];
1063                        numberFixed++;
1064                      } else if (value>upper[i]-1.0e-5&&dj[i]<-djFix) {
1065                        solution[i]=upper[i];
1066                        lower[i]=upper[i];
1067                        numberFixed++;
1068                      }
1069                    }
1070                  }
1071                  printf("%d columns fixed\n",numberFixed);
1072                }
1073                {
1074                  // integer presolve
1075                  CbcModel * model2 = model->integerPresolve();
1076                  if (model2) {
1077                    // Do complete search
1078                   
1079                    CbcRounding heuristic1(*model2);
1080                    if (useRounding)
1081                      model2->addHeuristic(&heuristic1);
1082                    if (algorithm) {
1083                      // user wants primal
1084                      model2->solver()->setHintParam(OsiDoDualInInitial,false,OsiHintTry);
1085                      model2->solver()->setHintParam(OsiDoDualInResolve,false,OsiHintTry);
1086                    }
1087                    model2->branchAndBound();
1088                    // get back solution
1089                    model->originalModel(model2,false);
1090                  } else {
1091                    // infeasible
1092                    exit(1);
1093                  }
1094                }
1095              } else
1096#endif
1097              { if (model->solver()->messageHandler()->logLevel())
1098                  model->solver()->messageHandler()->setLogLevel(1) ;
1099                model->initialSolve() ;
1100                if (gapRatio < 1.0e100)
1101                { double value = model->solver()->getObjValue() ;
1102                  double value2 = gapRatio*(1.0e-5+fabs(value)) ;
1103                  model->setAllowableGap(value2) ;
1104                  std::cout << "Continuous " << value
1105                            << ", so allowable gap set to "
1106                            << value2 << std::endl ; }
1107                CbcRounding heuristic1(*model) ;
1108                if (useRounding)
1109                  model->addHeuristic(&heuristic1) ;
1110                // add cut generators if wanted
1111                if (probingAction==1)
1112                  model->addCutGenerator(&probingGen,-1,"Probing");
1113                else if (probingAction==2)
1114                  model->addCutGenerator(&probingGen,-99,"Probing");
1115                if (gomoryAction==1)
1116                  model->addCutGenerator(&gomoryGen,-1,"Gomory");
1117                else if (gomoryAction==2)
1118                  model->addCutGenerator(&gomoryGen,-99,"Gomory");
1119                if (knapsackAction==1)
1120                  model->addCutGenerator(&knapsackGen,-1,"Knapsack");
1121                else if (knapsackAction==2)
1122                  model->addCutGenerator(&knapsackGen,-99,"Knapsack");
1123                if (oddholeAction==1)
1124                  model->addCutGenerator(&oddholeGen,-1,"OddHole");
1125                else if (oddholeAction==2)
1126                  model->addCutGenerator(&oddholeGen,-99,"OddHole");
1127                if (cliqueAction==1)
1128                  model->addCutGenerator(&cliqueGen,-1,"Clique");
1129                else if (cliqueAction==2)
1130                  model->addCutGenerator(&cliqueGen,-99,"Clique");
1131                if (mixedAction==1)
1132                  model->addCutGenerator(&mixedGen,-1,"MixedintegerRounding");
1133                else if (mixedAction==2)
1134                  model->addCutGenerator(&mixedGen,-99,"MixedintegerRounding");
1135                if (flowAction==1)
1136                  model->addCutGenerator(&flowGen,-1,"FlowCover");
1137                else if (flowAction==2)
1138                  model->addCutGenerator(&flowGen,-99,"FlowCover");
1139                if (twomirAction==1)
1140                  model->addCutGenerator(&twomirGen,-1,"TwoMirCuts");
1141                else if (twomirAction==2)
1142                  model->addCutGenerator(&twomirGen,-99,"TwoMirCuts");
1143                model->branchAndBound() ; }
1144              if (model->bestSolution())
1145              { std::cout << "Optimal solution "
1146                          << model->solver()->getObjValue() << std::endl ; }
1147              else
1148              { std::cout << "No integer solution found." << std::endl ; }
1149                       
1150              time2 = CoinCpuTime() ;
1151              totalTime += time2-time1 ;
1152              std::cout << "Result " << model->solver()->getObjValue()
1153                        << " took " << time2-time1 << " seconds - total "
1154                        << totalTime << std::endl ;
1155              time1 = time2 ;
1156            } else {
1157              // User is going to get what I think best
1158              if (!doScaling)
1159                model->solver()->setHintParam(OsiDoScale,false,OsiHintTry);
1160              model->initialSolve();
1161              // See if we want preprocessing
1162              OsiSolverInterface * saveSolver=NULL;
1163              CglPreProcess process;
1164              if (preProcess) {
1165                saveSolver=model->solver()->clone();
1166                /* Do not try and produce equality cliques and
1167                   do up to 10 passes */
1168                OsiSolverInterface * solver2 = process.preProcess(*saveSolver,false,10);
1169                if (!solver2) {
1170                  printf("Pre-processing says infeasible\n");
1171                  break;
1172                } else {
1173                  printf("processed model has %d rows and %d columns\n",
1174                         solver2->getNumRows(),solver2->getNumCols());
1175                }
1176                //solver2->resolve();
1177                // we have to keep solver2 so pass clone
1178                solver2 = solver2->clone();
1179                model->assignSolver(solver2);
1180                model->initialSolve();
1181              }
1182              model->setNodeComparison(compare);
1183              CbcRounding heuristic1(*model);
1184              if (useRounding)
1185                model->addHeuristic(&heuristic1) ;
1186              // add cut generators if wanted
1187              if (probingAction==1)
1188                model->addCutGenerator(&probingGen,-1,"Probing");
1189              else if (probingAction==2)
1190                model->addCutGenerator(&probingGen,-99,"Probing");
1191              if (gomoryAction==1)
1192                model->addCutGenerator(&gomoryGen,-1,"Gomory");
1193              else if (gomoryAction==2)
1194                model->addCutGenerator(&gomoryGen,-99,"Gomory");
1195              if (knapsackAction==1)
1196                model->addCutGenerator(&knapsackGen,-1,"Knapsack");
1197              else if (knapsackAction==2)
1198                model->addCutGenerator(&knapsackGen,-99,"Knapsack");
1199              if (oddholeAction==1)
1200                model->addCutGenerator(&oddholeGen,-1,"OddHole");
1201              else if (oddholeAction==2)
1202                model->addCutGenerator(&oddholeGen,-99,"OddHole");
1203              if (cliqueAction==1)
1204                model->addCutGenerator(&cliqueGen,-1,"Clique");
1205              else if (cliqueAction==2)
1206                model->addCutGenerator(&cliqueGen,-99,"Clique");
1207              if (mixedAction==1)
1208                model->addCutGenerator(&mixedGen,-1,"MixedintegerRounding");
1209              else if (mixedAction==2)
1210                model->addCutGenerator(&mixedGen,-99,"MixedintegerRounding");
1211              if (flowAction==1)
1212                model->addCutGenerator(&flowGen,-1,"FlowCover");
1213              else if (flowAction==2)
1214                model->addCutGenerator(&flowGen,-99,"FlowCover");
1215              if (twomirAction==1)
1216                model->addCutGenerator(&twomirGen,-1,"TwoMirCuts");
1217              else if (twomirAction==2)
1218                model->addCutGenerator(&twomirGen,-99,"TwoMirCuts");
1219              // Say we want timings
1220              int numberGenerators = model->numberCutGenerators();
1221              int iGenerator;
1222              for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) {
1223                CbcCutGenerator * generator = model->cutGenerator(iGenerator);
1224                generator->setTiming(true);
1225              }
1226              // Could tune more
1227              model->setMinimumDrop(min(1.0,
1228                                        fabs(model->getMinimizationObjValue())*1.0e-3+1.0e-4));
1229             
1230              if (model->getNumCols()<500)
1231                model->setMaximumCutPassesAtRoot(-100); // always do 100 if possible
1232              else if (model->getNumCols()<5000)
1233                model->setMaximumCutPassesAtRoot(100); // use minimum drop
1234              else
1235                model->setMaximumCutPassesAtRoot(20);
1236              model->setMaximumCutPasses(2);
1237             
1238              // Do more strong branching if small
1239              if (model->getNumCols()<5000)
1240                model->setNumberStrong(20);
1241              // Switch off strong branching if wanted
1242              //if (model->getNumCols()>10*model->getNumRows())
1243              //model->setNumberStrong(0);
1244              if (model->getNumCols()>2000||model->getNumRows()>1500||
1245                  model->messageHandler()->logLevel()>1)
1246                model->setPrintFrequency(100);
1247             
1248              model->solver()->setIntParam(OsiMaxNumIterationHotStart,100);
1249#ifdef COIN_USE_CLP
1250              OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model->solver());
1251              // go faster stripes
1252              if (osiclp->getNumRows()<300&&osiclp->getNumCols()<500) {
1253                osiclp->setupForRepeatedUse(2,0);
1254              }
1255#endif
1256              if (gapRatio < 1.0e100)
1257                { double value = model->solver()->getObjValue() ;
1258                double value2 = gapRatio*(1.0e-5+fabs(value)) ;
1259                model->setAllowableGap(value2) ;
1260                std::cout << "Continuous " << value
1261                          << ", so allowable gap set to "
1262                          << value2 << std::endl ; }
1263              model->branchAndBound();
1264              time2 = CoinCpuTime();
1265              totalTime += time2-time1;
1266              if (model->getMinimizationObjValue()<1.0e50) {
1267                // post process
1268                if (preProcess) {
1269                  process.postProcess(*model->solver());
1270                  // Solution now back in saveSolver
1271                  model->assignSolver(saveSolver);
1272                }
1273              }
1274              std::cout<<"Result "<<model->getObjValue()<<
1275                " iterations "<<model->getIterationCount()<<
1276                " nodes "<<model->getNodeCount()<<
1277                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
1278              time1 = time2;
1279            }
1280            } else
1281            { std::cout << "** Current model not valid" << std::endl ; }
1282            break ; }
1283          case IMPORT:
1284            {
1285              // get next field
1286              field = getString(argc,argv);
1287              std::string fileName;
1288              bool canOpen=false;
1289              if (field=="-") {
1290                // stdin
1291                canOpen=true;
1292                fileName = "-";
1293              } else {
1294                bool absolutePath;
1295                if (dirsep=='/') {
1296                  // non Windows (or cygwin)
1297                  absolutePath=(field[0]=='/');
1298                } else {
1299                  //Windows (non cycgwin)
1300                  absolutePath=(field[0]=='\\');
1301                  // but allow for :
1302                  if (strchr(field.c_str(),':'))
1303                    absolutePath=true;
1304                }
1305                if (absolutePath) {
1306                  fileName = field;
1307                } else if (field[0]=='~') {
1308                  char * environVar = getenv("HOME");
1309                  if (environVar) {
1310                    std::string home(environVar);
1311                    field=field.erase(0,1);
1312                    fileName = home+field;
1313                  } else {
1314                    fileName=field;
1315                  }
1316                } else {
1317                  fileName = directory+field;
1318                }
1319                FILE *fp=fopen(fileName.c_str(),"r");
1320                if (fp) {
1321                  // can open - lets go for it
1322                  fclose(fp);
1323                  canOpen=true;
1324                } else {
1325                  std::cout<<"Unable to open file "<<fileName<<std::endl;
1326                }
1327              }
1328              if (canOpen) {
1329                model->gutsOfDestructor();
1330                int status =model->solver()->readMps(fileName.c_str(),"");
1331                if (!status||(status>0&&allowImportErrors)) {
1332                  // I don't think there is any need for this but ..
1333                  //OsiWarmStartBasis allSlack;
1334                  goodModel=true;
1335                  //model->setBasis(allSlack);
1336                  time2 = CoinCpuTime();
1337                  totalTime += time2-time1;
1338                  time1=time2;
1339                } else {
1340                  // errors
1341                  std::cout<<"There were "<<status<<
1342                    " errors on input"<<std::endl;
1343                }
1344              }
1345            }
1346            break;
1347          case EXPORT:
1348            {
1349              // get next field
1350              field = getString(argc,argv);
1351              std::string fileName;
1352              bool canOpen=false;
1353              if (field[0]=='/'||field[0]=='~')
1354                fileName = field;
1355              else
1356                fileName = directory+field;
1357              FILE *fp=fopen(fileName.c_str(),"w");
1358              if (fp) {
1359                // can open - lets go for it
1360                fclose(fp);
1361                canOpen=true;
1362              } else {
1363                std::cout<<"Unable to open file "<<fileName<<std::endl;
1364              }
1365              if (canOpen) {
1366                model->solver()->writeMps(fileName.c_str(),"");
1367                time2 = CoinCpuTime();
1368                totalTime += time2-time1;
1369                time1=time2;
1370              }
1371            }
1372            break;
1373          case MAXIMIZE:
1374            model->solver()->setObjSense(-1);
1375            break;
1376          case MINIMIZE:
1377            model->solver()->setObjSense(1);
1378            break;
1379          case DIRECTORY:
1380          { directory = getString(argc,argv);
1381            if (directory[directory.length()-1] != '/')
1382              directory += '/' ;
1383            break ; }
1384          case STDIN:
1385            read_mode=-1;
1386            break;
1387          case VERSION:
1388            std::cout<<"Coin LP version "<<CBCVERSION
1389                     <<", build "<<__DATE__<<std::endl;
1390            break;
1391          case UNITTEST:
1392            {
1393              // okay so there is not a real unit test
1394
1395              int status =model->solver()->readMps("../Mps/Sample/p0033.mps",
1396                                                   "");
1397              assert(!status);
1398              model->branchAndBound();
1399              model->solver()->resolve();
1400              std::cout<<"Optimal solution "<<model->solver()->getObjValue()<<std::endl;
1401              assert(fabs(model->solver()->getObjValue()-3089.0)<1.0e-5);
1402              fprintf(stderr,"Test was okay\n");
1403              status =model->solver()->readMps("../Mps/Sample/p0033.mps",
1404                                                   "");
1405              assert(!status);
1406              model->setCutoff(1.0e20);
1407              model->setBestObjectiveValue(1.0e20);
1408              model->setMaximumSolutions(1);
1409              model->setSolutionCount(0);
1410              // Switch off strong branching to give better chance of NOT finding best
1411              model->setNumberStrong(0);
1412              // Definition of node choice
1413              CbcCompareDefault compare(100.0);
1414              model->setNodeComparison(compare);
1415              model->solver()->resolve();
1416              model->branchAndBound();
1417              model->solver()->resolve();
1418              std::cout<<"partial solution "<<model->solver()->getObjValue()<<std::endl;
1419              if (model->solver()->getObjValue()<3090.0) {
1420                std::cout<<"Got optimal solution by mistake!"<<std::endl;
1421              }
1422            }
1423            break;
1424          case MIPLIB:
1425            {
1426              int mainTest (int argc, const char *argv[]);
1427              // create fields for test
1428              const char * fields[3];
1429              int nFields=1;
1430              fields[0]="fake main for miplib";
1431              if (directory!="./") {
1432                fields[1]=("-miplibDir="+directory).c_str();
1433                nFields=2;
1434              }
1435              mainTest(nFields,fields);
1436            }
1437            break;
1438          case SOLUTION:
1439            if (goodModel) {
1440              // get next field
1441              field = getString(argc,argv);
1442              std::string fileName;
1443              FILE *fp=NULL;
1444              if (field=="-"||field=="EOL") {
1445                // stdout
1446                fp=stdout;
1447              } else {
1448                if (field[0]=='/'||field[0]=='~')
1449                  fileName = field;
1450                else
1451                  fileName = directory+field;
1452                fp=fopen(fileName.c_str(),"w");
1453              }
1454              if (fp) {
1455                // make fancy later on
1456                int iRow;
1457                int numberRows=model->solver()->getNumRows();
1458                const double * dualRowSolution = model->getRowPrice();
1459                const double * primalRowSolution =  model->getRowActivity();
1460                for (iRow=0;iRow<numberRows;iRow++) {
1461                  fprintf(fp,"%7d ",iRow);
1462                  fprintf(fp,"%15.8g        %15.8g\n",primalRowSolution[iRow],
1463                          dualRowSolution[iRow]);
1464                }
1465                int iColumn;
1466                int numberColumns=model->solver()->getNumCols();
1467                const double * dualColumnSolution = 
1468                  model->getReducedCost();
1469                const double * primalColumnSolution = 
1470                  model->getColSolution();
1471                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1472                  fprintf(fp,"%7d ",iColumn);
1473                  fprintf(fp,"%15.8g        %15.8g\n",
1474                          primalColumnSolution[iColumn],
1475                          dualColumnSolution[iColumn]);
1476                }
1477                if (fp!=stdout)
1478                  fclose(fp);
1479              } else {
1480                std::cout<<"Unable to open file "<<fileName<<std::endl;
1481              }
1482            } else {
1483              std::cout<<"** Current model not valid"<<std::endl;
1484             
1485            }
1486            break;
1487          default:
1488            abort();
1489          }
1490        } 
1491      } else if (!numberMatches) {
1492        std::cout<<"No match for "<<field<<" - ? for list of commands"
1493                 <<std::endl;
1494      } else if (numberMatches==1) {
1495        if (!numberQuery) {
1496          std::cout<<"Short match for "<<field<<" possible completion:"
1497                   <<std::endl;
1498          for ( iParam=0; iParam<numberParameters; iParam++ ) {
1499            int match = parameters[iParam].matches(field);
1500            if (match) 
1501              std::cout<<parameters[iParam].matchName()<<std::endl;
1502          }
1503        } else if (numberQuery) {
1504          std::cout<<"Short match for "<<field<<" completion:"
1505                   <<std::endl;
1506          for ( iParam=0; iParam<numberParameters; iParam++ ) {
1507            int match = parameters[iParam].matches(field);
1508            if (match) {
1509              std::cout<<parameters[iParam].matchName()<<" : ";
1510              std::cout<<parameters[iParam].shortHelp()<<std::endl;
1511            }
1512          }
1513        }
1514      } else {
1515        if (!numberQuery) 
1516          std::cout<<"Multiple matches for "<<field<<" - possible completions:"
1517                   <<std::endl;
1518        else
1519          std::cout<<"Completions of "<<field<<":"<<std::endl;
1520        for ( iParam=0; iParam<numberParameters; iParam++ ) {
1521          int match = parameters[iParam].matches(field);
1522          if (match) {
1523            std::cout<<parameters[iParam].matchName();
1524            if (numberQuery>=2) 
1525              std::cout<<" : "<<parameters[iParam].shortHelp();
1526            std::cout<<std::endl;
1527          }
1528        }
1529      }
1530    }
1531/*
1532  Final cleanup. Delete the model and the vector of available solvers.
1533*/
1534    delete model;
1535
1536    for (solverMapIter_t solverIter = solvers.begin() ;
1537         solverIter != solvers.end() ;
1538         solverIter++)
1539    { if (solverIter->second) delete solverIter->second ; }
1540  }
1541  return 0;
1542}   
Note: See TracBrowser for help on using the repository browser.