1 // Copyright (C) 2004, 2006 International Business Machines and others.
2 // All Rights Reserved.
3 // This code is published under the Common Public License.
4 //
5 // $Id: IpRegOptions.hpp 759 2006-07-07 03:07:08Z andreasw $
6 //
7 // Authors:  Carl Laird, Andreas Waechter     IBM    2005-06-18
8 
9 #ifndef __IPREGOPTIONS_HPP__
10 #define __IPREGOPTIONS_HPP__
11 
12 #include "IpUtils.hpp"
13 #include "IpReferenced.hpp"
14 #include "IpException.hpp"
15 #include "IpSmartPtr.hpp"
16 
17 #include <map>
18 
19 namespace SimTKIpopt
20 {
21 
22   enum RegisteredOptionType
23   {
24     OT_Number,
25     OT_Integer,
26     OT_String,
27     OT_Unknown
28   };
29 
30   /** Base class for registered options. The derived types are more
31    *  specific to a string option or a Number (real) option, etc.
32    */
33   class RegisteredOption : public ReferencedObject
34   {
35   public:
36     /** Constructors / Destructors */
37     //@{
RegisteredOption()38     RegisteredOption()
39         :
40         type_(OT_Unknown),
41         has_lower_(false),
42         has_upper_(false),
43         counter_(0)
44     {}
45 
RegisteredOption(const std::string & name,const std::string & short_description,const std::string & long_description,const std::string & registering_category)46     RegisteredOption(const std::string& name,
47                      const std::string& short_description,
48                      const std::string& long_description,
49                      const std::string& registering_category)
50         :
51         name_(name),
52         short_description_(short_description),
53         long_description_(long_description),
54         registering_category_(registering_category),
55         type_(OT_Unknown),
56         has_lower_(false),
57         has_upper_(false),
58         counter_(next_counter_++)
59     {}
60 
RegisteredOption(const RegisteredOption & copy)61     RegisteredOption(const RegisteredOption& copy)
62         :
63         name_(copy.name_),
64         short_description_(copy.short_description_),
65         long_description_(copy.long_description_),
66         registering_category_(copy.registering_category_),
67         type_(copy.type_),
68         has_lower_(copy.has_lower_),
69         lower_(copy.lower_),
70         has_upper_(copy.has_upper_),
71         upper_(copy.upper_),
72         valid_strings_(copy.valid_strings_),
73         counter_(copy.counter_)
74     {}
75 
~RegisteredOption()76     virtual ~RegisteredOption()
77     {}
78     //@}
79 
80     DECLARE_STD_EXCEPTION(ERROR_CONVERTING_STRING_TO_ENUM);
81 
82     /** Standard Get / Set Methods */
83     //@{
84     /** Get the option's name (tag in the input file) */
Name() const85     const std::string& Name() const
86     {
87       return name_;
88     }
89     /** Set the option's name (tag in the input file) */
SetName(const std::string & name)90     void SetName(const std::string& name)
91     {
92       name_ = name;
93     }
94     /** Get the short description */
ShortDescription() const95     const std::string& ShortDescription() const
96     {
97       return short_description_;
98     }
99     /** Get the long description */
LongDescription() const100     const std::string& LongDescription() const
101     {
102       return long_description_;
103     }
104     /** Set the short description */
SetShortDescription(const std::string & short_description)105     void SetShortDescription(const std::string& short_description)
106     {
107       short_description_ = short_description;
108     }
109     /** Set the long description */
SetLongDescription(const std::string & long_description)110     void SetLongDescription(const std::string& long_description)
111     {
112       long_description_ = long_description;
113     }
114     /** Get the registering class */
RegisteringCategory() const115     const std::string& RegisteringCategory() const
116     {
117       return registering_category_;
118     }
119     /** Set the registering class */
SetRegisteringCategory(const std::string & registering_category)120     void SetRegisteringCategory(const std::string& registering_category)
121     {
122       registering_category_ = registering_category;
123     }
124     /** Get the Option's type */
Type() const125     const RegisteredOptionType& Type() const
126     {
127       return type_;
128     }
129     /** Get the Option's type */
SetType(const RegisteredOptionType & type)130     void SetType(const RegisteredOptionType& type)
131     {
132       type_ = type;
133     }
134     /** Counter */
Counter() const135     Index Counter() const
136     {
137       return counter_;
138     }
139     //@}
140 
141     /** @name Get / Set methods valid for specific types - NOTE: the Type
142      *  must be set before calling these methods.
143      */
144     //@{
145     /** check if the option has a lower bound - can be called for
146      *  OT_Number & OT_Integer*/
HasLower() const147     const bool& HasLower() const
148     {
149       DBG_ASSERT(type_ == OT_Number || type_ == OT_Integer);
150       return has_lower_;
151     }
152     /** check if the lower bound is strict - can be called for
153     OT_Number */
LowerStrict() const154     const bool& LowerStrict() const
155     {
156       DBG_ASSERT(type_ == OT_Number && has_lower_ == true);
157       return lower_strict_;
158     }
159     /** get the Number version of the lower bound - can be called for
160      *  OT_Number */
LowerNumber() const161     Number LowerNumber() const
162     {
163       DBG_ASSERT(has_lower_ == true && type_ == OT_Number);
164       return lower_;
165     }
166     /** set the Number version of the lower bound - can be called for
167      *  OT_Number */
SetLowerNumber(const Number & lower,const bool & strict)168     void SetLowerNumber(const Number& lower, const bool& strict)
169     {
170       DBG_ASSERT(type_ == OT_Number);
171       lower_ = lower;
172       lower_strict_ = strict, has_lower_ = true;
173     }
174     /** get the Integer version of the lower bound can be called for
175      *  OT_Integer*/
LowerInteger() const176     Index LowerInteger() const
177     {
178       DBG_ASSERT(has_lower_ == true && type_ == OT_Integer);
179       return (Index)lower_;
180     }
181     /** set the Integer version of the lower bound - can be called for
182      *  OT_Integer */
SetLowerInteger(const Index & lower)183     void SetLowerInteger(const Index& lower)
184     {
185       DBG_ASSERT(type_ == OT_Integer);
186       lower_ = (Number)lower;
187       has_lower_ = true;
188     }
189     /** check if the option has an upper bound - can be called for
190      *  OT_Number & OT_Integer*/
HasUpper() const191     const bool& HasUpper() const
192     {
193       DBG_ASSERT(type_ == OT_Number || type_ == OT_Integer);
194       return has_upper_;
195     }
196     /** check if the upper bound is strict - can be called for
197      *  OT_Number */
UpperStrict() const198     const bool& UpperStrict() const
199     {
200       DBG_ASSERT(type_ == OT_Number && has_upper_ == true);
201       return upper_strict_;
202     }
203     /** get the Number version of the upper bound - can be called for
204      *  OT_Number */
UpperNumber()205     Number UpperNumber()
206     {
207       DBG_ASSERT(has_upper_ == true && type_ == OT_Number);
208       return upper_;
209     }
210     /** set the Number version of the upper bound - can be called for
211      *  OT_Number */
SetUpperNumber(const Number & upper,const bool & strict)212     void SetUpperNumber(const Number& upper, const bool& strict)
213     {
214       DBG_ASSERT(type_ == OT_Number);
215       upper_ = upper;
216       upper_strict_ = strict;
217       has_upper_ = true;
218     }
219     /** get the Integer version of the upper bound - can be called for
220      *  OT_Integer*/
UpperInteger() const221     Index UpperInteger() const
222     {
223       DBG_ASSERT(has_upper_ == true && type_ == OT_Integer);
224       return (Index)upper_;
225     }
226     /** set the Integer version of the upper bound - can be called for
227      *  OT_Integer */
SetUpperInteger(const Index & upper)228     void SetUpperInteger(const Index& upper)
229     {
230       DBG_ASSERT(type_ == OT_Integer);
231       upper_ = (Number)upper;
232       has_upper_ = true;
233     }
234     /** method to add valid string entries - can be called for
235      *  OT_String */
AddValidStringSetting(const std::string value,const std::string description)236     void AddValidStringSetting(const std::string value,
237                                const std::string description)
238     {
239       DBG_ASSERT(type_ == OT_String);
240       valid_strings_.push_back(string_entry(value, description));
241     }
242     /** get the default as a Number - can be called for OT_Number */
DefaultNumber() const243     Number DefaultNumber() const
244     {
245       DBG_ASSERT(type_ == OT_Number);
246       return default_number_;
247     }
248     /** Set the default as a Number - can be called for OT_Number */
SetDefaultNumber(const Number & default_value)249     void SetDefaultNumber(const Number& default_value)
250     {
251       DBG_ASSERT(type_ == OT_Number);
252       default_number_ = default_value;
253     }
254     /** get the default as an Integer - can be called for OT_Integer*/
DefaultInteger() const255     Index DefaultInteger() const
256     {
257       DBG_ASSERT(type_ == OT_Integer);
258       return (Index)default_number_;
259     }
260     /** Set the default as an Integer - can be called for
261     OT_Integer */
SetDefaultInteger(const Index & default_value)262     void SetDefaultInteger(const Index& default_value)
263     {
264       DBG_ASSERT(type_ == OT_Integer);
265       default_number_ = (Number)default_value;
266     }
267     /** get the default as a string - can be called for OT_String */
DefaultString() const268     std::string DefaultString() const
269     {
270       DBG_ASSERT(type_ == OT_String);
271       return default_string_;
272     }
273     /** get the default as a string, but as the index of the string in
274      *  the list - helps map from a string to an enum- can be called
275      *  for OT_String */
DefaultStringAsEnum() const276     Index DefaultStringAsEnum() const
277     {
278       DBG_ASSERT(type_ == OT_String);
279       return MapStringSettingToEnum(default_string_);
280     }
281     /** Set the default as a string - can be called for OT_String */
SetDefaultString(const std::string & default_value)282     void SetDefaultString(const std::string& default_value)
283     {
284       DBG_ASSERT(type_ == OT_String);
285       default_string_ = default_value;
286     }
287     /** Check if the Number value is a valid setting - can be called
288      *  for OT_Number */
IsValidNumberSetting(const Number & value) const289     bool IsValidNumberSetting(const Number& value) const
290     {
291       DBG_ASSERT(type_ == OT_Number);
292       if (has_lower_ && ((lower_strict_ == true && value <= lower_) ||
293                          (lower_strict_ == false && value < lower_))) {
294         return false;
295       }
296       if (has_upper_ && ((upper_strict_ == true && value >= upper_) ||
297                          (upper_strict_ == false && value > upper_))) {
298         return false;
299       }
300       return true;
301     }
302     /** Check if the Integer value is a valid setting - can be called
303      *  for OT_Integer */
IsValidIntegerSetting(const Index & value) const304     bool IsValidIntegerSetting(const Index& value) const
305     {
306       DBG_ASSERT(type_ == OT_Integer);
307       if (has_lower_ && value < lower_) {
308         return false;
309       }
310       if (has_upper_ && value > upper_) {
311         return false;
312       }
313       return true;
314     }
315     /** Check if the String value is a valid setting - can be called
316      *  for OT_String */
317     bool IsValidStringSetting(const std::string& value) const;
318 
319     /** Map a user setting (allowing any case) to the case used when
320      *  the setting was registered.
321      */
322     std::string MapStringSetting(const std::string& value) const;
323 
324     /** Map a user setting (allowing any case) to the index of the
325      *  matched setting in the list of string settings. Helps map a
326      *  string setting to an enumeration.
327      */
328     Index MapStringSettingToEnum(const std::string& value) const;
329     //@}
330 
331     /** output a description of the option */
332     void OutputDescription(const Journalist& jnlst) const;
333     /** output a more concise version */
334     void OutputShortDescription(const Journalist& jnlst) const;
335     /** output a latex version */
336     void OutputLatexDescription(const Journalist& jnlst) const;
337 
338   private:
339     std::string name_;
340     std::string short_description_;
341     std::string long_description_;
342     std::string registering_category_;
343     RegisteredOptionType type_;
344 
345     bool has_lower_;
346     bool lower_strict_;
347     Number lower_;
348     bool has_upper_;
349     bool upper_strict_;
350     Number upper_;
351     Number default_number_;
352 
353     void MakeValidLatexString(std::string source, std::string& dest) const;
354     std::string MakeValidLatexNumber(Number value) const;
355 
356     /** Compare two strings and return true if they are equal (case
357     insensitive comparison) */
358     bool string_equal_insensitive(const std::string& s1,
359                                   const std::string& s2) const;
360 
361     /** class to hold the valid string settings for a string option */
362     class string_entry
363     {
364     public:
string_entry(const std::string & value,const std::string & description)365       string_entry(const std::string& value, const std::string& description)
366           : value_(value), description_(description)
367       {}
368       std::string value_;
369       std::string description_;
370     };
371 
372     std::vector<string_entry> valid_strings_;
373     std::string default_string_;
374 
375     /** Has the information as how many-th option this one was
376      *  registered. */
377     const Index counter_;
378 
379     static Index next_counter_;
380   };
381 
382   /** Class for storing registered options. Used for validation and
383    *  documentation.
384    */
385   class RegisteredOptions : public ReferencedObject
386   {
387   public:
388     /** Constructors / Destructors */
389     //@{
390     /** Standard Constructor */
RegisteredOptions()391     RegisteredOptions()
392         :
393         current_registering_category_("Uncategorized")
394     {}
395 
396     /** Standard Destructor */
~RegisteredOptions()397     ~RegisteredOptions()
398     {}
399     //@}
400 
401     DECLARE_STD_EXCEPTION(OPTION_ALREADY_REGISTERED);
402 
403     /** Methods to interact with registered options */
404     //@{
405     /** set the registering class. All subsequent options will be
406      *  added with the registered class */
SetRegisteringCategory(const std::string & registering_category)407     void SetRegisteringCategory(const std::string& registering_category)
408     {
409       current_registering_category_ = registering_category;
410     }
411 
412     /** retrieve the value of the current registering category */
RegisteringCategory()413     std::string RegisteringCategory()
414     {
415       return current_registering_category_;
416     }
417 
418     /** Add a Number option (with no restrictions) */
419     void AddNumberOption(const std::string& name,
420                          const std::string& short_description,
421                          Number default_value,
422                          const std::string& long_description="");
423     /** Add a Number option (with a lower bound) */
424     void AddLowerBoundedNumberOption(const std::string& name,
425                                      const std::string& short_description,
426                                      Number lower, bool strict,
427                                      Number default_value,
428                                      const std::string& long_description="");
429     /** Add a Number option (with a upper bound) */
430     void AddUpperBoundedNumberOption(const std::string& name,
431                                      const std::string& short_description,
432                                      Number upper, bool strict,
433                                      Number default_value,
434                                      const std::string& long_description="");
435     /** Add a Number option (with a both bounds) */
436     void AddBoundedNumberOption(const std::string& name,
437                                 const std::string& short_description,
438                                 Number lower, bool lower_strict,
439                                 Number upper, bool upper_strict,
440                                 Number default_value,
441                                 const std::string& long_description="");
442     /** Add a Integer option (with no restrictions) */
443     void AddIntegerOption(const std::string& name,
444                           const std::string& short_description,
445                           Index default_value,
446                           const std::string& long_description="");
447     /** Add a Integer option (with a lower bound) */
448     void AddLowerBoundedIntegerOption(const std::string& name,
449                                       const std::string& short_description,
450                                       Index lower, Index default_value,
451                                       const std::string& long_description="");
452     /** Add a Integer option (with a upper bound) */
453     void AddUpperBoundedIntegerOption(const std::string& name,
454                                       const std::string& short_description,
455                                       Index upper, Index default_value,
456                                       const std::string& long_description="");
457     /** Add a Integer option (with a both bounds) */
458     void AddBoundedIntegerOption(const std::string& name,
459                                  const std::string& short_description,
460                                  Index lower, Index upper,
461                                  Index default_value,
462                                  const std::string& long_description="");
463 
464     /** Add a String option (with no restrictions) */
465     void AddStringOption(const std::string& name,
466                          const std::string& short_description,
467                          const std::string& default_value,
468                          const std::vector<std::string>& settings,
469                          const std::vector<std::string>& descriptions,
470                          const std::string& long_description="");
471     /** Methods that make adding string options with only a few
472      *  entries easier */
473     void AddStringOption1(const std::string& name,
474                           const std::string& short_description,
475                           const std::string& default_value,
476                           const std::string& setting1,
477                           const std::string& description1,
478                           const std::string& long_description="");
479     void AddStringOption2(const std::string& name,
480                           const std::string& short_description,
481                           const std::string& default_value,
482                           const std::string& setting1,
483                           const std::string& description1,
484                           const std::string& setting2,
485                           const std::string& description2,
486                           const std::string& long_description="");
487     void AddStringOption3(const std::string& name,
488                           const std::string& short_description,
489                           const std::string& default_value,
490                           const std::string& setting1,
491                           const std::string& description1,
492                           const std::string& setting2,
493                           const std::string& description2,
494                           const std::string& setting3,
495                           const std::string& description3,
496                           const std::string& long_description="");
497     void AddStringOption4(const std::string& name,
498                           const std::string& short_description,
499                           const std::string& default_value,
500                           const std::string& setting1,
501                           const std::string& description1,
502                           const std::string& setting2,
503                           const std::string& description2,
504                           const std::string& setting3,
505                           const std::string& description3,
506                           const std::string& setting4,
507                           const std::string& description4,
508                           const std::string& long_description="");
509     void AddStringOption5(const std::string& name,
510                           const std::string& short_description,
511                           const std::string& default_value,
512                           const std::string& setting1,
513                           const std::string& description1,
514                           const std::string& setting2,
515                           const std::string& description2,
516                           const std::string& setting3,
517                           const std::string& description3,
518                           const std::string& setting4,
519                           const std::string& description4,
520                           const std::string& setting5,
521                           const std::string& description5,
522                           const std::string& long_description="");
523     void AddStringOption6(const std::string& name,
524                           const std::string& short_description,
525                           const std::string& default_value,
526                           const std::string& setting1,
527                           const std::string& description1,
528                           const std::string& setting2,
529                           const std::string& description2,
530                           const std::string& setting3,
531                           const std::string& description3,
532                           const std::string& setting4,
533                           const std::string& description4,
534                           const std::string& setting5,
535                           const std::string& description5,
536                           const std::string& setting6,
537                           const std::string& description6,
538                           const std::string& long_description="");
539     void AddStringOption7(const std::string& name,
540                           const std::string& short_description,
541                           const std::string& default_value,
542                           const std::string& setting1,
543                           const std::string& description1,
544                           const std::string& setting2,
545                           const std::string& description2,
546                           const std::string& setting3,
547                           const std::string& description3,
548                           const std::string& setting4,
549                           const std::string& description4,
550                           const std::string& setting5,
551                           const std::string& description5,
552                           const std::string& setting6,
553                           const std::string& description6,
554                           const std::string& setting7,
555                           const std::string& description7,
556                           const std::string& long_description="");
557 
558     /** Get a registered option - this will return NULL if the option
559      *  does not exist */
560     SmartPtr<const RegisteredOption> GetOption(const std::string& name);
561 
562     /** Output documentation for the options - gives a description,
563      *  etc. */
564     void OutputOptionDocumentation(const Journalist& jnlst, std::list<std::string>& categories);
565 
566     /** Output documentation in Latex format to include in a latex file */
567     void OutputLatexOptionDocumentation(const Journalist& jnlst, std::list<std::string>& categories);
568     //@}
569 
570   private:
571     std::string current_registering_category_;
572     std::map<std::string, SmartPtr<RegisteredOption> > registered_options_;
573   };
574 } // namespace Ipopt
575 
576 #endif
577