source: trunk/Cbc/src/CbcMain.cpp @ 862

Last change on this file since 862 was 768, checked in by ladanyi, 12 years ago

Fixed path handling for Windows

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.3 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("dirSample","Set directory where the COIN-OR sample problems are.",
308               DIRSAMPLE);
309    parameters[numberParameters++]=
310      CbcParam("dirNetlib","Set directory where the netlib problems are.",
311               DIRNETLIB);
312    parameters[numberParameters++]=
313      CbcOrClpParam("dirMiplib","Set directory where the miplib 2003 problems are.",
314                    DIRMIPLIB);
315    parameters[numberParameters++]=
316      CbcParam("solver!","Set the solver used by cbc",
317               SOLVER) ;
318    parameters[numberParameters++]=
319      CbcParam("import","Import model from mps file",
320              IMPORT);
321    parameters[numberParameters++]=
322      CbcParam("export","Export model as mps file",
323              EXPORT);
324    parameters[numberParameters++]=
325      CbcParam("save!Model","Save model to binary file",
326              SAVE);
327    parameters[numberParameters++]=
328      CbcParam("restore!Model","Restore model from binary file",
329              RESTORE);
330    parameters[numberParameters++]=
331      CbcParam("presolve","Whether to use integer presolve - be careful",
332              "off",PRESOLVE);
333    parameters[numberParameters-1].append("on");
334    parameters[numberParameters++]=
335      CbcParam("preprocess","Whether to use integer preprocessing",
336              "off",PREPROCESS);
337    parameters[numberParameters-1].append("on");
338    parameters[numberParameters++]=
339      CbcParam("initialS!olve","Solve to continuous",
340              SOLVECONTINUOUS);
341    parameters[numberParameters++]=
342      CbcParam("branch!AndBound","Do Branch and Bound",
343              BAB);
344    parameters[numberParameters++]=
345      CbcParam("sol!ution","Prints solution to file",
346              SOLUTION);
347    parameters[numberParameters++]=
348      CbcParam("max!imize","Set optimization direction to maximize",
349              MAXIMIZE);
350    parameters[numberParameters++]=
351      CbcParam("min!imize","Set optimization direction to minimize",
352              MINIMIZE);
353    parameters[numberParameters++] =
354      CbcParam("time!Limit","Set a time limit for solving this problem",
355              1.0,(double)(60*60*24*365*10),TIMELIMIT) ;
356    parameters[numberParameters++]=
357      CbcParam("exit","Stops cbc execution",
358              EXIT);
359    parameters[numberParameters++]=
360      CbcParam("stop","Stops cbc execution",
361              EXIT);
362    parameters[numberParameters++]=
363      CbcParam("quit","Stops cbc execution",
364              EXIT);
365    parameters[numberParameters++]=
366      CbcParam("-","From stdin",
367              STDIN);
368    parameters[numberParameters++]=
369      CbcParam("stdin","From stdin",
370              STDIN);
371    parameters[numberParameters++]=
372      CbcParam("unitTest","Do unit test",
373              UNITTEST);
374    parameters[numberParameters++]=
375      CbcParam("miplib","Do some of miplib test set",
376              MIPLIB);
377    parameters[numberParameters++]=
378      CbcParam("ver!sion","Print out version",
379              PRINTVERSION);
380    parameters[numberParameters++]=
381      CbcParam("alg!orithm","Whether to use dual or primal",
382              "dual",ALGORITHM);
383    parameters[numberParameters-1].append("primal");
384
385    assert(numberParameters<MAXPARAMETERS);
386
387  return ; }
388
389#ifdef COIN_USE_READLINE     
390#include <readline/readline.h>
391#include <readline/history.h>
392#endif
393
394// Returns next valid field
395
396int read_mode=1;
397char line[1000];
398char * where=NULL;
399
400std::string
401nextField()
402{
403  std::string field;
404  if (!where) {
405    // need new line
406#ifdef COIN_USE_READLINE     
407    // Get a line from the user.
408    where = readline ("Cbc:");
409     
410    // If the line has any text in it, save it on the history.
411    if (where) {
412      if ( *where)
413        add_history (where);
414      strcpy(line,where);
415    }
416#else
417    fprintf(stdout,"Cbc:");
418    fflush(stdout);
419    where = fgets(line,1000,stdin);
420#endif
421    if (!where)
422      return field; // EOF
423    where = line;
424    // clean image
425    char * lastNonBlank = line-1;
426    while ( *where != '\0' ) {
427      if ( *where != '\t' && *where < ' ' ) {
428        break;
429      } else if ( *where != '\t' && *where != ' ') {
430        lastNonBlank = where;
431      }
432      where++;
433    }
434    where=line;
435    *(lastNonBlank+1)='\0';
436  }
437  // munch white space
438  while(*where==' '||*where=='\t')
439    where++;
440  char * saveWhere = where;
441  while (*where!=' '&&*where!='\t'&&*where!='\0')
442    where++;
443  if (where!=saveWhere) {
444    char save = *where;
445    *where='\0';
446    //convert to string
447    field=saveWhere;
448    *where=save;
449  } else {
450    where=NULL;
451    field="EOL";
452  }
453  return field;
454}
455
456std::string
457getCommand(int argc, const char *argv[])
458{
459  std::string field="EOL";
460  while (field=="EOL") {
461    if (read_mode>0) {
462      if (read_mode<argc) {
463        field = argv[read_mode++];
464        if (field=="-") {
465          std::cout<<"Switching to line mode"<<std::endl;
466          read_mode=-1;
467          field=nextField();
468        } else if (field[0]!='-') {
469          if (read_mode!=2) {
470            std::cout<<"skipping non-command "<<field<<std::endl;
471            field="EOL"; // skip
472          } else {
473            // special dispensation - taken as -import name
474            read_mode--;
475            field="import";
476          }
477        } else {
478          if (field!="--") {
479            // take off -
480            field = field.substr(1);
481          } else {
482            // special dispensation - taken as -import --
483            read_mode--;
484            field="import";
485          }
486        }
487      } else {
488        field="";
489      }
490    } else {
491      field=nextField();
492    }
493  }
494  //std::cout<<field<<std::endl;
495  return field;
496}
497std::string
498getString(int argc, const char *argv[])
499{
500  std::string field="EOL";
501  if (read_mode>0) {
502    if (read_mode<argc) {
503      if (argv[read_mode][0]!='-') { 
504        field = argv[read_mode++];
505      } else if (!strcmp(argv[read_mode],"--")) {
506        field = argv[read_mode++];
507        // -- means import from stdin
508        field = "-";
509      }
510    }
511  } else {
512    field=nextField();
513  }
514  //std::cout<<field<<std::endl;
515  return field;
516}
517
518// valid = 0 okay, 1 bad, 2 not there
519int
520getIntField(int argc, const char *argv[],int * valid)
521{
522  std::string field="EOL";
523  if (read_mode>0) {
524    if (read_mode<argc) {
525      // may be negative value so do not check for -
526      field = argv[read_mode++];
527    }
528  } else {
529    field=nextField();
530  }
531  int value=0;
532  //std::cout<<field<<std::endl;
533  if (field!="EOL") {
534    // how do I check valid
535    value =  atoi(field.c_str());
536    *valid=0;
537  } else {
538    *valid=2;
539  }
540  return value;
541}
542
543
544// valid = 0 okay, 1 bad, 2 not there
545double
546getDoubleField(int argc, const char *argv[],int * valid)
547{
548  std::string field="EOL";
549  if (read_mode>0) {
550    if (read_mode<argc) {
551      // may be negative value so do not check for -
552      field = argv[read_mode++];
553    }
554  } else {
555    field=nextField();
556  }
557  double value=0.0;
558  //std::cout<<field<<std::endl;
559  if (field!="EOL") {
560    // how do I check valid
561    value = atof(field.c_str());
562    *valid=0;
563  } else {
564    *valid=2;
565  }
566  return value;
567}
568
569/// For run timing
570
571double totalTime=0.0;
572
573}       /* end unnamed namespace */
574
575int CbcOrClpRead_mode=1;
576FILE * CbcOrClpReadCommand=stdin;
577
578int main (int argc, const char *argv[])
579{
580  // next {} is just to make sure all memory should be freed - for debug
581  {
582    std::ios::sync_with_stdio() ;
583/*
584  Create a vector of solver prototypes and establish a default solver. After
585  this the code is solver independent.
586
587  Creating multiple solvers is moderately expensive. If you don't want to
588  make use of this feature, best to define just one. The businesss with
589  CBC_DEFAULT_SOLVER will select the first available solver as the default,
590  unless overridden at compile time.
591
592  NOTE that processing of string parameters is case-independent, but maps are
593       case-sensitive. The solver name given here must contain only lower case
594       letters.
595*/
596    typedef std::map<std::string,OsiSolverInterface*> solverMap_t ;
597    typedef solverMap_t::const_iterator solverMapIter_t ;
598
599    solverMap_t solvers ;
600
601#   ifdef COIN_HAS_CLP
602#     ifndef CBC_DEFAULT_SOLVER
603#       define CBC_DEFAULT_SOLVER "clp"
604#     endif
605      solvers["clp"] = new OsiClpSolverInterface ;
606#   else
607      solvers["clp"] = 0 ;
608#   endif
609#   ifdef COIN_HAS_DYLP
610#     ifndef CBC_DEFAULT_SOLVER
611#       define CBC_DEFAULT_SOLVER "dylp"
612#     endif
613      solvers["dylp"] = new OsiDylpSolverInterface  ;
614#   else
615      solvers["dylp"] = 0 ;
616#   endif
617#   ifdef COIN_HAS_OSL
618#     ifndef CBC_DEFAULT_SOLVER
619#       define CBC_DEFAULT_SOLVER "osl"
620#     endif
621      solvers["osl"] = new OsiOslSolverInterface  ;
622#   else
623      solvers["osl"] = 0 ;
624#   endif
625/*
626  If we don't have a default solver, we're deeply confused.
627*/
628    OsiSolverInterface *dflt_solver = solvers[CBC_DEFAULT_SOLVER] ;
629    if (dflt_solver)
630    { std::cout << "Default solver is " << CBC_DEFAULT_SOLVER << std::endl ; }
631    else
632    { std::cerr << "No solvers! Aborting." << std::endl ;
633      return (1) ; }
634/*
635  For calculating run time.
636*/
637    double time1 = CoinCpuTime() ;
638    double time2;
639/*
640  Establish the command line interface: parameters, with associated info
641  messages, ranges, defaults. See CbcParam for details. Scan the vector of
642  solvers and add the names to the parameter object.
643*/
644    CbcParam parameters[MAXPARAMETERS];
645    int numberParameters ;
646    establishParams(numberParameters,parameters) ;
647
648    { int iSolver = 0 ;
649      for ( ; iSolver < numberParameters ; iSolver++)
650      { int match = parameters[iSolver].matches("solver") ;
651        if (match==1) break ; }
652      for (solverMapIter_t solverIter = solvers.begin() ;
653           solverIter != solvers.end() ;
654           solverIter++)
655      { if (solverIter->second)
656          parameters[iSolver].append(solverIter->first) ; }
657      int iKwd = parameters[iSolver].parameterOption(CBC_DEFAULT_SOLVER) ;
658      parameters[iSolver].setCurrentOption(iKwd) ; }
659/*
660  The rest of the default setup: establish a model, instantiate cut generators
661  and heuristics, set various default values.
662*/
663    dflt_solver->messageHandler()->setLogLevel(0) ;
664    CbcModel *model = new CbcModel(*dflt_solver) ;
665    model->messageHandler()->setLogLevel(1);
666    bool goodModel=false;
667   
668// Set up likely cut generators and defaults
669
670    CglGomory gomoryGen;
671    // try larger limit
672    gomoryGen.setLimit(300);
673    // set default action (0=off,1=on,2=root)
674    int gomoryAction=1;
675
676    CglProbing probingGen;
677    probingGen.setUsingObjective(true);
678    probingGen.setMaxPass(3);
679    probingGen.setMaxPassRoot(3);
680    // Number of unsatisfied variables to look at
681    probingGen.setMaxProbe(10);
682    probingGen.setMaxProbeRoot(50);
683    // How far to follow the consequences
684    probingGen.setMaxLook(10);
685    probingGen.setMaxLookRoot(50);
686    // Only look at rows with fewer than this number of elements
687    probingGen.setMaxElements(200);
688    probingGen.setRowCuts(3);
689    // set default action (0=off,1=on,2=root)
690    int probingAction=1;
691
692    CglKnapsackCover knapsackGen;
693    // set default action (0=off,1=on,2=root)
694    int knapsackAction=1;
695
696    CglOddHole oddholeGen;
697    oddholeGen.setMinimumViolation(0.005);
698    oddholeGen.setMinimumViolationPer(0.0002);
699    oddholeGen.setMaximumEntries(100);
700    // set default action (0=off,1=on,2=root)
701    int oddholeAction=0;
702
703    CglClique cliqueGen;
704    cliqueGen.setStarCliqueReport(false);
705    cliqueGen.setRowCliqueReport(false);
706    // set default action (0=off,1=on,2=root)
707    int cliqueAction=1;
708
709    CglMixedIntegerRounding mixedGen;
710    // set default action (0=off,1=on,2=root)
711    int mixedAction=1;
712
713    CglFlowCover flowGen;
714    // set default action (0=off,1=on,2=root)
715    int flowAction=1;
716
717    CglTwomir twomirGen;
718    // set default action (0=off,1=on,2=root)
719    int twomirAction=0;
720
721    bool useRounding=true;
722   
723    int allowImportErrors=0;
724    int algorithm=0; // dual
725    int keepImportNames=1;      // not implemented
726    int doScaling=1;
727    int preSolve=0;
728    int preProcess=1;
729    double djFix=1.0e100;
730    double gapRatio=1.0e100;
731    double tightenFactor=0.0;
732
733    // Set false if user does anything advanced
734    bool defaultSettings=true;
735
736    const char dirsep =  CoinFindDirSeparator();
737    std::string directory;
738    std::string dirSample;
739    std::string dirNetlib;
740    std::string dirMiplib;
741    if (dirsep == '/') {
742      directory = "./";
743      dirSample = "../../Data/Sample/";
744      dirNetlib = "../../Data/Netlib/";
745      dirMiplib = "../../Data/miplib3/";
746    } else {
747      directory = ".\\";
748      dirSample = "..\\..\\Data\\Sample\\";
749      dirNetlib = "..\\..\\Data\\Netlib\\";
750      dirMiplib = "..\\..\\Data\\miplib3\\";
751    }
752    std::string field;
753/*
754  The main command parsing loop.
755*/
756    // total number of commands read
757    int numberGoodCommands=0;
758   
759    while (1) {
760      // next command
761      field=getCommand(argc,argv);
762     
763      // exit if null or similar
764      if (!field.length()) {
765        if (numberGoodCommands==1&&goodModel) {
766          // we just had file name
767          field="branchAndBound";
768        } else if (!numberGoodCommands) {
769          // let's give the sucker a hint
770          std::cout
771            <<"Cbc takes input from arguments ( - switches to stdin)"
772            <<std::endl
773            <<"Enter ? for list of commands or (-)unitTest or -miplib"
774            <<" for tests"<<std::endl;
775          break;
776        } else {
777          break;
778        }
779      }
780     
781      // see if ? at end
782      int numberQuery=0;
783      if (field!="?") {
784        int length = field.length();
785        int i;
786        for (i=length-1;i>0;i--) {
787          if (field[i]=='?') 
788            numberQuery++;
789          else
790            break;
791        }
792        field=field.substr(0,length-numberQuery);
793      }
794      // find out if valid command
795      int iParam;
796      int numberMatches=0;
797      for ( iParam=0; iParam<numberParameters; iParam++ ) {
798        int match = parameters[iParam].matches(field);
799        if (match==1) {
800          numberMatches = 1;
801          break;
802        } else {
803          numberMatches += match>>1;
804        }
805      }
806      if (iParam<numberParameters&&!numberQuery) {
807        // found
808        CbcParam found = parameters[iParam];
809        CbcParameterType type = found.type();
810        int valid;
811        numberGoodCommands++;
812        if (type==GENERALQUERY) {
813          std::cout<<"In argument list keywords have leading - "
814            ", -stdin or just - switches to stdin"<<std::endl;
815          std::cout<<"One command per line (and no -)"<<std::endl;
816          std::cout<<"abcd? gives list of possibilities, if only one + explanation"<<std::endl;
817          std::cout<<"abcd?? adds explanation, if only one fuller help(LATER)"<<std::endl;
818          std::cout<<"abcd without value (where expected) gives current value"<<std::endl;
819          std::cout<<"abcd value or abcd = value sets value"<<std::endl;
820          std::cout<<"Commands are:"<<std::endl;
821          for ( iParam=0; iParam<numberParameters; iParam+=4 ) {
822            int i;
823            for (i=iParam;i<min(numberParameters,iParam+4);i++) 
824              std::cout<<parameters[i].matchName()<<"  ";
825            std::cout<<std::endl;
826          }
827        } else if (type<81) {
828          // get next field as double
829          double value = getDoubleField(argc,argv,&valid);
830          if (!valid) {
831            parameters[iParam].setDoubleParameter(*model,value);
832          } else if (valid==1) {
833            abort();
834          } else {
835            std::cout<<parameters[iParam].name()<<" has value "<<
836              parameters[iParam].doubleParameter(*model)<<std::endl;
837          }
838        } else if (type<101) {
839          // get next field as double for local use
840          double value = getDoubleField(argc,argv,&valid);
841          if (!valid) {
842            if (!parameters[iParam].checkDoubleParameter(value)) {
843              switch(type) {
844              case DJFIX:
845                djFix=value;
846                preSolve=5;
847                defaultSettings=false; // user knows what she is doing
848                break;
849              case GAPRATIO:
850                gapRatio=value;
851                break;
852              case TIGHTENFACTOR:
853                tightenFactor=value;
854                defaultSettings=false; // user knows what she is doing
855                break;
856              default:
857                abort();
858              }
859            }
860          } else if (valid==1) {
861            std::cout<<" is illegal for double parameter "<<parameters[iParam].name()<<" value remains "<<
862              parameters[iParam].doubleValue()<<std::endl;
863          } else {
864            switch(type) {
865            case DJFIX:
866              value = djFix ;
867              break;
868            case GAPRATIO:
869              value = gapRatio ;
870              break;
871            case TIGHTENFACTOR:
872              value = tightenFactor ;
873              break;
874            default:
875              abort();
876            }
877            std::cout << parameters[iParam].name() << " has value " <<
878                         value << std::endl ;
879          }
880        } else if (type<201) {
881          // get next field as int
882          int value = getIntField(argc,argv,&valid);
883          if (!valid) {
884            parameters[iParam].setIntParameter(*model,value);
885          } else if (valid==1) {
886            std::cout<<" is illegal for integer parameter "<<parameters[iParam].name()<<" value remains "<<
887              parameters[iParam].intValue()<<std::endl;
888          } else {
889            std::cout<<parameters[iParam].name()<<" has value "<<
890              parameters[iParam].intParameter(*model)<<std::endl;
891          }
892        } else if (type<301) {
893          // one of several strings
894          std::string value = getString(argc,argv);
895          int action = parameters[iParam].parameterOption(value);
896          if (action<0) {
897            if (value!="EOL") {
898              // no match
899              parameters[iParam].printOptions();
900            } else {
901              // print current value
902              std::cout<<parameters[iParam].name()<<" has value "<<
903                parameters[iParam].currentOption()<<std::endl;
904            }
905          } else {
906            parameters[iParam].setCurrentOption(action);
907            // for now hard wired
908            switch (type) {
909            case DIRECTION:
910              if (action==0)
911                model->solver()->setObjSense(1);
912              else
913                model->solver()->setObjSense(-1);
914              break;
915            case ERRORSALLOWED:
916              allowImportErrors = action;
917              break;
918            case ALGORITHM:
919              algorithm  = action;
920              defaultSettings=false; // user knows what she is doing
921              break;
922            case KEEPNAMES:
923              keepImportNames = 1-action;
924              break;
925            case SCALING:
926              doScaling = 1-action;
927              break;
928            case GOMORYCUTS:
929              defaultSettings=false; // user knows what she is doing
930              gomoryAction = action;
931              break;
932            case PROBINGCUTS:
933              defaultSettings=false; // user knows what she is doing
934              probingAction = action;
935              break;
936            case KNAPSACKCUTS:
937              defaultSettings=false; // user knows what she is doing
938              knapsackAction = action;
939              break;
940            case ODDHOLECUTS:
941              defaultSettings=false; // user knows what she is doing
942              oddholeAction = action;
943              break;
944            case CLIQUECUTS:
945              defaultSettings=false; // user knows what she is doing
946              cliqueAction = action;
947              break;
948            case FLOWCUTS:
949              defaultSettings=false; // user knows what she is doing
950              flowAction = action;
951              break;
952            case MIXEDCUTS:
953              defaultSettings=false; // user knows what she is doing
954              mixedAction = action;
955              break;
956            case TWOMIRCUTS:
957              defaultSettings=false; // user knows what she is doing
958              twomirAction = action;
959              break;
960            case ROUNDING:
961              defaultSettings=false; // user knows what she is doing
962              useRounding = action;
963              break;
964            case COSTSTRATEGY:
965              if (action!=1) {
966                printf("Pseudo costs not implemented yet\n");
967              } else {
968                int numberColumns = model->getNumCols();
969                int * sort = new int[numberColumns];
970                double * dsort = new double[numberColumns];
971                int * priority = new int [numberColumns];
972                const double * objective = model->getObjCoefficients();
973                int iColumn;
974                int n=0;
975                for (iColumn=0;iColumn<numberColumns;iColumn++) {
976                  if (model->isInteger(iColumn)) {
977                    sort[n]=n;
978                    dsort[n++]=-objective[iColumn];
979                  }
980                }
981                CoinSort_2(dsort,dsort+n,sort);
982                int level=0;
983                double last = -1.0e100;
984                for (int i=0;i<n;i++) {
985                  int iPut=sort[i];
986                  if (dsort[i]!=last) {
987                    level++;
988                    last=dsort[i];
989                  }
990                  priority[iPut]=level;
991                }
992                model->passInPriorities( priority,false);
993                delete [] priority;
994                delete [] sort;
995                delete [] dsort;
996              }
997              break;
998            case PRESOLVE:
999                defaultSettings=false; // user knows what she is doing
1000              preSolve = action*5;
1001              break;
1002            case PREPROCESS:
1003              preProcess = action;
1004              break;
1005            case SOLVER:
1006            { for (int i = 0 ; i < (int) value.length() ; i++)
1007                value[i] = tolower(value[i]) ;
1008              OsiSolverInterface *newSolver = solvers[value]->clone() ;
1009              model->assignSolver(newSolver) ;
1010              std::cout << "Solver set to " << value << "." << std::endl ;
1011              break ; }
1012            default:
1013            { std::cerr << "Unrecognized action. Aborting." << std::endl ;
1014              abort(); }
1015            }
1016          }
1017        } else {
1018          // action
1019          if (type==EXIT)
1020            break; // stop all
1021          switch (type) {
1022          case SOLVECONTINUOUS:
1023            if (goodModel) {
1024              model->initialSolve();
1025              time2 = CoinCpuTime();
1026              totalTime += time2-time1;
1027              std::cout<<"Result "<<model->solver()->getObjValue()<<
1028                " iterations "<<model->solver()->getIterationCount()<<
1029                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
1030              time1=time2;
1031            } else {
1032              std::cout<<"** Current model not valid"<<std::endl;
1033            }
1034            break;
1035/*
1036  Run branch-and-cut. First set a few options -- node comparison, scaling. If
1037  the solver is Clp, consider running some presolve code (not yet converted
1038  this to generic OSI) with branch-and-cut. If presolve is disabled, or the
1039  solver is not Clp, simply run branch-and-cut. Print elapsed time at the end.
1040*/
1041          case BAB: // branchAndBound
1042          { if (goodModel)
1043            { CbcCompareUser compare; // Definition of node choice
1044            // If user made settings then use them
1045            if (!defaultSettings) {
1046              model->setNodeComparison(compare);
1047              OsiSolverInterface * solver = model->solver();
1048              if (!doScaling)
1049                solver->setHintParam(OsiDoScale,false,OsiHintTry);
1050#ifdef COIN_HAS_CLP
1051              OsiClpSolverInterface * si =
1052                dynamic_cast<OsiClpSolverInterface *>(solver) ;
1053              if (preSolve&&si != NULL) {
1054                // get clp itself
1055                ClpSimplex * modelC = si->getModelPtr();
1056                if (si->messageHandler()->logLevel())
1057                  si->messageHandler()->setLogLevel(1);
1058                if (modelC->tightenPrimalBounds()!=0) {
1059                  std::cout<<"Problem is infeasible!"<<std::endl;
1060                  break;
1061                }
1062                model->initialSolve();
1063                // bounds based on continuous
1064                if (tightenFactor) {
1065                  if (modelC->tightenPrimalBounds(tightenFactor)!=0) {
1066                    std::cout<<"Problem is infeasible!"<<std::endl;
1067                    break;
1068                  }
1069                }
1070                if (gapRatio<1.0e100) {
1071                  double value = si->getObjValue();
1072                  double value2 = gapRatio*(1.0e-5+fabs(value));
1073                  model->setAllowableGap(value2);
1074                  model->setAllowableFractionGap(gapRatio);
1075                  std::cout<<"Continuous "<<value
1076                           <<", so allowable gap set to "<<value2<<std::endl;
1077                }
1078                if (djFix<1.0e20) {
1079                  // do some fixing
1080                  int numberColumns = modelC->numberColumns();
1081                  int i;
1082                  const char * type = modelC->integerInformation();
1083                  double * lower = modelC->columnLower();
1084                  double * upper = modelC->columnUpper();
1085                  double * solution = modelC->primalColumnSolution();
1086                  double * dj = modelC->dualColumnSolution();
1087                  int numberFixed=0;
1088                  for (i=0;i<numberColumns;i++) {
1089                    if (type[i]) {
1090                      double value = solution[i];
1091                      if (value<lower[i]+1.0e-5&&dj[i]>djFix) {
1092                        solution[i]=lower[i];
1093                        upper[i]=lower[i];
1094                        numberFixed++;
1095                      } else if (value>upper[i]-1.0e-5&&dj[i]<-djFix) {
1096                        solution[i]=upper[i];
1097                        lower[i]=upper[i];
1098                        numberFixed++;
1099                      }
1100                    }
1101                  }
1102                  printf("%d columns fixed\n",numberFixed);
1103                }
1104                {
1105                  // integer presolve
1106                  CbcModel * model2 = model->integerPresolve();
1107                  if (model2) {
1108                    // Do complete search
1109                   
1110                    CbcRounding heuristic1(*model2);
1111                    if (useRounding)
1112                      model2->addHeuristic(&heuristic1);
1113                    if (algorithm) {
1114                      // user wants primal
1115                      model2->solver()->setHintParam(OsiDoDualInInitial,false,OsiHintTry);
1116                      model2->solver()->setHintParam(OsiDoDualInResolve,false,OsiHintTry);
1117                    }
1118                    try
1119                    { model2->branchAndBound(); }
1120                    catch (CoinError err)
1121                    { std::cerr << "Exception: "
1122                                << err.className() << "::" << err.methodName()
1123                                << std::endl ;
1124                      std::cerr << err.message() << std::endl ;
1125                      exit (1) ; }
1126                    // get back solution
1127                    model->originalModel(model2,false);
1128                  } else {
1129                    // infeasible
1130                    exit(1);
1131                  }
1132                }
1133              } else
1134#endif
1135              { if (model->solver()->messageHandler()->logLevel())
1136                  model->solver()->messageHandler()->setLogLevel(1) ;
1137                model->initialSolve() ;
1138                if (gapRatio < 1.0e100)
1139                { double value = model->solver()->getObjValue() ;
1140                  double value2 = gapRatio*(1.0e-5+fabs(value)) ;
1141                  model->setAllowableGap(value2) ;
1142                  std::cout << "Continuous " << value
1143                            << ", so allowable gap set to "
1144                            << value2 << std::endl ; }
1145                CbcRounding heuristic1(*model) ;
1146                if (useRounding)
1147                  model->addHeuristic(&heuristic1) ;
1148                // add cut generators if wanted
1149                if (probingAction==1)
1150                  model->addCutGenerator(&probingGen,-1,"Probing");
1151                else if (probingAction==2)
1152                  model->addCutGenerator(&probingGen,-99,"Probing");
1153                if (gomoryAction==1)
1154                  model->addCutGenerator(&gomoryGen,-1,"Gomory");
1155                else if (gomoryAction==2)
1156                  model->addCutGenerator(&gomoryGen,-99,"Gomory");
1157                if (knapsackAction==1)
1158                  model->addCutGenerator(&knapsackGen,-1,"Knapsack");
1159                else if (knapsackAction==2)
1160                  model->addCutGenerator(&knapsackGen,-99,"Knapsack");
1161                if (oddholeAction==1)
1162                  model->addCutGenerator(&oddholeGen,-1,"OddHole");
1163                else if (oddholeAction==2)
1164                  model->addCutGenerator(&oddholeGen,-99,"OddHole");
1165                if (cliqueAction==1)
1166                  model->addCutGenerator(&cliqueGen,-1,"Clique");
1167                else if (cliqueAction==2)
1168                  model->addCutGenerator(&cliqueGen,-99,"Clique");
1169                if (mixedAction==1)
1170                  model->addCutGenerator(&mixedGen,-1,"MixedintegerRounding");
1171                else if (mixedAction==2)
1172                  model->addCutGenerator(&mixedGen,-99,"MixedintegerRounding");
1173                if (flowAction==1)
1174                  model->addCutGenerator(&flowGen,-1,"FlowCover");
1175                else if (flowAction==2)
1176                  model->addCutGenerator(&flowGen,-99,"FlowCover");
1177                if (twomirAction==1)
1178                  model->addCutGenerator(&twomirGen,-1,"TwoMirCuts");
1179                else if (twomirAction==2)
1180                  model->addCutGenerator(&twomirGen,-99,"TwoMirCuts");
1181                try
1182                { model->branchAndBound(); }
1183                catch (CoinError err)
1184                { std::cerr << "Exception: "
1185                            << err.className() << "::" << err.methodName()
1186                            << std::endl ;
1187                  std::cerr << err.message() << std::endl ;
1188                  exit (1) ; }
1189              }
1190              if (model->bestSolution())
1191              { std::cout << "Optimal solution "
1192                          << model->solver()->getObjValue() << std::endl ; }
1193              else
1194              { std::cout << "No integer solution found." << std::endl ; }
1195                       
1196              time2 = CoinCpuTime() ;
1197              totalTime += time2-time1 ;
1198              std::cout << "Result " << model->solver()->getObjValue()
1199                        << " took " << time2-time1 << " seconds - total "
1200                        << totalTime << std::endl ;
1201              time1 = time2 ;
1202            } else {
1203/*
1204  User is willing to accept cbc defaults. Do an initial solve.
1205*/
1206              if (!doScaling)
1207                model->solver()->setHintParam(OsiDoScale,false,OsiHintTry);
1208              model->initialSolve();
1209/*
1210  Integer preprocessing. For reasons that escape me just yet, the first thing
1211  we'll do is clone the solver for the model.
1212*/
1213              OsiSolverInterface * saveSolver=NULL;
1214              CglPreProcess process;
1215              if (preProcess) {
1216                saveSolver=model->solver()->clone();
1217                /* Do not try and produce equality cliques and
1218                   do up to 10 passes */
1219                OsiSolverInterface * solver2 = process.preProcess(*saveSolver,false,10);
1220                if (!solver2) {
1221                  printf("Pre-processing says infeasible\n");
1222                  break;
1223                } else {
1224                  printf("processed model has %d rows and %d columns\n",
1225                         solver2->getNumRows(),solver2->getNumCols());
1226                }
1227                //solver2->resolve();
1228                // we have to keep solver2 so pass clone
1229                solver2 = solver2->clone();
1230                model->assignSolver(solver2);
1231                model->initialSolve();
1232              }
1233              model->setNodeComparison(compare);
1234              CbcRounding heuristic1(*model);
1235              if (useRounding)
1236                model->addHeuristic(&heuristic1) ;
1237              // add cut generators if wanted
1238              if (probingAction==1)
1239                model->addCutGenerator(&probingGen,-1,"Probing");
1240              else if (probingAction==2)
1241                model->addCutGenerator(&probingGen,-99,"Probing");
1242              if (gomoryAction==1)
1243                model->addCutGenerator(&gomoryGen,-1,"Gomory");
1244              else if (gomoryAction==2)
1245                model->addCutGenerator(&gomoryGen,-99,"Gomory");
1246              if (knapsackAction==1)
1247                model->addCutGenerator(&knapsackGen,-1,"Knapsack");
1248              else if (knapsackAction==2)
1249                model->addCutGenerator(&knapsackGen,-99,"Knapsack");
1250              if (oddholeAction==1)
1251                model->addCutGenerator(&oddholeGen,-1,"OddHole");
1252              else if (oddholeAction==2)
1253                model->addCutGenerator(&oddholeGen,-99,"OddHole");
1254              if (cliqueAction==1)
1255                model->addCutGenerator(&cliqueGen,-1,"Clique");
1256              else if (cliqueAction==2)
1257                model->addCutGenerator(&cliqueGen,-99,"Clique");
1258              if (mixedAction==1)
1259                model->addCutGenerator(&mixedGen,-1,"MixedintegerRounding");
1260              else if (mixedAction==2)
1261                model->addCutGenerator(&mixedGen,-99,"MixedintegerRounding");
1262              if (flowAction==1)
1263                model->addCutGenerator(&flowGen,-1,"FlowCover");
1264              else if (flowAction==2)
1265                model->addCutGenerator(&flowGen,-99,"FlowCover");
1266              if (twomirAction==1)
1267                model->addCutGenerator(&twomirGen,-1,"TwoMirCuts");
1268              else if (twomirAction==2)
1269                model->addCutGenerator(&twomirGen,-99,"TwoMirCuts");
1270              // Say we want timings
1271              int numberGenerators = model->numberCutGenerators();
1272              int iGenerator;
1273              for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) {
1274                CbcCutGenerator * generator = model->cutGenerator(iGenerator);
1275                generator->setTiming(true);
1276              }
1277              // Could tune more
1278              model->setMinimumDrop(min(1.0,
1279                                        fabs(model->getMinimizationObjValue())*1.0e-3+1.0e-4));
1280             
1281              if (model->getNumCols()<500)
1282                model->setMaximumCutPassesAtRoot(-100); // always do 100 if possible
1283              else if (model->getNumCols()<5000)
1284                model->setMaximumCutPassesAtRoot(100); // use minimum drop
1285              else
1286                model->setMaximumCutPassesAtRoot(20);
1287              model->setMaximumCutPasses(2);
1288             
1289              // Do more strong branching if small
1290              if (model->getNumCols()<5000)
1291                model->setNumberStrong(20);
1292              // Switch off strong branching if wanted
1293              //if (model->getNumCols()>10*model->getNumRows())
1294              //model->setNumberStrong(0);
1295              if (model->getNumCols()>2000||model->getNumRows()>1500||
1296                  model->messageHandler()->logLevel()>1)
1297                model->setPrintFrequency(100);
1298             
1299              model->solver()->setIntParam(OsiMaxNumIterationHotStart,100);
1300#ifdef COIN_HAS_CLP
1301              OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model->solver());
1302              if (osiclp) {
1303                // go faster stripes
1304                if (osiclp->getNumRows()<300&&osiclp->getNumCols()<500) {
1305                  osiclp->setupForRepeatedUse(2,0);
1306                }
1307              }
1308#endif
1309              if (gapRatio < 1.0e100)
1310                { double value = model->solver()->getObjValue() ;
1311                double value2 = gapRatio*(1.0e-5+fabs(value)) ;
1312                model->setAllowableGap(value2) ;
1313                std::cout << "Continuous " << value
1314                          << ", so allowable gap set to "
1315                          << value2 << std::endl ; }
1316              try
1317              { model->branchAndBound(); }
1318              catch (CoinError err)
1319              { std::cerr << "Exception: "
1320                          << err.className() << "::" << err.methodName()
1321                          << std::endl ;
1322                std::cerr << err.message() << std::endl ;
1323                exit (1) ; }
1324              time2 = CoinCpuTime();
1325              totalTime += time2-time1;
1326              if (model->getMinimizationObjValue()<1.0e50) {
1327                // post process
1328                if (preProcess) {
1329                  process.postProcess(*model->solver());
1330                  // Solution now back in saveSolver
1331                  model->assignSolver(saveSolver);
1332                }
1333              }
1334              std::cout<<"Result "<<model->getObjValue()<<
1335                " iterations "<<model->getIterationCount()<<
1336                " nodes "<<model->getNodeCount()<<
1337                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
1338              time1 = time2;
1339            }
1340            } else
1341            { std::cout << "** Current model not valid" << std::endl ; }
1342            break ; }
1343          case IMPORT:
1344            {
1345              // get next field
1346              field = getString(argc,argv);
1347              std::string fileName;
1348              bool canOpen=false;
1349              if (field=="-") {
1350                // stdin
1351                canOpen=true;
1352                fileName = "-";
1353              } else {
1354                bool absolutePath;
1355                if (dirsep=='/') {
1356                  // non Windows (or cygwin)
1357                  absolutePath=(field[0]=='/');
1358                } else {
1359                  //Windows (non cycgwin)
1360                  absolutePath=(field[0]=='\\');
1361                  // but allow for :
1362                  if (strchr(field.c_str(),':'))
1363                    absolutePath=true;
1364                }
1365                if (absolutePath) {
1366                  fileName = field;
1367                } else if (field[0]=='~') {
1368                  char * environVar = getenv("HOME");
1369                  if (environVar) {
1370                    std::string home(environVar);
1371                    field=field.erase(0,1);
1372                    fileName = home+field;
1373                  } else {
1374                    fileName=field;
1375                  }
1376                } else {
1377                  fileName = directory+field;
1378                }
1379                FILE *fp=fopen(fileName.c_str(),"r");
1380                if (fp) {
1381                  // can open - lets go for it
1382                  fclose(fp);
1383                  canOpen=true;
1384                } else {
1385                  std::cout<<"Unable to open file "<<fileName<<std::endl;
1386                }
1387              }
1388              if (canOpen) {
1389                model->gutsOfDestructor();
1390                int status =model->solver()->readMps(fileName.c_str(),"");
1391                if (!status||(status>0&&allowImportErrors)) {
1392                  // I don't think there is any need for this but ..
1393                  //OsiWarmStartBasis allSlack;
1394                  goodModel=true;
1395                  //model->setBasis(allSlack);
1396                  time2 = CoinCpuTime();
1397                  totalTime += time2-time1;
1398                  time1=time2;
1399                } else {
1400                  // errors
1401                  std::cout<<"There were "<<status<<
1402                    " errors on input"<<std::endl;
1403                }
1404              }
1405            }
1406            break;
1407          case EXPORT:
1408            {
1409              // get next field
1410              field = getString(argc,argv);
1411              std::string fileName;
1412              bool canOpen=false;
1413              if (field[0]=='/'||field[0]=='~')
1414                fileName = field;
1415              else
1416                fileName = directory+field;
1417              FILE *fp=fopen(fileName.c_str(),"w");
1418              if (fp) {
1419                // can open - lets go for it
1420                fclose(fp);
1421                canOpen=true;
1422              } else {
1423                std::cout<<"Unable to open file "<<fileName<<std::endl;
1424              }
1425              if (canOpen) {
1426                model->solver()->writeMps(fileName.c_str(),"");
1427                time2 = CoinCpuTime();
1428                totalTime += time2-time1;
1429                time1=time2;
1430              }
1431            }
1432            break;
1433          case MAXIMIZE:
1434            model->solver()->setObjSense(-1);
1435            break;
1436          case MINIMIZE:
1437            model->solver()->setObjSense(1);
1438            break;
1439          case DIRECTORY:
1440          { directory = getString(argc,argv);
1441            if (directory[directory.length()-1] != dirsep)
1442              directory += dirsep ;
1443            break ; }
1444          case DIRSAMPLE:
1445          { dirSample = getString(argc,argv);
1446            if (dirSample[dirSample.length()-1] != dirsep)
1447              dirSample += dirsep ;
1448            break ; }
1449          case DIRNETLIB:
1450          { dirNetlib = getString(argc,argv);
1451            if (dirNetlib[dirNetlib.length()-1] != dirsep)
1452              dirNetlib += dirsep ;
1453            break ; }
1454          case DIRMIPLIB:
1455          { dirMiplib = getString(argc,argv);
1456            if (dirMiplib[dirMiplib.length()-1] != dirsep)
1457              dirMiplib += dirsep ;
1458            break ; }
1459          case STDIN:
1460            read_mode=-1;
1461            break;
1462          case PRINTVERSION:
1463            std::cout<<"Coin LP version "<<CBCVERSION
1464                     <<", build "<<__DATE__<<std::endl;
1465            break;
1466          case UNITTEST:
1467            {
1468              // okay so there is not a real unit test
1469
1470              int status =model->solver()->readMps("../../Data/Sample/p0033.mps",
1471                                                   "");
1472              assert(!status);
1473              try
1474              { model->branchAndBound(); }
1475              catch (CoinError err)
1476              { std::cerr << "Exception: "
1477                          << err.className() << "::" << err.methodName()
1478                          << std::endl ;
1479                std::cerr << err.message() << std::endl ;
1480                exit (1) ; }
1481              model->solver()->resolve();
1482              std::cout<<"Optimal solution "<<model->solver()->getObjValue()<<std::endl;
1483              assert(fabs(model->solver()->getObjValue()-3089.0)<1.0e-5);
1484              fprintf(stderr,"Test was okay\n");
1485              status =model->solver()->readMps("../../Data/Sample/p0033.mps",
1486                                                   "");
1487              assert(!status);
1488              model->setCutoff(1.0e20);
1489              model->setBestObjectiveValue(1.0e20);
1490              model->setMaximumSolutions(1);
1491              model->setSolutionCount(0);
1492              // Switch off strong branching to give better chance of NOT finding best
1493              model->setNumberStrong(0);
1494              // Definition of node choice
1495              CbcCompareDefault compare(100.0);
1496              model->setNodeComparison(compare);
1497              model->solver()->resolve();
1498              try
1499              { model->branchAndBound(); }
1500              catch (CoinError err)
1501              { std::cerr << "Exception: "
1502                          << err.className() << "::" << err.methodName()
1503                          << std::endl ;
1504                std::cerr << err.message() << std::endl ;
1505                exit (1) ; }
1506              model->solver()->resolve();
1507              std::cout<<"partial solution "<<model->solver()->getObjValue()<<std::endl;
1508              if (model->solver()->getObjValue()<3090.0) {
1509                std::cout<<"Got optimal solution by mistake!"<<std::endl;
1510              }
1511            }
1512            break;
1513          case MIPLIB:
1514            {
1515              int mainTest (int argc, const char *argv[]);
1516              // create fields for test
1517              const char * fields[3];
1518              int nFields=3;
1519              fields[0]="fake main for miplib";
1520              std::string mpsfield = "-dirSample=";
1521              mpsfield += dirSample.c_str();
1522              fields[1]=mpsfield.c_str();
1523              std::string mipfield = "-dirMiplib=";
1524              mipfield += dirMiplib.c_str();
1525              fields[2]=mipfield.c_str();
1526              mainTest(nFields,fields);
1527            }
1528            break;
1529          case SOLUTION:
1530            if (goodModel) {
1531              // get next field
1532              field = getString(argc,argv);
1533              std::string fileName;
1534              FILE *fp=NULL;
1535              if (field=="-"||field=="EOL") {
1536                // stdout
1537                fp=stdout;
1538              } else {
1539                if (field[0]=='/'||field[0]=='~')
1540                  fileName = field;
1541                else
1542                  fileName = directory+field;
1543                fp=fopen(fileName.c_str(),"w");
1544              }
1545              if (fp) {
1546                // make fancy later on
1547                int iRow;
1548                int numberRows=model->solver()->getNumRows();
1549                const double * dualRowSolution = model->getRowPrice();
1550                const double * primalRowSolution =  model->getRowActivity();
1551                for (iRow=0;iRow<numberRows;iRow++) {
1552                  fprintf(fp,"%7d ",iRow);
1553                  fprintf(fp,"%15.8g        %15.8g\n",primalRowSolution[iRow],
1554                          dualRowSolution[iRow]);
1555                }
1556                int iColumn;
1557                int numberColumns=model->solver()->getNumCols();
1558                const double * dualColumnSolution = 
1559                  model->getReducedCost();
1560                const double * primalColumnSolution = 
1561                  model->getColSolution();
1562                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1563                  fprintf(fp,"%7d ",iColumn);
1564                  fprintf(fp,"%15.8g        %15.8g\n",
1565                          primalColumnSolution[iColumn],
1566                          dualColumnSolution[iColumn]);
1567                }
1568                if (fp!=stdout)
1569                  fclose(fp);
1570              } else {
1571                std::cout<<"Unable to open file "<<fileName<<std::endl;
1572              }
1573            } else {
1574              std::cout<<"** Current model not valid"<<std::endl;
1575             
1576            }
1577            break;
1578          default:
1579            abort();
1580          }
1581        } 
1582      } else if (!numberMatches) {
1583        std::cout<<"No match for "<<field<<" - ? for list of commands"
1584                 <<std::endl;
1585      } else if (numberMatches==1) {
1586        if (!numberQuery) {
1587          std::cout<<"Short match for "<<field<<" possible completion:"
1588                   <<std::endl;
1589          for ( iParam=0; iParam<numberParameters; iParam++ ) {
1590            int match = parameters[iParam].matches(field);
1591            if (match) 
1592              std::cout<<parameters[iParam].matchName()<<std::endl;
1593          }
1594        } else if (numberQuery) {
1595          std::cout<<"Short match for "<<field<<" completion:"
1596                   <<std::endl;
1597          for ( iParam=0; iParam<numberParameters; iParam++ ) {
1598            int match = parameters[iParam].matches(field);
1599            if (match) {
1600              std::cout<<parameters[iParam].matchName()<<" : ";
1601              std::cout<<parameters[iParam].shortHelp()<<std::endl;
1602            }
1603          }
1604        }
1605      } else {
1606        if (!numberQuery) 
1607          std::cout<<"Multiple matches for "<<field<<" - possible completions:"
1608                   <<std::endl;
1609        else
1610          std::cout<<"Completions of "<<field<<":"<<std::endl;
1611        for ( iParam=0; iParam<numberParameters; iParam++ ) {
1612          int match = parameters[iParam].matches(field);
1613          if (match) {
1614            std::cout<<parameters[iParam].matchName();
1615            if (numberQuery>=2) 
1616              std::cout<<" : "<<parameters[iParam].shortHelp();
1617            std::cout<<std::endl;
1618          }
1619        }
1620      }
1621    }
1622/*
1623  Final cleanup. Delete the model and the vector of available solvers.
1624*/
1625    delete model;
1626
1627    for (solverMapIter_t solverIter = solvers.begin() ;
1628         solverIter != solvers.end() ;
1629         solverIter++)
1630    { if (solverIter->second) delete solverIter->second ; }
1631  }
1632  return 0;
1633}   
Note: See TracBrowser for help on using the repository browser.