RMOL Logo  0.25.3
C++ library of Revenue Management and Optimisation classes and functions
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros Pages
Forecaster.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 // StdAir
9 #include <stdair/basic/BasConst_General.hpp>
10 #include <stdair/basic/BasConst_Inventory.hpp>
11 #include <stdair/basic/RandomGeneration.hpp>
12 #include <stdair/bom/BomManager.hpp>
13 #include <stdair/bom/FlightDate.hpp>
14 #include <stdair/bom/LegDate.hpp>
15 #include <stdair/bom/SegmentDate.hpp>
16 #include <stdair/bom/LegCabin.hpp>
17 #include <stdair/bom/SegmentCabin.hpp>
18 #include <stdair/bom/GuillotineBlock.hpp>
19 #include <stdair/bom/BookingClass.hpp>
20 #include <stdair/service/Logger.hpp>
21 // RMOL
23 #include <rmol/bom/Utilities.hpp>
30 
31 namespace RMOL {
32 
33  // ////////////////////////////////////////////////////////////////////
34  bool Forecaster::
35  forecastUsingAdditivePickUp (stdair::FlightDate& ioFlightDate,
36  const stdair::DateTime_T& iEventTime) {
37  // Build the offset dates.
38  const stdair::Date_T& lEventDate = iEventTime.date();
39  stdair::Date_T lRefDate (2012, boost::gregorian::Jan, 01);
40 
41  //
42  bool isSucceeded = true;
43  const stdair::SegmentDateList_T& lSDList =
44  stdair::BomManager::getList<stdair::SegmentDate> (ioFlightDate);
45  for (stdair::SegmentDateList_T::const_iterator itSD = lSDList.begin();
46  itSD != lSDList.end(); ++itSD) {
47  stdair::SegmentDate* lSD_ptr = *itSD;
48  assert (lSD_ptr != NULL);
49 
50  const stdair::Date_T& lBoardingDate = lSD_ptr->getBoardingDate();
51  const stdair::DateOffset_T lSegmentDateOffset =
52  lBoardingDate - lEventDate;
53  const stdair::DTD_T lSegmentDTD = lSegmentDateOffset.days();
54 
55  // Build remaining DCP's for the segment-date.
56  // TODO: treat the case where the segment departure is not the
57  // same as the flight-date departure.
58  stdair::DCPList_T lDCPList;
59 
60  if (lEventDate < lRefDate) {
61  lDCPList = Utilities::buildRemainingDCPList (lSegmentDTD);
62  } else {
63  lDCPList = Utilities::buildRemainingDCPList2 (lSegmentDTD);
64  }
65 
66  //
67  const stdair::SegmentCabinList_T& lSCList =
68  stdair::BomManager::getList<stdair::SegmentCabin> (*lSD_ptr);
69  for (stdair::SegmentCabinList_T::const_iterator itSC = lSCList.begin();
70  itSC != lSCList.end(); ++itSC) {
71  stdair::SegmentCabin* lSC_ptr = *itSC;
72  assert (lSC_ptr != NULL);
73 
74  //
75  // STDAIR_LOG_NOTIFICATION (ioFlightDate.getDepartureDate()
76  // << ";" << lSegmentDTD);
77  bool isForecasted = forecastUsingAdditivePickUp (*lSC_ptr, lDCPList,
78  lEventDate);
79  if (isForecasted == false) {
80  isSucceeded = false;
81  }
82  }
83  }
84 
85  return isSucceeded;
86  }
87 
88  // ////////////////////////////////////////////////////////////////////
89  bool Forecaster::
90  forecastUsingAdditivePickUp (stdair::SegmentCabin& ioSegmentCabin,
91  const stdair::DCPList_T& iDCPList,
92  const stdair::Date_T& iEventDate) {
93  // Retrieve the number of departed similar segments.
94  stdair::NbOfSegments_T lNbOfDepartedSegments =
95  Utilities::getNbOfDepartedSimilarSegments (ioSegmentCabin, iEventDate);
96  // TODO
97  if (lNbOfDepartedSegments > 52) lNbOfDepartedSegments = 52;
98 
99  // DEBUG
100  STDAIR_LOG_DEBUG ("Nb of similar departed segments: "
101  << lNbOfDepartedSegments);
102 
103  // If the DCP list includes only DTD0 or the number of departed
104  // segments are less than two, remaining demand for all classes
105  // will be set to zero.
106  stdair::DCPList_T::const_iterator itDCP = iDCPList.begin();
107  assert (itDCP != iDCPList.end());
108  const stdair::DCP_T& lCurrentDTD = *itDCP;
109  if (iDCPList.size() == 1 || lNbOfDepartedSegments < 2) {
110  setRemainingDemandForecastToZero (ioSegmentCabin);
111  return false;
112  } else {
113  // Initialise a holder for the unconstrained demand.
114  UnconstrainedDemandVector_T lQEquivalentDemandVector (lNbOfDepartedSegments, 0.0);
116  const stdair::BookingClassList_T& lBCList =
117  stdair::BomManager::getList<stdair::BookingClass> (ioSegmentCabin);
118  for (stdair::BookingClassList_T::const_iterator itBC = lBCList.begin();
119  itBC != lBCList.end(); ++itBC) {
120  stdair::BookingClass* lBC_ptr = *itBC;
121  assert (lBC_ptr != NULL);
122  std::vector<stdair::NbOfRequests_T> lUncDemandVector (lNbOfDepartedSegments, 0.0);
123  bool insertionSucceeded = lBkgClassUncDemMap.insert
125  value_type (lBC_ptr, lUncDemandVector)).second;
126  assert (insertionSucceeded == true);
127  }
128 
129  // Build the DCP intervals and unconstrain censored booking figures for
130  // each interval.
131  stdair::DCPList_T::const_iterator itNextDCP = itDCP; ++itNextDCP;
132  for (; itNextDCP != iDCPList.end(); ++itDCP, ++itNextDCP) {
133  const stdair::DCP_T& lCurrentDCP = *itDCP;
134  const stdair::DCP_T& lNextDCP = *itNextDCP;
135 
136  // DEBUG
137  STDAIR_LOG_DEBUG ("Unconstrain demand for "
138  << ioSegmentCabin.describeKey()
139  << " and the DCP's " << lCurrentDCP << ", "
140  << lNextDCP);
142  lBkgClassUncDemMap,
143  lQEquivalentDemandVector,
144  lCurrentDCP-1, lNextDCP,
145  iEventDate);
146  STDAIR_LOG_DEBUG ("Detrucation successful");
147  }
148 
149  // Retrieve the FRAT5 coefficient and compute the sell-up coef.
150  FRAT5Curve_T::const_iterator itFRAT5 =
151  DEFAULT_CUMULATIVE_FRAT5_CURVE.lower_bound (lCurrentDTD);
152  assert (itFRAT5 != DEFAULT_CUMULATIVE_FRAT5_CURVE.end());
153  const double lFRAT5Coef = itFRAT5->second;
154  const double lSellUpCoef = -log(0.5) / (lFRAT5Coef - 1);
155 
156  forecastUsingAdditivePickUp (ioSegmentCabin, lBkgClassUncDemMap,
157  lQEquivalentDemandVector, lSellUpCoef);
158  return true;
159  }
160  }
161 
162  // ////////////////////////////////////////////////////////////////////
163  void Forecaster::
164  forecastUsingAdditivePickUp (stdair::SegmentCabin& ioSegmentCabin,
165  const BookingClassUnconstrainedDemandVectorMap_T& iClassUncDemMap,
166  const UnconstrainedDemandVector_T& iUncDemVector,
167  const double& iSellUpFactor) {
168  double lPriceOriMean; double lPriceOriStdDev;
169  Utilities::computeDistributionParameters (iUncDemVector, lPriceOriMean,
170  lPriceOriStdDev);
171 
172  // DEBUG
173  //STDAIR_LOG_NOTIFICATION (lPriceOriMean << ";" << lPriceOriStdDev);
174 
175  // Retrieve the classes from low to high and compute the distributions of
176  // product-oriented and price-oriented demand.
177  // Retrieve the lowest class.
178  const stdair::BookingClassList_T& lBCList =
179  stdair::BomManager::getList<stdair::BookingClass> (ioSegmentCabin);
180  stdair::BookingClassList_T::const_reverse_iterator itCurrentClass =
181  lBCList.rbegin();
182  assert (itCurrentClass != lBCList.rend());
183  stdair::BookingClassList_T::const_reverse_iterator itNextClass =
184  itCurrentClass;
185  ++itNextClass;
186  // If there is only one class in the cabin, the demand distribution of this
187  // class is equal to the price-oriented demand distribution of the cabin.
188  if (itNextClass == lBCList.rend()) {
189  stdair::BookingClass* lLowestBC_ptr = *itCurrentClass;
190  lLowestBC_ptr->setMean (lPriceOriMean);
191  lLowestBC_ptr->setStdDev (lPriceOriStdDev);
192  } else {
193  // Compute the demand for higher class using the formula
194  // Pro_sell_up_from_Q_to_F = e ^ ((y_F/y_Q - 1) * ln (0.5) / (FRAT5 - 1))
195  for (; itNextClass != lBCList.rend(); ++itCurrentClass, ++itNextClass) {
196  stdair::BookingClass* lCurrentBC_ptr = *itCurrentClass;
197  assert (lCurrentBC_ptr != NULL);
198  const stdair::Yield_T& lCurrentYield = lCurrentBC_ptr->getYield();
199  stdair::BookingClass* lNextBC_ptr = *itNextClass;
200  assert (lNextBC_ptr != NULL);
201  const stdair::Yield_T& lNextYield = lNextBC_ptr->getYield();
202 
203  // Compute the part of price-oriented demand distributed to the
204  // current class.
205  const double lSellUp =
206  exp ((1.0 - lNextYield/lCurrentYield) * iSellUpFactor);
207  const double lPriceOriDemMeanFrac = lPriceOriMean * (1.0 - lSellUp);
208  const double lPriceOriDemStdDevFrac = lPriceOriStdDev * (1.0 - lSellUp);
209 
210  // Compute the product-oriented demand distribution for the
211  // current class.
212  BookingClassUnconstrainedDemandVectorMap_T::const_iterator itBCUD =
213  iClassUncDemMap.find (lCurrentBC_ptr);
214  assert (itBCUD != iClassUncDemMap.end());
215  const UnconstrainedDemandVector_T& lDemandVector = itBCUD->second;
216  double lMean; double lStdDev;
217  Utilities::computeDistributionParameters(lDemandVector, lMean, lStdDev);
218 
219  // Compute the demand distribution for the current class;
220  lMean += lPriceOriDemMeanFrac;
221  lStdDev = sqrt (lStdDev * lStdDev +
222  lPriceOriDemStdDevFrac * lPriceOriDemStdDevFrac);
223  lCurrentBC_ptr->setMean (lMean);
224  lCurrentBC_ptr->setStdDev (lStdDev);
225 
226  // DEBUG
227  // STDAIR_LOG_NOTIFICATION ("Class " << lCurrentBC_ptr->describeKey()
228  // << ", mean = " << lMean
229  // << ", stddev = " << lStdDev);
230 
231  // Update the price-oriented demand
232  lPriceOriMean *= lSellUp;
233  lPriceOriStdDev *= lSellUp;
234  }
235 
236  // Compute the demand distribution for the highest class (which is the
237  // "current class")
238  stdair::BookingClass* lCurrentBC_ptr = *itCurrentClass;
239  assert (lCurrentBC_ptr != NULL);
240  BookingClassUnconstrainedDemandVectorMap_T::const_iterator itBCUD =
241  iClassUncDemMap.find (lCurrentBC_ptr);
242  assert (itBCUD != iClassUncDemMap.end());
243  const UnconstrainedDemandVector_T& lDemandVector = itBCUD->second;
244  double lMean; double lStdDev;
245  Utilities::computeDistributionParameters(lDemandVector, lMean, lStdDev);
246 
247  // Compute the demand distribution for the current class;
248  lMean += lPriceOriMean;
249  lStdDev = sqrt (lStdDev * lStdDev + lPriceOriStdDev * lPriceOriStdDev);
250  lCurrentBC_ptr->setMean (lMean);
251  lCurrentBC_ptr->setStdDev (lStdDev);
252 
253  // DEBUG
254  // STDAIR_LOG_NOTIFICATION ("Class " << lCurrentBC_ptr->describeKey()
255  // << ", mean = " << lMean
256  // << ", stddev = " << lStdDev);
257  }
258  }
259 
260  // ////////////////////////////////////////////////////////////////////
261  void Forecaster::
262  setRemainingDemandForecastToZero (const stdair::SegmentCabin& iSegmentCabin) {
263  // Set the demand forecast for all classes to zero.
264  const stdair::BookingClassList_T& lBCList =
265  stdair::BomManager::getList<stdair::BookingClass> (iSegmentCabin);
266  for (stdair::BookingClassList_T::const_iterator itBC = lBCList.begin();
267  itBC != lBCList.end(); ++itBC) {
268  stdair::BookingClass* lBC_ptr = *itBC;
269  assert (lBC_ptr != NULL);
270  lBC_ptr->setMean (0.0);
271  }
272  }
273 
274  // ////////////////////////////////////////////////////////////////////
275  bool Forecaster::
276  forecastUsingMultiplicativePickUp (stdair::FlightDate& ioFlightDate,
277  const stdair::DateTime_T& iEventTime) {
278  // Build the offset dates.
279  const stdair::Date_T& lEventDate = iEventTime.date();
280 
281  //
282  bool isSucceeded = true;
283  const stdair::SegmentDateList_T& lSDList =
284  stdair::BomManager::getList<stdair::SegmentDate> (ioFlightDate);
285  for (stdair::SegmentDateList_T::const_iterator itSD = lSDList.begin();
286  itSD != lSDList.end(); ++itSD) {
287  stdair::SegmentDate* lSD_ptr = *itSD;
288  assert (lSD_ptr != NULL);
289 
290  const stdair::Date_T& lBoardingDate = lSD_ptr->getBoardingDate();
291  const stdair::DateOffset_T lSegmentDateOffset =
292  lBoardingDate - lEventDate;
293  const stdair::DTD_T lSegmentDTD = lSegmentDateOffset.days();
294 
295  //
296  const stdair::SegmentCabinList_T& lSCList =
297  stdair::BomManager::getList<stdair::SegmentCabin> (*lSD_ptr);
298  for (stdair::SegmentCabinList_T::const_iterator itSC = lSCList.begin();
299  itSC != lSCList.end(); ++itSC) {
300  stdair::SegmentCabin* lSC_ptr = *itSC;
301  assert (lSC_ptr != NULL);
302 
303  bool isForecasted = forecastUsingMultiplicativePickUp (*lSC_ptr,
304  lEventDate,
305  lSegmentDTD);
306  if (isForecasted == false) {
307  isSucceeded = false;
308  }
309  }
310  }
311  return isSucceeded;
312  }
313 
314  // ////////////////////////////////////////////////////////////////////
315  bool Forecaster::
316  forecastUsingMultiplicativePickUp (stdair::SegmentCabin& ioSegmentCabin,
317  const stdair::Date_T& iEventDate,
318  const stdair::DTD_T& iSegmentDTD) {
319  // Retrieving the number of anterior similar segments.
320  const stdair::GuillotineBlock& lGuillotineBlock =
321  ioSegmentCabin.getGuillotineBlock();
322  stdair::NbOfSegments_T lNbOfAnteriorSimilarSegments =
324  getNbOfSegmentAlreadyPassedThisDTD (lGuillotineBlock, iSegmentDTD,
325  iEventDate) - 1;
326  // Retrieve the number of departed similar segments.
327  stdair::NbOfSegments_T lNbOfDepartedSegments =
328  Utilities::getNbOfDepartedSimilarSegments (ioSegmentCabin, iEventDate);
329  // TODO:
330  if (lNbOfDepartedSegments > 52) {
331  lNbOfAnteriorSimilarSegments =
332  lNbOfAnteriorSimilarSegments - lNbOfDepartedSegments + 52;
333  }
334 
335  // DEBUG
336  STDAIR_LOG_DEBUG ("Nb of anterior similar segments: "
337  << lNbOfAnteriorSimilarSegments);
338 
339  // If the iSegmentDTD is the last DCP or there is no anterior similar
340  // segment, remaining demand for all classes will be set to zero
341  stdair::DCPList_T::const_reverse_iterator itLastDCP =
342  stdair::DEFAULT_DCP_LIST.rbegin();
343  assert (itLastDCP != stdair::DEFAULT_DCP_LIST.rend());
344  const stdair::DCP_T& lLastDCP = *itLastDCP;
345  if (lNbOfAnteriorSimilarSegments < 1.0 || iSegmentDTD <= lLastDCP) {
346  setRemainingDemandForecastToZero (ioSegmentCabin);
347  return false;
348  } else {
349  // Retrieve the booking figures of the first DCP and consider them
350  // as unconstrained demand figures.
351  stdair::DCPList_T::const_iterator itDCP =stdair::DEFAULT_DCP_LIST.begin();
352  assert (itDCP != stdair::DEFAULT_DCP_LIST.end());
353  const stdair::DCP_T& lFirstDCP = *itDCP;
354 
355  // Initialise the unconstrained demand for classes.
356  stdair::NbOfSegments_T lNbOfUsableSegments =
358  getNbOfSegmentAlreadyPassedThisDTD (lGuillotineBlock, lFirstDCP,
359  iEventDate);
360  // TODO
361  unsigned short lSize = lNbOfUsableSegments;
362  if (lNbOfDepartedSegments > 52) {
363  lSize = lNbOfUsableSegments - lNbOfDepartedSegments + 52;
364  }
365 
366  STDAIR_LOG_DEBUG ("Nb of usable similar segments: "
367  << lNbOfUsableSegments);
368 
369  UnconstrainedDemandVector_T lQEquivalentDemandVector (lSize, 0.0);
370  stdair::NbOfBookings_T lCurrentSegmentQEquivalentDemand = 0.0;
371  BookingClassUnconstrainedDemandVectorMap_T lBkgClassUncDemVectorMap;
372  BookingClassUnconstrainedDemandMap_T lCurrentSegmentBkgClassDemMap;
373  const stdair::BookingClassList_T& lBCList =
374  stdair::BomManager::getList<stdair::BookingClass> (ioSegmentCabin);
375  for (stdair::BookingClassList_T::const_iterator itBC = lBCList.begin();
376  itBC != lBCList.end(); ++itBC) {
377  stdair::BookingClass* lBC_ptr = *itBC;
378  assert (lBC_ptr != NULL);
379 
380  UnconstrainedDemandVector_T lUncDemandVector (lSize, 0.0);
381  bool insertionSucceeded = lBkgClassUncDemVectorMap.
383  value_type (lBC_ptr, lUncDemandVector)).second;
384  assert (insertionSucceeded == true);
385  insertionSucceeded =
386  lCurrentSegmentBkgClassDemMap.
388  value_type (lBC_ptr, 0.0)).second;
389  assert (insertionSucceeded == true);
390  }
393  lBkgClassUncDemVectorMap,
394  lQEquivalentDemandVector,
395  lFirstDCP, lNbOfUsableSegments,
396  lSize);
397 
398  // Unconstrain the booking figures.
399  stdair::DCPList_T::const_iterator itNextDCP = itDCP; ++itNextDCP;
400  while (itNextDCP != stdair::DEFAULT_DCP_LIST.end()) {
401  const stdair::DCP_T& lCurrentDCP = *itDCP;
402  const stdair::DCP_T& lNextDCP = *itNextDCP;
403  if (lCurrentDCP <= iSegmentDTD) {
404  break;
405  }
408  lBkgClassUncDemVectorMap,
409  lQEquivalentDemandVector,
410  lCurrentDCP-1, lNextDCP,
411  iEventDate,
412  lNbOfDepartedSegments);
413  ++itNextDCP; ++itDCP;
414  }
415 
416  // Update the unconstrained demand for all the classes of the current
417  // segment.
418  lCurrentSegmentQEquivalentDemand =
419  lQEquivalentDemandVector.at (lNbOfAnteriorSimilarSegments);
420  BookingClassUnconstrainedDemandMap_T::iterator itBCUD =
421  lCurrentSegmentBkgClassDemMap.begin();
422  for (BookingClassUnconstrainedDemandVectorMap_T::iterator itBCUDV =
423  lBkgClassUncDemVectorMap.begin();
424  itBCUDV != lBkgClassUncDemVectorMap.end(); ++itBCUDV, ++itBCUD) {
425  assert (itBCUD != lCurrentSegmentBkgClassDemMap.end());
426  assert (itBCUD->first == itBCUDV->first);
427  stdair::NbOfRequests_T& lUncDem = itBCUD->second;
428  UnconstrainedDemandVector_T& lUncDemVector = itBCUDV->second;
429  lUncDem = lUncDemVector.at (lNbOfAnteriorSimilarSegments);
430  }
431 
432  // Forecast the remaining demand for all classes
433  const stdair::DCP_T& lCurrentDTD = *itDCP;
434  for (; itNextDCP != stdair::DEFAULT_DCP_LIST.end(); ++itNextDCP, ++itDCP){
435  const stdair::DCP_T& lCurrentDCP = *itDCP;
436  const stdair::DCP_T& lNextDCP = *itNextDCP;
437  forecastUsingMultiplicativePickUp (ioSegmentCabin,
438  lBkgClassUncDemVectorMap,
439  lQEquivalentDemandVector,
440  lCurrentDCP-1, lNextDCP, iEventDate,
441  lNbOfAnteriorSimilarSegments,
442  lNbOfDepartedSegments);
443  }
444 
445  // Update the remaining demand for all classes
446  lCurrentSegmentQEquivalentDemand =
447  lQEquivalentDemandVector.at (lNbOfAnteriorSimilarSegments)
448  - lCurrentSegmentQEquivalentDemand;
449  itBCUD = lCurrentSegmentBkgClassDemMap.begin();
450  for (BookingClassUnconstrainedDemandVectorMap_T::iterator itBCUDV =
451  lBkgClassUncDemVectorMap.begin();
452  itBCUDV != lBkgClassUncDemVectorMap.end(); ++itBCUDV, ++itBCUD) {
453  assert (itBCUD != lCurrentSegmentBkgClassDemMap.end());
454  assert (itBCUD->first == itBCUDV->first);
455  stdair::NbOfRequests_T& lUncDem = itBCUD->second;
456  UnconstrainedDemandVector_T& lUncDemVector = itBCUDV->second;
457  lUncDem = lUncDemVector.at (lNbOfAnteriorSimilarSegments) - lUncDem;
458  }
459 
460  // Retrieve the FRAT5 coefficient and compute the sell-up coef.
461  FRAT5Curve_T::const_iterator itFRAT5 =
462  DEFAULT_CUMULATIVE_FRAT5_CURVE.lower_bound (lCurrentDTD);
463  assert (itFRAT5 != DEFAULT_CUMULATIVE_FRAT5_CURVE.end());
464  const double lFRAT5Coef = itFRAT5->second;
465  const double lSellUpCoef = -log(0.5) / (lFRAT5Coef - 1);
466 
467  return forecastUsingMultiplicativePickUp(ioSegmentCabin,
468  lCurrentSegmentBkgClassDemMap,
469  lCurrentSegmentQEquivalentDemand,
470  lSellUpCoef);
471 
472  }
473  }
474 
475  // ////////////////////////////////////////////////////////////////////
477  (const stdair::SegmentCabin& iSegmentCabin,
478  BookingClassUnconstrainedDemandVectorMap_T& ioBkgClassUncDemMap,
479  UnconstrainedDemandVector_T& ioQEquivalentDemandVector,
480  const stdair::DCP_T& iDCPBegin, const stdair::DCP_T& iDCPEnd,
481  const stdair::Date_T& iCurrentDate,
482  const stdair::NbOfSegments_T& iNbOfAnteriorSimilarSegments,
483  const stdair::NbOfSegments_T& iNbOfDepartedSegments) {
484 
485  // Retrieve the guillotine block.
486  const stdair::GuillotineBlock& lGuillotineBlock =
487  iSegmentCabin.getGuillotineBlock();
488 
489  // Build the historical booking holders for the product-oriented bookings
490  // of the casses and the Q-equivalent (price-oriented) bookings of the cabin
491  const stdair::NbOfSegments_T lNbOfUsableSegments = GuillotineBlockHelper::
492  getNbOfSegmentAlreadyPassedThisDTD (lGuillotineBlock, iDCPEnd,
493  iCurrentDate);
494 
495  STDAIR_LOG_DEBUG ("Nb of usable similar segments: "
496  << lNbOfUsableSegments);
497 
498  if (lNbOfUsableSegments > 0) {
499 
500  // Parse the booking class list and unconstrain historical bookings.
501  for (BookingClassUnconstrainedDemandVectorMap_T::iterator itBCUDV =
502  ioBkgClassUncDemMap.begin(); itBCUDV != ioBkgClassUncDemMap.end();
503  ++itBCUDV) {
504  stdair::BookingClass* lBC_ptr = itBCUDV->first;
505  assert (lBC_ptr != NULL);
506  const stdair::MapKey_T& lBCKey = lBC_ptr->describeKey();
507  const stdair::BlockIndex_T& lBlockIdx =
508  lGuillotineBlock.getBlockIndex (lBCKey);
509  UnconstrainedDemandVector_T& lUncDemVector = itBCUDV->second;
510 
511  STDAIR_LOG_DEBUG ("Unconstrain product-oriented bookings for "<<lBCKey);
512  forecastUsingMultiplicativePickUp (lGuillotineBlock, lUncDemVector,
513  iDCPBegin, iDCPEnd,
514  lNbOfUsableSegments, lBlockIdx,
515  iNbOfAnteriorSimilarSegments,
516  iNbOfDepartedSegments);
517  }
518 
519  // Unconstrain the Q-equivalent bookings.
520  // Retrieve the block index of the segment-cabin.
521  std::ostringstream lSCMapKey;
522  lSCMapKey << stdair::DEFAULT_SEGMENT_CABIN_VALUE_TYPE
523  << iSegmentCabin.describeKey();
524  const stdair::BlockIndex_T& lCabinIdx =
525  lGuillotineBlock.getBlockIndex (lSCMapKey.str());
526 
527  STDAIR_LOG_DEBUG ("Unconstrain price-oriented bookings");
528  forecastUsingMultiplicativePickUp (lGuillotineBlock,
529  ioQEquivalentDemandVector,
530  iDCPBegin, iDCPEnd,
531  lNbOfUsableSegments, lCabinIdx,
532  iNbOfAnteriorSimilarSegments,
533  iNbOfDepartedSegments,
534  iSegmentCabin, iCurrentDate);
535  }
536  }
537 
538  // ////////////////////////////////////////////////////////////////////
540  (const stdair::GuillotineBlock& iGuillotineBlock,
541  UnconstrainedDemandVector_T& ioUncDemVector,
542  const stdair::DCP_T& iDCPBegin, const stdair::DCP_T& iDCPEnd,
543  const stdair::NbOfSegments_T& iNbOfUsableSegments,
544  const stdair::BlockIndex_T& iBlockIdx,
545  const stdair::NbOfSegments_T& iNbOfAnteriorSimilarSegments,
546  const stdair::NbOfSegments_T& iNbOfDepartedSegments) {
547  // TODO
548  stdair::NbOfSegments_T lSegBegin = 0;
549  if (iNbOfDepartedSegments > 52) {
550  lSegBegin = iNbOfDepartedSegments - 52;
551  }
552  // Retrieve the gross daily booking and availability snapshots.
553  stdair::ConstSegmentCabinDTDRangeSnapshotView_T lBookingView =
554  iGuillotineBlock.getConstSegmentCabinDTDRangeProductAndPriceOrientedBookingSnapshotView (lSegBegin, iNbOfUsableSegments -1, iDCPEnd, iDCPBegin);
555  stdair::ConstSegmentCabinDTDRangeSnapshotView_T lAvlView =
556  iGuillotineBlock.getConstSegmentCabinDTDRangeAvailabilitySnapshotView (lSegBegin, iNbOfUsableSegments -1, iDCPEnd, iDCPBegin);
557 
558  // Browse the list of segments and build the historical booking holder.
559  const stdair::ValueTypeIndexMap_T& lVTIdxMap =
560  iGuillotineBlock.getValueTypeIndexMap();
561  const unsigned int lNbOfValueTypes = lVTIdxMap.size();
562  HistoricalBookingHolder lHBHolder;
563  std::vector<short> lDataIndexList;
564  for (short i = 0; i < iNbOfUsableSegments-lSegBegin; ++i) {
565  stdair::Flag_T lCensorshipFlag = false;
566  stdair::NbOfBookings_T lNbOfHistoricalBkgs = 0.0;
567  const short lNbOfDTDs = iDCPBegin - iDCPEnd + 1;
568 
569  // Parse the DTDs during the period
570  for (short j = 0; j < lNbOfDTDs; ++j) {
571  // Check if the data has been censored during this day.
572  // STDAIR_LOG_DEBUG ("i: " << i << ", NbOfValues: " << lNbOfValueTypes
573  // << ", BlockIdx: " << iBlockIdx << ", j: " << j);
574  if (lCensorshipFlag == false) {
575  if (lAvlView[i*lNbOfValueTypes + iBlockIdx][j] < 1.0) {
576  lCensorshipFlag = true;
577  }
578  }
579 
580  // Get the bookings of the day.
581  // STDAIR_LOG_DEBUG ("Bookings of the day: " << lBookingView[i*lNbOfValueTypes + iBlockIdx][j]);
582  lNbOfHistoricalBkgs += lBookingView[i*lNbOfValueTypes + iBlockIdx][j];
583  }
584 
585  // If there is no booking till now for this class and for this segment,
586  // there will be no unconstraining process.
587  stdair::NbOfRequests_T& lUncDemand = ioUncDemVector.at (i);
588  if (lUncDemand < 1.0) {
589  lUncDemand += lNbOfHistoricalBkgs;
590  } else {
591  double lBkgDemandFactor = lNbOfHistoricalBkgs / lUncDemand;
592  HistoricalBooking lHistoricalBkg (lBkgDemandFactor, lCensorshipFlag);
593  lHBHolder.addHistoricalBooking (lHistoricalBkg);
594  lDataIndexList.push_back (i);
595  }
596 
597  // DEBUG
598  STDAIR_LOG_DEBUG ("Historical bkgs: " << lNbOfHistoricalBkgs
599  << ", censored: " << lCensorshipFlag);
600  }
601 
602  // DEBUG
603  STDAIR_LOG_DEBUG ("Unconstrain by multiplicative pick-up using EM");
604 
605  // Unconstrain the booking figures
607 
608  // Update the unconstrained demand vector.
609  short i = 0;
610  for (std::vector<short>::iterator itIdx = lDataIndexList.begin();
611  itIdx != lDataIndexList.end(); ++itIdx, ++i) {
612  short lIdx = *itIdx;
613  stdair::NbOfRequests_T& lPastDemand = ioUncDemVector.at (lIdx);
614  const stdair::NbOfRequests_T& lUncDemandFactorOfThisPeriod =
615  lHBHolder.getUnconstrainedDemand (i);
616  lPastDemand *= (1+lUncDemandFactorOfThisPeriod);
617  }
618 
619  // Update the unconstrained demand for the current segment.
620  if (lHBHolder.getNbOfFlights() > 0) {
621  const stdair::NbOfRequests_T& lUncDemandFactorMean =
622  lHBHolder.getDemandMean();
623  stdair::NbOfRequests_T& lPastDemand =
624  ioUncDemVector.at (iNbOfAnteriorSimilarSegments);
625  lPastDemand *= (1+lUncDemandFactorMean);
626  }
627  }
628 
629  // ////////////////////////////////////////////////////////////////////
631  (const stdair::GuillotineBlock& iGuillotineBlock,
632  UnconstrainedDemandVector_T& ioUncDemVector,
633  const stdair::DCP_T& iDCPBegin, const stdair::DCP_T& iDCPEnd,
634  const stdair::NbOfSegments_T& iNbOfUsableSegments,
635  const stdair::BlockIndex_T& iBlockIdx,
636  const stdair::NbOfSegments_T& iNbOfAnteriorSimilarSegments,
637  const stdair::NbOfSegments_T& iNbOfDepartedSegments,
638  const stdair::SegmentCabin& iSegmentCabin,
639  const stdair::Date_T& iCurrentDate) {
640  // TODO
641  stdair::NbOfSegments_T lSegBegin = 0;
642  if (iNbOfDepartedSegments > 52) {
643  lSegBegin = iNbOfDepartedSegments - 52;
644  }
645  // Retrieve the gross daily booking and availability snapshots.
646  stdair::ConstSegmentCabinDTDRangeSnapshotView_T lBookingView =
647  iGuillotineBlock.getConstSegmentCabinDTDRangeProductAndPriceOrientedBookingSnapshotView (lSegBegin, iNbOfUsableSegments -1, iDCPEnd, iDCPBegin);
648  stdair::ConstSegmentCabinDTDRangeSnapshotView_T lAvlView =
649  iGuillotineBlock.getConstSegmentCabinDTDRangeAvailabilitySnapshotView (lSegBegin, iNbOfUsableSegments -1, iDCPEnd, iDCPBegin);
650 
651  // Browse the list of segments and build the historical booking holder.
652  const stdair::ValueTypeIndexMap_T& lVTIdxMap =
653  iGuillotineBlock.getValueTypeIndexMap();
654  const unsigned int lNbOfValueTypes = lVTIdxMap.size();
655  HistoricalBookingHolder lHBHolder;
656  std::vector<short> lDataIndexList;
657  for (short i = 0; i < iNbOfUsableSegments-lSegBegin; ++i) {
658  stdair::Flag_T lCensorshipFlag = false;
659  stdair::NbOfBookings_T lNbOfHistoricalBkgs = 0.0;
660  const short lNbOfDTDs = iDCPBegin - iDCPEnd + 1;
661 
662  // Parse the DTDs during the period
663  for (short j = 0; j < lNbOfDTDs; ++j) {
664  // Check if the data has been censored during this day.
665  // STDAIR_LOG_DEBUG ("i: " << i << ", NbOfValues: " << lNbOfValueTypes
666  // << ", BlockIdx: " << iBlockIdx << ", j: " << j);
667  if (lCensorshipFlag == false) {
668  if (lAvlView[i*lNbOfValueTypes + iBlockIdx][j] < 1.0) {
669  lCensorshipFlag = true;
670  }
671  }
672 
673  // Get the bookings of the day.
674  // STDAIR_LOG_DEBUG ("Bookings of the day: " << lBookingView[i*lNbOfValueTypes + iBlockIdx][j]);
675  lNbOfHistoricalBkgs += lBookingView[i*lNbOfValueTypes + iBlockIdx][j];
676  }
677 
678  // If there is no booking till now for this class and for this segment,
679  // there will be no unconstraining process.
680  stdair::NbOfRequests_T& lUncDemand = ioUncDemVector.at (i);
681  if (lUncDemand < 1.0) {
682  lUncDemand += lNbOfHistoricalBkgs;
683  } else {
684  double lBkgDemandFactor = lNbOfHistoricalBkgs / lUncDemand;
685  HistoricalBooking lHistoricalBkg (lBkgDemandFactor, lCensorshipFlag);
686  lHBHolder.addHistoricalBooking (lHistoricalBkg);
687  lDataIndexList.push_back (i);
688  }
689 
690  // DEBUG
691  STDAIR_LOG_DEBUG ("Historical bkgs: " << lNbOfHistoricalBkgs
692  << ", censored: " << lCensorshipFlag);
693  }
694 
695  // DEBUG
696  STDAIR_LOG_DEBUG ("Unconstrain by multiplicative pick-up using EM");
697 
698  // Unconstrain the booking figures
700 
701  // Update the unconstrained demand vector.
702  // LOG
703  const stdair::SegmentDate& lSegmentDate = stdair::BomManager::
704  getParent<stdair::SegmentDate, stdair::SegmentCabin> (iSegmentCabin);
705  const stdair::FlightDate& lFlightDate = stdair::BomManager::
706  getParent<stdair::FlightDate, stdair::SegmentDate> (lSegmentDate);
707  const stdair::Date_T& lDepDate = lFlightDate.getDepartureDate();
708  const boost::gregorian::date_duration lDD = lDepDate - iCurrentDate;
709  const long lDTD = lDD.days();
710  stdair::Date_T lRefDate (2012, boost::gregorian::Jan, 01);
711  short i = 0;
712  for (std::vector<short>::iterator itIdx = lDataIndexList.begin();
713  itIdx != lDataIndexList.end(); ++itIdx, ++i) {
714  short lIdx = *itIdx;
715  stdair::NbOfRequests_T& lPastDemand = ioUncDemVector.at (lIdx);
716  const stdair::NbOfRequests_T& lUncDemandFactorOfThisPeriod =
717  lHBHolder.getUnconstrainedDemand (i);
718  const double lUncDemThisPeriod =
719  lPastDemand * lUncDemandFactorOfThisPeriod;
720  const double lQEBkgThisPeriod =
721  lPastDemand * lHBHolder.getHistoricalBooking (i);
722  lPastDemand *= (1+lUncDemandFactorOfThisPeriod);
723  if (lDepDate > lRefDate) {
724  const stdair::DateOffset_T lDateOffset (7 *(52 - i) + 420);
725  const stdair::Date_T lHDate = lDepDate - lDateOffset;
726  STDAIR_LOG_NOTIFICATION (boost::gregorian::to_iso_string(lDepDate)
727  << ";" << lDTD << ";" << iDCPBegin << ";"
728  << iDCPEnd << ";"
729  << boost::gregorian::to_iso_string (lHDate)
730  << ";" << lUncDemThisPeriod);
731  STDAIR_LOG_NOTIFICATION (boost::gregorian::to_iso_string(lDepDate)
732  << ";" << lDTD << ";" << iDCPBegin << ";"
733  << iDCPEnd << ";"
734  << boost::gregorian::to_iso_string (lHDate)
735  << ";" << lQEBkgThisPeriod);
736  }
737  }
738 
739  // Update the unconstrained demand for the current segment.
740  if (lHBHolder.getNbOfFlights() > 0) {
741  const stdair::NbOfRequests_T& lUncDemandFactorMean =
742  lHBHolder.getDemandMean();
743  stdair::NbOfRequests_T& lPastDemand =
744  ioUncDemVector.at (iNbOfAnteriorSimilarSegments);
745  lPastDemand *= (1+lUncDemandFactorMean);
746  }
747  }
748 
749  // ////////////////////////////////////////////////////////////////////
750  bool Forecaster::
751  forecastUsingMultiplicativePickUp (stdair::SegmentCabin& ioSegmentCabin,
752  const BookingClassUnconstrainedDemandMap_T& iClassUncDemMap,
753  const stdair::NbOfRequests_T& iUncDem,
754  const double& iSellUpFactor) {
755  double lPriceOriMean = iUncDem;
756  double lPriceOriStdDev = sqrt (iUncDem);
757 
758  // DEBUG
759  STDAIR_LOG_DEBUG ("Price-oriented demand: mean = " << lPriceOriMean
760  << ", stddev = " << lPriceOriStdDev);
761 
762  // Retrieve the classes from low to high and compute the distributions of
763  // product-oriented and price-oriented demand.
764  // Retrieve the lowest class.
765  const stdair::BookingClassList_T& lBCList =
766  stdair::BomManager::getList<stdair::BookingClass> (ioSegmentCabin);
767  stdair::BookingClassList_T::const_reverse_iterator itCurrentClass =
768  lBCList.rbegin();
769  assert (itCurrentClass != lBCList.rend());
770  stdair::BookingClassList_T::const_reverse_iterator itNextClass =
771  itCurrentClass;
772  ++itNextClass;
773  // If there is only one class in the cabin, the demand distribution of this
774  // class is equal to the price-oriented demand distribution of the cabin.
775  if (itNextClass == lBCList.rend()) {
776  stdair::BookingClass* lLowestBC_ptr = *itCurrentClass;
777  lLowestBC_ptr->setMean (lPriceOriMean);
778  lLowestBC_ptr->setStdDev (lPriceOriStdDev);
779  if (lPriceOriMean > 0) {
780  return true;
781  } else {
782  return false;
783  }
784  } else {
785  bool isSucceeded = false;
786  // Compute the demand for higher class using the formula
787  // Pro_sell_up_from_Q_to_F = e ^ ((y_F/y_Q - 1) * ln (0.5) / (FRAT5 - 1))
788  for (; itNextClass != lBCList.rend(); ++itCurrentClass, ++itNextClass) {
789  stdair::BookingClass* lCurrentBC_ptr = *itCurrentClass;
790  assert (lCurrentBC_ptr != NULL);
791  const stdair::Yield_T& lCurrentYield = lCurrentBC_ptr->getYield();
792  stdair::BookingClass* lNextBC_ptr = *itNextClass;
793  assert (lNextBC_ptr != NULL);
794  const stdair::Yield_T& lNextYield = lNextBC_ptr->getYield();
795 
796  // Compute the part of price-oriented demand distributed to the
797  // current class.
798  const double lSellUp =
799  exp ((1.0 - lNextYield/lCurrentYield) * iSellUpFactor);
800  const double lPriceOriDemMeanFrac = lPriceOriMean * (1.0 - lSellUp);
801  const double lPriceOriDemStdDevFrac = lPriceOriStdDev * (1.0 - lSellUp);
802 
803  // Compute the product-oriented demand distribution for the
804  // current class.
805  BookingClassUnconstrainedDemandMap_T::const_iterator itBCUD =
806  iClassUncDemMap.find (lCurrentBC_ptr);
807  assert (itBCUD != iClassUncDemMap.end());
808  double lMean = itBCUD->second;
809  double lStdDev = sqrt (lMean);
810 
811  // Compute the demand distribution for the current class;
812  lMean += lPriceOriDemMeanFrac;
813  lStdDev = sqrt (lStdDev * lStdDev +
814  lPriceOriDemStdDevFrac * lPriceOriDemStdDevFrac);
815  lCurrentBC_ptr->setMean (lMean);
816  lCurrentBC_ptr->setStdDev (lStdDev);
817 
818  if (lMean > 0) {
819  isSucceeded = true;
820  }
821 
822  // DEBUG
823  STDAIR_LOG_DEBUG ("Class " << lCurrentBC_ptr->describeKey()
824  << ", mean = " << lMean
825  << ", stddev = " << lStdDev);
826 
827  // Update the price-oriented demand
828  lPriceOriMean *= lSellUp;
829  lPriceOriStdDev *= lSellUp;
830  }
831 
832  // Compute the demand distribution for the highest class (which is the
833  // "current class")
834  stdair::BookingClass* lCurrentBC_ptr = *itCurrentClass;
835  assert (lCurrentBC_ptr != NULL);
836  BookingClassUnconstrainedDemandMap_T::const_iterator itBCUD =
837  iClassUncDemMap.find (lCurrentBC_ptr);
838  assert (itBCUD != iClassUncDemMap.end());
839  double lMean = itBCUD->second;
840  double lStdDev = sqrt (lMean);
841 
842  // Compute the demand distribution for the current class;
843  lMean += lPriceOriMean;
844  lStdDev = sqrt (lStdDev * lStdDev + lPriceOriStdDev * lPriceOriStdDev);
845  lCurrentBC_ptr->setMean (lMean);
846  lCurrentBC_ptr->setStdDev (lStdDev);
847 
848  if (lMean > 0) {
849  isSucceeded = true;
850  }
851 
852  // DEBUG
853  STDAIR_LOG_DEBUG ("Class " << lCurrentBC_ptr->describeKey()
854  << ", mean = " << lMean
855  << ", stddev = " << lStdDev);
856  return isSucceeded;
857  }
858  }
859 
860 }