$treeview $search $mathjax
TraDemGen Logo  1.00.0
$projectbrief
$projectbrief
$searchbox

trademgen_generateDemand.cpp

Go to the documentation of this file.
00001 // //////////////////////////////////////////////////////////////////////
00002 // Import section
00003 // //////////////////////////////////////////////////////////////////////
00004 // STL
00005 #include <cassert>
00006 #include <sstream>
00007 #include <fstream>
00008 #include <vector>
00009 #include <list>
00010 #include <string>
00011 //  //// Boost (Extended STL) ////
00012 // Boost Tokeniser
00013 #include <boost/tokenizer.hpp>
00014 // Boost Program Options
00015 #include <boost/program_options.hpp>
00016 // Boost Accumulators
00017 #include <boost/accumulators/accumulators.hpp>
00018 #include <boost/accumulators/statistics.hpp>
00019 // Boost Progress
00020 //#include <boost/progress.hpp>
00021 // StdAir
00022 #include <stdair/stdair_basic_types.hpp>
00023 #include <stdair/basic/BasConst_General.hpp>
00024 #include <stdair/basic/ProgressStatusSet.hpp>
00025 #include <stdair/basic/DemandGenerationMethod.hpp>
00026 #include <stdair/bom/EventStruct.hpp>
00027 #include <stdair/bom/BookingRequestStruct.hpp>
00028 #include <stdair/bom/BomDisplay.hpp>
00029 #include <stdair/service/Logger.hpp>
00030 // TraDemGen
00031 #include <trademgen/TRADEMGEN_Service.hpp>
00032 #include <trademgen/config/trademgen-paths.hpp>
00033 
00034 // Aliases for namespaces
00035 namespace ba = boost::accumulators;
00036 
00037 // //////// Specific type definitions ///////
00038 typedef unsigned int NbOfRuns_T;
00039 
00043 typedef ba::accumulator_set<double,
00044                             ba::stats<ba::tag::min, ba::tag::max,
00045                                       ba::tag::mean (ba::immediate),
00046                                       ba::tag::sum,
00047                                       ba::tag::variance> > stat_acc_type;
00048 
00049 // //////// Constants //////
00053 const stdair::Filename_T K_TRADEMGEN_DEFAULT_LOG_FILENAME ("trademgen_generateDemand.log");
00054 
00058 const stdair::Filename_T K_TRADEMGEN_DEFAULT_INPUT_FILENAME (STDAIR_SAMPLE_DIR
00059                                                              "/demand01.csv");
00060 
00064 const stdair::Filename_T K_TRADEMGEN_DEFAULT_OUTPUT_FILENAME ("request.csv");
00065 
00069 const stdair::DemandGenerationMethod
00070 K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD =
00071   stdair::DemandGenerationMethod::POI_PRO;
00072 
00076 const char K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD_CHAR =
00077   K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD.getMethodAsChar();
00078 
00082 const stdair::RandomSeed_T K_TRADEMGEN_DEFAULT_RANDOM_SEED =
00083   stdair::DEFAULT_RANDOM_SEED;
00084 
00088 const NbOfRuns_T K_TRADEMGEN_DEFAULT_RANDOM_DRAWS = 1;
00089 
00094 const bool K_TRADEMGEN_DEFAULT_BUILT_IN_INPUT = false;
00095 
00099 const int K_TRADEMGEN_EARLY_RETURN_STATUS = 99;
00100 
00101 
00105 void stat_display (std::ostream& oStream, const stat_acc_type& iStatAcc) {
00106 
00107   // Store current formatting flags of the output stream
00108   std::ios::fmtflags oldFlags = oStream.flags();
00109 
00110   //
00111   oStream.setf (std::ios::fixed);
00112   
00113   //
00114   oStream << "Statistics for the demand generation runs: " << std::endl;
00115   oStream << "  minimum   = " << ba::min (iStatAcc) << std::endl;
00116   oStream << "  mean      = " << ba::mean (iStatAcc) << std::endl;
00117   oStream << "  maximum   = " << ba::max (iStatAcc) << std::endl;
00118   oStream << "  count     = " << ba::count (iStatAcc) << std::endl;
00119   oStream << "  variance  = " << ba::variance (iStatAcc) << std::endl;
00120   
00121   // Reset formatting flags of output stream
00122   oStream.flags (oldFlags);
00123 }
00124 
00125 // ///////// Parsing of Options & Configuration /////////
00126 // A helper function to simplify the main part.
00127 template<class T> std::ostream& operator<< (std::ostream& os,
00128                                             const std::vector<T>& v) {
00129   std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " ")); 
00130   return os;
00131 }
00132 
00136 int readConfiguration (int argc, char* argv[], bool& ioIsBuiltin,
00137                        stdair::RandomSeed_T& ioRandomSeed,
00138                        NbOfRuns_T& ioRandomRuns,
00139                        stdair::Filename_T& ioInputFilename,
00140                        stdair::Filename_T& ioOutputFilename,
00141                        stdair::Filename_T& ioLogFilename,
00142                        stdair::DemandGenerationMethod& ioDemandGenerationMethod) {
00143 
00144   // Demand generation method as a single char (e.g., 'P' or 'S').
00145   char lDemandGenerationMethodChar;
00146 
00147   // Default for the built-in input
00148   ioIsBuiltin = K_TRADEMGEN_DEFAULT_BUILT_IN_INPUT;
00149 
00150   // Declare a group of options that will be allowed only on command line
00151   boost::program_options::options_description generic ("Generic options");
00152   generic.add_options()
00153     ("prefix", "print installation prefix")
00154     ("version,v", "print version string")
00155     ("help,h", "produce help message");
00156     
00157   // Declare a group of options that will be allowed both on command
00158   // line and in config file
00159   boost::program_options::options_description config ("Configuration");
00160   config.add_options()
00161     ("builtin,b",
00162      "The sample BOM tree can be either built-in or parsed from an input file. That latter must then be given with the -i/--input option")
00163     ("seed,s",
00164      boost::program_options::value<stdair::RandomSeed_T>(&ioRandomSeed)->default_value(K_TRADEMGEN_DEFAULT_RANDOM_SEED),
00165      "Seed for the random generation")
00166     ("draws,d",
00167      boost::program_options::value<NbOfRuns_T>(&ioRandomRuns)->default_value(K_TRADEMGEN_DEFAULT_RANDOM_DRAWS), 
00168      "Number of runs for the demand generations")
00169     ("demandgeneration,G",
00170      boost::program_options::value< char >(&lDemandGenerationMethodChar)->default_value(K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD_CHAR),
00171      "Method used to generate the demand (i.e., the booking requests): Poisson Process (P) or Order Statistics (S)")
00172     ("input,i",
00173      boost::program_options::value< std::string >(&ioInputFilename)->default_value(K_TRADEMGEN_DEFAULT_INPUT_FILENAME),
00174      "(CSV) input file for the demand distributions")
00175     ("output,o",
00176      boost::program_options::value< std::string >(&ioOutputFilename)->default_value(K_TRADEMGEN_DEFAULT_OUTPUT_FILENAME),
00177      "(CSV) output file for the generated requests")
00178     ("log,l",
00179      boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_TRADEMGEN_DEFAULT_LOG_FILENAME),
00180      "Filepath for the logs")
00181     ;
00182 
00183   // Hidden options, will be allowed both on command line and
00184   // in config file, but will not be shown to the user.
00185   boost::program_options::options_description hidden ("Hidden options");
00186   hidden.add_options()
00187     ("copyright",
00188      boost::program_options::value< std::vector<std::string> >(),
00189      "Show the copyright (license)");
00190         
00191   boost::program_options::options_description cmdline_options;
00192   cmdline_options.add(generic).add(config).add(hidden);
00193 
00194   boost::program_options::options_description config_file_options;
00195   config_file_options.add(config).add(hidden);
00196 
00197   boost::program_options::options_description visible ("Allowed options");
00198   visible.add(generic).add(config);
00199         
00200   boost::program_options::positional_options_description p;
00201   p.add ("copyright", -1);
00202         
00203   boost::program_options::variables_map vm;
00204   boost::program_options::
00205     store (boost::program_options::command_line_parser (argc, argv).
00206            options (cmdline_options).positional(p).run(), vm);
00207 
00208   std::ifstream ifs ("trademgen.cfg");
00209   boost::program_options::store (parse_config_file (ifs, config_file_options),
00210                                  vm);
00211   boost::program_options::notify (vm);
00212     
00213   if (vm.count ("help")) {
00214     std::cout << visible << std::endl;
00215     return K_TRADEMGEN_EARLY_RETURN_STATUS;
00216   }
00217 
00218   if (vm.count ("version")) {
00219     std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
00220     return K_TRADEMGEN_EARLY_RETURN_STATUS;
00221   }
00222 
00223   if (vm.count ("prefix")) {
00224     std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
00225     return K_TRADEMGEN_EARLY_RETURN_STATUS;
00226   }
00227 
00228   if (vm.count ("builtin")) {
00229     ioIsBuiltin = true;
00230   }
00231   const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
00232   std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
00233 
00234   if (ioIsBuiltin == false) {
00235 
00236     // The BOM tree should be built from parsing a demand input file
00237     if (vm.count ("input")) {
00238       ioInputFilename = vm["input"].as< std::string >();
00239       std::cout << "Input filename is: " << ioInputFilename << std::endl;
00240 
00241     } else {
00242       // The built-in option is not selected. However, no demand input file
00243       // is specified
00244       std::cerr << "Either one among the -b/--builtin and -i/--input "
00245                 << "options must be specified" << std::endl;
00246     }
00247   }
00248 
00249   if (vm.count ("output")) {
00250     ioOutputFilename = vm["output"].as< std::string >();
00251     std::cout << "Output filename is: " << ioOutputFilename << std::endl;
00252   }
00253 
00254   if (vm.count ("log")) {
00255     ioLogFilename = vm["log"].as< std::string >();
00256     std::cout << "Log filename is: " << ioLogFilename << std::endl;
00257   }
00258 
00259   if (vm.count ("demandgeneration")) {
00260     ioDemandGenerationMethod =
00261       stdair::DemandGenerationMethod (lDemandGenerationMethodChar);
00262     std::cout << "Date-time request generation method is: "
00263               << ioDemandGenerationMethod.describe() << std::endl;
00264   }
00265 
00266   //
00267   std::cout << "The random generation seed is: " << ioRandomSeed << std::endl;
00268 
00269   //
00270   std::cout << "The number of runs is: " << ioRandomRuns << std::endl;
00271   
00272   return 0;
00273 }
00274 
00275 // /////////////////////////////////////////////////////////////////////////
00276 void generateDemand (TRADEMGEN::TRADEMGEN_Service& ioTrademgenService,
00277                      const stdair::Filename_T& iOutputFilename,
00278                      const NbOfRuns_T& iNbOfRuns,
00279                      const stdair::DemandGenerationMethod& iDemandGenerationMethod) {
00280 
00281   // Open and clean the .csv output file
00282   std::ofstream output;
00283   output.open (iOutputFilename.c_str());
00284   output.clear();
00285     
00286   // Initialise the statistics collector/accumulator
00287   stat_acc_type lStatAccumulator;
00288 
00289   // Retrieve the expected (mean value of the) number of events to be
00290   // generated
00291   const stdair::Count_T& lExpectedNbOfEventsToBeGenerated =
00292     ioTrademgenService.getExpectedTotalNumberOfRequestsToBeGenerated();
00293 
00294   // Initialise the (Boost) progress display object
00295   boost::progress_display lProgressDisplay (lExpectedNbOfEventsToBeGenerated
00296                                             * iNbOfRuns);
00297   
00298   for (NbOfRuns_T runIdx = 1; runIdx <= iNbOfRuns; ++runIdx) {
00299     // /////////////////////////////////////////////////////
00300     output << "Run number: " << runIdx << std::endl;
00301 
00306     const stdair::Count_T& lActualNbOfEventsToBeGenerated =
00307       ioTrademgenService.generateFirstRequests (iDemandGenerationMethod);
00308 
00309     // DEBUG
00310     STDAIR_LOG_DEBUG ("[" << runIdx << "] Expected: "
00311                       << lExpectedNbOfEventsToBeGenerated << ", actual: "
00312                       << lActualNbOfEventsToBeGenerated);
00313       
00321     while (ioTrademgenService.isQueueDone() == false) {
00322 
00323       // Extract the next event from the event queue
00324       stdair::EventStruct lEventStruct;
00325       stdair::ProgressStatusSet lProgressStatusSet =
00326         ioTrademgenService.popEvent (lEventStruct);
00327       
00328       // DEBUG
00329       // STDAIR_LOG_DEBUG ("[" << runIdx << "] Poped event: '"
00330       //                   << lEventStruct.describe() << "'.");
00331       
00332       // Extract the corresponding demand/booking request
00333       const stdair::BookingRequestStruct& lPoppedRequest =
00334         lEventStruct.getBookingRequest();
00335         
00336       // DEBUG
00337       STDAIR_LOG_DEBUG ("[" << runIdx << "] Poped booking request: '"
00338                         << lPoppedRequest.describe() << "'.");
00339     
00340       // Dump the request into the dedicated CSV file
00341       // stdair::BomDisplay::csvDisplay (output, lPoppedRequest);
00342         
00343       // Retrieve the corresponding demand stream key
00344       const stdair::DemandGeneratorKey_T& lDemandStreamKey =
00345         lPoppedRequest.getDemandGeneratorKey();
00346       
00347       // Assess whether more events should be generated for that demand stream
00348       const bool stillHavingRequestsToBeGenerated = ioTrademgenService.
00349         stillHavingRequestsToBeGenerated (lDemandStreamKey,
00350                                           lProgressStatusSet,
00351                                           iDemandGenerationMethod);
00352 
00353       // DEBUG
00354       STDAIR_LOG_DEBUG (lProgressStatusSet.describe());
00355       STDAIR_LOG_DEBUG ("=> [" << lDemandStreamKey << "] is now processed. "
00356                         << "Still generate events for that demand stream? "
00357                         << stillHavingRequestsToBeGenerated);
00358     
00359       // If there are still events to be generated for that demand stream,
00360       // generate and add them to the event queue
00361       if (stillHavingRequestsToBeGenerated == true) {
00362         
00363         stdair::BookingRequestPtr_T lNextRequest_ptr =
00364           ioTrademgenService.generateNextRequest (lDemandStreamKey,
00365                                                   iDemandGenerationMethod);
00366         
00367         assert (lNextRequest_ptr != NULL);
00368 
00369         // Sanity check
00370         const stdair::Duration_T lDuration =
00371           lNextRequest_ptr->getRequestDateTime()
00372           - lPoppedRequest.getRequestDateTime();
00373         if (lDuration.total_milliseconds() < 0) {
00374           STDAIR_LOG_ERROR ("[" << lDemandStreamKey
00375                             << "] The date-time of the generated event ("
00376                             << lNextRequest_ptr->getRequestDateTime()
00377                             << ") is lower than the date-time "
00378                             << "of the current event ("
00379                             << lPoppedRequest.getRequestDateTime() << ")");
00380           assert (false);
00381         }
00382 
00383         // DEBUG
00384         STDAIR_LOG_DEBUG ("[" << lDemandStreamKey << "] Added request: '"
00385                           << lNextRequest_ptr->describe()
00386                           << "'. Is queue done? "
00387                           << ioTrademgenService.isQueueDone());
00388       }
00389       // DEBUG
00390       STDAIR_LOG_DEBUG ("");
00391       
00392       // Update the progress display
00393       ++lProgressDisplay;
00394     }
00395 
00396     // Add the number of events to the statistics accumulator
00397     lStatAccumulator (lActualNbOfEventsToBeGenerated);
00398     
00399     // Reset the service (including the event queue) for the next run
00400     ioTrademgenService.reset();
00401   }
00402 
00403   // DEBUG
00404   STDAIR_LOG_DEBUG ("End of the demand generation. Following are some "
00405                     "statistics for the " << iNbOfRuns << " runs.");
00406   std::ostringstream oStatStr;
00407   stat_display (oStatStr, lStatAccumulator);
00408   STDAIR_LOG_DEBUG (oStatStr.str());
00409 
00410   // DEBUG
00411   const std::string& lBOMStr = ioTrademgenService.csvDisplay();
00412   STDAIR_LOG_DEBUG (lBOMStr);
00413 
00414   // Close the output file
00415   output.close();
00416 }
00417 
00418 
00419 // /////////////// M A I N /////////////////
00420 int main (int argc, char* argv[]) {
00421 
00422   // State whether the BOM tree should be built-in or parsed from an input file
00423   bool isBuiltin;
00424 
00425   // Random generation seed
00426   stdair::RandomSeed_T lRandomSeed;
00427 
00428   // Number of random draws to be generated (best if greater than 100)
00429   NbOfRuns_T lNbOfRuns;
00430     
00431   // Input file name
00432   stdair::Filename_T lInputFilename;
00433 
00434   // Output file name
00435   stdair::Filename_T lOutputFilename;
00436 
00437   // Output log File
00438   stdair::Filename_T lLogFilename;
00439   
00440   // Demand generation method.
00441   stdair::DemandGenerationMethod
00442     lDemandGenerationMethod (K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD);
00443 
00444   // Call the command-line option parser
00445   const int lOptionParserStatus = 
00446     readConfiguration (argc, argv, isBuiltin, lRandomSeed, lNbOfRuns,
00447                        lInputFilename, lOutputFilename, lLogFilename,
00448                        lDemandGenerationMethod);
00449 
00450   if (lOptionParserStatus == K_TRADEMGEN_EARLY_RETURN_STATUS) {
00451     return 0;
00452   }
00453 
00454   // Set the log parameters
00455   std::ofstream logOutputFile;
00456   // Open and clean the log outputfile
00457   logOutputFile.open (lLogFilename.c_str());
00458   logOutputFile.clear();
00459 
00460   // Set up the log parameters
00461   const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
00462 
00463   // Initialise the TraDemGen service object
00464   TRADEMGEN::TRADEMGEN_Service trademgenService (lLogParams, lRandomSeed);
00465 
00466   // Check wether or not a (CSV) input file should be read
00467   if (isBuiltin == true) {
00468     // Create a sample DemandStream object, and insert it within the BOM tree
00469     trademgenService.buildSampleBom();
00470 
00471   } else {
00472     // Create the DemandStream objects, and insert them within the BOM tree
00473     const TRADEMGEN::DemandFilePath lDemandFilePath (lInputFilename);
00474     trademgenService.parseAndLoad (lDemandFilePath);
00475   }  
00476 
00477   // Calculate the expected number of events to be generated.
00478   generateDemand (trademgenService, lOutputFilename, lNbOfRuns,
00479                   lDemandGenerationMethod);
00480 
00481   // Close the Log outputFile
00482   logOutputFile.close();
00483 
00484   /*
00485     \note: as that program is not intended to be run on a server in
00486     production, it is better not to catch the exceptions. When it
00487     happens (that an exception is throwned), that way we get the
00488     call stack.
00489   */
00490 
00491   return 0;
00492 }