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 | |