-
Notifications
You must be signed in to change notification settings - Fork 9
/
ordering.py
201 lines (138 loc) · 6.53 KB
/
ordering.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
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import collections
def frequency(target_items):
"""
Orders the learning of items based purely on frequency. Targets ordered by
when they are achieved.
The input `target_items` is a dictionary mapping targets to the
prerequisite items.
This is a generator that yields the target along with a set of the items
for that target that have not yet been seen (plus any others of higher
frequency, even if they aren't needed by the target)
"""
# a dictionary mapping targets to a set of items still not learnt
MISSING_IN_TARGET = {}
# a dictionary mapping items to a set of targets the items are needed for
# and are missing from
TARGETS_MISSING = collections.defaultdict(set)
c = collections.Counter()
for target, items in target_items.items():
c.update(items)
MISSING_IN_TARGET[target] = set(items)
for item in items:
TARGETS_MISSING[item].add(target)
ITEMS_TO_LEARN = set()
for next_item, count in c.most_common():
ITEMS_TO_LEARN.add(next_item)
# for each target missing that item, remove the item
for target in TARGETS_MISSING[next_item]:
MISSING_IN_TARGET[target].remove(next_item)
# if the target is now missing no items...
if len(MISSING_IN_TARGET[target]) == 0:
yield target, ITEMS_TO_LEARN
# remove from missing in that target
del MISSING_IN_TARGET[target]
# reset items to learn
ITEMS_TO_LEARN = set()
# remove the item from all targets requiring it
del TARGETS_MISSING[next_item]
def frequency_optimised(target_items):
"""
Orders the learning of targets by firstly ordering items by frequency but
then only requiring learning of those items required by the targets
achievable by the frequency ordering.
The input `target_items` is a dictionary mapping targets to the
prerequisite items.
This is a generator that yields the target along with a set of the items
for that target that have not yet been seen.
"""
# track the set of all items already learnt
ALREADY_LEARNT = set()
# a dictionary mapping targets to the set of prerequisite items
IN_TARGET = {}
# a dictionary mapping targets to a set of items still not learnt
MISSING_IN_TARGET = {}
# a dictionary mapping items to a set of targets the items are needed for
# and are missing from
TARGETS_MISSING = collections.defaultdict(set)
c = collections.Counter()
for target, items in target_items.items():
c.update(items)
IN_TARGET[target] = set(items)
MISSING_IN_TARGET[target] = set(items)
for item in items:
TARGETS_MISSING[item].add(target)
for next_item, count in c.most_common():
# for each target missing that item, remove the item
for target in TARGETS_MISSING[next_item]:
MISSING_IN_TARGET[target].remove(next_item)
# if the target is now missing no items...
if len(MISSING_IN_TARGET[target]) == 0:
# calculate what is new to learn for that target
items_to_learn = IN_TARGET[target] - ALREADY_LEARNT
yield target, items_to_learn
# remove from missing in that target
del MISSING_IN_TARGET[target]
# add to items already learnt
ALREADY_LEARNT.update(items_to_learn)
# remove the item from all targets requiring it
del TARGETS_MISSING[next_item]
def next_best(target_items):
"""
Orders the learning of targets based on, at each step, assigning a score to
each unknown item and prioritising the highest scoring item next before
recalculating the scores all over again with the remaining items.
The score is currently the sum of
1 / 2 ** number_of_items_missing_from_target
for each target in which the item is missing.
Therefore, at each step, it favours a next item that is the only missing
item (or one of only a few missing items) from lots of targets.
Once all the prerequisite items in a target have come up as the next item,
that target is yielded along with a set of the items for that target that
have not yet been seen.
The input `target_items` is a dictionary mapping targets to the
prerequisite items.
"""
# track the set of all items already learnt
ALREADY_LEARNT = set()
# a dictionary mapping targets to the set of prerequisite items
IN_TARGET = {}
# a dictionary mapping targets to a set of items still not learnt
MISSING_IN_TARGET = {}
# a dictionary mapping items to a set of targets the items are needed for
# and are missing from
TARGETS_MISSING = collections.defaultdict(set)
## fill the dictionaries with initial data based on the input
for target, items in target_items.items():
IN_TARGET[target] = set(items)
MISSING_IN_TARGET[target] = set(items)
for item in items:
TARGETS_MISSING[item].add(target)
while True:
# for each item, a score of how bad it is that it is missing
MISSING_ITEMS = collections.defaultdict(int)
for missing in MISSING_IN_TARGET.values():
for item in missing:
# if item is only missing item for a target, add 1/2 to its score
# if item is 1 of 2 missing items for a target, add 1/4
# if item is 1 of 3 missing items for a target, add 1/8
# and so on...
MISSING_ITEMS[item] += 1. / (2 ** len(missing))
# stop if there are no missing items
if not MISSING_ITEMS:
break
# otherwise the next item to learn is the one with the highest score
next_item = sorted(MISSING_ITEMS, key=MISSING_ITEMS.get)[-1]
# for each target missing that item, remove the item
for target in TARGETS_MISSING[next_item]:
MISSING_IN_TARGET[target].remove(next_item)
# if the target is now missing no items...
if len(MISSING_IN_TARGET[target]) == 0:
# calculate what is new to learn for that target
items_to_learn = IN_TARGET[target] - ALREADY_LEARNT
yield target, items_to_learn
# remove from missing in that target
del MISSING_IN_TARGET[target]
# add to items already learnt
ALREADY_LEARNT.update(items_to_learn)
# remove the item from all targets requiring it
del TARGETS_MISSING[next_item]