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

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

Presolve (no changes to Makefile)

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