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

Last change on this file since 19 was 19, checked in by ladanyi, 17 years ago

reordering Clp

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