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