source: trunk/Test/CbcMain.cpp @ 277

Last change on this file since 277 was 277, checked in by lou, 14 years ago

Revise cbc build process for better control of solvers included in build
(COIN_USE_XXX -> CBC_USE_XXX). Add CbcEventHandler? for independence from
clp.

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