From d12d24ca0cc93bf787c34f3dfc33387ebcd9a21f Mon Sep 17 00:00:00 2001 From: Samuel Brand <48288458+SamuelBrand1@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:34:48 +0000 Subject: [PATCH] add and fix unit tests --- pipeline/test/constructors/constructors.jl | 175 +++++++++++++++++ .../test/constructors/remake_latent_model.jl | 56 ++++++ .../test/constructors/test_constructors.jl | 177 +----------------- pipeline/test/forecast/test_forecast.jl | 5 +- pipeline/test/infer/test_InferenceConfig.jl | 4 +- pipeline/test/infer/test_define_epiprob.jl | 4 +- 6 files changed, 240 insertions(+), 181 deletions(-) create mode 100644 pipeline/test/constructors/constructors.jl create mode 100644 pipeline/test/constructors/remake_latent_model.jl diff --git a/pipeline/test/constructors/constructors.jl b/pipeline/test/constructors/constructors.jl new file mode 100644 index 000000000..f97fa8265 --- /dev/null +++ b/pipeline/test/constructors/constructors.jl @@ -0,0 +1,175 @@ +@testset "make_gi_params: returns a dictionary with correct keys" begin + pipeline = EpiAwareExamplePipeline() + params = make_gi_params(pipeline) + + @test params isa Dict + @test haskey(params, "gi_means") + @test haskey(params, "gi_stds") +end + +@testset "make_inf_generating_processes" begin + pipeline = EpiAwareExamplePipeline() + igps = make_inf_generating_processes(pipeline) + @test igps == [DirectInfections, ExpGrowthRate, Renewal] +end + +@testset "make_Rt: returns an array" begin + map([EpiAwareExamplePipeline(), SmoothOutbreakPipeline(), + MeasuresOutbreakPipeline(), SmoothEndemicPipeline(), RoughEndemicPipeline()]) do pipeline + Rt = make_Rt(pipeline) + @test Rt isa Array + end +end + +@testset "default_tspan: returns an Tuple{Integer, Integer}" begin + pipeline = EpiAwareExamplePipeline() + + tspan = make_tspan(pipeline; lookback = 90) + @test tspan isa Tuple{Integer, Integer} +end + +@testset "make_model_priors: generates a dict with correct keys and distributions" begin + using Distributions + pipeline = EpiAwareExamplePipeline() + + priors_dict = make_model_priors(pipeline) + + # Check if the priors dictionary is constructed correctly + @test haskey(priors_dict, "transformed_process_init_prior") + @test haskey(priors_dict, "std_prior") + @test haskey(priors_dict, "damp_param_prior") + + # Check if the values are all distributions + @test valtype(priors_dict) <: Distribution +end + +@testset "make_epiaware_name_latentmodel_pairs: generates a vector of Pairs with correct keys and latent models" begin + pipeline = EpiAwareExamplePipeline() + + namemodel_vect = make_epiaware_name_latentmodel_pairs(pipeline) + + @test first.(namemodel_vect) == ["ar", "rw", "diff_ar"] + @test all([model isa AbstractTuringLatentModel for model in last.(namemodel_vect)]) +end + +@testset "make_inference_method: constructor and defaults" begin + using ADTypes, AbstractMCMC + pipeline = EpiAwareExamplePipeline() + + method = make_inference_method(pipeline) + + @test length(method.pre_sampler_steps) == 1 + @test method.pre_sampler_steps[1] isa ManyPathfinder + @test method.pre_sampler_steps[1].nruns == 4 + @test method.pre_sampler_steps[1].maxiters == 100 + @test method.sampler isa NUTSampler + @test method.sampler.adtype isa AbstractADType + @test method.sampler.ndraws == 20 + @test method.sampler.nchains == 4 + @test method.sampler.mcmc_parallel == MCMCThreads() +end + +@testset "make_inference_method: for prior predictive checking" begin + using EpiAwarePipeline, EpiAware, ADTypes, AbstractMCMC + pipetype = [SmoothOutbreakPipeline, MeasuresOutbreakPipeline, + SmoothEndemicPipeline, RoughEndemicPipeline] |> rand + pipeline = pipetype(; ndraws = 100, testmode = true, priorpredictive = true) + + method = make_inference_method(pipeline) + + @test length(method.pre_sampler_steps) == 0 + @test method.sampler isa DirectSample +end + +@testset "make_truth_data_configs" begin + pipeline = SmoothOutbreakPipeline() + example_pipeline = EpiAwareExamplePipeline() + @testset "make_truth_data_configs should return a dictionary" begin + config_dicts = make_truth_data_configs(pipeline) + @test eltype(config_dicts) <: Dict + end + + @testset "make_truth_data_configs should contain gi_mean and gi_std keys" begin + config_dicts = make_truth_data_configs(pipeline) + @test all(config_dicts .|> config -> haskey(config, "gi_mean")) + @test all(config_dicts .|> config -> haskey(config, "gi_std")) + end + + @testset "make_truth_data_configs should return a vector of length 1 for EpiAwareExamplePipeline" begin + config_dicts = make_truth_data_configs(example_pipeline) + @test length(config_dicts) == 1 + end +end + +@testset "default inference configurations" begin + pipeline = SmoothOutbreakPipeline() + example_pipeline = EpiAwareExamplePipeline() + + @testset "make_inference_configs should return a vector of dictionaries" begin + inference_configs = make_inference_configs(pipeline) + @test eltype(inference_configs) <: Dict + end + + @testset "make_inference_configs should contain igp, latent_namemodels, observation_model, gi_mean, gi_std, and log_I0_prior keys" begin + inference_configs = make_inference_configs(pipeline) + @test inference_configs .|> (config -> haskey(config, "igp")) |> all + @test inference_configs .|> (config -> haskey(config, "latent_namemodels")) |> all + @test inference_configs .|> (config -> haskey(config, "observation_model")) |> all + @test inference_configs .|> (config -> haskey(config, "gi_mean")) |> all + @test inference_configs .|> (config -> haskey(config, "gi_std")) |> all + @test inference_configs .|> (config -> haskey(config, "log_I0_prior")) |> all + end + + @testset "make_inference_configs should return a vector of length 1 for EpiAwareExamplePipeline" begin + inference_configs = make_inference_configs(example_pipeline) + @test length(inference_configs) == 1 + end +end + +@testset "make_default_params" begin + pipeline = SmoothOutbreakPipeline() + + # Expected default parameters + expected_params = Dict( + "Rt" => make_Rt(pipeline), + "logit_daily_ascertainment" => [zeros(5); -0.5 * ones(2)], + "cluster_factor" => 0.05, + "I0" => 100.0, + "α_delay" => 4.0, + "θ_delay" => 5.0 / 4.0, + "lookahead" => 21, + "lookback" => 90, + "stride" => 7 + ) + + # Test the make_default_params function + @test make_default_params(pipeline) == expected_params +end + +@testset "make_delay_distribution" begin + using Distributions + pipeline = SmoothOutbreakPipeline() + delay_distribution = make_delay_distribution(pipeline) + @test delay_distribution isa Distribution + @test delay_distribution isa Gamma + @test delay_distribution.α == 4.0 + @test delay_distribution.θ == 5.0 / 4.0 +end + +@testset "make_observation_model" begin + # Mock pipeline object + pipeline = SmoothOutbreakPipeline() + default_params = make_default_params(pipeline) + obs = make_observation_model(pipeline) + + # Test case 1: Check if the returned object is of type LatentDelay + @testset "Returned object type" begin + @test obs isa LatentDelay + end + + # Test case 2: Check if the default parameters are correctly passed to ascertainment_dayofweek + @testset "Default parameters" begin + @test obs.model.model.cluster_factor_prior == + HalfNormal(default_params["cluster_factor"]) + end +end diff --git a/pipeline/test/constructors/remake_latent_model.jl b/pipeline/test/constructors/remake_latent_model.jl new file mode 100644 index 000000000..305eb9543 --- /dev/null +++ b/pipeline/test/constructors/remake_latent_model.jl @@ -0,0 +1,56 @@ +@testset "remake_latent_model tests" begin + struct MockPipeline <: AbstractRtwithoutRenewalPipeline end + function make_model_priors(pipeline::MockPipeline) + return Dict( + "damp_param_prior" => Beta(2, 8), + "transformed_process_init_prior" => Normal(0, 1) + ) + end + pipeline = MockPipeline() + + @testset "diff_ar model" begin + inference_config = Dict( + "igp" => ExpGrowthRate, "latent_namemodels" => ("diff_ar" => "diff_ar")) + model = remake_latent_model(inference_config, pipeline) + @test model isa DiffLatentModel + @test model.model isa AR + + inference_config = Dict( + "igp" => DirectInfections, "latent_namemodels" => ("diff_ar" => "diff_ar")) + model = remake_latent_model(inference_config, pipeline) + @test model isa DiffLatentModel + @test model.model isa AR + end + + @testset "ar model" begin + inference_config = Dict("igp" => Renewal, "latent_namemodels" => Pair("ar", "ar")) + model = remake_latent_model(inference_config, pipeline) + @test model isa AR + + inference_config = Dict( + "igp" => ExpGrowthRate, "latent_namemodels" => Pair("ar", "ar")) + model = remake_latent_model(inference_config, pipeline) + @test model isa AR + + inference_config = Dict( + "igp" => DirectInfections, "latent_namemodels" => Pair("ar", "ar")) + model = remake_latent_model(inference_config, pipeline) + @test model isa AR + end + + @testset "rw model" begin + inference_config = Dict("igp" => Renewal, "latent_namemodels" => Pair("rw", "rw")) + model = remake_latent_model(inference_config, pipeline) + @test model isa RandomWalk + + inference_config = Dict( + "igp" => ExpGrowthRate, "latent_namemodels" => Pair("rw", "rw")) + model = remake_latent_model(inference_config, pipeline) + @test model isa RandomWalk + + inference_config = Dict( + "igp" => DirectInfections, "latent_namemodels" => Pair("rw", "rw")) + model = remake_latent_model(inference_config, pipeline) + @test model isa RandomWalk + end +end diff --git a/pipeline/test/constructors/test_constructors.jl b/pipeline/test/constructors/test_constructors.jl index f97fa8265..d80f2c267 100644 --- a/pipeline/test/constructors/test_constructors.jl +++ b/pipeline/test/constructors/test_constructors.jl @@ -1,175 +1,2 @@ -@testset "make_gi_params: returns a dictionary with correct keys" begin - pipeline = EpiAwareExamplePipeline() - params = make_gi_params(pipeline) - - @test params isa Dict - @test haskey(params, "gi_means") - @test haskey(params, "gi_stds") -end - -@testset "make_inf_generating_processes" begin - pipeline = EpiAwareExamplePipeline() - igps = make_inf_generating_processes(pipeline) - @test igps == [DirectInfections, ExpGrowthRate, Renewal] -end - -@testset "make_Rt: returns an array" begin - map([EpiAwareExamplePipeline(), SmoothOutbreakPipeline(), - MeasuresOutbreakPipeline(), SmoothEndemicPipeline(), RoughEndemicPipeline()]) do pipeline - Rt = make_Rt(pipeline) - @test Rt isa Array - end -end - -@testset "default_tspan: returns an Tuple{Integer, Integer}" begin - pipeline = EpiAwareExamplePipeline() - - tspan = make_tspan(pipeline; lookback = 90) - @test tspan isa Tuple{Integer, Integer} -end - -@testset "make_model_priors: generates a dict with correct keys and distributions" begin - using Distributions - pipeline = EpiAwareExamplePipeline() - - priors_dict = make_model_priors(pipeline) - - # Check if the priors dictionary is constructed correctly - @test haskey(priors_dict, "transformed_process_init_prior") - @test haskey(priors_dict, "std_prior") - @test haskey(priors_dict, "damp_param_prior") - - # Check if the values are all distributions - @test valtype(priors_dict) <: Distribution -end - -@testset "make_epiaware_name_latentmodel_pairs: generates a vector of Pairs with correct keys and latent models" begin - pipeline = EpiAwareExamplePipeline() - - namemodel_vect = make_epiaware_name_latentmodel_pairs(pipeline) - - @test first.(namemodel_vect) == ["ar", "rw", "diff_ar"] - @test all([model isa AbstractTuringLatentModel for model in last.(namemodel_vect)]) -end - -@testset "make_inference_method: constructor and defaults" begin - using ADTypes, AbstractMCMC - pipeline = EpiAwareExamplePipeline() - - method = make_inference_method(pipeline) - - @test length(method.pre_sampler_steps) == 1 - @test method.pre_sampler_steps[1] isa ManyPathfinder - @test method.pre_sampler_steps[1].nruns == 4 - @test method.pre_sampler_steps[1].maxiters == 100 - @test method.sampler isa NUTSampler - @test method.sampler.adtype isa AbstractADType - @test method.sampler.ndraws == 20 - @test method.sampler.nchains == 4 - @test method.sampler.mcmc_parallel == MCMCThreads() -end - -@testset "make_inference_method: for prior predictive checking" begin - using EpiAwarePipeline, EpiAware, ADTypes, AbstractMCMC - pipetype = [SmoothOutbreakPipeline, MeasuresOutbreakPipeline, - SmoothEndemicPipeline, RoughEndemicPipeline] |> rand - pipeline = pipetype(; ndraws = 100, testmode = true, priorpredictive = true) - - method = make_inference_method(pipeline) - - @test length(method.pre_sampler_steps) == 0 - @test method.sampler isa DirectSample -end - -@testset "make_truth_data_configs" begin - pipeline = SmoothOutbreakPipeline() - example_pipeline = EpiAwareExamplePipeline() - @testset "make_truth_data_configs should return a dictionary" begin - config_dicts = make_truth_data_configs(pipeline) - @test eltype(config_dicts) <: Dict - end - - @testset "make_truth_data_configs should contain gi_mean and gi_std keys" begin - config_dicts = make_truth_data_configs(pipeline) - @test all(config_dicts .|> config -> haskey(config, "gi_mean")) - @test all(config_dicts .|> config -> haskey(config, "gi_std")) - end - - @testset "make_truth_data_configs should return a vector of length 1 for EpiAwareExamplePipeline" begin - config_dicts = make_truth_data_configs(example_pipeline) - @test length(config_dicts) == 1 - end -end - -@testset "default inference configurations" begin - pipeline = SmoothOutbreakPipeline() - example_pipeline = EpiAwareExamplePipeline() - - @testset "make_inference_configs should return a vector of dictionaries" begin - inference_configs = make_inference_configs(pipeline) - @test eltype(inference_configs) <: Dict - end - - @testset "make_inference_configs should contain igp, latent_namemodels, observation_model, gi_mean, gi_std, and log_I0_prior keys" begin - inference_configs = make_inference_configs(pipeline) - @test inference_configs .|> (config -> haskey(config, "igp")) |> all - @test inference_configs .|> (config -> haskey(config, "latent_namemodels")) |> all - @test inference_configs .|> (config -> haskey(config, "observation_model")) |> all - @test inference_configs .|> (config -> haskey(config, "gi_mean")) |> all - @test inference_configs .|> (config -> haskey(config, "gi_std")) |> all - @test inference_configs .|> (config -> haskey(config, "log_I0_prior")) |> all - end - - @testset "make_inference_configs should return a vector of length 1 for EpiAwareExamplePipeline" begin - inference_configs = make_inference_configs(example_pipeline) - @test length(inference_configs) == 1 - end -end - -@testset "make_default_params" begin - pipeline = SmoothOutbreakPipeline() - - # Expected default parameters - expected_params = Dict( - "Rt" => make_Rt(pipeline), - "logit_daily_ascertainment" => [zeros(5); -0.5 * ones(2)], - "cluster_factor" => 0.05, - "I0" => 100.0, - "α_delay" => 4.0, - "θ_delay" => 5.0 / 4.0, - "lookahead" => 21, - "lookback" => 90, - "stride" => 7 - ) - - # Test the make_default_params function - @test make_default_params(pipeline) == expected_params -end - -@testset "make_delay_distribution" begin - using Distributions - pipeline = SmoothOutbreakPipeline() - delay_distribution = make_delay_distribution(pipeline) - @test delay_distribution isa Distribution - @test delay_distribution isa Gamma - @test delay_distribution.α == 4.0 - @test delay_distribution.θ == 5.0 / 4.0 -end - -@testset "make_observation_model" begin - # Mock pipeline object - pipeline = SmoothOutbreakPipeline() - default_params = make_default_params(pipeline) - obs = make_observation_model(pipeline) - - # Test case 1: Check if the returned object is of type LatentDelay - @testset "Returned object type" begin - @test obs isa LatentDelay - end - - # Test case 2: Check if the default parameters are correctly passed to ascertainment_dayofweek - @testset "Default parameters" begin - @test obs.model.model.cluster_factor_prior == - HalfNormal(default_params["cluster_factor"]) - end -end +include("constructors.jl") +include("remake_latent_model.jl") diff --git a/pipeline/test/forecast/test_forecast.jl b/pipeline/test/forecast/test_forecast.jl index 010674ca1..785a0fdb6 100644 --- a/pipeline/test/forecast/test_forecast.jl +++ b/pipeline/test/forecast/test_forecast.jl @@ -9,8 +9,9 @@ tspan = (1, 28) epimethod = make_inference_method(pipeline) - epiprob = InferenceConfig(rand(inference_configs); case_data, truth_I_t = I_t, - truth_I0 = I0, tspan, epimethod, pipeline = pipeline) |> + epiprob = InferenceConfig( + rand(inference_configs), pipeline; case_data, truth_I_t = I_t, + truth_I0 = I0, tspan, epimethod) |> define_epiprob @test_throws AssertionError define_forecast_epiprob(epiprob, -1) diff --git a/pipeline/test/infer/test_InferenceConfig.jl b/pipeline/test/infer/test_InferenceConfig.jl index 5509fa25b..7721a192e 100644 --- a/pipeline/test/infer/test_InferenceConfig.jl +++ b/pipeline/test/infer/test_InferenceConfig.jl @@ -51,8 +51,8 @@ @testset "construct from config dictionary" begin pipeline = SmoothOutbreakPipeline() inference_configs = make_inference_configs(pipeline) - @test [InferenceConfig(ic; case_data, truth_I_t = I_t, - truth_I0 = I0, tspan, epimethod, pipeline = pipeline) isa + @test [InferenceConfig(ic, pipeline; case_data, truth_I_t = I_t, + truth_I0 = I0, tspan, epimethod) isa InferenceConfig for ic in inference_configs] |> all end diff --git a/pipeline/test/infer/test_define_epiprob.jl b/pipeline/test/infer/test_define_epiprob.jl index a59175b96..b86d404c3 100644 --- a/pipeline/test/infer/test_define_epiprob.jl +++ b/pipeline/test/infer/test_define_epiprob.jl @@ -9,8 +9,8 @@ tspan = (1, 28) epimethod = make_inference_method(pipeline) - epiprob = InferenceConfig(rand(inference_configs); case_data, tspan, - epimethod, truth_I_t = I_t, truth_I0 = I0, pipeline = pipeline) |> + epiprob = InferenceConfig(rand(inference_configs), pipeline; case_data, tspan, + epimethod, truth_I_t = I_t, truth_I0 = I0) |> define_epiprob @test epiprob isa EpiProblem