$treeview $search $mathjax
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 }