TraDemGen Logo  0.2.2
C++ Simulated Travel Demand Generation Library
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Pages
DemandStream.cpp
Go to the documentation of this file.
1 // //////////////////////////////////////////////////////////////////////
2 // Import section
3 // //////////////////////////////////////////////////////////////////////
4 // STL
5 #include <cassert>
6 #include <sstream>
7 #include <cmath>
8 #include <iomanip>
9 // Boost
10 #include <boost/make_shared.hpp>
11 // StdAir
12 #include <stdair/basic/BasConst_General.hpp>
13 #include <stdair/basic/BasConst_Inventory.hpp>
14 #include <stdair/basic/BasConst_Request.hpp>
15 #include <stdair/bom/BookingRequestStruct.hpp>
16 #include <stdair/service/Logger.hpp>
17 // TraDemGen
20 
21 namespace TRADEMGEN {
22 
23  // ////////////////////////////////////////////////////////////////////
24  DemandStream::DemandStream()
25  : _key (stdair::DEFAULT_ORIGIN, stdair::DEFAULT_DESTINATION,
26  stdair::DEFAULT_DEPARTURE_DATE, stdair::DEFAULT_CABIN_CODE),
27  _parent (NULL),
28  _demandCharacteristics (ArrivalPatternCumulativeDistribution_T(),
35  0.0,
37  _posProMass (DEFAULT_POS_PROBALILITY_MASS),
38  _firstDateTimeRequest (true) {
39  assert (false);
40  }
41 
42  // ////////////////////////////////////////////////////////////////////
43  DemandStream::DemandStream (const DemandStream&)
44  : _key (stdair::DEFAULT_ORIGIN, stdair::DEFAULT_DESTINATION,
45  stdair::DEFAULT_DEPARTURE_DATE, stdair::DEFAULT_CABIN_CODE),
46  _parent (NULL),
47  _demandCharacteristics (ArrivalPatternCumulativeDistribution_T(),
54  0.0,
56  _posProMass (DEFAULT_POS_PROBALILITY_MASS),
57  _firstDateTimeRequest (true) {
58  assert (false);
59  }
60 
61  // ////////////////////////////////////////////////////////////////////
62  DemandStream::DemandStream (const Key_T& iKey) :
63  _key (iKey) {
64  }
65 
66  // ////////////////////////////////////////////////////////////////////
68  }
69 
70  // ////////////////////////////////////////////////////////////////////
71  std::string DemandStream::toString() const {
72  std::ostringstream oStr;
73  oStr << _key.toString();
74  return oStr.str();
75  }
76 
77  // ////////////////////////////////////////////////////////////////////
78  void DemandStream::
80  const POSProbabilityMassFunction_T& iPOSProbMass,
81  const ChannelProbabilityMassFunction_T& iChannelProbMass,
82  const TripTypeProbabilityMassFunction_T& iTripTypeProbMass,
83  const StayDurationProbabilityMassFunction_T& iStayDurationProbMass,
84  const FrequentFlyerProbabilityMassFunction_T& iFrequentFlyerProbMass,
85  const PreferredDepartureTimeContinuousDistribution_T& iPreferredDepartureTimeContinuousDistribution,
86  const stdair::WTP_T& iMinWTP,
87  const ValueOfTimeContinuousDistribution_T& iValueOfTimeContinuousDistribution,
88  const DemandDistribution& iDemandDistribution,
89  stdair::BaseGenerator_T& ioSharedGenerator,
90  const stdair::RandomSeed_T& iRequestDateTimeSeed,
91  const stdair::RandomSeed_T& iDemandCharacteristicsSeed,
92  const POSProbabilityMass_T& iDefaultPOSProbablityMass) {
93 
94  setDemandCharacteristics (iArrivalPattern, iPOSProbMass,
95  iChannelProbMass, iTripTypeProbMass,
96  iStayDurationProbMass, iFrequentFlyerProbMass,
97  iPreferredDepartureTimeContinuousDistribution,
98  iMinWTP, iValueOfTimeContinuousDistribution);
99 
100  setDemandDistribution (iDemandDistribution);
102  setRequestDateTimeRandomGeneratorSeed (iRequestDateTimeSeed);
103  setDemandCharacteristicsRandomGeneratorSeed (iDemandCharacteristicsSeed);
104  setPOSProbabilityMass (iDefaultPOSProbablityMass);
105 
106  //
107  init (ioSharedGenerator);
108  }
109 
110  // ////////////////////////////////////////////////////////////////////
111  std::string DemandStream::display() const {
112  std::ostringstream oStr;
113 
114  oStr << "Demand stream key: " << _key.toString() << std::endl;
115 
116  //
118 
119  //
120  oStr << _demandDistribution.describe() << " => "
121  << _totalNumberOfRequestsToBeGenerated << " to be generated"
122  << std::endl;
123 
124  //
125  oStr << "Random generation context: " << _randomGenerationContext
126  << std::endl;
127 
128  //
129  oStr << "Random generator for date-time: "
130  << _requestDateTimeRandomGenerator << std::endl;
131  oStr << "Random generator for demand characteristics: "
133 
134  //
135  oStr << _posProMass.displayProbabilityMass() << std::endl;
136 
137  return oStr.str();
138  }
139 
140  // ////////////////////////////////////////////////////////////////////
141  void DemandStream::init (stdair::BaseGenerator_T& ioSharedGenerator) {
142 
143  // Generate the number of requests
144  const stdair::RealNumber_T lMu = _demandDistribution._meanNumberOfRequests;
145  const stdair::RealNumber_T lSigma =
147 
148  stdair::NormalDistribution_T lDistrib (lMu, lSigma);
149  stdair::NormalGenerator_T lNormalGen (ioSharedGenerator, lDistrib);
150 
151  const stdair::RealNumber_T lRealNumberOfRequestsToBeGenerated =lNormalGen();
152 
153  const stdair::NbOfRequests_T lIntegerNumberOfRequestsToBeGenerated =
154  std::floor (lRealNumberOfRequestsToBeGenerated + 0.5);
155 
156  _totalNumberOfRequestsToBeGenerated = lIntegerNumberOfRequestsToBeGenerated;
157 
158  _stillHavingRequestsToBeGenerated = true;
159  _firstDateTimeRequest = true;
160  }
161 
162  // ////////////////////////////////////////////////////////////////////
163  const bool DemandStream::
164  stillHavingRequestsToBeGenerated (const stdair::DemandGenerationMethod& iDemandGenerationMethod) const {
165 
166  const stdair::DemandGenerationMethod::EN_DemandGenerationMethod& lENDemandGenerationMethod =
167  iDemandGenerationMethod.getMethod();
168  if (lENDemandGenerationMethod == stdair::DemandGenerationMethod::STA_ORD) {
169  bool hasStillHavingRequestsToBeGenerated = true;
170 
171  // Check whether enough requests have already been generated
172  const stdair::Count_T lNbOfRequestsGeneratedSoFar =
174 
175  const stdair::Count_T lRemainingNumberOfRequestsToBeGenerated =
176  _totalNumberOfRequestsToBeGenerated - lNbOfRequestsGeneratedSoFar;
177 
178  if (lRemainingNumberOfRequestsToBeGenerated <= 0) {
179  hasStillHavingRequestsToBeGenerated = false;
180  }
181 
182  return hasStillHavingRequestsToBeGenerated;
183  } else {
184  return _stillHavingRequestsToBeGenerated;
185  }
186  }
187 
188  // ////////////////////////////////////////////////////////////////////
190 
191  // Prepare arrival pattern.
192  const ContinuousFloatDuration_T& lArrivalPattern =
194 
195  const stdair::Time_T lHardcodedReferenceDepartureTime =
196  boost::posix_time::hours (8);
197 
198  // Prepare departure date time.
199  const stdair::DateTime_T lDepartureDateTime =
200  boost::posix_time::ptime (_key.getPreferredDepartureDate(),
201  lHardcodedReferenceDepartureTime);
202 
203  // If no request has been generated so far...
204  if (_firstDateTimeRequest) {
205  const stdair::Probability_T lProbabilityFirstRequest = 0;
206 
207  // Get the lower bound of the arrival pattern (correponding
208  // to a cumulative probability of 0).
209  _dateTimeLastRequest =
210  lArrivalPattern.getValue (lProbabilityFirstRequest);
211 
212  _firstDateTimeRequest = false;
213  }
214 
215  // Sanity check.
216  assert (_firstDateTimeRequest == false);
217 
218  // If the date time of the last request is equal to the lower bound of
219  // the last daily rate interval (default value is -1, meaning one day
220  // before departure), we stopped generating request by returning a
221  // request date time after departure date time.
222  if (_dateTimeLastRequest == DEFAULT_LAST_LOWER_BOUND_ARRIVAL_PATTERN) {
223  _stillHavingRequestsToBeGenerated = false;
224 
225  // Get a positive number of days.
226  const stdair::Duration_T lDifferenceBetweenDepartureAndThisLowerBound =
228 
229  // Calculate a request date-time after the departure date time to end
230  // the demand generation algorithm.
231  const stdair::DateTime_T oDateTimeThisRequest =
232  lDepartureDateTime + lDifferenceBetweenDepartureAndThisLowerBound;
233 
234  return oDateTimeThisRequest;
235  }
236 
237  // Get the upper bound of the current daily rate interval.
238  stdair::FloatDuration_T lUpperBound =
239  lArrivalPattern.getUpperBound (_dateTimeLastRequest);
240 
241  // Compute the daily rate demand.
242  double lDailyRate =lArrivalPattern.getDerivativeValue(_dateTimeLastRequest);
243  // Get the expected average number of requests.
244  const double lDemandMean = _demandDistribution._meanNumberOfRequests;
245  // Multiply the daily rate by the expected average number of requests.
246  lDailyRate *= lDemandMean;
247 
248  // Generate an exponential variable.
249  const stdair::FloatDuration_T lExponentialVariable =
250  _requestDateTimeRandomGenerator.generateExponential (lDailyRate);
251 
252  // Compute the new date time request.
253  const stdair::FloatDuration_T lDateTimeThisRequest =
254  _dateTimeLastRequest + lExponentialVariable;
255 
256  stdair::DateTime_T oDateTimeThisRequest;
257 
258  // Verify if this request is in the given daily rate interval.
259  if (lDateTimeThisRequest < lUpperBound) {
260 
261  // Conversion.
262  const stdair::Duration_T lDifferenceBetweenDepartureAndThisRequest =
263  convertFloatIntoDuration (lDateTimeThisRequest);
264 
265  // The request date-time is derived from departure date and arrival pattern.
266  oDateTimeThisRequest = lDepartureDateTime
267  + lDifferenceBetweenDepartureAndThisRequest;
268 
269  // Remember this date time request.
270  _dateTimeLastRequest = lDateTimeThisRequest;
271 
272  // Update the counter of requests generated so far.
274 
275  const double lRefDateTimeThisRequest = lDateTimeThisRequest + double(28800.001/86400.0);
276  STDAIR_LOG_NOTIFICATION (boost::gregorian::to_iso_string(_key.getPreferredDepartureDate()) << ";" << std::setprecision(10) << lRefDateTimeThisRequest);
277  } else {
278 
279  // The current request is not in the given daily rate interval.
280  // Change the daily rate.
281  _dateTimeLastRequest = lUpperBound;
282 
283  // Generate a date time request in the new daily rate interval.
284  oDateTimeThisRequest = generateTimeOfRequestPoissonProcess ();
285  }
286 
287  return oDateTimeThisRequest;
288  }
289 
290  // ////////////////////////////////////////////////////////////////////
292 
309  //
310  // Calculate the result of the formula above step by step.
311  //
312 
313  // 1) Get the number of requests generated so far.
314  // (equal to k - 1)
315  const stdair::Count_T& lNbOfRequestsGeneratedSoFar =
317 
318  // 2) Deduce the number of requests not generated yet.
319  // (equal to n - k + 1)
320  const stdair::Count_T lRemainingNumberOfRequestsToBeGenerated =
321  _totalNumberOfRequestsToBeGenerated - lNbOfRequestsGeneratedSoFar;
322 
323  // Assert that there are still requests to be generated.
324  assert (lRemainingNumberOfRequestsToBeGenerated > 0);
325 
326  // 3) Inverse the number of requests not generated yet.
327  // 1/(n - k + 1)
328  const double lRemainingRate =
329  1.0 / static_cast<double> (lRemainingNumberOfRequestsToBeGenerated);
330 
331  // 4) Get the cumulative probality so far and take its complement.
332  // (equal to 1 - x(k-1))
333  const stdair::Probability_T& lCumulativeProbabilitySoFar =
335  const stdair::Probability_T lComplementOfCumulativeProbabilitySoFar =
336  1.0 - lCumulativeProbabilitySoFar;
337 
338  // 5) Draw a random variable y and calculate the factor equal to
339  // (1 - y)^(1/(n - k + 1)).
340  const stdair::Probability_T& lVariate = _requestDateTimeRandomGenerator();
341  double lFactor = std::pow (1.0 - lVariate, lRemainingRate);
342  if (lFactor >= 1.0 - 1e-6){
343  lFactor = 1.0 - 1e-6;
344  }
345 
346  // 6) Apply the whole formula above to calculate the cumulative probability
347  // of the new request.
348  // (equal to 1 - (1 - x(k-1))(1 - y)^(1/(n - k + 1)))
349  const stdair::Probability_T lCumulativeProbabilityThisRequest =
350  1.0 - lComplementOfCumulativeProbabilitySoFar * lFactor;
351 
352  // Now that the cumulative proportion of events generated has been
353  // calculated, we deduce from the arrival pattern the arrival time of the
354  // k-th event.
355  const stdair::FloatDuration_T lNumberOfDaysBetweenDepartureAndThisRequest =
356  _demandCharacteristics._arrivalPattern.getValue (lCumulativeProbabilityThisRequest);
357 
358  const stdair::Duration_T lDifferenceBetweenDepartureAndThisRequest =
359  convertFloatIntoDuration (lNumberOfDaysBetweenDepartureAndThisRequest);
360 
361  const stdair::Time_T lHardcodedReferenceDepartureTime =
362  boost::posix_time::hours (8);
363 
364  const stdair::DateTime_T lDepartureDateTime =
365  boost::posix_time::ptime (_key.getPreferredDepartureDate(),
366  lHardcodedReferenceDepartureTime);
367 
368  // The request date-time is derived from departure date and arrival pattern.
369  const stdair::DateTime_T oDateTimeThisRequest =
370  lDepartureDateTime + lDifferenceBetweenDepartureAndThisRequest;
371 
372  // Update random generation context
373  _randomGenerationContext.setCumulativeProbabilitySoFar (lCumulativeProbabilityThisRequest);
374 
375  // Update the counter of requests generated so far.
377 
378  // DEBUG
379  // STDAIR_LOG_DEBUG (lCumulativeProbabilityThisRequest << "; "
380  // << lNumberOfDaysBetweenDepartureAndThisRequest);
381 
382  // NOTIFICATION
383  double lRefNumberOfDaysBetweenDepartureAndThisRequest =
384  lNumberOfDaysBetweenDepartureAndThisRequest + double(1.0/3.0);
385  STDAIR_LOG_NOTIFICATION (boost::gregorian::to_iso_string(_key.getPreferredDepartureDate()) << ";" << std::setprecision(10) << lRefNumberOfDaysBetweenDepartureAndThisRequest);
386 
387  return oDateTimeThisRequest;
388  }
389 
390  // ////////////////////////////////////////////////////////////////////
391 
392  const stdair::Duration_T DemandStream::
393  convertFloatIntoDuration (const stdair::FloatDuration_T iNumberOfDays) {
394 
395  // Convert the number of days in number of seconds + number of milliseconds
396  const stdair::FloatDuration_T lNumberOfSeconds =
397  iNumberOfDays * stdair::SECONDS_IN_ONE_DAY;
398 
399  // Get the number of seconds.
400  const stdair::IntDuration_T lIntNumberOfSeconds =
401  std::floor (lNumberOfSeconds);
402 
403  // Get the number of milliseconds.
404  const stdair::FloatDuration_T lNumberOfMilliseconds =
405  (lNumberOfSeconds - lIntNumberOfSeconds)
406  * stdair::MILLISECONDS_IN_ONE_SECOND;
407 
408  // +1 is a trick to ensure that the next Event is strictly later
409  // than the current one
410  const stdair::IntDuration_T lIntNumberOfMilliseconds =
411  std::floor (lNumberOfMilliseconds) + 1;
412 
413  // Convert the number of seconds and milliseconds into a duration.
414  const stdair::Duration_T lDifferenceBetweenDepartureAndThisRequest =
415  boost::posix_time::seconds (lIntNumberOfSeconds)
416  + boost::posix_time::millisec (lIntNumberOfMilliseconds);
417 
418  return lDifferenceBetweenDepartureAndThisRequest;
419  }
420 
421  // ////////////////////////////////////////////////////////////////////
422  const stdair::AirportCode_T DemandStream::generatePOS() {
423 
424  // Generate a random number between 0 and 1.
425  const stdair::Probability_T& lVariate = _demandCharacteristicsRandomGenerator();
426  const stdair::AirportCode_T& oPOS = _demandCharacteristics.getPOSValue (lVariate);
427 
428  return oPOS;
429  }
430 
431  // ////////////////////////////////////////////////////////////////////
432  const stdair::ChannelLabel_T DemandStream::generateChannel() {
433  // Generate a random number between 0 and 1.
434  const stdair::Probability_T lVariate =
436 
438  }
439 
440  // ////////////////////////////////////////////////////////////////////
441  const stdair::TripType_T DemandStream::generateTripType() {
442  // Generate a random number between 0 and 1.
443  const stdair::Probability_T lVariate =
445 
447  }
448 
449  // ////////////////////////////////////////////////////////////////////
450  const stdair::DayDuration_T DemandStream::generateStayDuration() {
451  // Generate a random number between 0 and 1.
452  const stdair::Probability_T lVariate =
454 
456  }
457 
458  // ////////////////////////////////////////////////////////////////////
459  const stdair::FrequentFlyer_T DemandStream::generateFrequentFlyer() {
460  // Generate a random number between 0 and 1.
461  const stdair::Probability_T lVariate =
463 
465  }
466 
467  // ////////////////////////////////////////////////////////////////////
468  const stdair::Duration_T DemandStream::generatePreferredDepartureTime() {
469  // Generate a random number between 0 and 1.
470  const stdair::Probability_T lVariate =
472  const stdair::IntDuration_T lNbOfSeconds = _demandCharacteristics.
473  _preferredDepartureTimeCumulativeDistribution.getValue (lVariate);
474 
475  const stdair::Duration_T oTime = boost::posix_time::seconds (lNbOfSeconds);
476 
477  return oTime;
478  }
479 
480  // ////////////////////////////////////////////////////////////////////
481  const stdair::WTP_T DemandStream::
482  generateWTP (stdair::RandomGeneration& ioGenerator,
483  const stdair::Date_T& iDepartureDate,
484  const stdair::DateTime_T& iDateTimeThisRequest,
485  const stdair::DayDuration_T& iDurationOfStay) {
486  const stdair::Date_T lDateThisRequest = iDateTimeThisRequest.date();
487  const stdair::DateOffset_T lAP = iDepartureDate - lDateThisRequest;
488  const stdair::DayDuration_T lAPInDays = lAP.days();
489 
490  stdair::RealNumber_T lProb = -lAPInDays;
491  //1 - lAPInDays / DEFAULT_MAX_ADVANCE_PURCHASE;
492  if (lProb < 0.0) { lProb = 0.0; }
493  stdair::RealNumber_T lFrat5Coef =
495 
496  const stdair::WTP_T lWTP = _demandCharacteristics._minWTP
497  * (1.0 + (lFrat5Coef - 1.0) * log(ioGenerator()) / log(0.5));
498 
499  return lWTP;
500  }
501 
502  // ////////////////////////////////////////////////////////////////////
503  const stdair::PriceValue_T DemandStream::generateValueOfTime() {
504  // Generate a random number between 0 and 1.
505  const stdair::Probability_T lVariate =
507 
509  }
510 
511  // ////////////////////////////////////////////////////////////////////
512  stdair::BookingRequestPtr_T DemandStream::
513  generateNextRequest (stdair::RandomGeneration& ioGenerator,
514  const stdair::DemandGenerationMethod& iDemandGenerationMethod) {
515 
516  // Origin
517  const stdair::AirportCode_T& lOrigin = _key.getOrigin();
518  // Destination
519  const stdair::AirportCode_T& lDestination = _key.getDestination();
520  // Preferred departure date
521  const stdair::Date_T& lPreferredDepartureDate =
523  // Preferred cabin
524  const stdair::CabinCode_T& lPreferredCabin = _key.getPreferredCabin();
525  // Party size
526  const stdair::NbOfSeats_T lPartySize = stdair::DEFAULT_PARTY_SIZE;
527  // POS
528  const stdair::AirportCode_T lPOS = generatePOS();
529 
530  // Compute the request date time with the correct algorithm.
531  stdair::DateTime_T lDateTimeThisRequest;
532  const stdair::DemandGenerationMethod::EN_DemandGenerationMethod& lENDemandGenerationMethod =
533  iDemandGenerationMethod.getMethod();
534  switch(lENDemandGenerationMethod) {
535  case stdair::DemandGenerationMethod::POI_PRO:
536  lDateTimeThisRequest = generateTimeOfRequestPoissonProcess(); break;
537  case stdair::DemandGenerationMethod::STA_ORD:
538  lDateTimeThisRequest = generateTimeOfRequestStatisticsOrder(); break;
539  default: assert (false); break;
540  }
541 
542  // Booking channel.
543  const stdair::ChannelLabel_T lChannelLabel = generateChannel();
544  // Trip type.
545  const stdair::TripType_T lTripType = generateTripType();
546  // Stay duration.
547  const stdair::DayDuration_T lStayDuration = generateStayDuration();
548  // Frequet flyer type.
549  const stdair::FrequentFlyer_T lFrequentFlyer = generateFrequentFlyer();
550  // Preferred departure time.
551  const stdair::Duration_T lPreferredDepartureTime =
553  // Value of time
554  const stdair::PriceValue_T lValueOfTime = generateValueOfTime();
555  // WTP
556  const stdair::WTP_T lWTP = generateWTP (ioGenerator,lPreferredDepartureDate,
557  lDateTimeThisRequest,lStayDuration);
558 
559  // TODO 1: understand why the following form does not work, knowing
560  // that:
561  // typedef boost::shared_ptr<stdair::BookingRequestStruct> stdair::BookingRequestPtr_T
562  // stdair::BookingRequestPtr_T oBookingRequest_ptr =
563  // boost::make_shared<stdair::BookingRequestStruct> ();
564 
565 
566  // TODO 2: move the creation of the structure out of the BOM layer
567  // (into the command layer, e.g., within the DemandManager command).
568 
569  // Create the booking request
570  stdair::BookingRequestPtr_T oBookingRequest_ptr =
571  stdair::BookingRequestPtr_T
572  (new stdair::BookingRequestStruct (describeKey(), lOrigin,
573  lDestination, lPOS,
574  lPreferredDepartureDate,
575  lDateTimeThisRequest,
576  lPreferredCabin, lPartySize,
577  lChannelLabel, lTripType,
578  lStayDuration, lFrequentFlyer,
579  lPreferredDepartureTime,
580  lWTP, lValueOfTime));
581 
582  // DEBUG
583  // STDAIR_LOG_DEBUG ("\n[BKG] " << oBookingRequest_ptr->describe());
584 
585  return oBookingRequest_ptr;
586  }
587 
588  // ////////////////////////////////////////////////////////////////////
589  void DemandStream::reset (stdair::BaseGenerator_T& ioSharedGenerator) {
591  init (ioSharedGenerator);
592  }
593 
594 }