-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbst.py
More file actions
302 lines (232 loc) · 10.2 KB
/
Copy pathbst.py
File metadata and controls
302 lines (232 loc) · 10.2 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
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# ACT-R tutorial unit6 building sticks experiment.
# This experiment displays three posssible sticks
# which can be used to create a given target stick's
# length. It is an isomorph of Luchins water jug
# problem, and the experiment for the model is the
# one from:
#
# Lovett, M. C., & Anderson, J. R. (1996). History of success
# and current context in problem solving: Combined influences
# on operator selection. Cognitive Psychology, 31, 168-217.
#
# The task is presented with buttons to pick the sticks
# and a button to reset the current trial.
# Import the actr module for tutorial tasks
import actr
# Load the corresponding ACT-R starting model.
actr.load_act_r_model ("ACT-R:tutorial;unit6;bst-model.lisp")
# Global variables to hold the information about the
# current trial information.
target = None
current_stick = None
current_line = None
done = False
choice = None
window = None
visible = False
# The data from the experiment, the lengths of the sticks
# used in the experiment, and two example problems for
# demonstration.
exp_data = [20, 67, 20, 47, 87, 20, 80, 93, 83, 13, 29, 27, 80, 73, 53]
exp_stims = [[15,250,55,125],[10,155,22,101],[14,200,37,112],
[22,200,32,114],[10,243,37,159],[22,175,40,73],
[15,250,49,137],[10,179,32,105],[20,213,42,104],
[14,237,51,116],[12,149,30,72],[14,237,51,121],
[22,200,32,114],[14,200,37,112],[15,250,55,125]]
no_learn_stims = [[15,200,41,103],[10,200,29,132]]
# build_display takes the lengths of the sticks for a trial.
# It sets the global variables and draws the initial interface.
def build_display (a,b,c,goal):
global window,target,current_stick,done,current_line,choice
target = goal
current_stick = 0
done = False
choice = None
current_line = None
window = actr.open_exp_window("Building Sticks Task",visible=visible,width=600,height=400)
# Add buttons for the participant to press in the window.
# The action specifies a command to call and any parameters to pass it
# when that button is pressed. The others describe the details of how
# the button is shown.
actr.add_button_to_exp_window(window, text="A", x=5, y=23, action=["bst-button-pressed",a,"under"], height=24, width=40)
actr.add_button_to_exp_window(window, text="B", x=5, y=48, action=["bst-button-pressed",b,"over"], height=24, width=40)
actr.add_button_to_exp_window(window, text="C", x=5, y=73, action=["bst-button-pressed",c,"under"], height=24, width=40)
actr.add_button_to_exp_window(window, text="Reset", x=5, y=123, action="bst-reset-button-pressed", height=24, width=65)
# Draw the lines for the choices and target.
actr.add_line_to_exp_window(window,[75,35],[a + 75,35],"black")
actr.add_line_to_exp_window(window,[75,60],[b + 75,60],"black")
actr.add_line_to_exp_window(window,[75,85],[c + 75,85],"black")
actr.add_line_to_exp_window(window,[75,110],[goal + 75,110],"green")
# button_pressed will be added as the bst-button-pressed command
# for use as the action of the stick choice buttons. It takes
# a parameter to indicate the length of the stick and whether
# the stick is associated with under or over shoot as a first
# choice.
def button_pressed(len,dir):
global choice,current_stick
# If there is no choice recorded for this trial
# set that to dir.
if not(choice):
choice = dir
# If the trial is not done then add or subtract
# this stick from the target as appropriate and
# call update_current_line to check its length
# and redraw it.
if not(done):
if current_stick > target:
current_stick -= len
else:
current_stick += len
update_current_line()
# reset_display will be added as the bst-reseet-button-pressed
# command for use as the action of the reset buttons. If the
# trial is not over, then it sets the current stick length to 0
# and redraws it.
def reset_display():
global current_stick
if not(done):
current_stick = 0
update_current_line()
# Add the commands for those two functions so they can be
# used as button actions.
actr.add_command("bst-button-pressed",button_pressed,"Choice button action for the Building Sticks Task. Do not call directly")
actr.add_command("bst-reset-button-pressed",reset_display,"Reset button action for the Building Sticks Task. Do not call directly")
# update_current_line compares the length of the current
# stick to the target stick length. If they match the
# the trial is over, it redraws the current line, and
# displays the done prompt. If it is zero it removes the
# line from the display. If there is a current line then
# it is updated to match the current length, and if there
# is not a current line then one is drawn and saved for
# future modification.
def update_current_line():
global current_line,done
if current_stick == target:
done = True
actr.modify_line_for_exp_window(current_line, [75,135], [target + 75,135])
actr.add_text_to_exp_window(window, "Done", x=180, y=200)
elif current_stick == 0:
if current_line:
actr.remove_items_from_exp_window(window,current_line)
current_line = None
elif current_line:
actr.modify_line_for_exp_window(current_line,[75,135],[current_stick + 75,135])
else:
current_line = actr.add_line_to_exp_window(window,[75,135],[current_stick + 75,135],"blue")
# do_experiment takes a required parameter which is
# a list of stick lengths and an optional parameter
# which indicates whether a person is doing the task.
# It draws the initial sticks and then waits for
# a person to complete the task or runs the model
# for up to a minute to do the task.
def do_experiment(sticks, human=False):
build_display(*sticks)
if human:
if actr.visible_virtuals_available():
wait_for_human()
else:
actr.install_device(window)
actr.start_hand_at_mouse()
actr.run(60,visible)
# wait_for_human takes no parameters. It waits for
# a person to finish the task, and then waits one
# more second after the done prompt is displayed to
# give the person a chance to read it.
def wait_for_human ():
while not(done):
actr.process_events()
start = actr.get_time(False)
while (actr.get_time(False) - start) < 1000:
actr.process_events()
# bst_set takes three required parameters and one optional
# parameter. The first parameter indicates whether it
# is a person or the model performing the task, and the
# second indicates whether it should use a visible or
# virtual window. The third parameter is a list of
# stick lengths for the trials to present. The optional
# parameter indicates whether the model should learn from
# trial to trial or be reset before each new trial.
# It returns a list of strings indicating whether each
# trial presented was started with the over-shoot or
# under-shoot approach.
def bst_set(human,vis,stims,learn=True):
global visible
result = []
visible = vis
for stim in stims:
if not(learn) and not(human):
actr.reset()
do_experiment(stim,human)
result.append(choice)
return result
# test is used to run multiple instances of the 2 demo
# problems. It takes one required parameter which indicates
# how many times to run that set of two items, and an optional
# parameter to indicate if it should be a person or model
# doing the task. It returns a list with the counts of the
# times over-shoot was tried on each of the problems.
# When the model runs the task it is not learning, and starts
# each trial as if it were the first time doing the task.
# If the model is running once through the set then it will
# use a visible window to show the interaction, otherwise it
# will use a virtual window.
def test(n,human=False):
l = len(no_learn_stims)
result = [0]*l
if human or (n == 1):
v = True
else:
v = False
for i in range(n):
d = bst_set(human,v,no_learn_stims,False)
for j in range(l):
if d[j] == "over":
result[j] += 1
return result
# experiment is used to run the full experiment multiple
# times and report the results and fit to the experiment data.
# It has a required parameter which indicates how many times
# to run the task, and an optional parameter indicating whether
# it should be a person performing the task.
# It collects the over- or under- shoot choices for each problem
# and computes the proportion of time it's chosen for comparison
# to the original data. It displays the data and its fit to the
# data from the original experiment along with the average utility
# value over the trials for each of the four productions in the
# model which make the choice.
def experiment(n,human=False):
l = len(exp_stims)
result = [0] * l
p_values = [["decide-over",0],["decide-under",0],["force-over",0],["force-under",0]]
for i in range(n):
actr.reset()
d = bst_set(human,human,exp_stims)
for j in range(l):
if d[j] == "over":
result[j] += 1
# Usehide_output to suppress the output from the spp command in Python
actr.hide_output()
for p in p_values:
p[1]+=production_u_value(p[0])
# Use unhide_output to restore model output in Python
actr.unhide_output()
result = list(map(lambda x: 100 * x / n,result))
if len(result) == len(exp_data):
actr.correlation(result,exp_data)
actr.mean_deviation(result,exp_data)
print()
print("Trial ",end="")
for i in range(l):
print("%-8d"%(i + 1),end="")
print()
print(" ",end="")
for i in range(l):
print("%8.2f"%result[i],end="")
print()
print()
for p in p_values:
print("%-12s: %6.4f"%(p[0],p[1]/n))
# production_u_value returns the current :u parameter
# value from the indicated production.
def production_u_value(prod):
return actr.spp(prod,":u")[0][0]