| 1 | /* |
| 2 | * Legal Notice |
| 3 | * |
| 4 | * This document and associated source code (the "Work") is a part of a |
| 5 | * benchmark specification maintained by the TPC. |
| 6 | * |
| 7 | * The TPC reserves all right, title, and interest to the Work as provided |
| 8 | * under U.S. and international laws, including without limitation all patent |
| 9 | * and trademark rights therein. |
| 10 | * |
| 11 | * No Warranty |
| 12 | * |
| 13 | * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION |
| 14 | * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE |
| 15 | * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER |
| 16 | * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY, |
| 17 | * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES, |
| 18 | * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR |
| 19 | * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF |
| 20 | * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE. |
| 21 | * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT, |
| 22 | * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT |
| 23 | * WITH REGARD TO THE WORK. |
| 24 | * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO |
| 25 | * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE |
| 26 | * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS |
| 27 | * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT, |
| 28 | * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY, |
| 29 | * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT |
| 30 | * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD |
| 31 | * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. |
| 32 | * |
| 33 | * Contributors |
| 34 | * - Sergey Vasilevskiy, Doug Johnson |
| 35 | */ |
| 36 | |
| 37 | /****************************************************************************** |
| 38 | * Description: Implementation of the CustomerSelection class. |
| 39 | * (see CustomerSelction.h for details) |
| 40 | ******************************************************************************/ |
| 41 | |
| 42 | #include "main/EGenTables_stdafx.h" |
| 43 | |
| 44 | using namespace TPCE; |
| 45 | |
| 46 | /* |
| 47 | * Default constructor. |
| 48 | */ |
| 49 | CCustomerSelection::CCustomerSelection() |
| 50 | : m_pRND(NULL), m_iStartFromCustomer(0 + iTIdentShift), m_iCustomerCount(0), m_bPartitionByCID(false), |
| 51 | m_iPartitionPercent(0), m_iMyStartFromCustomer(0 + iTIdentShift), m_iMyCustomerCount(0) { |
| 52 | } |
| 53 | |
| 54 | /* |
| 55 | * Constructor to set the customer range when not partitioining |
| 56 | */ |
| 57 | CCustomerSelection::CCustomerSelection(CRandom *pRND, TIdent iStartFromCustomer, TIdent iCustomerCount) |
| 58 | : m_pRND(pRND), m_iStartFromCustomer(iStartFromCustomer + iTIdentShift), m_iCustomerCount(iCustomerCount), |
| 59 | m_bPartitionByCID(false), m_iPartitionPercent(0), m_iMyStartFromCustomer(0 + iTIdentShift), |
| 60 | m_iMyCustomerCount(0) { |
| 61 | } |
| 62 | |
| 63 | /* |
| 64 | * Constructor to set subrange when partitioning by C_ID. |
| 65 | */ |
| 66 | CCustomerSelection::CCustomerSelection(CRandom *pRND, TIdent iStartFromCustomer, TIdent iCustomerCount, |
| 67 | int iPartitionPercent, TIdent iMyStartFromCustomer, TIdent iMyCustomerCount) |
| 68 | : m_pRND(pRND), m_iStartFromCustomer(iStartFromCustomer + iTIdentShift), m_iCustomerCount(iCustomerCount) |
| 69 | |
| 70 | , |
| 71 | m_bPartitionByCID(true), m_iPartitionPercent(iPartitionPercent), |
| 72 | m_iMyStartFromCustomer(iMyStartFromCustomer + iTIdentShift), m_iMyCustomerCount(iMyCustomerCount) { |
| 73 | if ((iStartFromCustomer == iMyStartFromCustomer) && (iCustomerCount == iMyCustomerCount)) { |
| 74 | // Even though the partitioning constructor was called, we're apparently |
| 75 | // not really partitioning. |
| 76 | m_bPartitionByCID = false; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | /* |
| 81 | * Re-set the customer range for the partition. |
| 82 | */ |
| 83 | void CCustomerSelection::SetPartitionRange(TIdent iStartFromCustomer, TIdent iCustomerCount) { |
| 84 | if (m_bPartitionByCID) { |
| 85 | m_iMyStartFromCustomer = iStartFromCustomer; |
| 86 | m_iMyCustomerCount = iCustomerCount; |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | * Forward permutation. |
| 92 | */ |
| 93 | TIdent CCustomerSelection::Permute(TIdent iLow, TIdent iHigh) { |
| 94 | return ((677 * iLow + 33 * (iHigh + 1)) % 1000); |
| 95 | } |
| 96 | |
| 97 | /* |
| 98 | * Inverse permutation. |
| 99 | */ |
| 100 | TIdent CCustomerSelection::InversePermute(TIdent iLow, TIdent iHigh) { |
| 101 | // Extra mod to make the result always positive |
| 102 | // |
| 103 | return (((((613 * (iLow - 33 * (iHigh + 1))) % 1000) + 1000) % 1000)); |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | * Return scrambled inverse customer id in range of 0 to 999. |
| 108 | */ |
| 109 | UINT CCustomerSelection::GetInverseCID(TIdent C_ID) { |
| 110 | UINT iCHigh = (UINT)CHigh(C_ID); |
| 111 | UINT iInverseCID = (UINT)InversePermute(CLow(C_ID), iCHigh); |
| 112 | |
| 113 | if (iInverseCID < 200) // Tier 1: value 0 to 199 |
| 114 | { |
| 115 | return ((3 * iInverseCID + (iCHigh + 1)) % 200); |
| 116 | } else { |
| 117 | if (iInverseCID < 800) // Tier 2: value 200 to 799 |
| 118 | { |
| 119 | return (((59 * iInverseCID + 47 * (iCHigh + 1)) % 600) + 200); |
| 120 | } else // Tier 3: value 800 to 999 |
| 121 | { |
| 122 | return (((23 * iInverseCID + 17 * (iCHigh + 1)) % 200) + 800); |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | /* |
| 128 | * Return customer tier. |
| 129 | */ |
| 130 | eCustomerTier CCustomerSelection::GetTier(TIdent C_ID) { |
| 131 | TIdent iRevC_ID = InversePermute(CLow(C_ID), CHigh(C_ID)); |
| 132 | |
| 133 | if (iRevC_ID < 200) { |
| 134 | return eCustomerTierOne; |
| 135 | } else { |
| 136 | if (iRevC_ID < 800) { |
| 137 | return eCustomerTierTwo; |
| 138 | } else { |
| 139 | return eCustomerTierThree; |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | /* |
| 145 | * Return a non-uniform random customer and the associated tier. |
| 146 | */ |
| 147 | void CCustomerSelection::GenerateRandomCustomer(TIdent &C_ID, eCustomerTier &C_TIER) { |
| 148 | // Can't use this function if there is no external RNG. |
| 149 | // |
| 150 | if (m_pRND == NULL) { |
| 151 | return; |
| 152 | } |
| 153 | |
| 154 | double fCW = m_pRND->RndDoubleIncrRange(0.0001, 2000, 0.000000001); |
| 155 | |
| 156 | // Uniformly select the higher portion of the C_ID. |
| 157 | // Use "short-circuit" logic to avoid unnecessary call to RNG. |
| 158 | TIdent iCHigh; |
| 159 | if (m_bPartitionByCID && m_pRND->RndPercent(m_iPartitionPercent)) { |
| 160 | // Generate a load unit inside the partition. |
| 161 | iCHigh = (m_pRND->RndInt64Range(m_iMyStartFromCustomer, |
| 162 | m_iMyStartFromCustomer + m_iMyCustomerCount - 1) - |
| 163 | 1) // minus 1 for the upper boundary case |
| 164 | / 1000; |
| 165 | } else { |
| 166 | // Generate a load unit across the entire range |
| 167 | iCHigh = (m_pRND->RndInt64Range(m_iStartFromCustomer, |
| 168 | m_iStartFromCustomer + m_iCustomerCount - 1) - |
| 169 | 1) // minus 1 for the upper boundary case |
| 170 | / 1000; |
| 171 | } |
| 172 | |
| 173 | // Non-uniformly select the lower portion of the C_ID. |
| 174 | // |
| 175 | int iCLow; |
| 176 | |
| 177 | if (fCW <= 200) { |
| 178 | // tier one |
| 179 | // |
| 180 | iCLow = (int)ceil(sqrt(22500 + 500 * fCW) - 151); |
| 181 | |
| 182 | C_TIER = eCustomerTierOne; |
| 183 | } else { |
| 184 | if (fCW <= 1400) { |
| 185 | // tier two |
| 186 | // |
| 187 | iCLow = (int)ceil(sqrt(290000 + 1000 * fCW) - 501); |
| 188 | |
| 189 | C_TIER = eCustomerTierTwo; |
| 190 | } else { |
| 191 | // tier three |
| 192 | // |
| 193 | iCLow = (int)ceil(149 + sqrt(500 * fCW - 277500)); |
| 194 | |
| 195 | C_TIER = eCustomerTierThree; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | C_ID = iCHigh * 1000 + Permute(iCLow, iCHigh) + 1; |
| 200 | } |
| 201 | |
| 202 | /////////* |
| 203 | ////////* Return a non-uniform random customer and tier. |
| 204 | ////////*/ |
| 205 | ////////void CCustomerSelection::GenerateCustomerIdAndTier(TIdent &C_ID, |
| 206 | /// eCustomerTier &C_TIER, bool bAcrossEntireRange) |
| 207 | ////////{ |
| 208 | //////// // Can't use this function if there is no external RNG. |
| 209 | //////// // |
| 210 | //////// if (m_pRND == NULL) |
| 211 | //////// { |
| 212 | //////// return; |
| 213 | //////// } |
| 214 | //////// |
| 215 | //////// double fCW = m_pRND->RndDoubleRange(0.0001, 2000); |
| 216 | //////// |
| 217 | //////// // Select uniformly higher portion of the Customer ID. |
| 218 | //////// // |
| 219 | //////// TIdent iCHigh; |
| 220 | //////// if (bAcrossEntireRange) |
| 221 | //////// { |
| 222 | //////// // Generate a load unit across the entire range |
| 223 | //////// iCHigh = (m_pRND->RndInt64Range(1, |
| 224 | /// m_iAdjustedTotalCustomerCount) - 1) // minus 1 for the upper boundary case |
| 225 | //////// / 1000; |
| 226 | //////// if( iCHigh >= ( m_iStartFromCustomer / 1000 )) |
| 227 | //////// { |
| 228 | //////// iCHigh += ( m_iCustomerCount / 1000 ); |
| 229 | //////// } |
| 230 | //////// } |
| 231 | //////// else |
| 232 | //////// { |
| 233 | //////// // Generate a load unit inside the parition. |
| 234 | //////// iCHigh = (m_pRND->RndInt64Range(m_iStartFromCustomer, |
| 235 | //////// m_iStartFromCustomer + |
| 236 | /// m_iCustomerCount - 1) - 1) // minus 1 for the upper boundary case |
| 237 | //////// / 1000; |
| 238 | //////// } |
| 239 | //////// |
| 240 | //////// // Select non-uniformly the lower portion of the Customer ID. |
| 241 | //////// // |
| 242 | //////// int iCLow; |
| 243 | //////// |
| 244 | //////// if (fCW <= 200) |
| 245 | //////// { |
| 246 | //////// // tier one |
| 247 | //////// // |
| 248 | //////// iCLow = (int) ceil( sqrt(22500 + 500 * fCW) - 151 ); |
| 249 | //////// |
| 250 | //////// C_TIER = eCustomerTierOne; |
| 251 | //////// } |
| 252 | //////// else |
| 253 | //////// { |
| 254 | //////// if (fCW <=1400) |
| 255 | //////// { |
| 256 | //////// // tier two |
| 257 | //////// // |
| 258 | //////// iCLow = (int) ceil( sqrt(290000 + 1000 * fCW) - 501 ); |
| 259 | //////// |
| 260 | //////// C_TIER = eCustomerTierTwo; |
| 261 | //////// } |
| 262 | //////// else |
| 263 | //////// { |
| 264 | //////// // tier three |
| 265 | //////// // |
| 266 | //////// iCLow = (int) ceil( 149 + sqrt(500 * fCW - 277500) ); |
| 267 | //////// |
| 268 | //////// C_TIER = eCustomerTierThree; |
| 269 | //////// } |
| 270 | //////// } |
| 271 | //////// |
| 272 | //////// C_ID = iCHigh * 1000 + Permute(iCLow, iCHigh) + 1; |
| 273 | ////////} |
| 274 | |