source: trunk/Test/CbcMain.cpp @ 122

Last change on this file since 122 was 122, checked in by forrest, 16 years ago

major changes

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