source: branches/devel-1/Test/ClpMain.cpp @ 33

Last change on this file since 33 was 33, checked in by forrest, 17 years ago

Presolve in as option

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.7 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 <cstdio>
10#include <cmath>
11#include <cfloat>
12#include <string>
13#include <iostream>
14
15#include <time.h>
16#include <sys/times.h>
17#include <sys/resource.h>
18#include <unistd.h>
19
20#define CLPVERSION "0.92"
21
22//#include "CoinPackedMatrix.hpp"
23//#include "CoinPackedVector.hpp"
24#include "CoinMpsIO.hpp"
25
26#include "ClpFactorization.hpp"
27#include "ClpSimplex.hpp"
28#include "ClpDualRowSteepest.hpp"
29#include "ClpDualRowDantzig.hpp"
30#include "ClpPrimalColumnSteepest.hpp"
31#include "ClpPrimalColumnDantzig.hpp"
32
33#include "Presolve.hpp"
34// For Branch and bound
35//  #include "OsiClpSolverInterface.hpp"
36//  #include "OsiCuts.hpp"
37//  #include "OsiRowCut.hpp"
38//  #include "OsiColCut.hpp"
39
40#ifdef DMALLOC
41#include "dmalloc.h"
42#endif
43static double totalTime=0.0;
44static double cpuTime()
45{
46  double cpu_temp;
47#if defined(_MSC_VER)
48  unsigned int ticksnow;        /* clock_t is same as int */
49 
50  ticksnow = (unsigned int)clock();
51 
52  cpu_temp = (double)((double)ticksnow/CLOCKS_PER_SEC);
53#else
54  struct rusage usage;
55  getrusage(RUSAGE_SELF,&usage);
56  cpu_temp = usage.ru_utime.tv_sec;
57  cpu_temp += 1.0e-6*((double) usage.ru_utime.tv_usec);
58#endif
59  return cpu_temp;
60}
61
62
63//#############################################################################
64
65#ifdef NDEBUG
66#undef NDEBUG
67#endif
68
69int mainTest (int argc, const char *argv[],bool doDual,
70              ClpSimplex empty, bool doPresolve);
71enum ClpParameterType {
72  GENERALQUERY=-100,
73 
74  DUALTOLERANCE=1,PRIMALTOLERANCE,DUALBOUND,PRIMALWEIGHT,
75
76  LOGLEVEL=101,MAXFACTOR,PERTURBATION,MAXITERATION,PRESOLVE,
77 
78  DIRECTION=201,DUALPIVOT,SCALING,ERRORSALLOWED,KEEPNAMES,SPARSEFACTOR,
79  PRIMALPIVOT,
80 
81  DIRECTORY=301,IMPORT,EXPORT,RESTORE,SAVE,DUALSIMPLEX,PRIMALSIMPLEX,BAB,
82  MAXIMIZE,MINIMIZE,EXIT,STDIN,UNITTEST,NETLIB_DUAL,NETLIB_PRIMAL,SOLUTION,
83  TIGHTEN,FAKEBOUND,VERSION,
84
85  INVALID=1000
86};
87/// Very simple class for setting parameters
88class ClpItem {
89
90public:
91
92  /**@name Constructor and destructor */
93  //@{
94  /// Constructors
95  ClpItem (  );
96  ClpItem (std::string name, std::string help,
97           double lower, double upper, ClpParameterType type);
98  ClpItem (std::string name, std::string help,
99           int lower, int upper, ClpParameterType type);
100  // Other strings will be added by insert
101  ClpItem (std::string name, std::string help, std::string defaultValue,
102           ClpParameterType type);
103  // Action
104  ClpItem (std::string name, std::string help,
105           ClpParameterType type);
106  /// Copy constructor.
107  ClpItem(const ClpItem &);
108  /// Assignment operator. This copies the data
109    ClpItem & operator=(const ClpItem & rhs);
110  /// Destructor
111  ~ClpItem (  );
112  //@}
113
114  /**@name stuff */
115  //@{
116  /// Insert string (only valid for keywords)
117  void append(std::string keyWord);
118  /// Adds one help line
119  void addHelp(std::string keyWord);
120  /// Returns name
121  inline std::string  name(  ) const {
122    return name_;
123  };
124  /// Returns short help
125  inline std::string  shortHelp(  ) const {
126    return shortHelp_;
127  };
128  /// Sets a double parameter (nonzero code if error)
129  int setDoubleParameter(ClpSimplex * model, double value) const;
130  /// Gets a double parameter
131  double doubleParameter(ClpSimplex * model) const;
132  /// Sets a int parameter (nonzero code if error)
133  int setIntParameter(ClpSimplex * model, int value) const;
134  /// Gets a int parameter
135  int intParameter(ClpSimplex * model) const;
136  /// Returns name which could match
137  std::string matchName (  ) const;
138  /// Returns parameter option which matches (-1 if none)
139  int parameterOption ( std::string check ) const;
140  /// Prints parameter options
141  void printOptions (  ) const;
142  /// Returns current parameter option
143  inline std::string currentOption (  ) const
144  { return definedKeyWords_[currentKeyWord_]; };
145  /// Sets current parameter option
146  inline void setCurrentOption ( int value )
147  { currentKeyWord_=value; };
148  /// Returns 1 if matches minimum, 2 if matches less, 0 if not matched
149  int matches (std::string input) const;
150  /// type
151  inline ClpParameterType type() const
152  { return type_;};
153private:
154  /// gutsOfConstructor
155  void gutsOfConstructor();
156  //@}
157////////////////// data //////////////////
158private:
159
160  /**@name data
161   We might as well throw all type data in - could derive?
162  */
163  //@{
164  // Type see ClpParameterType
165  ClpParameterType type_;
166  /// If double == okay
167  double lowerDoubleValue_;
168  double upperDoubleValue_;
169  /// If int == okay
170  int lowerIntValue_;
171  int upperIntValue_;
172  // Length of name
173  unsigned int lengthName_;
174  // Minimum match
175  unsigned int lengthMatch_;
176  /// set of valid strings
177  std::vector<std::string> definedKeyWords_;
178  /// Name
179  std::string name_;
180  /// Short help
181  std::string shortHelp_;
182  /// Long help
183  std::vector<std::string> longHelp_;
184  /// Action
185  ClpParameterType action_;
186  /// Current keyWord (if a keyword parameter)
187  int currentKeyWord_;
188  //@}
189};
190//#############################################################################
191// Constructors / Destructor / Assignment
192//#############################################################################
193
194//-------------------------------------------------------------------
195// Default Constructor
196//-------------------------------------------------------------------
197ClpItem::ClpItem () 
198  : type_(INVALID),
199    lowerDoubleValue_(0.0),
200    upperDoubleValue_(0.0),
201    lowerIntValue_(0),
202    upperIntValue_(0),
203    lengthName_(0),
204    lengthMatch_(0),
205    definedKeyWords_(),
206    name_(),
207    shortHelp_(),
208    longHelp_(),
209    action_(INVALID),
210    currentKeyWord_(-1)
211{
212}
213// Other constructors
214ClpItem::ClpItem (std::string name, std::string help,
215           double lower, double upper, ClpParameterType type)
216  : type_(type),
217    lowerIntValue_(0),
218    upperIntValue_(0),
219    definedKeyWords_(),
220    name_(name),
221    shortHelp_(help),
222    longHelp_(),
223    action_(type),
224    currentKeyWord_(-1)
225{
226  lowerDoubleValue_ = lower;
227  upperDoubleValue_ = upper;
228  gutsOfConstructor();
229}
230ClpItem::ClpItem (std::string name, std::string help,
231           int lower, int upper, ClpParameterType type)
232  : type_(type),
233    lowerDoubleValue_(0.0),
234    upperDoubleValue_(0.0),
235    definedKeyWords_(),
236    name_(name),
237    shortHelp_(help),
238    longHelp_(),
239    action_(type),
240    currentKeyWord_(-1)
241{
242  gutsOfConstructor();
243  lowerIntValue_ = lower;
244  upperIntValue_ = upper;
245}
246// Other strings will be added by append
247ClpItem::ClpItem (std::string name, std::string help, 
248                  std::string defaultValue,
249                  ClpParameterType type)
250  : type_(type),
251    lowerDoubleValue_(0.0),
252    upperDoubleValue_(0.0),
253    lowerIntValue_(0),
254    upperIntValue_(0),
255    definedKeyWords_(),
256    name_(name),
257    shortHelp_(help),
258    longHelp_(),
259    action_(type),
260    currentKeyWord_(0)
261{
262  gutsOfConstructor();
263  definedKeyWords_.push_back(defaultValue);
264}
265// Action
266ClpItem::ClpItem (std::string name, std::string help,
267           ClpParameterType type)
268  : type_(type),
269    lowerDoubleValue_(0.0),
270    upperDoubleValue_(0.0),
271    lowerIntValue_(0),
272    upperIntValue_(0),
273    definedKeyWords_(),
274    name_(name),
275    shortHelp_(help),
276    longHelp_(),
277    action_(type),
278    currentKeyWord_(-1)
279{
280  gutsOfConstructor();
281}
282
283//-------------------------------------------------------------------
284// Copy constructor
285//-------------------------------------------------------------------
286ClpItem::ClpItem (const ClpItem & rhs) 
287{ 
288  type_ = rhs.type_;
289  lowerDoubleValue_ = rhs.lowerDoubleValue_;
290  upperDoubleValue_ = rhs.upperDoubleValue_;
291  lowerIntValue_ = rhs.lowerIntValue_;
292  upperIntValue_ = rhs.upperIntValue_;
293  lengthName_ = rhs.lengthName_;
294  lengthMatch_ = rhs.lengthMatch_;
295  definedKeyWords_ = rhs.definedKeyWords_;
296  name_ = rhs.name_;
297  shortHelp_ = rhs.shortHelp_;
298  longHelp_ = rhs.longHelp_;
299  action_ = rhs.action_;
300  currentKeyWord_ = rhs.currentKeyWord_;
301 
302}
303
304//-------------------------------------------------------------------
305// Destructor
306//-------------------------------------------------------------------
307ClpItem::~ClpItem ()
308{
309}
310
311//----------------------------------------------------------------
312// Assignment operator
313//-------------------------------------------------------------------
314ClpItem &
315ClpItem::operator=(const ClpItem& rhs)
316{
317  if (this != &rhs) {
318    type_ = rhs.type_;
319    lowerDoubleValue_ = rhs.lowerDoubleValue_;
320    upperDoubleValue_ = rhs.upperDoubleValue_;
321    lowerIntValue_ = rhs.lowerIntValue_;
322    upperIntValue_ = rhs.upperIntValue_;
323    lengthName_ = rhs.lengthName_;
324    lengthMatch_ = rhs.lengthMatch_;
325    definedKeyWords_ = rhs.definedKeyWords_;
326    name_ = rhs.name_;
327    shortHelp_ = rhs.shortHelp_;
328    longHelp_ = rhs.longHelp_;
329    action_ = rhs.action_;
330    currentKeyWord_ = rhs.currentKeyWord_;
331  }
332  return *this;
333}
334void 
335ClpItem::gutsOfConstructor()
336{
337  unsigned int  shriekPos = name_.find('!');
338  lengthName_ = name_.length();
339  if ( shriekPos==std::string::npos ) {
340    //does not contain '!'
341    lengthMatch_= lengthName_;
342  } else {
343    lengthMatch_=shriekPos;
344    name_ = name_.substr(0,shriekPos)+name_.substr(shriekPos+1);
345    lengthName_--;
346  }
347}
348// Insert string (only valid for keywords)
349void 
350ClpItem::append(std::string keyWord)
351{
352  definedKeyWords_.push_back(keyWord);
353}
354
355int 
356ClpItem::matches (std::string input) const
357{
358  // look up strings to do more elegantly
359  if (input.length()>lengthName_) {
360    return 0;
361  } else {
362    unsigned int i;
363    for (i=0;i<input.length();i++) {
364      if (tolower(name_[i])!=tolower(input[i])) 
365        break;
366    }
367    if (i<input.length()) {
368      return 0;
369    } else if (i>=lengthMatch_) {
370      return 1;
371    } else {
372      // matched but too short
373      return 2;
374    }
375  }
376}
377// Returns name which could match
378std::string
379ClpItem::matchName (  ) const
380{ 
381  if (lengthMatch_==lengthName_) 
382    return name_;
383  else
384    return name_.substr(0,lengthMatch_)+"("+name_.substr(lengthMatch_)+")";
385}
386
387// Returns parameter option which matches (-1 if none)
388int 
389ClpItem::parameterOption ( std::string check ) const
390{
391  int numberItems = definedKeyWords_.size();
392  if (!numberItems) {
393    return -1;
394  } else {
395    int whichItem=0;
396    unsigned int it;
397    for (it=0;it<definedKeyWords_.size();it++) {
398      std::string thisOne = definedKeyWords_[it];
399      unsigned int  shriekPos = thisOne.find('!');
400      unsigned int length1 = thisOne.length();
401      unsigned int length2 = length1;
402      if ( shriekPos!=std::string::npos ) {
403        //contains '!'
404        length2 = shriekPos;
405        thisOne = thisOne.substr(0,shriekPos)+
406          thisOne.substr(shriekPos+1);
407        length1 = thisOne.length();
408      }
409      if (check.length()<=length1) {
410        unsigned int i;
411        for (i=0;i<check.length();i++) {
412          if (tolower(thisOne[i])!=tolower(check[i])) 
413            break;
414        }
415        if (i<check.length()) {
416          whichItem++;
417        } else if (i>=length2) {
418          break;
419        } 
420      } else {
421        whichItem++;
422      }
423    }
424    if (whichItem<numberItems)
425      return whichItem;
426    else
427      return -1;
428  }
429}
430// Prints parameter options
431void 
432ClpItem::printOptions (  ) const
433{
434  std::cout<<"Possible options for "<<name_<<" are:"<<std::endl;
435  unsigned int it;
436  for (it=0;it<definedKeyWords_.size();it++) {
437    std::string thisOne = definedKeyWords_[it];
438    unsigned int  shriekPos = thisOne.find('!');
439    if ( shriekPos!=std::string::npos ) {
440      //contains '!'
441      thisOne = thisOne.substr(0,shriekPos)+
442        "("+thisOne.substr(shriekPos+1)+")";
443    }
444    std::cout<<thisOne<<std::endl;
445  }
446}
447int
448ClpItem::setDoubleParameter (ClpSimplex * model,double value) const
449{
450  double oldValue = doubleParameter(model);
451  if (value<lowerDoubleValue_||value>upperDoubleValue_) {
452    std::cout<<value<<" was provided for "<<name_<<
453      " - valid range is "<<lowerDoubleValue_<<" to "<<
454      upperDoubleValue_<<std::endl;
455    return 1;
456  } else {
457    std::cout<<name_<<" was changed from "<<oldValue<<" to "
458             <<value<<std::endl;
459    switch(type_) {
460    case DUALTOLERANCE:
461      model->setDualTolerance(value);
462      break;
463    case PRIMALTOLERANCE:
464      model->setPrimalTolerance(value);
465      break;
466    case DUALBOUND:
467      model->setDualBound(value);
468      break;
469    case PRIMALWEIGHT:
470      model->setInfeasibilityCost(value);
471      break;
472    default:
473      abort();
474    }
475    return 0;
476  }
477}
478double 
479ClpItem::doubleParameter (ClpSimplex * model) const
480{
481  double value;
482  switch(type_) {
483  case DUALTOLERANCE:
484    value=model->dualTolerance();
485    break;
486  case PRIMALTOLERANCE:
487    value=model->primalTolerance();
488    break;
489  case DUALBOUND:
490    value=model->dualBound();
491    break;
492  case PRIMALWEIGHT:
493    value=model->infeasibilityCost();
494    break;
495  default:
496    abort();
497  }
498  return value;
499}
500int 
501ClpItem::setIntParameter (ClpSimplex * model,int value) const
502{
503  int oldValue = intParameter(model);
504  if (value<lowerIntValue_||value>upperIntValue_) {
505    std::cout<<value<<" was provided for "<<name_<<
506      " - valid range is "<<lowerIntValue_<<" to "<<
507      upperIntValue_<<std::endl;
508    return 1;
509  } else {
510    std::cout<<name_<<" was changed from "<<oldValue<<" to "
511             <<value<<std::endl;
512    switch(type_) {
513    case LOGLEVEL:
514      model->setLogLevel(value);
515      break;
516    case MAXFACTOR:
517      model->factorization()->maximumPivots(value);
518      break;
519    case DIRECTION:
520      model->setOptimizationDirection(value);
521      break;
522    case PERTURBATION:
523      model->setPerturbation(value);
524      break;
525    case MAXITERATION:
526      model->setMaximumIterations(value);
527      break;
528    default:
529      abort();
530    }
531    return 0;
532  }
533}
534int 
535ClpItem::intParameter (ClpSimplex * model) const
536{
537  int value;
538  switch(type_) {
539  case LOGLEVEL:
540    value=model->logLevel();
541    break;
542  case MAXFACTOR:
543    value=model->factorization()->maximumPivots();
544    break;
545  case DIRECTION:
546    value=model->optimizationDirection();
547    break;
548  case PERTURBATION:
549    value=model->perturbation();
550    break;
551  case MAXITERATION:
552    value=model->maximumIterations();
553    break;
554  default:
555    abort();
556  }
557  return value;
558}
559#ifdef READLINE     
560#include "/usr/include/readline/readline.h"
561#include "/usr/include/readline/history.h"
562#include <signal.h>
563static ClpSimplex * currentModel = NULL;
564static void signal_handler(int whichSignal)
565{
566  if (currentModel!=NULL) 
567    currentModel->setMaximumIterations(0); // stop at next iterations
568  return;
569}
570#endif
571// Returns next valid field
572static int read_mode=1;
573static char line[1000];
574static char * where=NULL;
575
576std::string
577nextField()
578{
579  std::string field;
580  if (!where) {
581    // need new line
582#ifdef READLINE     
583    // Get a line from the user.
584    where = readline ("Clp:");
585     
586    // If the line has any text in it, save it on the history.
587    if (where) {
588      if ( *where)
589        add_history (where);
590      strcpy(line,where);
591    }
592#else
593    fprintf(stdout,"Clp:");
594    fflush(stdout);
595    where = fgets(line,1000,stdin);
596#endif
597    if (!where)
598      return field; // EOF
599    where = line;
600    // clean image
601    char * lastNonBlank = line-1;
602    while ( *where != '\0' ) {
603      if ( *where != '\t' && *where < ' ' ) {
604        break;
605      } else if ( *where != '\t' && *where != ' ') {
606        lastNonBlank = where;
607      }
608      where++;
609    }
610    where=line;
611    *(lastNonBlank+1)='\0';
612  }
613  // munch white space
614  while(*where==' '||*where=='\t')
615    where++;
616  char * saveWhere = where;
617  while (*where!=' '&&*where!='\t'&&*where!='\0')
618    where++;
619  if (where!=saveWhere) {
620    char save = *where;
621    *where='\0';
622    //convert to string
623    field=saveWhere;
624    *where=save;
625  } else {
626    where=NULL;
627    field="EOL";
628  }
629  return field;
630}
631
632std::string
633getCommand(int argc, const char *argv[])
634{
635  std::string field="EOL";
636  while (field=="EOL") {
637    if (read_mode>0) {
638      if (read_mode<argc) {
639        field = argv[read_mode++];
640        if (field=="-") {
641          std::cout<<"Switching to line mode"<<std::endl;
642          read_mode=-1;
643          field=nextField();
644        } else if (field[0]!='-') {
645          if (read_mode!=2) {
646            std::cout<<"skipping non-command "<<field<<std::endl;
647            field="EOL"; // skip
648          } else {
649            // special dispensation - taken as -import name
650            read_mode--;
651            field="import";
652          }
653        } else {
654          if (field!="--") {
655            // take off -
656            field = field.substr(1);
657          } else {
658            // special dispensation - taken as -import --
659            read_mode--;
660            field="import";
661          }
662        }
663      } else {
664        field="";
665      }
666    } else {
667      field=nextField();
668    }
669  }
670  //std::cout<<field<<std::endl;
671  return field;
672}
673std::string
674getString(int argc, const char *argv[])
675{
676  std::string field="EOL";
677  if (read_mode>0) {
678    if (read_mode<argc) {
679      if (argv[read_mode][0]!='-') { 
680        field = argv[read_mode++];
681      } else if (!strcmp(argv[read_mode],"--")) {
682        field = argv[read_mode++];
683        // -- means import from stdin
684        field = "-";
685      }
686    }
687  } else {
688    field=nextField();
689  }
690  //std::cout<<field<<std::endl;
691  return field;
692}
693// valid 0 - okay, 1 bad, 2 not there
694int
695getIntField(int argc, const char *argv[],int * valid)
696{
697  std::string field="EOL";
698  if (read_mode>0) {
699    if (read_mode<argc) {
700      // may be negative value so do not check for -
701      field = argv[read_mode++];
702    }
703  } else {
704    field=nextField();
705  }
706  int value=0;
707  //std::cout<<field<<std::endl;
708  if (field!="EOL") {
709    // how do I check valid
710    value =  atoi(field.c_str());
711    *valid=0;
712  } else {
713    *valid=2;
714  }
715  return value;
716}
717double
718getDoubleField(int argc, const char *argv[],int * valid)
719{
720  std::string field="EOL";
721  if (read_mode>0) {
722    if (read_mode<argc) {
723      // may be negative value so do not check for -
724      field = argv[read_mode++];
725    }
726  } else {
727    field=nextField();
728  }
729  double value=0.0;
730  //std::cout<<field<<std::endl;
731  if (field!="EOL") {
732    // how do I check valid
733    value = atof(field.c_str());
734    *valid=0;
735  } else {
736    *valid=2;
737  }
738  return value;
739}
740int main (int argc, const char *argv[])
741{
742  // next {} is just to make sure all memory should be freed - for debug
743  {
744    double time1 = cpuTime(),time2;
745#define MAXPARAMETERS 100
746    ClpItem parameters[MAXPARAMETERS];
747    int numberParameters=0;
748    parameters[numberParameters++]=
749      ClpItem("?","For help",GENERALQUERY);
750    parameters[numberParameters++]=
751      ClpItem("dualT!olerance","For an optimal solution \
752no dual infeasibility may exceed this value",
753              1.0e-20,1.0e12,DUALTOLERANCE);
754    parameters[numberParameters++]=
755      ClpItem("primalT!olerance","For an optimal solution \
756no primal infeasibility may exceed this value",
757              1.0e-20,1.0e12,PRIMALTOLERANCE);
758    parameters[numberParameters++]=
759      ClpItem("dualB!ound","Initially algorithm acts as if no \
760gap between bounds exceeds this value",
761              1.0e-20,1.0e12,DUALBOUND);
762    parameters[numberParameters++]=
763      ClpItem("primalW!eight","Initially algorithm acts as if it \
764costs this much to be infeasible",
765              1.0e-20,1.0e12,PRIMALWEIGHT);
766    parameters[numberParameters++]=
767      ClpItem("log!Level","Level of detail in output",
768              0,63,LOGLEVEL);
769    parameters[numberParameters++]=
770      ClpItem("maxF!actor","Maximum number of iterations between \
771refactorizations",
772              1,999999,MAXFACTOR);
773    parameters[numberParameters++]=
774      ClpItem("maxIt!erations","Maximum number of iterations before \
775stopping",
776              0,99999999,MAXITERATION);
777    parameters[numberParameters++]=
778      ClpItem("pert!urbation","Method of perturbation",
779              -50,102,PERTURBATION);
780    parameters[numberParameters++]=
781      ClpItem("direction","Minimize or Maximize",
782              "min!imize",DIRECTION);
783    parameters[numberParameters-1].append("max!imize");
784    parameters[numberParameters++]=
785      ClpItem("dualP!ivot","Dual pivot choice algorithm",
786              "steep!est",DUALPIVOT);
787    parameters[numberParameters-1].append("dant!zig");
788    parameters[numberParameters++]=
789      ClpItem("primalP!ivot","Primal pivot choice algorithm",
790              "steep!est",PRIMALPIVOT);
791    parameters[numberParameters-1].append("exa!ct");
792    parameters[numberParameters-1].append("dant!zig");
793    parameters[numberParameters++]=
794      ClpItem("scal!ing","Whether to scale problem",
795              "on",SCALING);
796    parameters[numberParameters-1].append("off");
797    parameters[numberParameters++]=
798      ClpItem("presolve","Whether to presolve problem - how many passes",
799              0,100,PRESOLVE);
800    parameters[numberParameters++]=
801      ClpItem("spars!eFactor","Whether factorization treated as sparse",
802              "on",SPARSEFACTOR);
803    parameters[numberParameters-1].append("off");
804    parameters[numberParameters++]=
805      ClpItem("error!sAllowed","Whether to allow import errors",
806              "off",ERRORSALLOWED);
807    parameters[numberParameters-1].append("on");
808    parameters[numberParameters++]=
809      ClpItem("keepN!ames","Whether to keep names from import",
810              "on",KEEPNAMES);
811    parameters[numberParameters-1].append("off");
812    parameters[numberParameters++]=
813      ClpItem("directory","Set Default import directory",
814              DIRECTORY);
815    parameters[numberParameters++]=
816      ClpItem("import","Import model from mps file",
817              IMPORT);
818    parameters[numberParameters++]=
819      ClpItem("export","Export model as mps file",
820              EXPORT);
821    parameters[numberParameters++]=
822      ClpItem("save!Model","Save model to binary file",
823              SAVE);
824    parameters[numberParameters++]=
825      ClpItem("restore!Model","Restore model from binary file",
826              RESTORE);
827    parameters[numberParameters++]=
828      ClpItem("dualS!implex","Do dual simplex algorithm",
829              DUALSIMPLEX);
830    parameters[numberParameters++]=
831      ClpItem("primalS!implex","Do primal simplex algorithm",
832              PRIMALSIMPLEX);
833    parameters[numberParameters++]=
834      ClpItem("branch!Andbound","Do Branch and Bound",
835              BAB);
836    parameters[numberParameters++]=
837      ClpItem("tight!en","Poor person's preSolve for now",
838              TIGHTEN);
839    parameters[numberParameters++]=
840      ClpItem("sol!ution","Prints solution to file",
841              SOLUTION);
842    parameters[numberParameters++]=
843      ClpItem("max!imize","Set optimization direction to maximize",
844              MAXIMIZE);
845    parameters[numberParameters++]=
846      ClpItem("min!imize","Set optimization direction to minimize",
847              MINIMIZE);
848    parameters[numberParameters++]=
849      ClpItem("exit","Stops clp execution",
850              EXIT);
851    parameters[numberParameters++]=
852      ClpItem("stop","Stops clp execution",
853              EXIT);
854    parameters[numberParameters++]=
855      ClpItem("quit","Stops clp execution",
856              EXIT);
857    parameters[numberParameters++]=
858      ClpItem("-","From stdin",
859              STDIN);
860    parameters[numberParameters++]=
861      ClpItem("stdin","From stdin",
862              STDIN);
863    parameters[numberParameters++]=
864      ClpItem("unitTest","Do unit test",
865              UNITTEST);
866    parameters[numberParameters++]=
867      ClpItem("netlib","Solev entlib test set",
868              NETLIB_DUAL);
869    parameters[numberParameters++]=
870      ClpItem("netlibP!rimal","Solev entlib test set",
871              NETLIB_PRIMAL);
872    parameters[numberParameters++]=
873      ClpItem("fakeB!ound","All bounds <= this value - DEBUG",
874              1.0,1.0e15,FAKEBOUND);
875    parameters[numberParameters++]=
876      ClpItem("ver!sion","Print out version",
877              VERSION);
878    assert(numberParameters<MAXPARAMETERS);
879   
880    // total number of commands read
881    int numberGoodCommands=0;
882    //int numberModels=1;
883    ClpSimplex * models = new ClpSimplex[1];
884    bool * goodModels = new bool[1];
885   
886#ifdef READLINE     
887    currentModel = models;
888    // register signal handler
889    signal(SIGINT,signal_handler);
890#endif
891   
892    // default action on import
893    int allowImportErrors=0;
894    int keepImportNames=1;
895    int preSolve=0;
896   
897    int iModel=0;
898    goodModels[0]=false;
899    // set reasonable defaults
900    models[0].scaling(1);
901    models[0].setDualBound(1.0e6);
902    models[0].setDualTolerance(1.0e-7);
903    ClpDualRowSteepest steep;
904    models[0].setDualRowPivotAlgorithm(steep);
905    models[0].setPrimalTolerance(1.0e-8);
906    ClpPrimalColumnSteepest steepP;
907    models[0].setPrimalColumnPivotAlgorithm(steepP);
908    std::string directory ="./";
909    std::string field;
910   
911    while (1) {
912      // next command
913      field=getCommand(argc,argv);
914     
915      // exit if null or similar
916      if (!field.length()) {
917        if (numberGoodCommands==1&&goodModels[0]) {
918          // we just had file name
919          models[0].scaling(1);
920          int saveMaxIterations = models[0].maximumIterations();
921          models[0].dual();
922          models[0].setMaximumIterations(saveMaxIterations);
923        } else if (!numberGoodCommands) {
924          // let's give the sucker a hint
925          std::cout
926            <<"Clp takes input from arguments ( - switches to stdin)"
927            <<std::endl
928            <<"Enter ? for list of commands, (-)unitTest or (-)netlib"
929            <<" for tests"<<std::endl;
930        }
931        break;
932      }
933     
934      // see if ? at end
935      int numberQuery=0;
936      if (field!="?") {
937        int length = field.length();
938        int i;
939        for (i=length-1;i>0;i--) {
940          if (field[i]=='?') 
941            numberQuery++;
942          else
943            break;
944        }
945        field=field.substr(0,length-numberQuery);
946      }
947      // find out if valid command
948      int iParam;
949      int numberMatches=0;
950      for ( iParam=0; iParam<numberParameters; iParam++ ) {
951        int match = parameters[iParam].matches(field);
952        if (match==1) {
953          numberMatches = 1;
954          break;
955        } else {
956          numberMatches += match>>1;
957        }
958      }
959      if (iParam<numberParameters&&!numberQuery) {
960        // found
961        ClpItem found = parameters[iParam];
962        ClpParameterType type = found.type();
963        int valid;
964        numberGoodCommands++;
965        if (type==GENERALQUERY) {
966          std::cout<<"In argument list keywords have leading - "
967            ", -stdin or just - switches to stdin"<<std::endl;
968          std::cout<<"One command per line (and no -)"<<std::endl;
969          std::cout<<"abcd? gives list of possibilities, if only one + explanation"<<std::endl;
970          std::cout<<"abcd?? adds explanation, if only one fuller help(LATER)"<<std::endl;
971          std::cout<<"abcd without value (where expected) gives current value"<<std::endl;
972          std::cout<<"abcd value or abcd = value sets value"<<std::endl;
973          std::cout<<"Commands are:"<<std::endl;
974          for ( iParam=0; iParam<numberParameters; iParam+=4 ) {
975            int i;
976            for (i=iParam;i<min(numberParameters,iParam+4);i++) 
977              std::cout<<parameters[i].matchName()<<"  ";
978            std::cout<<std::endl;
979          }
980        } else if (type<101) {
981          // get next field as double
982          double value = getDoubleField(argc,argv,&valid);
983          if (!valid) {
984            parameters[iParam].setDoubleParameter(models+iModel,value);
985          } else if (valid==1) {
986            abort();
987          } else {
988            std::cout<<parameters[iParam].name()<<" has value "<<
989              parameters[iParam].doubleParameter(models+iModel)<<std::endl;
990          }
991        } else if (type<201) {
992          // get next field as int
993          int value = getIntField(argc,argv,&valid);
994          if (!valid) {
995            if (parameters[iParam].type()==PRESOLVE)
996              preSolve = value;
997            else
998              parameters[iParam].setIntParameter(models+iModel,value);
999          } else if (valid==1) {
1000            abort();
1001          } else {
1002            std::cout<<parameters[iParam].name()<<" has value "<<
1003              parameters[iParam].intParameter(models+iModel)<<std::endl;
1004          }
1005        } else if (type<301) {
1006          // one of several strings
1007          std::string value = getString(argc,argv);
1008          int action = parameters[iParam].parameterOption(value);
1009          if (action<0) {
1010            if (value!="EOL") {
1011              // no match
1012              parameters[iParam].printOptions();
1013            } else {
1014              // print current value
1015              std::cout<<parameters[iParam].name()<<" has value "<<
1016                parameters[iParam].currentOption()<<std::endl;
1017            }
1018          } else {
1019            parameters[iParam].setCurrentOption(action);
1020            // for now hard wired
1021            switch (type) {
1022            case DIRECTION:
1023              if (action==0)
1024                models[iModel].setOptimizationDirection(1);
1025              else
1026                models[iModel].setOptimizationDirection(-11);
1027              break;
1028            case DUALPIVOT:
1029              if (action==0) {
1030                ClpDualRowSteepest steep;
1031                models[iModel].setDualRowPivotAlgorithm(steep);
1032              } else {
1033                ClpDualRowDantzig dantzig;
1034                models[iModel].setDualRowPivotAlgorithm(dantzig);
1035              }
1036              break;
1037            case PRIMALPIVOT:
1038              if (action==0) {
1039                ClpPrimalColumnSteepest steep(1);
1040                models[iModel].setPrimalColumnPivotAlgorithm(steep);
1041              } else if (action==1) {
1042                ClpPrimalColumnSteepest steep(0);
1043                models[iModel].setPrimalColumnPivotAlgorithm(steep);
1044              } else {
1045                ClpPrimalColumnDantzig dantzig;
1046                models[iModel].setPrimalColumnPivotAlgorithm(dantzig);
1047              }
1048              break;
1049            case SCALING:
1050              models[iModel].scaling(1-action);
1051              break;
1052            case SPARSEFACTOR:
1053              models[iModel].setSparseFactorization(1-action);
1054              break;
1055            case ERRORSALLOWED:
1056              allowImportErrors = action;
1057              break;
1058            case KEEPNAMES:
1059              keepImportNames = 1-action;
1060              break;
1061            default:
1062              abort();
1063            }
1064          }
1065        } else {
1066          // action
1067          if (type==EXIT)
1068            break; // stop all
1069          switch (type) {
1070          case DUALSIMPLEX:
1071          case PRIMALSIMPLEX:
1072            if (goodModels[iModel]) {
1073              int saveMaxIterations = models[iModel].maximumIterations();
1074              ClpSimplex * model2 = models+iModel;
1075#ifdef USE_PRESOLVE
1076              Presolve pinfo;
1077              if (preSolve) 
1078                model2 = pinfo.presolvedModel(models[iModel],1.0e-8,preSolve);
1079#endif
1080#ifdef READLINE     
1081              currentModel = model2;
1082#endif
1083              if (type==DUALSIMPLEX)
1084                model2->dual();
1085              else
1086                model2->primal();
1087#ifdef USE_PRESOLVE
1088              if (preSolve) {
1089                pinfo.postsolve(true);
1090               
1091                delete model2;
1092                printf("Resolving from postsolved model\n");
1093               
1094#ifdef READLINE     
1095                currentModel = models+iModel;
1096#endif
1097                models[iModel].primal(1);
1098              }
1099#endif
1100              models[iModel].setMaximumIterations(saveMaxIterations);
1101              time2 = cpuTime();
1102              totalTime += time2-time1;
1103              std::cout<<"Result "<<models[iModel].status()<<
1104                " - "<<models[iModel].objectiveValue()<<
1105                " iterations "<<models[iModel].numberIterations()<<
1106                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
1107              if (models[iModel].status())
1108                std::cerr<<"Non zero status "<<models[iModel].status()<<
1109                  std::endl;
1110              time1=time2;
1111            } else {
1112              std::cout<<"** Current model not valid"<<std::endl;
1113            }
1114            break;
1115          case TIGHTEN:
1116            if (goodModels[iModel]) {
1117              int numberInfeasibilities = models[iModel].tightenPrimalBounds();
1118              if (numberInfeasibilities)
1119                std::cout<<"** Analysis indicates model infeasible"<<std::endl;
1120            } else {
1121              std::cout<<"** Current model not valid"<<std::endl;
1122            }
1123            break;
1124          case BAB:
1125#if 0
1126            if (goodModels[iModel]) {
1127              int saveMaxIterations = models[iModel].maximumIterations();
1128#ifdef READLINE     
1129              currentModel = models+iModel;
1130#endif
1131              {
1132                // get OsiClp stuff
1133                OsiClpSolverInterface m(models+iModel);
1134                m.getModelPtr()->messageHandler()->setLogLevel(0);
1135                m.branchAndBound();
1136                m.resolve();
1137                std::cout<<"Optimal solution "<<m.getObjValue()<<std::endl;
1138                m.releaseClp();
1139              }
1140              models[iModel].setMaximumIterations(saveMaxIterations);
1141              time2 = cpuTime();
1142              totalTime += time2-time1;
1143              std::cout<<"Result "<<models[iModel].status()<<
1144                " - "<<models[iModel].objectiveValue()<<
1145                " iterations "<<models[iModel].numberIterations()<<
1146                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
1147              if (models[iModel].status())
1148                std::cerr<<"Non zero status "<<models[iModel].status()<<
1149                  std::endl;
1150              time1=time2;
1151            } else {
1152              std::cout<<"** Current model not valid"<<std::endl;
1153            }
1154#endif
1155            break;
1156          case IMPORT:
1157            {
1158              // get next field
1159              field = getString(argc,argv);
1160              std::string fileName;
1161              bool canOpen=false;
1162              if (field=="-") {
1163                // stdin
1164                canOpen=true;
1165                fileName = "-";
1166              } else {
1167                if (field[0]=='/'||field[0]=='~')
1168                  fileName = field;
1169                else
1170                  fileName = directory+field;
1171                FILE *fp=fopen(fileName.c_str(),"r");
1172                if (fp) {
1173                  // can open - lets go for it
1174                  fclose(fp);
1175                  canOpen=true;
1176                } else {
1177                  std::cout<<"Unable to open file "<<fileName<<std::endl;
1178                }
1179              }
1180              if (canOpen) {
1181                int status =models[iModel].readMps(fileName.c_str(),
1182                                                   keepImportNames,
1183                                                   allowImportErrors);
1184                if (!status||(status>0&&allowImportErrors)) {
1185                  goodModels[iModel]=true;
1186                  // sets to all slack (not necessary?)
1187                  models[iModel].createStatus();
1188                  time2 = cpuTime();
1189                  totalTime += time2-time1;
1190                  time1=time2;
1191                } else {
1192                  // errors
1193                  std::cout<<"There were "<<status<<
1194                    " errors on input"<<std::endl;
1195                }
1196              }
1197            }
1198            break;
1199          case EXPORT:
1200            {
1201              // get next field
1202              field = getString(argc,argv);
1203              std::string fileName;
1204              bool canOpen=false;
1205              if (field[0]=='/'||field[0]=='~')
1206                fileName = field;
1207              else
1208                fileName = directory+field;
1209              FILE *fp=fopen(fileName.c_str(),"w");
1210              if (fp) {
1211                // can open - lets go for it
1212                fclose(fp);
1213                canOpen=true;
1214              } else {
1215                std::cout<<"Unable to open file "<<fileName<<std::endl;
1216              }
1217              if (canOpen) {
1218                // Convert names
1219                int iRow;
1220                int numberRows=models[iModel].numberRows();
1221
1222                char ** rowNames = new char * [numberRows];
1223                for (iRow=0;iRow<numberRows;iRow++) {
1224                  rowNames[iRow] = 
1225                    strdup(models[iModel].rowName(iRow).c_str());
1226                }
1227                int iColumn;
1228                int numberColumns=models[iModel].numberColumns();
1229
1230                char ** columnNames = new char * [numberColumns];
1231                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1232                  columnNames[iColumn] = 
1233                    strdup(models[iModel].columnName(iColumn).c_str());
1234                }
1235
1236                ClpSimplex& m = models[iModel];
1237                CoinMpsIO writer;
1238                writer.setMpsData(*m.matrix(), CLP_INFINITY,
1239                                  m.getColLower(), m.getColUpper(),
1240                                  m.getObjCoefficients(),
1241                                  (const char*) 0 /*integrality*/,
1242                                  m.getRowLower(), m.getRowUpper(),
1243                                  columnNames, rowNames);
1244                writer.writeMps(fileName.c_str());
1245                for (iRow=0;iRow<numberRows;iRow++) {
1246                  free(rowNames[iRow]);
1247                }
1248                delete [] rowNames;
1249                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1250                  free(columnNames[iColumn]);
1251                }
1252                delete [] columnNames;
1253                time2 = cpuTime();
1254                totalTime += time2-time1;
1255                time1=time2;
1256              }
1257            }
1258            break;
1259          case SAVE:
1260            {
1261              // get next field
1262              field = getString(argc,argv);
1263              std::string fileName;
1264              bool canOpen=false;
1265              if (field[0]=='/'||field[0]=='~')
1266                fileName = field;
1267              else
1268                fileName = directory+field;
1269              FILE *fp=fopen(fileName.c_str(),"wb");
1270              if (fp) {
1271                // can open - lets go for it
1272                fclose(fp);
1273                canOpen=true;
1274              } else {
1275                std::cout<<"Unable to open file "<<fileName<<std::endl;
1276              }
1277              if (canOpen) {
1278                int status =models[iModel].saveModel(fileName.c_str());
1279                if (!status) {
1280                  goodModels[iModel]=true;
1281                  time2 = cpuTime();
1282                  totalTime += time2-time1;
1283                  time1=time2;
1284                } else {
1285                  // errors
1286                  std::cout<<"There were errors on output"<<std::endl;
1287                }
1288              }
1289            }
1290            break;
1291          case RESTORE:
1292            {
1293              // get next field
1294              field = getString(argc,argv);
1295              std::string fileName;
1296              bool canOpen=false;
1297              if (field[0]=='/'||field[0]=='~')
1298                fileName = field;
1299              else
1300                fileName = directory+field;
1301              FILE *fp=fopen(fileName.c_str(),"rb");
1302              if (fp) {
1303                // can open - lets go for it
1304                fclose(fp);
1305                canOpen=true;
1306              } else {
1307                std::cout<<"Unable to open file "<<fileName<<std::endl;
1308              }
1309              if (canOpen) {
1310                int status =models[iModel].restoreModel(fileName.c_str());
1311                if (!status) {
1312                  goodModels[iModel]=true;
1313                  time2 = cpuTime();
1314                  totalTime += time2-time1;
1315                  time1=time2;
1316                } else {
1317                  // errors
1318                  std::cout<<"There were errors on input"<<std::endl;
1319                }
1320              }
1321            }
1322            break;
1323          case MAXIMIZE:
1324            models[iModel].setOptimizationDirection(-1);
1325            break;
1326          case MINIMIZE:
1327            models[iModel].setOptimizationDirection(1);
1328            break;
1329          case DIRECTORY:
1330            directory = getString(argc,argv);
1331            break;
1332          case STDIN:
1333            read_mode=-1;
1334            break;
1335          case NETLIB_DUAL:
1336          case NETLIB_PRIMAL:
1337            {
1338              // create fields for unitTest
1339              const char * fields[4];
1340              int nFields=2;
1341              fields[0]="fake main from unitTest";
1342              fields[1]="-netlib";
1343              if (directory!="./") {
1344                fields[2]="-netlibDir";
1345                fields[3]=directory.c_str();
1346                nFields=4;
1347              }
1348              if (type==NETLIB_DUAL)
1349                std::cerr<<"Doing netlib with dual agorithm"<<std::endl;
1350              else
1351                std::cerr<<"Doing netlib with primal agorithm"<<std::endl;
1352              mainTest(nFields,fields,(type==NETLIB_DUAL),models[iModel],
1353                       (preSolve!=0));
1354            }
1355            break;
1356          case UNITTEST:
1357            {
1358              // create fields for unitTest
1359              const char * fields[3];
1360              int nFields=1;
1361              fields[0]="fake main from unitTest";
1362              if (directory!="./") {
1363                fields[1]="-mpsDir";
1364                fields[2]=directory.c_str();
1365                nFields=3;
1366              }
1367              mainTest(nFields,fields,false,models[iModel],(preSolve!=0));
1368            }
1369            break;
1370          case FAKEBOUND:
1371            if (goodModels[iModel]) {
1372              // get bound
1373              double value = getDoubleField(argc,argv,&valid);
1374              if (!valid) {
1375                std::cout<<"Setting "<<parameters[iParam].name()<<
1376                  " to DEBUG "<<value<<std::endl;
1377                int iRow;
1378                int numberRows=models[iModel].numberRows();
1379                double * rowLower = models[iModel].rowLower();
1380                double * rowUpper = models[iModel].rowUpper();
1381                for (iRow=0;iRow<numberRows;iRow++) {
1382                  // leave free ones for now
1383                  if (rowLower[iRow]>-1.0e20||rowUpper[iRow]<1.0e20) {
1384                    rowLower[iRow]=max(rowLower[iRow],-value);
1385                    rowUpper[iRow]=min(rowUpper[iRow],value);
1386                  }
1387                }
1388                int iColumn;
1389                int numberColumns=models[iModel].numberColumns();
1390                double * columnLower = models[iModel].columnLower();
1391                double * columnUpper = models[iModel].columnUpper();
1392                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1393                  // leave free ones for now
1394                  if (columnLower[iColumn]>-1.0e20||
1395                      columnUpper[iColumn]<1.0e20) {
1396                    columnLower[iColumn]=max(columnLower[iColumn],-value);
1397                    columnUpper[iColumn]=min(columnUpper[iColumn],value);
1398                  }
1399                }
1400              } else if (valid==1) {
1401                abort();
1402              } else {
1403                std::cout<<"enter value for "<<parameters[iParam].name()<<
1404                  std::endl;
1405              }
1406            }
1407            break;
1408          case VERSION:
1409            std::cout<<"Coin LP version "<<CLPVERSION
1410                     <<", build "<<__DATE__<<std::endl;
1411            break;
1412          case SOLUTION:
1413            if (goodModels[iModel]) {
1414              // get next field
1415              field = getString(argc,argv);
1416              std::string fileName;
1417              FILE *fp=NULL;
1418              if (field=="-"||field=="EOL") {
1419                // stdout
1420                fp=stdout;
1421              } else {
1422                if (field[0]=='/'||field[0]=='~')
1423                  fileName = field;
1424                else
1425                  fileName = directory+field;
1426                fp=fopen(fileName.c_str(),"w");
1427              }
1428              if (fp) {
1429                // make fancy later on
1430                int iRow;
1431                int numberRows=models[iModel].numberRows();
1432                int lengthName = models[iModel].lengthNames(); // 0 if no names
1433                // in general I don't want to pass around massive
1434                // amounts of data but seems simpler here
1435                std::vector<std::string> rowNames =
1436                  *(models[iModel].rowNames());
1437                std::vector<std::string> columnNames =
1438                  *(models[iModel].columnNames());
1439
1440                double * dualRowSolution = models[iModel].dualRowSolution();
1441                double * primalRowSolution = 
1442                  models[iModel].primalRowSolution();
1443                char format[6];
1444                sprintf(format,"%%-%ds",max(lengthName,8));
1445                for (iRow=0;iRow<numberRows;iRow++) {
1446                  fprintf(fp,"%7d ",iRow);
1447                  if (lengthName)
1448                    fprintf(fp,format,rowNames[iRow].c_str());
1449                  fprintf(fp,"%15.8g        %15.8g\n",primalRowSolution[iRow],
1450                          dualRowSolution[iRow]);
1451                }
1452                int iColumn;
1453                int numberColumns=models[iModel].numberColumns();
1454                double * dualColumnSolution = 
1455                  models[iModel].dualColumnSolution();
1456                double * primalColumnSolution = 
1457                  models[iModel].primalColumnSolution();
1458                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1459                  fprintf(fp,"%7d ",iColumn);
1460                  if (lengthName)
1461                    fprintf(fp,format,columnNames[iColumn].c_str());
1462                  fprintf(fp,"%15.8g        %15.8g\n",
1463                          primalColumnSolution[iColumn],
1464                          dualColumnSolution[iColumn]);
1465                }
1466                if (fp!=stdout)
1467                  fclose(fp);
1468              } else {
1469                std::cout<<"Unable to open file "<<fileName<<std::endl;
1470              }
1471            } else {
1472              std::cout<<"** Current model not valid"<<std::endl;
1473             
1474            }
1475            break;
1476          default:
1477            abort();
1478          }
1479        } 
1480      } else if (!numberMatches) {
1481        std::cout<<"No match for "<<field<<" - ? for list of commands"
1482                 <<std::endl;
1483      } else if (numberMatches==1) {
1484        if (!numberQuery) {
1485          std::cout<<"Short match for "<<field<<" possible completion:"
1486                   <<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()<<std::endl;
1491          }
1492        } else if (numberQuery) {
1493          std::cout<<"Short match for "<<field<<" completion:"
1494                   <<std::endl;
1495          for ( iParam=0; iParam<numberParameters; iParam++ ) {
1496            int match = parameters[iParam].matches(field);
1497            if (match) {
1498              std::cout<<parameters[iParam].matchName()<<" : ";
1499              std::cout<<parameters[iParam].shortHelp()<<std::endl;
1500            }
1501          }
1502        }
1503      } else {
1504        if (!numberQuery) 
1505          std::cout<<"Multiple matches for "<<field<<" - possible completions:"
1506                   <<std::endl;
1507        else
1508          std::cout<<"Completions of "<<field<<":"<<std::endl;
1509        for ( iParam=0; iParam<numberParameters; iParam++ ) {
1510          int match = parameters[iParam].matches(field);
1511          if (match) {
1512            std::cout<<parameters[iParam].matchName();
1513            if (numberQuery>=2) 
1514              std::cout<<" : "<<parameters[iParam].shortHelp();
1515            std::cout<<std::endl;
1516          }
1517        }
1518      }
1519    }
1520    delete [] models;
1521    delete [] goodModels;
1522  }
1523  // By now all memory should be freed
1524#ifdef DMALLOC
1525  dmalloc_log_unfreed();
1526  dmalloc_shutdown();
1527#endif
1528  return 0;
1529}   
Note: See TracBrowser for help on using the repository browser.