command_line_options.hpp

00001 /*
00002 This file is part of GraphLab.
00003 
00004 GraphLab is free software: you can redistribute it and/or modify
00005 it under the terms of the GNU Lesser General Public License as 
00006 published by the Free Software Foundation, either version 3 of 
00007 the License, or (at your option) any later version.
00008 
00009 GraphLab is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public 
00015 License along with GraphLab.  If not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 #ifndef GRAPHLAB_COMMAND_LINE_OPTIONS
00019 #define GRAPHLAB_COMMAND_LINE_OPTIONS
00020 
00021 #include <string>
00022 
00023 
00024 #include <boost/program_options.hpp>
00025 
00026 
00027 #include <graphlab/engine/engine_options.hpp>
00028 
00029 
00030 namespace boost {
00031   /**
00032     \ingroup util
00033     Converts a vector of any stream output-able type to a string
00034   */
00035   template<typename T>
00036   std::string graphlab_vec_to_string(const std::vector<T>& vec) {
00037     std::stringstream strm;
00038     strm << "{" ;
00039     for(size_t i = 0; i < vec.size(); ++i) {
00040       strm << vec[i];
00041       if(i < vec.size() - 1) strm << ", ";
00042     }
00043     strm << "}";
00044     return strm.str();
00045   }
00046   /**
00047    \ingroup util
00048    Provides lexical cast from vector<size_t> to string.
00049    Converts a vector of 1,2,3 to the string "{1, 2, 3}"
00050   */
00051   template<>
00052   std::string lexical_cast<std::string>(const std::vector<size_t>& vec);
00053   
00054   /**
00055    \ingroup util
00056    Provides lexical cast from vector<int> to string.
00057    Converts a vector of 1,2,3 to the string "{1, 2, 3}"
00058   */  
00059   template<>
00060   std::string lexical_cast< std::string>(const std::vector<int>& vec);
00061   
00062   /**
00063    \ingroup util
00064    Provides lexical cast from vector<double> to string.
00065    Converts a vector of 1.1,2.2,3.3 to the string "{1.1, 2.2, 3.3}"
00066   */
00067   template<>
00068   std::string lexical_cast< std::string >(const std::vector<double>& vec);
00069   
00070   /**
00071    \ingroup util
00072    Provides lexical cast from vector<float> to string.
00073    Converts a vector of 1.1,2.2,3.3 to the string "{1.1, 2.2, 3.3}"
00074   */
00075   template<>
00076   std::string lexical_cast< std::string>(const std::vector<float>& vec);
00077   
00078   /**
00079    \ingroup util
00080    Provides lexical cast from vector<string> to string.
00081    Converts a vector of "hello", "world" to the string "{hello, world}"
00082   */
00083   template<>
00084   std::string lexical_cast< std::string>(const std::vector<std::string>& vec);
00085 
00086 }; // end of namespace boost
00087 
00088 
00089 namespace graphlab {
00090   /**
00091   \ingroup util
00092   Because of the many engine options GraphLab has relatively
00093   sophisticated command line parsing tools. However we have found that
00094   many of our ML applications had poorly written command line parsing
00095   support so we tried to generalize the GraphLab command line tools to
00096   enable user applications to benefit from sophisticated and still
00097   easy to use command line parsing.
00098 
00099   The command_line_options data-structure extends (wrapping) the
00100   boost::program_options library. We have tried to retain much of the
00101   functionality of the boost::program_options library while hiding
00102   some of the less "friendly" template meta-programming "features".
00103   
00104   Here is an example of how the library is used:
00105   
00106   \code
00107   int main(int argc, char** argv) {
00108   
00109     std::string filename;
00110     size_t dimensions = 20;
00111     double bound = 1E-5;
00112     bool use_x = false;
00113     std::vector<size_t> nsamples(1,10000);
00114   
00115     // Parse command line options
00116     graphlab::command_line_options clopts("Welcome to a the HelloWorld");
00117     clopts.attach_option("file", &filename, 
00118                          "The input filename (required)");
00119     clopts.add_positional("file");
00120     clopts.attach_option("dim",
00121                          &dimensions, dimensions,
00122                          "the dimension of the grid");
00123     clopts.attach_option("bound",
00124                          &bound, bound,
00125                          "The termination bound");
00126     clopts.attach_option("usex",
00127                          &use_x, use_x,
00128                          "Use algorithm x");
00129     clopts.attach_option("nsamples",
00130                          &nsamples, nsamples,
00131                          "A vector of the number of samples"); 
00132     clopts.set_scheduler_type("fifo");
00133     clopts.set_scope_type("edge");
00134   
00135     if(!clopts.parse(argc, argv)) return EXIT_FAILURE;
00136   
00137     if(!clopts.is_set("file")) {
00138       std::cout << "Input file not provided" << std::endl;
00139   
00140       clopts.print_description();
00141       return EXIT_FAILURE;
00142     }
00143   }
00144   \endcode
00145   
00146   
00147   */
00148   class command_line_options : public engine_options {
00149 
00150     boost::program_options::options_description desc;
00151     boost::program_options::positional_options_description 
00152     pos_opts;
00153     boost::program_options::variables_map vm;
00154     
00155     bool surpress_graphlab_options;
00156     
00157   public:
00158     command_line_options(const std::string& desc_str = "GraphLab program.",
00159                          size_t default_ncpus = 2,
00160                          const std::string& default_engine = "async",
00161                          const std::string& default_scope = "edge",
00162                          const std::string& default_scheduler = "fifo") : 
00163       desc(desc_str), surpress_graphlab_options(false) {
00164       ncpus = default_ncpus;
00165       engine_type = default_engine;
00166       scope_type = default_scope;
00167       scheduler_type = default_scheduler;
00168       // Add documentation for help
00169       namespace boost_po = boost::program_options;
00170       
00171       desc.add_options()("help", "Print this help message.");
00172       
00173     
00174     } // End constructor
00175 
00176     command_line_options(const std::string& desc_str,
00177                          bool surpress_graphlab_options) : 
00178       desc(desc_str), 
00179       surpress_graphlab_options(surpress_graphlab_options) {     
00180       // Add documentation for help
00181       namespace boost_po = boost::program_options;      
00182       desc.add_options()("help", "Print this help message.");
00183       
00184     } // End constructor
00185 
00186 
00187 
00188     
00189     /// Print the same message that is printed when the --help command
00190     /// line argument is provided.
00191     inline void print_description() const { std::cout << desc << std::endl; }
00192 
00193 
00194     /**
00195     \brief This function should be called AFTER all the options have
00196     been seen (including positionals). The parse function reads the
00197     standard command line arguments and fills in the attached
00198     variables. If there is an error in the syntax or parsing fails the
00199     parse routine will print the error and return false.
00200     */
00201     bool parse(int argc, char** argv);
00202 
00203     /** The is set function is used to test if the user provided the option. 
00204     The option string should match one of the attached options. 
00205     */
00206     bool is_set(const std::string& option);
00207 
00208 
00209     /**
00210     \brief attach a user defined option to the command line options
00211     parser.
00212     
00213     The attach option command is used to attach a user defined option
00214     to the command line options parser.
00215     
00216     \param option The name of the command line flag for that option.
00217 
00218     \param ret_cont A pointer to an "arbitrary" type which can be any
00219                     of the basic types (char, int, size_t, float,
00220                     double, bool, string...) or an std::vector of
00221                     basic types. It is important that the ret_cont
00222                     point to a memory block that will exist when parse
00223                     is invoked.
00224                     
00225     \param description Used to describe the option when --help 
00226           is called or when print_description is invoked.
00227     */
00228     template<typename T>
00229     void attach_option(const std::string& option,
00230                        T* ret_cont,
00231                        const std::string& description) {
00232       namespace boost_po = boost::program_options;
00233       assert(ret_cont != NULL);
00234       desc.add_options()
00235         (option.c_str(), 
00236          boost_po::value<T>(ret_cont), 
00237          description.c_str());
00238     }
00239 
00240 
00241     /**
00242     \brief attach a user defined option to the command line options
00243     parser.
00244     
00245     The attach option command is used to attach a user defined option
00246     to the command line options parser.
00247     
00248     \param option The name of the command line flag for that option.
00249 
00250     \param ret_cont A pointer to an "arbitrary" type which can be any
00251                     of the basic types (char, int, size_t, float,
00252                     double, bool, string...) or an std::vector of
00253                     basic types. It is important that the ret_cont
00254                     point to a memory block that will exist when parse
00255                     is invoked.
00256 
00257     \param default_value The default value of the parameter if the
00258                          user does not provide this parameter on the
00259                          command line.
00260 
00261     \param description Used to describe the option when --help 
00262           is called or when print_description is invoked.
00263     */
00264     template<typename T>
00265     void attach_option(const std::string& option,
00266                        T* ret_cont,
00267                        const T& default_value, 
00268                        const std::string& description) {
00269       namespace boost_po = boost::program_options;
00270       assert(ret_cont != NULL);
00271       desc.add_options()
00272         (option.c_str(),
00273          boost_po::value<T>(ret_cont)->default_value(default_value),
00274          description.c_str());
00275     }
00276     
00277     /** This function adds the option as a positional argument.  A
00278     positional argument does not require --option and instead is read
00279     based on its location. Each add_positional call adds to the next
00280     position. */
00281     void add_positional(const std::string& str);
00282 
00283     
00284   }; // end class command line options
00285 
00286 
00287   
00288 
00289 
00290 
00291 
00292 }; // end namespace graphlab
00293 
00294 
00295 #endif
00296