Skip to content

Commit 5663460

Browse files
author
Frankie Robertson
committed
Add item bank to power_summary of RecordedCatLoop
* Clear recorded data on run_cat startup
1 parent cd77e3b commit 5663460

File tree

9 files changed

+121
-51
lines changed

9 files changed

+121
-51
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ DocStringExtensions = " ^0.9"
5050
EffectSizes = "^1.0.1"
5151
ElasticArrays = "1.2.12"
5252
FillArrays = "0.13, 1.5.0"
53-
FittedItemBanks = "^0.7.2"
53+
FittedItemBanks = "^0.7.3"
5454
ForwardDiff = "1"
5555
HypothesisTests = "^0.10.12, ^0.11.0"
5656
Interpolations = "^0.14, ^0.15"
@@ -62,7 +62,7 @@ MacroTools = "^0.5.6"
6262
Mmap = "^1.11"
6363
Optim = "1.7.3"
6464
PrecompileTools = "1.2.1"
65-
PsychometricsBazaarBase = "^0.8.4"
65+
PsychometricsBazaarBase = "^0.8.6"
6666
QuickHeaps = "0.2.2"
6767
Random = "^1.11"
6868
Reexport = "1"

src/Aggregators/Aggregators.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ using FittedItemBanks: AbstractItemBank, ContinuousDomain,
2020
using ..Responses
2121
using ..Responses: concrete_response_type, function_xs, function_ys, Responses
2222
using ..ConfigBase
23+
using PsychometricsBazaarBase: power_summary
2324
using PsychometricsBazaarBase.ConfigTools: @requiresome, @returnsome,
2425
find1_instance, find1_type,
2526
find1_type_sloppy

