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

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

Taking out dependence on CoinWarmStartBasis?

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