Skip to content

Commit 42a085b

Browse files
author
Frankie Robertson
committed
Refactor next item rules including adding pointwise utils and switch
tests away from xunit
1 parent 1998aa0 commit 42a085b

19 files changed

+261
-206
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ LogarithmicNumbers = "1"
5252
MacroTools = "^0.5.6"
5353
Measurements = "^2.10.0"
5454
OrderedCollections = "^1.6"
55-
PsychometricsBazaarBase = "^0.8.0"
55+
PsychometricsBazaarBase = "^0.8.1"
5656
Reexport = "1"
5757
Setfield = "^1"
5858
StaticArrays = "1"

src/TerminationConditions.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ function (condition::SimpleFunctionTerminationCondition)(responses::TrackedRespo
4141
end
4242

4343
struct RunForeverTerminationCondition <: TerminationCondition end
44-
function (condition::RunForeverTerminationCondition)(responses::TrackedResponses,
45-
items::AbstractItemBank)
44+
function (condition::RunForeverTerminationCondition)(::TrackedResponses, ::AbstractItemBank)
4645
return false
4746
end
4847

src/next_item_rules/NextItemRules.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export MatrixScalarizer, DeterminantScalarizer, TraceScalarizer
4747
export AbilityCovarianceStateMultiCriterion, StateMultiCriterion, ItemMultiCriterion
4848
export InformationMatrixCriteria
4949
export ScalarizedStateCriteron, ScalarizedItemCriteron
50+
export DRuleItemCriterion, TRuleItemCriterion
5051

5152
# Prelude
5253
include("./prelude/abstract.jl")
@@ -61,15 +62,18 @@ include("./strategies/exhaustive.jl")
6162
# Combinators
6263
include("./combinators/expectation.jl")
6364
include("./combinators/scalarizers.jl")
65+
include("./combinators/likelihood.jl")
6466

6567
# Criteria
6668
include("./criteria/item/information_special.jl")
6769
include("./criteria/item/information_support.jl")
6870
include("./criteria/item/information.jl")
6971
include("./criteria/item/urry.jl")
7072
include("./criteria/state/ability_variance.jl")
73+
include("./criteria/pointwise/kl.jl")
7174

7275
# Porcelain
76+
include("./porcelain/porcelain.jl")
7377
include("./porcelain/aliases.jl")
7478

7579
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
struct LikelihoodWeightedItemCriterion{
2+
PointwiseItemCriterionT <: PointwiseItemCriterion,
3+
AbilityIntegratorT <: AbilityIntegrator,
4+
AbilityEstimatorT <: DistributionAbilityEstimator
5+
} <: ItemCriterion
6+
criterion::PointwiseItemCriterionT
7+
integrator::AbilityIntegratorT
8+
estimator::AbilityEstimatorT
9+
end
10+
11+
function compute_criterion(
12+
lwic::LikelihoodWeightedItemCriterion,
13+
tracked_responses::TrackedResponses,
14+
item_idx
15+
)
16+
func = FunctionProduct(
17+
pdf(lwic.estimator, tracked_responses), lwic.criterion(tracked_responses, item_idx))
18+
lwic.integrator(func, 0, lwic.estimator, tracked_responses)
19+
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function kl(item_response::ItemResponse, r0, theta)
2+
r = resp_vec(item_response, theta)
3+
resp = 0.0
4+
for (p0, p) in zip(r0, r)
5+
resp += p0 * (log(p0) - log(p))
6+
end
7+
return resp
8+
end
9+
10+
struct PosteriorExpectedKLInformationItemCriterion{
11+
PointEstimatorT <: PointAbilityEstimator,
12+
DistributionEstimatorT <: DistributionAbilityEstimator,
13+
IntegratorT <: AbilityIntegrator
14+
} <: PointwiseItemCriterion
15+
end
16+
17+
function PosteriorExpectedKLInformationItemCriterion(bits...)
18+
@requiresome point_estimator = PointAbilityEstimator(bits...)
19+
@requiresome distribution_estimator = DistributionAbilityEstimator(bits...)
20+
@requiresome integrator = AbilityIntegrator(bits...)
21+
PosteriorExpectedKLInformationItemCriterion(
22+
point_estimator, distribution_estimator, integrator)
23+
end
24+
25+
function compute_pointwise_criterion(
26+
item_criterion::PosteriorExpectedKLInformationItemCriterion,
27+
tracked_responses::TrackedResponses,
28+
item_idx)
29+
theta_0 = maybe_tracked_ability_estimate(tracked_responses,
30+
item_criterion.point_estimator)
31+
item_response = ItemResponse(tracked_responses.item_bank, item_idx)
32+
r0 = resp_vec(item_response, theta_0)
33+
expectation(
34+
theta -> kl(item_response, r0, theta),
35+
item_criterion.integrator,
36+
item_criterion.distribution_estimator,
37+
tracked_responses)
38+
end

src/next_item_rules/criteria/state/ability_variance.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ function _get_dist_est_and_integrator(bits...)
1818
# XXX: Weakness in this initialisation system is showing now
1919
# This needs ot be explicitly passed dist_est and integrator, but this may
2020
# be burried within a MeanAbilityEstimator
21-
@returnsome find1_instance(AbilityVarianceStateCriterion, bits)
2221
dist_est = DistributionAbilityEstimator(bits...)
2322
integrator = AbilityIntegrator(bits...)
2423
if dist_est !== nothing && integrator !== nothing
@@ -27,12 +26,14 @@ function _get_dist_est_and_integrator(bits...)
2726
# So let's just handle this case individually for now
2827
# (Is this going to cause a problem with this being picked over something more appropriate?)
2928
@requiresome mean_ability_est = MeanAbilityEstimator(bits...)
30-
return (dist_est, integrator)
29+
return (mean_ability_est.dist_est, mean_ability_est.integrator)
3130
end
3231

3332
function AbilityVarianceStateCriterion(bits...)
3433
skip_zero = false
35-
@requiresome (dist_est, integrator) = _get_dist_est_and_integrator(bits...)
34+
@returnsome find1_instance(AbilityVarianceStateCriterion, bits)
35+
@requiresome dist_est_integrator_pair = _get_dist_est_and_integrator(bits...)
36+
(dist_est, integrator) = dist_est_integrator_pair
3637
return AbilityVarianceStateCriterion(dist_est, integrator, skip_zero)
3738
end
3839

src/next_item_rules/porcelain/aliases.jl

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,8 @@ const mirtcat_next_item_aliases = Dict(
4141
"MEPV" => _mirtcat_helper((bits, ability_estimator) -> ExpectationBasedItemCriterion(
4242
ability_estimator,
4343
AbilityVarianceStateCriterion(bits...))),
44-
"Drule" => _mirtcat_helper((bits, ability_estimator) -> ScalarizedItemCriteron(
45-
InformationMatrixCriteria(ability_estimator),
46-
DeterminantScalarizer())),
47-
"Trule" => _mirtcat_helper((bits, ability_estimator) -> ScalarizedItemCriteron(
48-
InformationMatrixCriteria(ability_estimator),
49-
TraceScalarizer()))
44+
"Drule" => _mirtcat_helper((bits, ability_estimator) -> DRuleItemCriteron(ability_estimator)),
45+
"Trule" => _mirtcat_helper((bits, ability_estimator) -> TRuleItemCriteron(ability_estimator))
5046
)
5147

5248
# 'MLWI' for maximum likelihood weighted information
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
1+
function DRuleItemCriterion(ability_estimator)
2+
ScalarizedItemCriteron(
3+
InformationMatrixCriteria(ability_estimator),
4+
DeterminantScalarizer())
5+
end
16

7+
function TRuleItemCriterion(ability_estimator)
8+
ScalarizedItemCriteron(
9+
InformationMatrixCriteria(ability_estimator),
10+
TraceScalarizer())
11+
end

test/Project.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ PsychometricsBazaarBase = "b0d9cada-d963-45e9-a4c6-4746243987f1"
1111
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1212
ResumableFunctions = "c5292f4c-5179-55e1-98c5-05642aab7184"
1313
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
14-
XUnit = "3e3c03f2-1a94-11e9-2981-050a4ca824ab"
1514

1615
[compat]
1716
Aqua = "0.5.5, 0.6.5"

test/ability_estimator_1d.jl

Lines changed: 53 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -38,64 +38,67 @@ map_1d = ModeAbilityEstimator(pa_est_1d, optimizer_1d)
3838
mle_mean_1d = MeanAbilityEstimator(lh_est_1d, integrator_1d)
3939
mle_mode_1d = ModeAbilityEstimator(lh_est_1d, optimizer_1d)
4040

41-
@testcase "Estimator: single dim MAP" begin
42-
@test map_1d(tracked_responses_1d)1.0 atol=0.001
43-
end
41+
@testset "abilest_1d" begin
42+
@testset "Estimator: single dim MAP" begin
43+
@test map_1d(tracked_responses_1d)1.0 atol=0.001
44+
end
4445

45-
@testcase "Estimator: single dim EAP" begin
46-
@test eap_1d(tracked_responses_1d)1.0 atol=0.001
47-
end
46+
@testset "Estimator: single dim EAP" begin
47+
@test eap_1d(tracked_responses_1d)1.0 atol=0.001
48+
end
4849

49-
@testcase "Estimator: single mle mean" begin
50-
@test mle_mean_1d(tracked_responses_1d)1.0 atol=0.001
51-
end
50+
@testset "Estimator: single mle mean" begin
51+
@test mle_mean_1d(tracked_responses_1d)1.0 atol=0.001
52+
end
5253

53-
@testcase "Estimator: single mle mode" begin
54-
@test mle_mode_1d(tracked_responses_1d)1.0 atol=0.001
55-
end
54+
@testset "Estimator: single mle mode" begin
55+
@test mle_mode_1d(tracked_responses_1d)1.0 atol=0.001
56+
end
5657

57-
information_item_criterion = InformationItemCriterion(mle_mean_1d)
58+
information_item_criterion = InformationItemCriterion(mle_mean_1d)
5859

59-
@testcase "1 dim neg information smaller closer to current estimate" begin
60-
@test (
61-
compute_criterion(information_item_criterion, tracked_responses_1d, 5) <
62-
compute_criterion(information_item_criterion, tracked_responses_1d, 6)
63-
)
64-
end
60+
@testset "1 dim neg information smaller closer to current estimate" begin
61+
@test (
62+
compute_criterion(information_item_criterion, tracked_responses_1d, 5) <
63+
compute_criterion(information_item_criterion, tracked_responses_1d, 6)
64+
)
65+
end
6566

66-
@testcase "1 dim neg information smaller with igher discrimination" begin
67-
@test (
68-
compute_criterion(information_item_criterion, tracked_responses_1d, 7) <
69-
compute_criterion(information_item_criterion, tracked_responses_1d, 5) <
70-
compute_criterion(information_item_criterion, tracked_responses_1d, 8)
71-
)
72-
end
73-
74-
ability_variance_state_criterion = AbilityVarianceStateCriterion(lh_est_1d, integrator_1d)
75-
ability_variance_item_criterion = ExpectationBasedItemCriterion(
76-
mle_mean_1d,
77-
ability_variance_state_criterion
78-
)
67+
@testset "1 dim neg information smaller with igher discrimination" begin
68+
@test (
69+
compute_criterion(information_item_criterion, tracked_responses_1d, 7) <
70+
compute_criterion(information_item_criterion, tracked_responses_1d, 5) <
71+
compute_criterion(information_item_criterion, tracked_responses_1d, 8)
72+
)
73+
end
7974

80-
@testcase "postposterior 1 dim variance smaller closer to current estimate" begin
81-
@test (
82-
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 5) <
83-
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 6)
75+
ability_variance_state_criterion = AbilityVarianceStateCriterion(
76+
lh_est_1d, integrator_1d)
77+
ability_variance_item_criterion = ExpectationBasedItemCriterion(
78+
mle_mean_1d,
79+
ability_variance_state_criterion
8480
)
85-
end
8681