src/Aggregators/ability_estimator.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function show(io::IO, ::MIME"text/plain", ability_estimator::PosteriorAbilityEst
6565
println(io, "Ability posterior distribution")
6666
indent_io = indent(io, 2)
6767
print(indent_io, "Prior: ")
68-
show(indent_io, MIME("text/plain"), ability_estimator.prior)
68+
power_summary(indent_io, ability_estimator.prior)
6969
println(io)
7070
end
7171

src/Rules.jl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ using ..NextItemRules: NextItemRule
1212
using ..TerminationConditions: TerminationCondition
1313
using ..ConfigBase
1414
import Base: show
15+
import PsychometricsBazaarBase: power_summary
1516

1617
"""
1718
$(TYPEDEF)
@@ -82,12 +83,21 @@ function CatRules(bits...)
8283
end
8384

8485
function show(io::IO, ::MIME"text/plain", rules::CatRules)
86+
power_summary(io, rules; toplevel=true)
87+
end
88+
89+
function power_summary(io::IO, rules::CatRules; toplevel=false)
90+
# TODO
8591
print(io, "Next item rule: ")
8692
show(io, MIME("text/plain"), rules.next_item)
87-
println(io)
93+
if toplevel
94+
println(io)
95+
end
8896
print(io, "Termination condition: ")
8997
show(io, MIME("text/plain"), rules.termination_condition)
90-
println(io)
98+
if toplevel
99+
println(io)
100+
end
91101
print(io, "Ability estimator: ")
92102
show(io, MIME("text/plain"), rules.ability_estimator)
93103
end

src/Sim/Sim.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ module Sim
22

33
using DataFrames: DataFrame
44
using ElasticArrays
5-
using ElasticArrays: sizehint_lastdim!
5+
using ElasticArrays: sizehint_lastdim!, resize_lastdim!
66
using DocStringExtensions
77
using StatsBase
88
using FittedItemBanks: AbstractItemBank, ResponseType, ItemResponse, domdims
9+
using PsychometricsBazaarBase: show_into_buf, power_summary_into_buf
910
using PsychometricsBazaarBase.Integrators
1011
using PsychometricsBazaarBase.IndentWrappers: indent
1112
using ..ConfigBase
@@ -25,6 +26,7 @@ using ..Aggregators: TrackedResponses,
2526
RiemannEnumerationIntegrator
2627
using ..NextItemRules: AbilityVariance, compute_criteria, best_item
2728
import Base: show
29+
import PsychometricsBazaarBase: power_summary
2830

2931
export CatRecorder, CatRecording
3032
export CatLoop, record!

src/Sim/loop.jl

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,40 +24,48 @@ struct CatLoop{CatEngineT} <: CatConfigBase
2424
A callback called each time there is a new responses.
2525
If provided, it is passed `(responses::TrackedResponses, terminating)`.
2626
"""
27-
new_response_callback
27+
new_response_callback::Any
28+
"""
29+
A callback called each time a CAT is run
30+
If provided, it is passed `(item_bank::AbstractItemBank)`.
31+
"""
32+
init_callback::Any
2833
end
2934

3035
function show(io::IO, ::MIME"text/plain", rules::CatLoop)
31-
print(io, "Next item rule: ")
32-
show(io, MIME("text/plain"), rules.next_item)
33-
print(io, "Termination condition: ")
34-
show(io, MIME("text/plain"), rules.termination_condition)
35-
print(io, "Ability estimator: ")
36-
show(io, MIME("text/plain"), rules.ability_estimator)
36+
print(io, "Computer-Adaptive Test Loop based on ")
37+
show(io, MIME("text/plain"), rules.rules)
38+
end
39+
40+
function collate_cat_callbacks(callbacks...)
41+
callbacks = filter(!isnothing, callbacks)
42+
function all_callbacks(args...)
43+
for callback in callbacks
44+
callback(args...)
45+
end
46+
nothing
47+
end
48+
all_callbacks
3749
end
3850

3951
function CatLoop(;
4052
rules,
4153
get_response,
4254
new_response_callback = nothing,
4355
new_response_callbacks = Any[],
56+
init_callback = nothing,
57+
init_callbacks = Any[],
4458
recorder = nothing
4559
)
46-
new_response_callbacks = collect(new_response_callbacks)
47-
if new_response_callback !== nothing
48-
push!(new_response_callbacks, new_response_callback)
49-
end
50-
if recorder !== nothing && showable(MIME("text/plain"), rules)
51-
buf = IOBuffer()
52-
show(buf, MIME("text/plain"), rules)
53-
recorder.recording.rules_description = String(take!(buf))
54-
push!(new_response_callbacks, catrecorder_callback(recorder))
55-
end
56-
function all_callbacks(responses, terminating)
57-
for callback in new_response_callbacks
58-
callback(responses, terminating)
59-
end
60-
nothing
61-
end
62-
CatLoop{typeof(rules)}(rules, get_response, all_callbacks)
63-
end
60+
new_response_callback = collate_cat_callbacks(
61+
new_response_callbacks...,
62+
new_response_callback,
63+
isnothing(recorder) ? nothing : recorder_response_callback(recorder)
64+
)
65+
init_callback = collate_cat_callbacks(
66+
init_callbacks...,
67+
init_callback,
68+
isnothing(recorder) ? nothing : recorder_init_callback(recorder)
69+
)
70+
CatLoop{typeof(rules)}(rules, get_response, new_response_callback, init_callback)
71+
end

src/Sim/recorded_loop.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,8 @@ function run_cat(loop::RecordedCatLoop; ib_labels = nothing)
191191
end
192192
run_cat(loop, loop.item_bank; ib_labels=ib_labels)
193193
end
194+
195+
function show(io::IO, ::MIME"text/plain", loop::RecordedCatLoop)
196+
println(io, "Recorded Computer-Adaptive Test:")
197+
power_summary(io, loop.recorder.recording; skip_first_line=true)
198+
end

src/Sim/recorder.jl

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ Base.@kwdef mutable struct CatRecording{LikelihoodsT <: NamedTuple}
2222
data::LikelihoodsT
2323
item_index::Vector{Int}
2424
item_correctness::Vector{Bool}
25-
rules_description::Union{Nothing, String} = nothing
25+
rules_description::Union{Nothing, IOBuffer} = nothing
26+
item_bank_description::Union{Nothing, IOBuffer} = nothing
2627
end
2728

2829
function Base.getproperty(obj::CatRecording, sym::Symbol)
@@ -67,26 +68,33 @@ function prepare_dataframe(recording::CatRecording)
6768
end
6869

6970
function show(io::IO, ::MIME"text/plain", recording::CatRecording)
70-
println(io, "Recording of a Computer-Adaptive Test")
71-
if recording.rules_description === nothing
71+
power_summary(io, recording; include_cat_config = :always)
72+
end
73+
74+
function power_summary(io::IO, recording::CatRecording; include_cat_config = :always, skip_first_line=false, kwargs...)
75+
if !skip_first_line
76+
println(io, "Recording of a Computer-Adaptive Test")
77+
end
78+
if recording.rules_description === nothing && include_cat_config == :always
7279
println(io, " Unknown CAT configuration")
73-
else
80+
elseif include_cat_config != :never # :available or :always
7481
println(io, " CAT configuration:")
75-
for line in split(strip(recording.rules_description, '\n'), "\n")
76-
println(io, " ", line)
77-
end
82+
write(indent(io, 4), recording.rules_description)
83+
seekstart(recording.rules_description)
84+
println(io)
85+
end
86+
if recording.item_bank_description === nothing
87+
println(io, " Unknown item bank")
88+
else
89+
println(io, " Item bank:")
90+
write(indent(io, 4), recording.item_bank_description)
91+
seekstart(recording.item_bank_description)
92+
println(io)
7893
end
79-
println(io)
8094
println(io, " Recorded information:")
8195
df = prepare_dataframe(recording)
82-
buf = IOBuffer()
83-
show(buf, MIME("text/plain"), df; summary=false, eltypes=false, rowlabel=:Number)
84-
seekstart(buf)
85-
for line in eachline(buf)
86-
println(io, " ", line)
87-
end
88-
#println(io)
89-
#println(io, " Final information:")
96+
buf = show_into_buf(df; summary = false, eltypes = false, rowlabel = :Number)
97+
write(indent(io, 4), buf)
9098
end
9199

92100
#=
@@ -132,6 +140,18 @@ function record!(recording::CatRecording, responses; data...)
132140
push!(recording.item_correctness, item_correct)
133141
end
134142

143+
function Base.empty!(recording::CatRecording)
144+
empty!(recording.item_index)
145+
empty!(recording.item_correctness)
146+
for (name, value) in pairs(recording.data)
147+
if value.data isa AbstractVector
148+
empty!(value.data)
149+
elseif value.data isa ElasticArray
150+
resize_lastdim!(value.data, 0)
151+
end
152+
end
153+
end
154+
135155
#=
136156
"""
137157
$(TYPEDSIGNATURES)
@@ -402,6 +422,27 @@ function record!(recorder::CatRecorder, tracked_responses)
402422
record!(recorder.recording, tracked_responses.responses)
403423
end
404424

405-
function catrecorder_callback(recoder::CatRecorder)
406-
return (tracked_responses, _) -> record!(recoder, tracked_responses)
425+
function recorder_response_callback(recorder::CatRecorder)
426+
return (tracked_responses, _) -> record!(recorder, tracked_responses)
427+
end
428+
429+
function recorder_init_callback(recorder::CatRecorder)
430+
return function (cat_loop, item_bank)
431+
empty!(recorder.recording)
432+
if showable(MIME("text/plain"), cat_loop.rules)
433+
recorder.recording.rules_description = power_summary_into_buf(cat_loop.rules; toplevel=false)
434+
end
435+
if showable(MIME("text/plain"), item_bank)
436+
recorder.recording.item_bank_description = power_summary_into_buf(item_bank)
437+
end
438+
end
439+
end
440+
441+
function show(io::IO, ::MIME"text/plain", recorder::CatRecorder)
442+
indent_io = indent(io, 4)
443+
println(io, "Computer-Adaptive Test Recorder")
444+
println(io, " Requests:")
445+
show(indent_io, MIME"text/plain", recorder.requests)
446+
println(io, " Recording:")
447+
show(indent_io, MIME"text/plain", recorder.recording)
407448
end

src/Sim/run.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ If `ib_labels` is not given, default labels of the form
4343
function run_cat(loop::CatLoop{RulesT},
4444
item_bank::AbstractItemBank;
4545
ib_labels = nothing) where {RulesT <: CatRules}
46-
(; rules, get_response, new_response_callback) = loop
46+
(; rules, get_response, new_response_callback, init_callback) = loop
47+
if init_callback !== nothing
48+
init_callback(loop, item_bank)
49+
end
4750
(; next_item, termination_condition, ability_estimator, ability_tracker) = rules
4851
responses = TrackedResponses(BareResponses(ResponseType(item_bank)),
4952
item_bank,
@@ -81,4 +84,4 @@ function run_cat(loop::CatLoop{RulesT},
8184
end
8285
end
8386
(responses.responses, ability_estimator(responses))
84-
end
87+
end

0 commit comments

Comments
 (0)