-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
169 lines (127 loc) · 5.45 KB
/
utils.py
File metadata and controls
169 lines (127 loc) · 5.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
from random import uniform, randint
from abc import abstractmethod, ABC
from time import time, perf_counter
import matplotlib.pyplot as plt
from seed_random import IsolatedBernoulliArm
from permutation import IsolatedPermutation
class Timer:
"""Timer class allows to time a arbitrary blocks of code by using "with" python statement.
This object allows to time several not nested blocks of code as follows:
timer = Timer()
with timer:
sleep(20)
print("Execution time (s): {}".format(time.execution_time_in_seconds()))
Warning: Current implementation of does not support nested blocks timing.
In a such way, the timer will be reset each time the time is reused in a with statement.
"""
def __init__(self):
self.__total_execution_time : float = 0
self.__running : bool = False
self.__start : float = 0
def __enter__(self):
self.__has_start = True
self.__start = perf_counter()
def __exit__(self, exc_type, exc_val, exc_tb):
end = perf_counter()
self.__total_execution_time += end - self.__start
self.__running = False
self.__start = 0
def execution_time_in_seconds(self) -> float:
"""Returns elapsed time in seconds.
Returns:
The elapsed time between the beginning and the end of the "with" block.
"""
return self.__total_execution_time
def randint_if_none( value ):
if value is None:
return randint( 10, 1000 )
else:
return value
def parse_bench_log( filename : str ):
result = {}
with open(filename) as file:
lines = "".join(file.readlines()).replace("\n", "").split("#")
for line in lines:
if line == "": continue
node, cpu_usage_time = line.split(":")
result[node] = float(cpu_usage_time)
return result
class BernoulliArm:
"""Bandit arm with a bernoulli bandit arm.
"""
def __init__(self, p):
"""Bernoulli arm initialization.
This arm returns 1 value with a given probability p and 0 with a probability 1 - p.
:param p: Probability to obtains an 1
"""
self.p = p
def pull(self):
"""Pulled arm in order to obtain a value in bernoulli distribution.
Returns 1 with a probability p and 0 with a probability 1 - p.
"""
return int(uniform(0, 1) < self.p)
class BanditsAlgorithm:
@abstractmethod
def play( self, budget ) -> int: pass
class DebugBanditsAlgorithm(BanditsAlgorithm):
@abstractmethod
def pulled_arm_at_each_turn(self) -> [BernoulliArm] : pass
@abstractmethod
def rewards_at_each_turn(self) -> [int]: pass
@abstractmethod
def get_probabilities(self) -> [float]: pass
class StandardBanditsAlgorithm(BanditsAlgorithm, ABC):
def __init__(self, arms_probabilities: [float], reward_seed = 123):
self.K = len(arms_probabilities)
self.arms = [ IsolatedBernoulliArm( p, reward_seed ) for p in arms_probabilities ]
def get_arm_by_index(self, arm_index) -> IsolatedBernoulliArm: return self.arms[arm_index]
def debug_algorithm( budget : int, algorithms : [DebugBanditsAlgorithm] ):
if not isinstance(algorithms, list):
algorithms = [algorithms]
for algorithm in algorithms:
print("Debugging ", type(algorithm))
start = time()
algorithm.play( budget )
end = time()
rewards_at_each_turn = algorithm.rewards_at_each_turn()
arm_at_each_turn = algorithm.pulled_arm_at_each_turn()
assert len(arm_at_each_turn) == budget, "Pulled arm at each turn has not the same length that budget: {} instead of {}".format(len(arm_at_each_turn), budget)
assert len(rewards_at_each_turn) == budget, "Rewards at each turn has not the same length that budget: {} instread of {}".format(len(rewards_at_each_turn), budget)
# Computing regret at each turn.
# Starting by searching the best arm's probability.
probs = algorithm.get_probabilities()
prob_max = max(probs)
optimal_rewards = int(budget * prob_max)
total_regret = optimal_rewards - sum(rewards_at_each_turn)
regret_at_each_turn = []
for i in range( budget ):
regret_at_each_turn.append( i * prob_max - sum(rewards_at_each_turn[:(i+1)]) )
#plt.plot(regret_at_each_turn, label=type(algorithm).__name__)
best_arm_pulling_percentage_at_each_turn = []
best_arm_pulling_number = 0
for i in range(budget):
pulled_arm_at_turn_i = arm_at_each_turn[i]
if pulled_arm_at_turn_i.p == prob_max:
best_arm_pulling_number += 1
best_arm_pulling_percentage_at_each_turn.append(best_arm_pulling_number / (i + 1))
plt.plot( best_arm_pulling_percentage_at_each_turn, label=type(algorithm).__name__ )
plt.legend()
plt.show()
def permute_and_max( l, perm_seed : int, turn : int, key = lambda x: x ):
permutation = IsolatedPermutation.new(len(l), perm_seed, turn)
permuted_l = permutation.permute(l)
max_index = 0
max_value = key(permuted_l[0])
for i in range(1, len(permuted_l)):
vi = key(permuted_l[i])
if vi > max_value:
max_index = i
max_value = vi
return permuted_l[max_index]
def read_arms_from_file( filename ):
with open(filename) as file:
lines = file.readlines()[1:]
arms_probs = []
for line in lines:
arms_probs.append(float(line))
return arms_probs