source: stable/2.4/Cbc/src/CbcMain.cpp @ 1271

Last change on this file since 1271 was 1271, checked in by forrest, 10 years ago

Creating new stable branch 2.4 from trunk (rev 1270)

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