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

rmol/command/MarginalRevenueTransformation.cpp

Go to the documentation of this file.
00001 // //////////////////////////////////////////////////////////////////////
00002 // Import section
00003 // //////////////////////////////////////////////////////////////////////
00004 // STL
00005 #include <cassert>
00006 #include <sstream>
00007 #include <cmath>
00008 // StdAir
00009 #include <stdair/basic/BasConst_General.hpp>
00010 #include <stdair/basic/BasConst_Inventory.hpp>
00011 #include <stdair/bom/BomManager.hpp>
00012 #include <stdair/bom/SegmentCabin.hpp>
00013 #include <stdair/bom/BookingClass.hpp>
00014 #include <stdair/bom/SimpleNestingStructure.hpp>
00015 #include <stdair/bom/NestingNode.hpp>
00016 #include <stdair/bom/Policy.hpp>
00017 #include <stdair/factory/FacBomManager.hpp>
00018 #include <stdair/service/Logger.hpp>
00019 // RMOL
00020 #include <rmol/bom/PolicyHelper.hpp>
00021 #include <rmol/bom/Utilities.hpp>
00022 #include <rmol/command/MarginalRevenueTransformation.hpp>
00023 
00024 namespace RMOL {
00025 
00026   // ////////////////////////////////////////////////////////////////////
00027   bool MarginalRevenueTransformation::
00028   prepareDemandInput (stdair::SegmentCabin& ioSegmentCabin) {
00029     // Build the convex hull, then adjust the yield and demand of all
00030     // classes based on the hull.
00031   
00032     buildNestedConvexHull (ioSegmentCabin);
00033     bool isSucceeded = adjustYieldAndDemand (ioSegmentCabin);
00034 
00035     return isSucceeded;
00036   }
00037 
00038   // ////////////////////////////////////////////////////////////////////
00039   void MarginalRevenueTransformation::
00040   buildConvexHull (stdair::SegmentCabin& ioSegmentCabin) {
00041     // Reset the convex hull of the segment.
00042     ioSegmentCabin.resetConvexHull();
00043     
00044     // The first (from the left side) point of the convex hull is the "empty"
00045     // policy, i.e. the one with all fare families closed.
00046     const stdair::PolicyList_T& lPolicyList =
00047       stdair::BomManager::getList<stdair::Policy> (ioSegmentCabin);
00048 
00049     // By construction, the empty policy is the first one on the list of
00050     // eligible policies.
00051     stdair::PolicyList_T::const_iterator itPolicy=lPolicyList.begin();
00052     stdair::Policy* lEmptyPolicy_ptr = *itPolicy;
00053     assert (lEmptyPolicy_ptr != NULL);
00054     ioSegmentCabin.addPolicy (*lEmptyPolicy_ptr);
00055 
00056     // Pointer on the current policy of the convex hull.
00057     stdair::Policy* lCurrentPolicy_ptr = lEmptyPolicy_ptr;
00058     bool lEndOfHull = false;
00059 
00060     // The end of hull is reached when from the current policy, we cannot
00061     // find an other one with greater demand and total revenue.
00062     while (lEndOfHull == false) {
00063       // Demand and total revenue of the current policy.
00064       const double& lCurrentDem = lCurrentPolicy_ptr->getDemand();
00065       const double lCurrentTR = lCurrentPolicy_ptr->getTotalRevenue();
00066       
00067       // Search for the next policy.
00068       double lGradient = 0.0;
00069       stdair::Policy* lNextPolicy_ptr = NULL;
00070       for (stdair::PolicyList_T::const_iterator itPol = lPolicyList.begin();
00071            itPol != lPolicyList.end(); ++itPol) {
00072         stdair::Policy* lPolicy_ptr = *itPol;
00073         assert (lPolicy_ptr != NULL);
00074 
00075         const double& lDem = lPolicy_ptr->getDemand();
00076         const double lTR = lPolicy_ptr->getTotalRevenue();
00077         if (lDem > lCurrentDem && lTR > lCurrentTR) {
00078           const double lNewGradient = (lTR-lCurrentTR)/(lDem-lCurrentDem);
00079           if (lNewGradient > lGradient) {
00080             lGradient = lNewGradient;
00081             lNextPolicy_ptr = lPolicy_ptr;
00082           }
00083         }
00084       }
00085 
00086       // Check if we have found the next policy
00087       if (lNextPolicy_ptr == NULL) {
00088         lEndOfHull = true;
00089       } else {
00090         ioSegmentCabin.addPolicy (*lNextPolicy_ptr);
00091         lCurrentPolicy_ptr = lNextPolicy_ptr;
00092       }
00093     }
00094   }
00095 
00096   // ////////////////////////////////////////////////////////////////////
00097   void MarginalRevenueTransformation::
00098   buildNestedConvexHull (stdair::SegmentCabin& ioSegmentCabin) {
00099     // Reset the convex hull of the segment.
00100     ioSegmentCabin.resetConvexHull();
00101     
00102     // The first (from the left side) point of the convex hull is the "empty"
00103     // policy, i.e. the one with all fare families closed.
00104     const stdair::PolicyList_T& lPolicyList =
00105       stdair::BomManager::getList<stdair::Policy> (ioSegmentCabin);
00106 
00107     // By construction, the empty policy is the first one on the list of
00108     // eligible policies.
00109     stdair::PolicyList_T::const_iterator itPolicy=lPolicyList.begin();
00110     stdair::Policy* lEmptyPolicy_ptr = *itPolicy;
00111     assert (lEmptyPolicy_ptr != NULL);
00112     ioSegmentCabin.addPolicy (*lEmptyPolicy_ptr);
00113 
00114     // Pointer on the current policy of the convex hull.
00115     stdair::Policy* lCurrentPolicy_ptr = lEmptyPolicy_ptr;
00116     bool lEndOfHull = false;
00117 
00118     // The end of hull is reached when from the current policy, we cannot
00119     // find an other one with greater demand and total revenue.
00120     while (lEndOfHull == false) {
00121       // Demand and total revenue of the current policy.
00122       const double& lCurrentDem = lCurrentPolicy_ptr->getDemand();
00123       const double lCurrentTR = lCurrentPolicy_ptr->getTotalRevenue();
00124 
00125       // Search for the next policy.
00126       double lGradient = 0.0;
00127       stdair::Policy* lNextPolicy_ptr = NULL;
00128       for (stdair::PolicyList_T::const_iterator itPol = lPolicyList.begin();
00129            itPol != lPolicyList.end(); ++itPol) {
00130         stdair::Policy* lPolicy_ptr = *itPol;
00131         assert (lPolicy_ptr != NULL);
00132 
00133         const double& lDem = lPolicy_ptr->getDemand();
00134         const double lTR = lPolicy_ptr->getTotalRevenue();
00135         if (lDem > lCurrentDem && lTR > lCurrentTR
00136             && PolicyHelper::isNested (*lCurrentPolicy_ptr, *lPolicy_ptr)) {
00137           const double lNewGradient = (lTR-lCurrentTR)/(lDem-lCurrentDem);
00138           if (lNewGradient > lGradient) {
00139             lGradient = lNewGradient;
00140             lNextPolicy_ptr = lPolicy_ptr;
00141           }
00142         }
00143       }
00144 
00145       // Check if we have found the next policy
00146       if (lNextPolicy_ptr == NULL) {
00147         lEndOfHull = true;
00148       } else {
00149         ioSegmentCabin.addPolicy (*lNextPolicy_ptr);
00150         lCurrentPolicy_ptr = lNextPolicy_ptr;
00151       }
00152     }
00153   }
00154 
00155   // ////////////////////////////////////////////////////////////////////
00156   bool MarginalRevenueTransformation::
00157   adjustYieldAndDemand (stdair::SegmentCabin& ioSegmentCabin) {
00158     bool isSucceeded = false;
00159     stdair::NbOfClasses_T lBookingClassCounter = 0;
00160     // Browse the list of policies on the convex hull, compute the differences
00161     // between pairs of consecutive policies.
00162     const stdair::PolicyList_T& lConvexHull = ioSegmentCabin.getConvexHull();
00163     stdair::PolicyList_T::const_iterator itCurrentPolicy = lConvexHull.begin();
00164     assert (itCurrentPolicy != lConvexHull.end());
00165     stdair::PolicyList_T::const_iterator itNextPolicy = itCurrentPolicy;
00166     ++itNextPolicy;
00167     // If the nesting has only one element (the empty policy),
00168     // there is no optimisation and no pre-optimisation.
00169     if (itNextPolicy == lConvexHull.end()) {
00170       return isSucceeded;
00171     }
00172 
00173     // Reset the yield-based nesting structure
00174     stdair::FacBomManager::resetYieldBasedNestingStructure (ioSegmentCabin);
00175 
00176     // Retrieve the yield-based nesting structure.
00177     stdair::SimpleNestingStructure& lYieldBasedNS =
00178       stdair::BomManager::getObject<stdair::SimpleNestingStructure> (ioSegmentCabin, stdair::YIELD_BASED_NESTING_STRUCTURE_CODE);
00179     const stdair::NestingNodeList_T& lNodeList =
00180       stdair::BomManager::getList<stdair::NestingNode> (lYieldBasedNS);
00181     stdair::NestingNodeList_T::const_iterator itNode = lNodeList.begin();
00182 
00183     for (; itNextPolicy != lConvexHull.end();
00184          ++itCurrentPolicy, ++itNextPolicy, ++itNode){
00185       const stdair::Policy* lCurrentPolicy_ptr = *itCurrentPolicy;
00186       assert (lCurrentPolicy_ptr != NULL);
00187       const stdair::Policy* lNextPolicy_ptr = *itNextPolicy;
00188       assert (lNextPolicy_ptr != NULL);
00189 
00190       // Retrieve the node. If there isn't any node left, create new one.
00191       stdair::NestingNode* lNode_ptr = NULL;
00192       if (itNode == lNodeList.end()) {
00193         // Create a nesting node
00194         stdair::NestingNodeCode_T lNodeCode ("XXX");
00195         stdair::NestingNodeKey lNodeKey (lNodeCode);
00196         stdair::NestingNode& lNestingNode =
00197           stdair::FacBom<stdair::NestingNode>::instance().create (lNodeKey);
00198         stdair::FacBomManager::addToList (lYieldBasedNS, lNestingNode);
00199         stdair::FacBomManager::linkWithParent (lYieldBasedNS, lNestingNode);
00200         lNode_ptr = &lNestingNode;
00201       } else {
00202         lNode_ptr = *itNode;
00203       }
00204       assert (lNode_ptr != NULL);
00205       PolicyHelper::diffBetweenTwoPolicies (*lNode_ptr, *lNextPolicy_ptr,
00206                                             *lCurrentPolicy_ptr);
00207 
00208       // Compute the adjusted yield, demand mean and demand standard deviation.
00209       // Note: because of the nature of the convex hull, in the adjusted
00210       // standard deviation computation, we can take the difference between
00211       // the squares of the standard deviations of the two policies instead of
00212       // the sum of the squares.
00213       const stdair::MeanValue_T lAdjustedDemMean =
00214         lNextPolicy_ptr->getDemand()-lCurrentPolicy_ptr->getDemand();
00215       assert (lAdjustedDemMean > 0.0);
00216       const stdair::StdDevValue_T& lCurrentStdDev = 
00217         lCurrentPolicy_ptr->getStdDev();
00218       const stdair::StdDevValue_T& lNextStdDev = lNextPolicy_ptr->getStdDev();
00219       assert (lNextStdDev > lCurrentStdDev);
00220       const stdair::StdDevValue_T lAdjustedDemStdDev =
00221         std::sqrt (lNextStdDev*lNextStdDev - lCurrentStdDev*lCurrentStdDev);
00222       const stdair::Yield_T lAdjustedYield =
00223         (lNextPolicy_ptr->getTotalRevenue()-lCurrentPolicy_ptr->getTotalRevenue())/(lAdjustedDemMean);
00224       assert (lAdjustedYield > 0.0);
00225       lNode_ptr->setYield (lAdjustedYield);
00226 
00227       // Browse the list of booking classes in the node. Set the adjusted yield
00228       // for each class. However, the adjusted demand forecast will be
00229       // distributed only to the first class of the list.
00230       const stdair::BookingClassList_T lBCList =
00231         stdair::BomManager::getList<stdair::BookingClass> (*lNode_ptr);
00232       stdair::BookingClassList_T::const_iterator itBC = lBCList.begin();
00233       assert (itBC != lBCList.end());
00234       stdair::BookingClass* lFirstClass = *itBC;
00235       assert (lFirstClass != NULL);
00236       lFirstClass->setMean (lAdjustedDemMean);
00237       lFirstClass->setStdDev (lAdjustedDemStdDev);
00238       for (; itBC != lBCList.end(); ++itBC) {
00239         stdair::BookingClass* lClass = *itBC;
00240         assert (lClass != NULL);
00241         lClass->setAdjustedYield (lAdjustedYield);
00242         ++lBookingClassCounter;
00243       }
00244     }
00245 
00246     const stdair::BookingClassList_T& lSCBookingClassList = 
00247        stdair::BomManager::getList<stdair::BookingClass> (ioSegmentCabin);
00248     const stdair::NbOfClasses_T lNbOfBookingClass = lSCBookingClassList.size();
00249     assert (lNbOfBookingClass >= lBookingClassCounter); 
00250     if (lBookingClassCounter < lNbOfBookingClass) {
00251       // At the last node. All the classes which haven't been added to the
00252       // nesting structure will be added to the next nesting node, with
00253       // an adjusted yield of zero.
00254       // Retrieve the node. If there isn't any node left, create new one.
00255       stdair::NestingNode* lLastNode_ptr = NULL;
00256       if (itNode == lNodeList.end()) {
00257         // Create a nesting node
00258         stdair::NestingNodeCode_T lNodeCode ("XXX");
00259         stdair::NestingNodeKey lNodeKey (lNodeCode);
00260         stdair::NestingNode& lNestingNode =
00261           stdair::FacBom<stdair::NestingNode>::instance().create (lNodeKey);
00262         stdair::FacBomManager::addToList (lYieldBasedNS, lNestingNode);
00263         stdair::FacBomManager::linkWithParent (lYieldBasedNS, lNestingNode);
00264         lLastNode_ptr = 
00265           stdair::BomManager::getObjectPtr<stdair::NestingNode>(lYieldBasedNS, 
00266                                                            lNodeKey.toString());
00267       } else {
00268         lLastNode_ptr = *itNode;
00269       }
00270       assert (lLastNode_ptr != NULL);
00271       const stdair::Policy* lLastPolicy_ptr = *itCurrentPolicy;
00272       assert (lLastPolicy_ptr != NULL);
00273       PolicyHelper::computeLastNode (*lLastNode_ptr, *lLastPolicy_ptr,
00274                                      ioSegmentCabin);
00275     }
00276 
00277     isSucceeded = true;
00278     return isSucceeded;
00279   }
00280   
00281 }