87-
@testcase "postposterior 1 dim variance smaller with higher discrimination" begin
88-
@test (
89-
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 7) <
90-
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 5) <
91-
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 8)
92-
)
93-
end
82+
@testset "postposterior 1 dim variance smaller closer to current estimate" begin
83+
@test (
84+
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 5) <
85+
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 6)
86+
)
87+
end
88+
89+
@testset "postposterior 1 dim variance smaller with higher discrimination" begin
90+
@test (
91+
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 7) <
92+
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 5) <
93+
compute_criterion(ability_variance_item_criterion, tracked_responses_1d, 8)
94+
)
95+
end
9496

95-
@testcase "1 dim variance decreases with new responses" begin
96-
orig_var = compute_criterion(ability_variance_state_criterion, tracked_responses_1d)
97-
next_responses = deepcopy(tracked_responses_1d)
98-
add_response!(next_responses, Response(ResponseType(item_bank_1d), 5, 0))
99-
new_var = compute_criterion(ability_variance_state_criterion, next_responses)
100-
@test new_var < orig_var
97+
@testset "1 dim variance decreases with new responses" begin
98+
orig_var = compute_criterion(ability_variance_state_criterion, tracked_responses_1d)
99+
next_responses = deepcopy(tracked_responses_1d)
100+
add_response!(next_responses, Response(ResponseType(item_bank_1d), 5, 0))
101+
new_var = compute_criterion(ability_variance_state_criterion, next_responses)
102+
@test new_var < orig_var
103+
end
101104
end

0 commit comments

Comments
 (0)