source: branches/devel/Cbc/src/CbcMain.cpp @ 534

Last change on this file since 534 was 388, checked in by andreasw, 13 years ago

fixed problem with VERSION preprocessor symbol

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