-
Notifications
You must be signed in to change notification settings - Fork 0
/
optimizer.py
141 lines (101 loc) · 3.79 KB
/
optimizer.py
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
import random
import math
import utils
from simulation import Simulation
from model import Model
from activity import *
from student import *
from event import *
from model import *
'''
Optimizer
'''
class Optimizer:
def __init__(self, nA):
self.nA = nA
self.history = {}
def nextActivity(self, studentID):
raise Exception('Parent method not implemented')
def submitResult(self, studentID, activityID, result):
raise Exception('Parent method not implemented')
'''
RandomOptimizer
'''
class RandomOptimizer(Optimizer):
def __init__(self, nA):
self.nA = nA
self.history = {}
def nextActivity(self, studentID):
if studentID not in self.history:
self.history[studentID] = set()
available = list(set(range(1, self.nA)) - self.history[studentID])
nextA = random.choice(available) if len(available) > 0 else None
return nextA
def submitResult(self, studentID, activityID, result):
if studentID not in self.history:
self.history[studentID] = set()
if(result == 1):
self.history[studentID].add(activityID)
'''
Bandit Optimizer
'''
class BanditOptimizer(Optimizer):
def __init__(self, nA):
self.nA = nA
self.model = ModelLFA(nA)
for id in range(nA):
self.model.activities[id] = self.model.getActivityModel(id)
self.count = 1
self.activityCounts = [1 for _ in range(self.nA)]
self.fitCount = 2
def nextActivity(self, studentID):
optActivities = [None]
optScore = -10.
state = self.model.students[studentID].getState(None) if studentID in self.model.students else {}
available = [a.id for a in self.model.activities.values() if a.id not in state and a.id != 0]
for activityID in available:
confidence = (2. * math.log(self.count) / self.activityCounts[activityID]) ** 0.5
param = 1. / (1 + math.exp(- self.model.activities[0].params[activityID] - self.model.activities[0].params[-1]))
score = param + confidence
if score > optScore:
optScore = score
optActivities = [ activityID ]
elif score > optScore - 1e-4:
optActivities.append(activityID)
choice = random.choice(optActivities)
return choice
def submitResult(self, studentID, activityID, result):
self.count += 1
self.activityCounts[activityID] += 1
self.model.reportEvent(studentID, activityID, result, self.count, withState=True)
if self.activityCounts[0] > (self.fitCount ** 2.) / 4.:
self.fitCount += 1
self.model.activities[0].fit()
'''
Epsilon Optimizer
'''
class EpsilonOptimizer(Optimizer):
def __init__(self, nA, nS, eps):
self.nA = nA
self.nS = nS
self.eps = eps
self.model = ModelLFA(nA)
for id in range(nA):
self.model.activities[id] = self.model.getActivityModel(id)
self.count = 1
self.studentCount = 0
self.fitted = False
def nextActivity(self, studentID):
state = self.model.students[studentID].getState(None) if studentID in self.model.students else {}
available = [a.id for a in self.model.activities.values() if a.id not in state and a.id != 0]
if not self.fitted:
return random.choice(available)
return self.model.optimalChoice(state)
def submitResult(self, studentID, activityID, result):
self.count += 1
self.model.reportEvent(studentID, activityID, result, self.count, withState=True)
if activityID == 0:
self.studentCount += 1
if not self.fitted and self.studentCount > self.eps:
self.fitted = True
self.model.activities[0].fit()