-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsimLearning.jl
More file actions
141 lines (131 loc) · 4.84 KB
/
simLearning.jl
File metadata and controls
141 lines (131 loc) · 4.84 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
# Simulates learning from a random initial state across many repetitions
#
# Call the script as
#
# simLearning.jl configfile model N [α] [fromrep-torep]
#
# where conf/configfile.ini is the configuation file, model is the learning model,
# and N is the input dimensionality. α is the optional learning rate (only required
# for certain models). If [fromrep-torep] is provided, only the specified
# repetitions are performed, and the filename contains torep.
#
# The function simulates a certain number of trials across many repetisions, and
# writes the output to
#
# data/learning_configfile_model_N[_α][_fromrep].csv
using ProgressMeter
include("common.jl")
include("models.jl")
# parse command line arguments
function parseargs()
length(ARGS) ∈ (3, 4, 5) || error("Expected three to five arguments")
conffile = ARGS[1]
modelname = ARGS[2]
N = parse(Int64, ARGS[3])
α = nothing
fromrep = nothing
torep = nothing
if length(ARGS) == 4
m = match(r"^(\d+)-(\d+)", ARGS[4])
if m == nothing
α = parse(Float64, ARGS[4])
else
fromrep = parse(Int64, m.captures[1])
torep = parse(Int64, m.captures[2])
end
elseif length(ARGS) == 5
α = parse(Float64, ARGS[4])
m = match(r"^(\d+)-(\d+)", ARGS[5])
if m == nothing
error("Expected fifth argument of form fromrep-torep")
end
fromrep = parse(Int64, m.captures[1])
torep = parse(Int64, m.captures[2])
end
return conffile, modelname, N, α, fromrep, torep
end
# read configuration file
function readconf(conffile, modelname, N, α)
conf = ConfParse("conf/$(conffile).ini")
parse_conf!(conf)
task = createtask(conf)
diffstats = readdiffstats(conf, N)
model = createmodel(conf, modelname, N, α)
inputs = createinputs(conf, task, N)
trials = parse(Int64, retrieve(conf, "simlearning", "trials"))
repetitions = parse(Int64, retrieve(conf, "simlearning", "repetitions"))
return task, diffstats, model, inputs, trials, repetitions
end
# runs single repetition, i.e. sequence of trials
function runrep(task, diffstats, model, inputs, trials)
σμ = getσμ(task)
withdiff = diffstats != nothing
# resample w and get μ-independent input statistics
samplew!(inputs)
μxprime = getμxprime(inputs)
trueI = dot(μxprime, getΣx(inputs) \ μxprime)
# reset/initialize model
reset!(model, wmoments(inputs)..., getw(inputs))
# run 'trials' trials and collect response statistics
df = DataFrame(trial=Int64[], μ=Float64[], choice=Int64[], t=Float64[],
EPC=Float64[], EDT=Float64[], Eperf=Float64[],
trueI=Float64[], modelI=Float64[], angerr=Float64[])
for trial = 1:trials
# draw latent state, simulate model choice, and provide model feedback
μ = drawμ(task)
choice, t, x = simdiffusion(getw(model), getμx(inputs, μ), getΣx(inputs), task.θ)
w = feedback!(model, μ > 0 ? 1 : -1, t, x, getw(inputs))
# collect statistics
EPC, EDT = avgperf(inputs, task, w)
Eperf = taskperf(task, EPC, EDT)
angerr = getangerr(inputs, w)
modelI = getIloss(inputs, w)
push!(df, [trial, μ, choice, t, EPC, EDT, Eperf, trueI, modelI, angerr])
# diffuse model and state
if withdiff
diffuse!(inputs, diffstats...)
diffuse!(model)
end
end
return df
end
# collect data across multiple repetitions
function runsim(task, diffstats, model, inputs, trials, fromrep, torep, verbose::Bool=false)
# first run is separate
if verbose
p = Progress(torep-fromrep+1, 1, "Simulating...")
end
df = runrep(task, diffstats, model, inputs, trials)
df[:repetition] = 1
!verbose || next!(p)
# others are in loop
for repetition = (fromrep+1):torep
dfrep = runrep(task, diffstats, model, inputs, trials)
dfrep[:repetition] = repetition
append!(df, dfrep)
!verbose || next!(p)
end
return df
end
# main
conffile, modelname, N, α, fromrep, torep = parseargs()
hasreprange = fromrep != nothing
task, diffstats, model, inputs, trials, repetitions = readconf(conffile, modelname, N, α)
if !hasreprange
fromrep = 1
torep = repetitions
end
print("Running simulations for conf $(conffile), model $(modelname), N=$(N), rep=$(fromrep)-$(torep)")
!requiresα(modelname) || print(", α=$(@sprintf("%.2f", α))")
println()
#df = runsim(task, model, inputs, trials, 2, true)
#@profile df = runsim(task, diffstats, model, inputs, trials, repetitions, true)
#Profile.print()
df = runsim(task, diffstats, model, inputs, trials, fromrep, torep, true)
fnα = requiresα(modelname) ? @sprintf("_%.2f", α) : ""
datafile = "data/learning_$(conffile)_$(modelname)_$(N)$(fnα)"
if hasreprange
writecompressedtable(datafile, df, fromrep)
else
writecompressedtable(datafile, df)
end