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
44using namespace TPCE;
45
46/*
47 * Default constructor.
48 */
49CCustomerSelection::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 */
57CCustomerSelection::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 */
66CCustomerSelection::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 */
83void 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 */
93TIdent CCustomerSelection::Permute(TIdent iLow, TIdent iHigh) {
94 return ((677 * iLow + 33 * (iHigh + 1)) % 1000);
95}
96
97/*
98 * Inverse permutation.
99 */
100TIdent 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 */
109UINT 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 */
130eCustomerTier 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 */
147void 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