1 | import numpy as np
|
---|
2 | from sklearn.linear_model import LinearRegression
|
---|
3 |
|
---|
4 | """
|
---|
5 | Key assumptions:
|
---|
6 | 1. turns_left will only be called during our agent's "turn"
|
---|
7 | 2. times will be added to their respective lists using the progress function
|
---|
8 | """
|
---|
9 | class TimeEstimator:
|
---|
10 |
|
---|
11 | def __init__(self):
|
---|
12 | self.self_times = []
|
---|
13 | self.rounds = []
|
---|
14 | #self.roundsquare = []
|
---|
15 | # self.outliers = []
|
---|
16 | self.opp_times = []
|
---|
17 | self.self_diff = []
|
---|
18 | self.FRAME_LENGTHS = [10000, 100]
|
---|
19 | self.UPDATE_PERIODS = [1, 1]
|
---|
20 | self.models = [None for _ in range(len(self.FRAME_LENGTHS))]
|
---|
21 | self.stdevs = [None for _ in range(len(self.FRAME_LENGTHS))]
|
---|
22 | self.self_times_adj = []
|
---|
23 | self.opp_times_adj = []
|
---|
24 |
|
---|
25 | self.round_count = 0
|
---|
26 | self.outlier_count = 0
|
---|
27 | self.time_factor = 1.0
|
---|
28 |
|
---|
29 | def update_time_factor(self, time_factor: float):
|
---|
30 | self.time_factor = time_factor
|
---|
31 |
|
---|
32 | def get_new_time_factor(self, predicted_negs_left: list, bid_pool_size: int):
|
---|
33 | if len(predicted_negs_left) > bid_pool_size:
|
---|
34 | return self.time_factor / max((predicted_negs_left[-bid_pool_size] / bid_pool_size), 0.01)
|
---|
35 | elif len(predicted_negs_left) > 10:
|
---|
36 | return self.time_factor / max((predicted_negs_left[5] / (len(predicted_negs_left) - 5)), 0.01)
|
---|
37 | elif len(predicted_negs_left):
|
---|
38 | return self.time_factor / max(predicted_negs_left[-1], 0.01)
|
---|
39 | else:
|
---|
40 | return self.time_factor
|
---|
41 |
|
---|
42 | def self_times_add(self, time: float):
|
---|
43 | self.round_count += 1
|
---|
44 | self.self_times.append(time)
|
---|
45 | self.rounds.append(self.round_count)
|
---|
46 | if self.round_count > 5 and time > np.mean(self.self_times) + 3 * np.std(self.self_times):
|
---|
47 | self.outlier_count += 1
|
---|
48 | # self.outliers.append(self.outlier_count)
|
---|
49 | #self.roundsquare.append(self.round_count * self.round_count)
|
---|
50 |
|
---|
51 | self.update_model()
|
---|
52 |
|
---|
53 | def opp_times_add(self, value: float):
|
---|
54 | self.opp_times.append(value)
|
---|
55 | self.self_diff.append(value - self.self_times[-1])
|
---|
56 |
|
---|
57 | def _generate_model(self, frame_length):
|
---|
58 | y_list = self.self_times if len(self.self_times) < frame_length else self.self_times[-frame_length:]
|
---|
59 | x1_list = self.rounds if len(self.rounds) < frame_length else self.rounds[-frame_length:]
|
---|
60 | # x2_list = self.roundsquare if len(self.roundsquare) < frame_length else self.rounds[-frame_length:]
|
---|
61 | y = np.array(y_list)
|
---|
62 | x1 = np.array(x1_list)
|
---|
63 | # x2 = np.array(x2_list)
|
---|
64 | # X = np.stack([x1, x2]).transpose((1,0))
|
---|
65 | X = np.array([x1]).transpose((1,0))
|
---|
66 | model1 = LinearRegression().fit(X, y)
|
---|
67 | # model2 = LinearRegression().fit(X2, y)
|
---|
68 | y_pred = model1.predict(X)
|
---|
69 | res = y_pred - y
|
---|
70 | stdev = np.std(res)
|
---|
71 | return model1, stdev
|
---|
72 |
|
---|
73 | def update_model(self):
|
---|
74 | issue_count = len(self.self_times)
|
---|
75 | for i, (frame_length, update_period) in enumerate(zip(self.FRAME_LENGTHS, self.UPDATE_PERIODS)):
|
---|
76 | if issue_count % update_period == 0 or i < 5:
|
---|
77 | model, stdev = self._generate_model(frame_length)
|
---|
78 | self.models[i] = model
|
---|
79 | self.stdevs[i] = stdev
|
---|
80 |
|
---|
81 | def turns_left(self, time):
|
---|
82 | """
|
---|
83 | If your turn starts at time, how many turns are left?
|
---|
84 | """
|
---|
85 | if len(self.self_times) <= 1:
|
---|
86 | return 2000
|
---|
87 | p_list = [np.append(model.coef_, model.intercept_ - 1.0) for model in self.models]
|
---|
88 | # final_turn_counts = np.array([np.max(np.roots(p)) / (1.0 + stdev) for p, stdev in zip(p_list, self.stdevs)])
|
---|
89 | final_turn_counts = np.array([np.max(np.roots(p)) / (1.0 + stdev) * self.time_factor for p, stdev in zip(p_list, self.stdevs)])
|
---|
90 |
|
---|
91 | p_list = [np.append(model.coef_, model.intercept_ - time) for model in self.models]
|
---|
92 | # time_turn_counts = np.array([np.max(np.roots(p)) / (1.0 + stdev) for p, stdev in zip(p_list, self.stdevs)])
|
---|
93 | time_turn_counts = np.array([np.max(np.roots(p)) / (1.0 + stdev) * self.time_factor for p, stdev in zip(p_list, self.stdevs)])
|
---|
94 |
|
---|
95 | return int(np.min(final_turn_counts - time_turn_counts))
|
---|
96 |
|
---|
97 | # #adds adjusted values to the adjusted lists by subtracting the "start point" provided by the preceding progress value from each value
|
---|
98 | # def lists_adjust(self):
|
---|
99 | # #first iteration
|
---|
100 | # if self.idx == 0:
|
---|
101 | # #our agent made the first bid
|
---|
102 | # if self.self_times[0] < self.opp_times[0]:
|
---|
103 | # self.self_times_adj.append(self.self_times[0])
|
---|
104 | # self.opp_times_adj.append(self.opp_times[self.idx] - self.self_times[self.idx])
|
---|
105 | # self.idx += 1
|
---|
106 | # while self.idx < len(self.self_times):
|
---|
107 | # self.self_times_adj.append(self.self_times[self.idx]-self.opp_times[self.idx-1])
|
---|
108 | # self.opp_times_adj.append(self.opp_times[self.idx]-self.self_times[self.idx])
|
---|
109 | # self.idx += 1
|
---|
110 | # #the opponent made the first bid
|
---|
111 | # else:
|
---|
112 | # self.self_times_adj.append(self.self_times[self.idx]-self.opp_times[self.idx])
|
---|
113 | # self.opp_times_adj.append(self.opp_times[0])
|
---|
114 | # self.opp_times_adj.append(self.opp_times[self.idx+1]-self.self_times[self.idx])
|
---|
115 | # self.idx += 1
|
---|
116 | # while self.idx < len(self.self_times):
|
---|
117 | # self.self_times_adj.append(self.self_times[self.idx]-self.opp_times[self.idx])
|
---|
118 | # self.opp_times_adj.append(self.opp_times[self.idx+1]-self.self_times[self.idx])
|
---|
119 | # self.idx += 1
|
---|
120 | # #further iterations
|
---|
121 | # else:
|
---|
122 | # #continuing case where our agent made the first bid
|
---|
123 | # if self.self_times[self.idx] < self.opp_times[self.idx]:
|
---|
124 | # while self.idx < len(self.self_times):
|
---|
125 | # self.self_times_adj.append(self.self_times[self.idx]-self.opp_times[self.idx-1])
|
---|
126 | # self.opp_times_adj.append(self.opp_times[self.idx]-self.self_times[self.idx])
|
---|
127 | # self.idx += 1
|
---|
128 | # #cintinuing case where opponent made the first bid
|
---|
129 | # else:
|
---|
130 | # while self.idx < len(self.self_times):
|
---|
131 | # self.self_times_adj.append(self.self_times[self.idx]-self.opp_times[self.idx])
|
---|
132 | # self.opp_times_adj.append(self.opp_times[self.idx+1]-self.self_times[self.idx])
|
---|
133 | # self.idx += 1
|
---|
134 |
|
---|
135 | # #feeder function to be deleted after regression implemented
|
---|
136 | # def opp_avg(self):
|
---|
137 | # Sum = sum(self.opp_times_adj)
|
---|
138 | # O_avg = Sum / len(self.opp_times_adj)
|
---|
139 | # return O_avg
|
---|
140 |
|
---|
141 | # #feeder function to be deleted after regression implemented
|
---|
142 | # def self_avg(self):
|
---|
143 | # Sum = sum(self.self_times_adj)
|
---|
144 | # S_avg = Sum/len(self.self_times_adj)
|
---|
145 | # return S_avg
|
---|
146 |
|
---|
147 | # def turns_left(self, progress: float):
|
---|
148 | # self.lists_adjust()
|
---|
149 | # opp_time = self.opp_avg()
|
---|
150 | # self_time = self.self_avg()
|
---|
151 | # i = 0
|
---|
152 | # count = 0
|
---|
153 |
|
---|
154 | # #make sure order is correct
|
---|
155 | # while progress < 1:
|
---|
156 | # if (i % 2 == 0):
|
---|
157 | # progress += self_time
|
---|
158 | # else:
|
---|
159 | # progress += opp_time
|
---|
160 |
|
---|
161 | # count += 1
|
---|
162 | # i += 1
|
---|
163 |
|
---|
164 | # return count |
---|