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

Last change on this file since 34 was 34, checked in by forrest, 18 years ago

Allow Presolve to work with gaps

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.0 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,PRESOLVEPASS,
77 
78  DIRECTION=201,DUALPIVOT,SCALING,ERRORSALLOWED,KEEPNAMES,SPARSEFACTOR,
79  PRIMALPIVOT,PRESOLVE,
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",
799              "off",PRESOLVE);
800    parameters[numberParameters-1].append("on");
801    parameters[numberParameters++]=
802      ClpItem("passP!resolve","How many passes in presolve",
803              0,100,PRESOLVEPASS);
804    parameters[numberParameters++]=
805      ClpItem("spars!eFactor","Whether factorization treated as sparse",
806              "on",SPARSEFACTOR);
807    parameters[numberParameters-1].append("off");
808    parameters[numberParameters++]=
809      ClpItem("error!sAllowed","Whether to allow import errors",
810              "off",ERRORSALLOWED);
811    parameters[numberParameters-1].append("on");
812    parameters[numberParameters++]=
813      ClpItem("keepN!ames","Whether to keep names from import",
814              "on",KEEPNAMES);
815    parameters[numberParameters-1].append("off");
816    parameters[numberParameters++]=
817      ClpItem("directory","Set Default import directory",
818              DIRECTORY);
819    parameters[numberParameters++]=
820      ClpItem("import","Import model from mps file",
821              IMPORT);
822    parameters[numberParameters++]=
823      ClpItem("export","Export model as mps file",
824              EXPORT);
825    parameters[numberParameters++]=
826      ClpItem("save!Model","Save model to binary file",
827              SAVE);
828    parameters[numberParameters++]=
829      ClpItem("restore!Model","Restore model from binary file",
830              RESTORE);
831    parameters[numberParameters++]=
832      ClpItem("dualS!implex","Do dual simplex algorithm",
833              DUALSIMPLEX);
834    parameters[numberParameters++]=
835      ClpItem("primalS!implex","Do primal simplex algorithm",
836              PRIMALSIMPLEX);
837    parameters[numberParameters++]=
838      ClpItem("branch!Andbound","Do Branch and Bound",
839              BAB);
840    parameters[numberParameters++]=
841      ClpItem("tight!en","Poor person's preSolve for now",
842              TIGHTEN);
843    parameters[numberParameters++]=
844      ClpItem("sol!ution","Prints solution to file",
845              SOLUTION);
846    parameters[numberParameters++]=
847      ClpItem("max!imize","Set optimization direction to maximize",
848              MAXIMIZE);
849    parameters[numberParameters++]=
850      ClpItem("min!imize","Set optimization direction to minimize",
851              MINIMIZE);
852    parameters[numberParameters++]=
853      ClpItem("exit","Stops clp execution",
854              EXIT);
855    parameters[numberParameters++]=
856      ClpItem("stop","Stops clp execution",
857              EXIT);
858    parameters[numberParameters++]=
859      ClpItem("quit","Stops clp execution",
860              EXIT);
861    parameters[numberParameters++]=
862      ClpItem("-","From stdin",
863              STDIN);
864    parameters[numberParameters++]=
865      ClpItem("stdin","From stdin",
866              STDIN);
867    parameters[numberParameters++]=
868      ClpItem("unitTest","Do unit test",
869              UNITTEST);
870    parameters[numberParameters++]=
871      ClpItem("netlib","Solev entlib test set",
872              NETLIB_DUAL);
873    parameters[numberParameters++]=
874      ClpItem("netlibP!rimal","Solev entlib test set",
875              NETLIB_PRIMAL);
876    parameters[numberParameters++]=
877      ClpItem("fakeB!ound","All bounds <= this value - DEBUG",
878              1.0,1.0e15,FAKEBOUND);
879    parameters[numberParameters++]=
880      ClpItem("ver!sion","Print out version",
881              VERSION);
882    assert(numberParameters<MAXPARAMETERS);
883   
884    // total number of commands read
885    int numberGoodCommands=0;
886    //int numberModels=1;
887    ClpSimplex * models = new ClpSimplex[1];
888    bool * goodModels = new bool[1];
889   
890#ifdef READLINE     
891    currentModel = models;
892    // register signal handler
893    signal(SIGINT,signal_handler);
894#endif
895   
896    // default action on import
897    int allowImportErrors=0;
898    int keepImportNames=1;
899    int preSolve=0;
900   
901    int iModel=0;
902    goodModels[0]=false;
903    // set reasonable defaults
904    models[0].scaling(1);
905    models[0].setDualBound(1.0e6);
906    models[0].setDualTolerance(1.0e-7);
907    ClpDualRowSteepest steep;
908    models[0].setDualRowPivotAlgorithm(steep);
909    models[0].setPrimalTolerance(1.0e-8);
910    ClpPrimalColumnSteepest steepP;
911    models[0].setPrimalColumnPivotAlgorithm(steepP);
912    std::string directory ="./";
913    std::string field;
914   
915    while (1) {
916      // next command
917      field=getCommand(argc,argv);
918     
919      // exit if null or similar
920      if (!field.length()) {
921        if (numberGoodCommands==1&&goodModels[0]) {
922          // we just had file name
923          models[0].scaling(1);
924          int saveMaxIterations = models[0].maximumIterations();
925          models[0].dual();
926          models[0].setMaximumIterations(saveMaxIterations);
927        } else if (!numberGoodCommands) {
928          // let's give the sucker a hint
929          std::cout
930            <<"Clp takes input from arguments ( - switches to stdin)"
931            <<std::endl
932            <<"Enter ? for list of commands, (-)unitTest or (-)netlib"
933            <<" for tests"<<std::endl;
934        }
935        break;
936      }
937     
938      // see if ? at end
939      int numberQuery=0;
940      if (field!="?") {
941        int length = field.length();
942        int i;
943        for (i=length-1;i>0;i--) {
944          if (field[i]=='?') 
945            numberQuery++;
946          else
947            break;
948        }
949        field=field.substr(0,length-numberQuery);
950      }
951      // find out if valid command
952      int iParam;
953      int numberMatches=0;
954      for ( iParam=0; iParam<numberParameters; iParam++ ) {
955        int match = parameters[iParam].matches(field);
956        if (match==1) {
957          numberMatches = 1;
958          break;
959        } else {
960          numberMatches += match>>1;
961        }
962      }
963      if (iParam<numberParameters&&!numberQuery) {
964        // found
965        ClpItem found = parameters[iParam];
966        ClpParameterType type = found.type();
967        int valid;
968        numberGoodCommands++;
969        if (type==GENERALQUERY) {
970          std::cout<<"In argument list keywords have leading - "
971            ", -stdin or just - switches to stdin"<<std::endl;
972          std::cout<<"One command per line (and no -)"<<std::endl;
973          std::cout<<"abcd? gives list of possibilities, if only one + explanation"<<std::endl;
974          std::cout<<"abcd?? adds explanation, if only one fuller help(LATER)"<<std::endl;
975          std::cout<<"abcd without value (where expected) gives current value"<<std::endl;
976          std::cout<<"abcd value or abcd = value sets value"<<std::endl;
977          std::cout<<"Commands are:"<<std::endl;
978          for ( iParam=0; iParam<numberParameters; iParam+=4 ) {
979            int i;
980            for (i=iParam;i<min(numberParameters,iParam+4);i++) 
981              std::cout<<parameters[i].matchName()<<"  ";
982            std::cout<<std::endl;
983          }
984        } else if (type<101) {
985          // get next field as double
986          double value = getDoubleField(argc,argv,&valid);
987          if (!valid) {
988            parameters[iParam].setDoubleParameter(models+iModel,value);
989          } else if (valid==1) {
990            abort();
991          } else {
992            std::cout<<parameters[iParam].name()<<" has value "<<
993              parameters[iParam].doubleParameter(models+iModel)<<std::endl;
994          }
995        } else if (type<201) {
996          // get next field as int
997          int value = getIntField(argc,argv,&valid);
998          if (!valid) {
999            if (parameters[iParam].type()==PRESOLVEPASS)
1000              preSolve = value;
1001            else
1002              parameters[iParam].setIntParameter(models+iModel,value);
1003          } else if (valid==1) {
1004            abort();
1005          } else {
1006            std::cout<<parameters[iParam].name()<<" has value "<<
1007              parameters[iParam].intParameter(models+iModel)<<std::endl;
1008          }
1009        } else if (type<301) {
1010          // one of several strings
1011          std::string value = getString(argc,argv);
1012          int action = parameters[iParam].parameterOption(value);
1013          if (action<0) {
1014            if (value!="EOL") {
1015              // no match
1016              parameters[iParam].printOptions();
1017            } else {
1018              // print current value
1019              std::cout<<parameters[iParam].name()<<" has value "<<
1020                parameters[iParam].currentOption()<<std::endl;
1021            }
1022          } else {
1023            parameters[iParam].setCurrentOption(action);
1024            // for now hard wired
1025            switch (type) {
1026            case DIRECTION:
1027              if (action==0)
1028                models[iModel].setOptimizationDirection(1);
1029              else
1030                models[iModel].setOptimizationDirection(-11);
1031              break;
1032            case DUALPIVOT:
1033              if (action==0) {
1034                ClpDualRowSteepest steep;
1035                models[iModel].setDualRowPivotAlgorithm(steep);
1036              } else {
1037                ClpDualRowDantzig dantzig;
1038                models[iModel].setDualRowPivotAlgorithm(dantzig);
1039              }
1040              break;
1041            case PRIMALPIVOT:
1042              if (action==0) {
1043                ClpPrimalColumnSteepest steep(1);
1044                models[iModel].setPrimalColumnPivotAlgorithm(steep);
1045              } else if (action==1) {
1046                ClpPrimalColumnSteepest steep(0);
1047                models[iModel].setPrimalColumnPivotAlgorithm(steep);
1048              } else {
1049                ClpPrimalColumnDantzig dantzig;
1050                models[iModel].setPrimalColumnPivotAlgorithm(dantzig);
1051              }
1052              break;
1053            case SCALING:
1054              models[iModel].scaling(1-action);
1055              break;
1056            case SPARSEFACTOR:
1057              models[iModel].setSparseFactorization(1-action);
1058              break;
1059            case ERRORSALLOWED:
1060              allowImportErrors = action;
1061              break;
1062            case KEEPNAMES:
1063              keepImportNames = 1-action;
1064              break;
1065            case PRESOLVE:
1066              preSolve = action*5;
1067              break;
1068            default:
1069              abort();
1070            }
1071          }
1072        } else {
1073          // action
1074          if (type==EXIT)
1075            break; // stop all
1076          switch (type) {
1077          case DUALSIMPLEX:
1078          case PRIMALSIMPLEX:
1079            if (goodModels[iModel]) {
1080              int saveMaxIterations = models[iModel].maximumIterations();
1081              ClpSimplex * model2 = models+iModel;
1082#ifdef USE_PRESOLVE
1083              Presolve pinfo;
1084              if (preSolve) 
1085                model2 = pinfo.presolvedModel(models[iModel],1.0e-8,preSolve);
1086#endif
1087#ifdef READLINE     
1088              currentModel = model2;
1089#endif
1090              if (type==DUALSIMPLEX)
1091                model2->dual();
1092              else
1093                model2->primal();
1094#ifdef USE_PRESOLVE
1095              if (preSolve) {
1096                pinfo.postsolve(true);
1097               
1098                delete model2;
1099                printf("Resolving from postsolved model\n");
1100               
1101#ifdef READLINE     
1102                currentModel = models+iModel;
1103#endif
1104                models[iModel].primal(1);
1105              }
1106#endif
1107              models[iModel].setMaximumIterations(saveMaxIterations);
1108              time2 = cpuTime();
1109              totalTime += time2-time1;
1110              std::cout<<"Result "<<models[iModel].status()<<
1111                " - "<<models[iModel].objectiveValue()<<
1112                " iterations "<<models[iModel].numberIterations()<<
1113                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
1114              if (models[iModel].status())
1115                std::cerr<<"Non zero status "<<models[iModel].status()<<
1116                  std::endl;
1117              time1=time2;
1118            } else {
1119              std::cout<<"** Current model not valid"<<std::endl;
1120            }
1121            break;
1122          case TIGHTEN:
1123            if (goodModels[iModel]) {
1124              int numberInfeasibilities = models[iModel].tightenPrimalBounds();
1125              if (numberInfeasibilities)
1126                std::cout<<"** Analysis indicates model infeasible"<<std::endl;
1127            } else {
1128              std::cout<<"** Current model not valid"<<std::endl;
1129            }
1130            break;
1131          case BAB:
1132#if 0
1133            if (goodModels[iModel]) {
1134              int saveMaxIterations = models[iModel].maximumIterations();
1135#ifdef READLINE     
1136              currentModel = models+iModel;
1137#endif
1138              {
1139                // get OsiClp stuff
1140                OsiClpSolverInterface m(models+iModel);
1141                m.getModelPtr()->messageHandler()->setLogLevel(0);
1142                m.branchAndBound();
1143                m.resolve();
1144                std::cout<<"Optimal solution "<<m.getObjValue()<<std::endl;
1145                m.releaseClp();
1146              }
1147              models[iModel].setMaximumIterations(saveMaxIterations);
1148              time2 = cpuTime();
1149              totalTime += time2-time1;
1150              std::cout<<"Result "<<models[iModel].status()<<
1151                " - "<<models[iModel].objectiveValue()<<
1152                " iterations "<<models[iModel].numberIterations()<<
1153                " took "<<time2-time1<<" seconds - total "<<totalTime<<std::endl;
1154              if (models[iModel].status())
1155                std::cerr<<"Non zero status "<<models[iModel].status()<<
1156                  std::endl;
1157              time1=time2;
1158            } else {
1159              std::cout<<"** Current model not valid"<<std::endl;
1160            }
1161#endif
1162            break;
1163          case IMPORT:
1164            {
1165              // get next field
1166              field = getString(argc,argv);
1167              std::string fileName;
1168              bool canOpen=false;
1169              if (field=="-") {
1170                // stdin
1171                canOpen=true;
1172                fileName = "-";
1173              } else {
1174                if (field[0]=='/'||field[0]=='~')
1175                  fileName = field;
1176                else
1177                  fileName = directory+field;
1178                FILE *fp=fopen(fileName.c_str(),"r");
1179                if (fp) {
1180                  // can open - lets go for it
1181                  fclose(fp);
1182                  canOpen=true;
1183                } else {
1184                  std::cout<<"Unable to open file "<<fileName<<std::endl;
1185                }
1186              }
1187              if (canOpen) {
1188                int status =models[iModel].readMps(fileName.c_str(),
1189                                                   keepImportNames,
1190                                                   allowImportErrors);
1191                if (!status||(status>0&&allowImportErrors)) {
1192                  goodModels[iModel]=true;
1193                  // sets to all slack (not necessary?)
1194                  models[iModel].createStatus();
1195                  time2 = cpuTime();
1196                  totalTime += time2-time1;
1197                  time1=time2;
1198                } else {
1199                  // errors
1200                  std::cout<<"There were "<<status<<
1201                    " errors on input"<<std::endl;
1202                }
1203              }
1204            }
1205            break;
1206          case EXPORT:
1207            {
1208              // get next field
1209              field = getString(argc,argv);
1210              std::string fileName;
1211              bool canOpen=false;
1212              if (field[0]=='/'||field[0]=='~')
1213                fileName = field;
1214              else
1215                fileName = directory+field;
1216              FILE *fp=fopen(fileName.c_str(),"w");
1217              if (fp) {
1218                // can open - lets go for it
1219                fclose(fp);
1220                canOpen=true;
1221              } else {
1222                std::cout<<"Unable to open file "<<fileName<<std::endl;
1223              }
1224              if (canOpen) {
1225                // Convert names
1226                int iRow;
1227                int numberRows=models[iModel].numberRows();
1228
1229                char ** rowNames = new char * [numberRows];
1230                for (iRow=0;iRow<numberRows;iRow++) {
1231                  rowNames[iRow] = 
1232                    strdup(models[iModel].rowName(iRow).c_str());
1233                }
1234                int iColumn;
1235                int numberColumns=models[iModel].numberColumns();
1236
1237                char ** columnNames = new char * [numberColumns];
1238                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1239                  columnNames[iColumn] = 
1240                    strdup(models[iModel].columnName(iColumn).c_str());
1241                }
1242
1243                ClpSimplex& m = models[iModel];
1244                CoinMpsIO writer;
1245                writer.setMpsData(*m.matrix(), CLP_INFINITY,
1246                                  m.getColLower(), m.getColUpper(),
1247                                  m.getObjCoefficients(),
1248                                  (const char*) 0 /*integrality*/,
1249                                  m.getRowLower(), m.getRowUpper(),
1250                                  columnNames, rowNames);
1251                writer.writeMps(fileName.c_str());
1252                for (iRow=0;iRow<numberRows;iRow++) {
1253                  free(rowNames[iRow]);
1254                }
1255                delete [] rowNames;
1256                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1257                  free(columnNames[iColumn]);
1258                }
1259                delete [] columnNames;
1260                time2 = cpuTime();
1261                totalTime += time2-time1;
1262                time1=time2;
1263              }
1264            }
1265            break;
1266          case SAVE:
1267            {
1268              // get next field
1269              field = getString(argc,argv);
1270              std::string fileName;
1271              bool canOpen=false;
1272              if (field[0]=='/'||field[0]=='~')
1273                fileName = field;
1274              else
1275                fileName = directory+field;
1276              FILE *fp=fopen(fileName.c_str(),"wb");
1277              if (fp) {
1278                // can open - lets go for it
1279                fclose(fp);
1280                canOpen=true;
1281              } else {
1282                std::cout<<"Unable to open file "<<fileName<<std::endl;
1283              }
1284              if (canOpen) {
1285                int status =models[iModel].saveModel(fileName.c_str());
1286                if (!status) {
1287                  goodModels[iModel]=true;
1288                  time2 = cpuTime();
1289                  totalTime += time2-time1;
1290                  time1=time2;
1291                } else {
1292                  // errors
1293                  std::cout<<"There were errors on output"<<std::endl;
1294                }
1295              }
1296            }
1297            break;
1298          case RESTORE:
1299            {
1300              // get next field
1301              field = getString(argc,argv);
1302              std::string fileName;
1303              bool canOpen=false;
1304              if (field[0]=='/'||field[0]=='~')
1305                fileName = field;
1306              else
1307                fileName = directory+field;
1308              FILE *fp=fopen(fileName.c_str(),"rb");
1309              if (fp) {
1310                // can open - lets go for it
1311                fclose(fp);
1312                canOpen=true;
1313              } else {
1314                std::cout<<"Unable to open file "<<fileName<<std::endl;
1315              }
1316              if (canOpen) {
1317                int status =models[iModel].restoreModel(fileName.c_str());
1318                if (!status) {
1319                  goodModels[iModel]=true;
1320                  time2 = cpuTime();
1321                  totalTime += time2-time1;
1322                  time1=time2;
1323                } else {
1324                  // errors
1325                  std::cout<<"There were errors on input"<<std::endl;
1326                }
1327              }
1328            }
1329            break;
1330          case MAXIMIZE:
1331            models[iModel].setOptimizationDirection(-1);
1332            break;
1333          case MINIMIZE:
1334            models[iModel].setOptimizationDirection(1);
1335            break;
1336          case DIRECTORY:
1337            directory = getString(argc,argv);
1338            break;
1339          case STDIN:
1340            read_mode=-1;
1341            break;
1342          case NETLIB_DUAL:
1343          case NETLIB_PRIMAL:
1344            {
1345              // create fields for unitTest
1346              const char * fields[4];
1347              int nFields=2;
1348              fields[0]="fake main from unitTest";
1349              fields[1]="-netlib";
1350              if (directory!="./") {
1351                fields[2]="-netlibDir";
1352                fields[3]=directory.c_str();
1353                nFields=4;
1354              }
1355              if (type==NETLIB_DUAL)
1356                std::cerr<<"Doing netlib with dual agorithm"<<std::endl;
1357              else
1358                std::cerr<<"Doing netlib with primal agorithm"<<std::endl;
1359              mainTest(nFields,fields,(type==NETLIB_DUAL),models[iModel],
1360                       (preSolve!=0));
1361            }
1362            break;
1363          case UNITTEST:
1364            {
1365              // create fields for unitTest
1366              const char * fields[3];
1367              int nFields=1;
1368              fields[0]="fake main from unitTest";
1369              if (directory!="./") {
1370                fields[1]="-mpsDir";
1371                fields[2]=directory.c_str();
1372                nFields=3;
1373              }
1374              mainTest(nFields,fields,false,models[iModel],(preSolve!=0));
1375            }
1376            break;
1377          case FAKEBOUND:
1378            if (goodModels[iModel]) {
1379              // get bound
1380              double value = getDoubleField(argc,argv,&valid);
1381              if (!valid) {
1382                std::cout<<"Setting "<<parameters[iParam].name()<<
1383                  " to DEBUG "<<value<<std::endl;
1384                int iRow;
1385                int numberRows=models[iModel].numberRows();
1386                double * rowLower = models[iModel].rowLower();
1387                double * rowUpper = models[iModel].rowUpper();
1388                for (iRow=0;iRow<numberRows;iRow++) {
1389                  // leave free ones for now
1390                  if (rowLower[iRow]>-1.0e20||rowUpper[iRow]<1.0e20) {
1391                    rowLower[iRow]=max(rowLower[iRow],-value);
1392                    rowUpper[iRow]=min(rowUpper[iRow],value);
1393                  }
1394                }
1395                int iColumn;
1396                int numberColumns=models[iModel].numberColumns();
1397                double * columnLower = models[iModel].columnLower();
1398                double * columnUpper = models[iModel].columnUpper();
1399                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1400                  // leave free ones for now
1401                  if (columnLower[iColumn]>-1.0e20||
1402                      columnUpper[iColumn]<1.0e20) {
1403                    columnLower[iColumn]=max(columnLower[iColumn],-value);
1404                    columnUpper[iColumn]=min(columnUpper[iColumn],value);
1405                  }
1406                }
1407              } else if (valid==1) {
1408                abort();
1409              } else {
1410                std::cout<<"enter value for "<<parameters[iParam].name()<<
1411                  std::endl;
1412              }
1413            }
1414            break;
1415          case VERSION:
1416            std::cout<<"Coin LP version "<<CLPVERSION
1417                     <<", build "<<__DATE__<<std::endl;
1418            break;
1419          case SOLUTION:
1420            if (goodModels[iModel]) {
1421              // get next field
1422              field = getString(argc,argv);
1423              std::string fileName;
1424              FILE *fp=NULL;
1425              if (field=="-"||field=="EOL") {
1426                // stdout
1427                fp=stdout;
1428              } else {
1429                if (field[0]=='/'||field[0]=='~')
1430                  fileName = field;
1431                else
1432                  fileName = directory+field;
1433                fp=fopen(fileName.c_str(),"w");
1434              }
1435              if (fp) {
1436                // make fancy later on
1437                int iRow;
1438                int numberRows=models[iModel].numberRows();
1439                int lengthName = models[iModel].lengthNames(); // 0 if no names
1440                // in general I don't want to pass around massive
1441                // amounts of data but seems simpler here
1442                std::vector<std::string> rowNames =
1443                  *(models[iModel].rowNames());
1444                std::vector<std::string> columnNames =
1445                  *(models[iModel].columnNames());
1446
1447                double * dualRowSolution = models[iModel].dualRowSolution();
1448                double * primalRowSolution = 
1449                  models[iModel].primalRowSolution();
1450                char format[6];
1451                sprintf(format,"%%-%ds",max(lengthName,8));
1452                for (iRow=0;iRow<numberRows;iRow++) {
1453                  fprintf(fp,"%7d ",iRow);
1454                  if (lengthName)
1455                    fprintf(fp,format,rowNames[iRow].c_str());
1456                  fprintf(fp,"%15.8g        %15.8g\n",primalRowSolution[iRow],
1457                          dualRowSolution[iRow]);
1458                }
1459                int iColumn;
1460                int numberColumns=models[iModel].numberColumns();
1461                double * dualColumnSolution = 
1462                  models[iModel].dualColumnSolution();
1463                double * primalColumnSolution = 
1464                  models[iModel].primalColumnSolution();
1465                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1466                  fprintf(fp,"%7d ",iColumn);
1467                  if (lengthName)
1468                    fprintf(fp,format,columnNames[iColumn].c_str());
1469                  fprintf(fp,"%15.8g        %15.8g\n",
1470                          primalColumnSolution[iColumn],
1471                          dualColumnSolution[iColumn]);
1472                }
1473                if (fp!=stdout)
1474                  fclose(fp);
1475              } else {
1476                std::cout<<"Unable to open file "<<fileName<<std::endl;
1477              }
1478            } else {
1479              std::cout<<"** Current model not valid"<<std::endl;
1480             
1481            }
1482            break;
1483          default:
1484            abort();
1485          }
1486        } 
1487      } else if (!numberMatches) {
1488        std::cout<<"No match for "<<field<<" - ? for list of commands"
1489                 <<std::endl;
1490      } else if (numberMatches==1) {
1491        if (!numberQuery) {
1492          std::cout<<"Short match for "<<field<<" possible completion:"
1493                   <<std::endl;
1494          for ( iParam=0; iParam<numberParameters; iParam++ ) {
1495            int match = parameters[iParam].matches(field);
1496            if (match) 
1497              std::cout<<parameters[iParam].matchName()<<std::endl;
1498          }
1499        } else if (numberQuery) {
1500          std::cout<<"Short match for "<<field<<" completion:"
1501                   <<std::endl;
1502          for ( iParam=0; iParam<numberParameters; iParam++ ) {
1503            int match = parameters[iParam].matches(field);
1504            if (match) {
1505              std::cout<<parameters[iParam].matchName()<<" : ";
1506              std::cout<<parameters[iParam].shortHelp()<<std::endl;
1507            }
1508          }
1509        }
1510      } else {
1511        if (!numberQuery) 
1512          std::cout<<"Multiple matches for "<<field<<" - possible completions:"
1513                   <<std::endl;
1514        else
1515          std::cout<<"Completions of "<<field<<":"<<std::endl;
1516        for ( iParam=0; iParam<numberParameters; iParam++ ) {
1517          int match = parameters[iParam].matches(field);
1518          if (match) {
1519            std::cout<<parameters[iParam].matchName();
1520            if (numberQuery>=2) 
1521              std::cout<<" : "<<parameters[iParam].shortHelp();
1522            std::cout<<std::endl;
1523          }
1524        }
1525      }
1526    }
1527    delete [] models;
1528    delete [] goodModels;
1529  }
1530  // By now all memory should be freed
1531#ifdef DMALLOC
1532  dmalloc_log_unfreed();
1533  dmalloc_shutdown();
1534#endif
1535  return 0;
1536}   
Note: See TracBrowser for help on using the repository browser.