From a42cdc5eb60898194b31583564f2a12d00187f15 Mon Sep 17 00:00:00 2001 From: Laar Date: Wed, 14 Jun 2023 10:03:18 +0200 Subject: [PATCH 1/2] wip --- src/Part2/Rx/agent.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Part2/Rx/agent.jl b/src/Part2/Rx/agent.jl index 8024342..9f7a43a 100644 --- a/src/Part2/Rx/agent.jl +++ b/src/Part2/Rx/agent.jl @@ -35,18 +35,18 @@ function initializeAgent(A_0, B, C, D_0) # Define possible policies G = Matrix{Union{Float64, Missing}}(missing, 4, 4) if t === 1 - pols = [(1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)] + pols = [(1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)] elseif t === 2 - a1 = a[1] # Register first move - if a1 in [2, 3] + a1 = a[1] # Register first move + if a1 in [2, 3] pols = [(a1,1)] # Mandatory move to 1 - else + else pols = [(a1,1), (a1,2), (a1,3), (a1,4)] - end + end elseif t === 3 - a1 = a[1] # Register both moves - a2 = a[2] - pols = [(a1, a2)] + a1 = a[1] # Register both moves + a2 = a[2] + pols = [(a1, a2)] end # Define (un)observed data for meta objects From f4c8a47af6207306e089d56209f1e1bc40b4edbb Mon Sep 17 00:00:00 2001 From: Laar Date: Wed, 14 Jun 2023 12:54:32 +0200 Subject: [PATCH 2/2] prepare for publication --- .gitignore | 3 +- Manifest.toml | 1334 +++++++++++++++++ .../Policy_Inference.ipynb | 20 +- {src/Part1 => Part1}/helpers.jl | 30 +- {src/Part1 => Part1}/transition_mixture/in.jl | 0 .../transition_mixture/marginals.jl | 0 .../Part1 => Part1}/transition_mixture/out.jl | 0 .../transition_mixture/switch.jl | 0 .../transition_mixture/testing_ground.jl | 0 .../transition_mixture/transition_mixture.jl | 0 .../Part2/Rx => Part2}/T-maze_Aggregate.ipynb | 18 +- {src/Part2/Rx => Part2}/T-maze_Bethe.ipynb | 6 +- .../Rx => Part2}/T-maze_Generalized.ipynb | 8 +- {src/Part2/Rx => Part2}/agent.jl | 0 {src/Part2/Rx => Part2}/environment.jl | 0 Part2/figures/BFE_A.png | Bin 0 -> 35911 bytes Part2/figures/BFE_FE.png | Bin 0 -> 89510 bytes Part2/figures/GFE_A.png | Bin 0 -> 41630 bytes Part2/figures/GFE_FE.png | Bin 0 -> 131838 bytes Part2/figures/GFE_hist.png | Bin 0 -> 37468 bytes Part2/figures/GFE_wins.png | Bin 0 -> 53375 bytes Part2/figures/wins_100_30.jld2 | Bin 0 -> 148651 bytes {src/Part2/Rx => Part2}/helpers.jl | 0 {src/Part2/Rx => Part2}/visualizations.jl | 0 Project.toml | 11 - README.md | 38 +- archive/DiscreteLAIF.jl | 244 --- archive/GFECategorical.jl | 128 -- archive/GFECategorical_old.jl | 108 -- archive/GFEGaussian.jl | 95 -- archive/GFEtesting.jl | 128 -- archive/Project.toml | 1 - archive/T-maze, GFE vs BFE.ipynb | 298 ---- archive/T-maze, GFE vs BFE.jl | 116 -- archive/approx_marginal_categorical.jl | 40 - archive/backup.jl | 46 - archive/dirichlet_t_maze.jl | 42 - archive/efe_from_gbfe.jl | 116 -- archive/fixed_t_maze.jl | 77 - archive/fixed_t_maze_2.jl | 77 - archive/fixed_t_maze_novelty.jl | 193 --- archive/fl_results_remake.jl | 63 - archive/gaussian.jl | 45 - archive/gfe_hmm_test.jl | 62 - archive/gfe_vs_vfe.jl | 84 -- archive/gfe_vs_vfe_composite.jl | 73 - archive/matrixlogpdf.jl | 89 -- archive/stability_test.jl | 67 - archive/t_maze.jl | 105 -- archive/t_maze_novelty.jl | 110 -- archive/test_hmm.jl | 97 -- archive/testing.jl | 47 - archive/testing_grounds.jl | 116 -- archive/tm.jl | 102 -- archive/tm_back.jl | 102 -- archive/tm_test.jl | 79 - .../distributions.jl => distributions.jl | 0 ...goal_observation.jl => goal_observation.jl | 0 .../T-maze, GFE vs BFE-checkpoint.ipynb | 239 --- .../T-maze_GFE-checkpoint.ipynb | 247 --- ...T-maze_GFE_planning-Copy1-checkpoint.ipynb | 529 ------- .../T-maze_GFE_planning-checkpoint.ipynb | 249 --- .../T-maze_interactive-checkpoint.ipynb | 935 ------------ .../T-maze_interactive_2-checkpoint.ipynb | 294 ---- .../T-maze_planning_GBFE-checkpoint.ipynb | 718 --------- .../multi_T-maze_GFE-checkpoint.ipynb | 244 --- .../param_direct-checkpoint.ipynb | 612 -------- .../param_iterate-checkpoint.ipynb | 640 -------- .../T-maze_GFE_planning-Copy1.ipynb | 671 --------- .../T-maze_planning_BFE-checkpoint.ipynb | 171 --- src/Part1/goal_observation.jl | 270 ---- src/Part1/t_maze.jl | 99 -- src/Part2/FL/Project.toml | 8 - src/Part2/FL/T-maze_BFE.ipynb | 897 ----------- src/Part2/FL/T-maze_GFE.ipynb | 917 ----------- src/Part2/FL/T-maze_GFE_planning.ipynb | 240 --- src/Part2/FL/T-maze_GFE_policy.ipynb | 337 ----- src/Part2/FL/agent.jl | 106 -- src/Part2/FL/archive/T-maze_BFE.ipynb | 277 ---- src/Part2/FL/archive/T-maze_full_GBFE.ipynb | 231 --- src/Part2/FL/archive/T-maze_interactive.ipynb | 282 ---- .../FL/archive/T-maze_interactive_2.ipynb | 539 ------- .../FL/archive/T-maze_interactive_3.ipynb | 382 ----- .../FL/archive/T-maze_planning_BFE.ipynb | 242 --- .../FL/archive/T-maze_planning_EFE.ipynb | 111 -- .../T-maze_planning_EFE_from_GMFE.ipynb | 287 ---- .../FL/archive/T-maze_planning_GBFE.ipynb | 284 ---- .../FL/archive/T-maze_planning_GMFE.ipynb | 303 ---- src/Part2/FL/archive/agent.jl | 215 --- src/Part2/FL/archive/agent_2.jl | 147 -- src/Part2/FL/archive/agent_3.jl | 124 -- src/Part2/FL/archive/ep_distribution.ipynb | 149 -- src/Part2/FL/archive/ep_kl.ipynb | 152 -- src/Part2/FL/archive/ep_laplace.ipynb | 141 -- src/Part2/FL/archive/instability.ipynb | 515 ------- src/Part2/FL/archive/landscape_kl.ipynb | 227 --- src/Part2/FL/archive/minimal_planning.ipynb | 450 ------ .../FL/archive/minimal_planning_newton.ipynb | 595 -------- src/Part2/FL/archive/param_direct.ipynb | 137 -- src/Part2/FL/archive/param_iterate.ipynb | 165 -- src/Part2/FL/archive/simple_planning.ipynb | 930 ------------ src/Part2/FL/environment.jl | 115 -- .../FL/factor_nodes/discrete_observation.jl | 103 -- src/Part2/FL/helpers.jl | 94 -- src/Part2/FL/multi_T-maze_GFE.ipynb | 817 ---------- .../FL/update_rules/discrete_observation.jl | 321 ---- src/Part2/FL/visualizations.jl | 206 --- .../T-maze_Aggregate-checkpoint.ipynb | 680 --------- .../T-maze_Generalized-checkpoint.ipynb | 644 -------- src/Part2/Rx/Project.toml | 12 - src/Part2/Rx/README.md | 35 - src/Part2/Rx/distributions.jl | 108 -- src/forward/forward_transition.jl | 82 - 113 files changed, 1397 insertions(+), 21546 deletions(-) create mode 100644 Manifest.toml rename src/Part1/Policy Inference.ipynb => Part1/Policy_Inference.ipynb (91%) rename {src/Part1 => Part1}/helpers.jl (64%) rename {src/Part1 => Part1}/transition_mixture/in.jl (100%) rename {src/Part1 => Part1}/transition_mixture/marginals.jl (100%) rename {src/Part1 => Part1}/transition_mixture/out.jl (100%) rename {src/Part1 => Part1}/transition_mixture/switch.jl (100%) rename {src/Part1 => Part1}/transition_mixture/testing_ground.jl (100%) rename {src/Part1 => Part1}/transition_mixture/transition_mixture.jl (100%) rename {src/Part2/Rx => Part2}/T-maze_Aggregate.ipynb (92%) rename {src/Part2/Rx => Part2}/T-maze_Bethe.ipynb (97%) rename {src/Part2/Rx => Part2}/T-maze_Generalized.ipynb (97%) rename {src/Part2/Rx => Part2}/agent.jl (100%) rename {src/Part2/Rx => Part2}/environment.jl (100%) create mode 100644 Part2/figures/BFE_A.png create mode 100644 Part2/figures/BFE_FE.png create mode 100644 Part2/figures/GFE_A.png create mode 100644 Part2/figures/GFE_FE.png create mode 100644 Part2/figures/GFE_hist.png create mode 100644 Part2/figures/GFE_wins.png create mode 100644 Part2/figures/wins_100_30.jld2 rename {src/Part2/Rx => Part2}/helpers.jl (100%) rename {src/Part2/Rx => Part2}/visualizations.jl (100%) delete mode 100644 archive/DiscreteLAIF.jl delete mode 100644 archive/GFECategorical.jl delete mode 100644 archive/GFECategorical_old.jl delete mode 100644 archive/GFEGaussian.jl delete mode 100644 archive/GFEtesting.jl delete mode 100644 archive/Project.toml delete mode 100644 archive/T-maze, GFE vs BFE.ipynb delete mode 100644 archive/T-maze, GFE vs BFE.jl delete mode 100644 archive/approx_marginal_categorical.jl delete mode 100644 archive/backup.jl delete mode 100644 archive/dirichlet_t_maze.jl delete mode 100644 archive/efe_from_gbfe.jl delete mode 100644 archive/fixed_t_maze.jl delete mode 100644 archive/fixed_t_maze_2.jl delete mode 100644 archive/fixed_t_maze_novelty.jl delete mode 100644 archive/fl_results_remake.jl delete mode 100644 archive/gaussian.jl delete mode 100644 archive/gfe_hmm_test.jl delete mode 100644 archive/gfe_vs_vfe.jl delete mode 100644 archive/gfe_vs_vfe_composite.jl delete mode 100644 archive/matrixlogpdf.jl delete mode 100644 archive/stability_test.jl delete mode 100644 archive/t_maze.jl delete mode 100644 archive/t_maze_novelty.jl delete mode 100644 archive/test_hmm.jl delete mode 100644 archive/testing.jl delete mode 100644 archive/testing_grounds.jl delete mode 100644 archive/tm.jl delete mode 100644 archive/tm_back.jl delete mode 100644 archive/tm_test.jl rename src/Part1/distributions.jl => distributions.jl (100%) rename src/Part2/Rx/goal_observation.jl => goal_observation.jl (100%) delete mode 100644 src/.ipynb_checkpoints/T-maze, GFE vs BFE-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/T-maze_GFE-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-Copy1-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/T-maze_interactive-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/T-maze_interactive_2-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/T-maze_planning_GBFE-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/multi_T-maze_GFE-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/param_direct-checkpoint.ipynb delete mode 100644 src/FLSimulations/.ipynb_checkpoints/param_iterate-checkpoint.ipynb delete mode 100644 src/FLSimulations/T-maze_GFE_planning-Copy1.ipynb delete mode 100644 src/FLSimulations/archive/.ipynb_checkpoints/T-maze_planning_BFE-checkpoint.ipynb delete mode 100644 src/Part1/goal_observation.jl delete mode 100644 src/Part1/t_maze.jl delete mode 100644 src/Part2/FL/Project.toml delete mode 100644 src/Part2/FL/T-maze_BFE.ipynb delete mode 100644 src/Part2/FL/T-maze_GFE.ipynb delete mode 100644 src/Part2/FL/T-maze_GFE_planning.ipynb delete mode 100644 src/Part2/FL/T-maze_GFE_policy.ipynb delete mode 100644 src/Part2/FL/agent.jl delete mode 100644 src/Part2/FL/archive/T-maze_BFE.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_full_GBFE.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_interactive.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_interactive_2.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_interactive_3.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_planning_BFE.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_planning_EFE.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_planning_EFE_from_GMFE.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_planning_GBFE.ipynb delete mode 100644 src/Part2/FL/archive/T-maze_planning_GMFE.ipynb delete mode 100644 src/Part2/FL/archive/agent.jl delete mode 100644 src/Part2/FL/archive/agent_2.jl delete mode 100644 src/Part2/FL/archive/agent_3.jl delete mode 100644 src/Part2/FL/archive/ep_distribution.ipynb delete mode 100644 src/Part2/FL/archive/ep_kl.ipynb delete mode 100644 src/Part2/FL/archive/ep_laplace.ipynb delete mode 100644 src/Part2/FL/archive/instability.ipynb delete mode 100644 src/Part2/FL/archive/landscape_kl.ipynb delete mode 100644 src/Part2/FL/archive/minimal_planning.ipynb delete mode 100644 src/Part2/FL/archive/minimal_planning_newton.ipynb delete mode 100644 src/Part2/FL/archive/param_direct.ipynb delete mode 100644 src/Part2/FL/archive/param_iterate.ipynb delete mode 100644 src/Part2/FL/archive/simple_planning.ipynb delete mode 100644 src/Part2/FL/environment.jl delete mode 100644 src/Part2/FL/factor_nodes/discrete_observation.jl delete mode 100644 src/Part2/FL/helpers.jl delete mode 100644 src/Part2/FL/multi_T-maze_GFE.ipynb delete mode 100644 src/Part2/FL/update_rules/discrete_observation.jl delete mode 100644 src/Part2/FL/visualizations.jl delete mode 100644 src/Part2/Rx/.ipynb_checkpoints/T-maze_Aggregate-checkpoint.ipynb delete mode 100644 src/Part2/Rx/.ipynb_checkpoints/T-maze_Generalized-checkpoint.ipynb delete mode 100644 src/Part2/Rx/Project.toml delete mode 100644 src/Part2/Rx/README.md delete mode 100644 src/Part2/Rx/distributions.jl delete mode 100644 src/forward/forward_transition.jl diff --git a/.gitignore b/.gitignore index 8658990..763513e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -Manifest.toml -\figures \ No newline at end of file +.ipynb_checkpoints diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 0000000..977363c --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,1334 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.8.2" +manifest_format = "2.0" +project_hash = "9b8a1945f5816801b7562238471dff88c334a7e3" + +[[deps.Adapt]] +deps = ["LinearAlgebra", "Requires"] +git-tree-sha1 = "76289dc51920fdc6e0013c872ba9551d54961c24" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "3.6.2" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.ArrayInterface]] +deps = ["Adapt", "LinearAlgebra", "Requires", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "917286faa2abb288796e75b88ca67edc016f3219" +uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" +version = "7.4.5" + +[[deps.ArrayInterfaceCore]] +deps = ["LinearAlgebra", "SnoopPrecompile", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "e5f08b5689b1aad068e01751889f2f615c7db36d" +uuid = "30b0a656-2188-435a-8636-2ec0e6a096e2" +version = "0.1.29" + +[[deps.ArrayLayouts]] +deps = ["FillArrays", "LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "4aff5fa660eb95c2e0deb6bcdabe4d9a96bc4667" +uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" +version = "0.8.18" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.BitFlags]] +git-tree-sha1 = "43b1a4a8f797c1cddadf60499a8a077d4af2cd2d" +uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" +version = "0.1.7" + +[[deps.BitTwiddlingConvenienceFunctions]] +deps = ["Static"] +git-tree-sha1 = "0c5f81f47bbbcf4aea7b2959135713459170798b" +uuid = "62783981-4cbd-42fc-bca8-16325de8dc4b" +version = "0.1.5" + +[[deps.Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.8+0" + +[[deps.CPUSummary]] +deps = ["CpuId", "IfElse", "Static"] +git-tree-sha1 = "2c144ddb46b552f72d7eafe7cc2f50746e41ea21" +uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" +version = "0.2.2" + +[[deps.Cairo_jll]] +deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.16.1+1" + +[[deps.Calculus]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" +uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" +version = "0.5.1" + +[[deps.ChainRulesCore]] +deps = ["Compat", "LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "e30f2f4e20f7f186dc36529910beaedc60cfa644" +uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +version = "1.16.0" + +[[deps.ChangesOfVariables]] +deps = ["LinearAlgebra", "Test"] +git-tree-sha1 = "f84967c4497e0e1955f9a582c232b02847c5f589" +uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" +version = "0.1.7" + +[[deps.CloseOpenIntervals]] +deps = ["Static", "StaticArrayInterface"] +git-tree-sha1 = "70232f82ffaab9dc52585e0dd043b5e0c6b714f1" +uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9" +version = "0.1.12" + +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "9c209fb7536406834aa938fb149964b985de6c83" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.1" + +[[deps.ColorSchemes]] +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] +git-tree-sha1 = "be6ab11021cd29f0344d5c4357b163af05a48cba" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.21.0" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.4" + +[[deps.ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"] +git-tree-sha1 = "600cc5508d66b78aae350f7accdb58763ac18589" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.9.10" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "fc08e5930ee9a4e03f84bfb5211cb54e7769758a" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.10" + +[[deps.Combinatorics]] +git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860" +uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" +version = "1.0.2" + +[[deps.CommonSubexpressions]] +deps = ["MacroTools", "Test"] +git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.0" + +[[deps.Compat]] +deps = ["Dates", "LinearAlgebra", "UUIDs"] +git-tree-sha1 = "7a60c856b9fa189eb34f5f8a6f6b5529b7942957" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.6.1" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "0.5.2+0" + +[[deps.CompositeTypes]] +git-tree-sha1 = "02d2316b7ffceff992f3096ae48c7829a8aa0638" +uuid = "b152e2b5-7a66-4b01-a709-34e65c35f657" +version = "0.1.3" + +[[deps.ConcurrentUtilities]] +deps = ["Serialization", "Sockets"] +git-tree-sha1 = "96d823b94ba8d187a6d8f0826e731195a74b90e9" +uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" +version = "2.2.0" + +[[deps.ConstructionBase]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "738fec4d684a9a6ee9598a8bfee305b26831f28c" +uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +version = "1.5.2" + +[[deps.Contour]] +git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.6.2" + +[[deps.CpuId]] +deps = ["Markdown"] +git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" +uuid = "adafc99b-e345-5852-983c-f28acb93d879" +version = "0.3.1" + +[[deps.DataAPI]] +git-tree-sha1 = "8da84edb865b0b5b0100c0666a9bc9a0b71c553c" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.15.0" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "d1fff3a548102f48987a52a2e0d114fa97d730f0" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.13" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.DelimitedFiles]] +deps = ["Mmap"] +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" + +[[deps.DensityInterface]] +deps = ["InverseFunctions", "Test"] +git-tree-sha1 = "80c3e8639e3353e5d2912fb3a1916b8455e2494b" +uuid = "b429d917-457f-4dbc-8f4c-0cc954292b1d" +version = "0.4.0" + +[[deps.DiffResults]] +deps = ["StaticArraysCore"] +git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" +uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +version = "1.1.0" + +[[deps.DiffRules]] +deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] +git-tree-sha1 = "a4ad7ef19d2cdc2eff57abbbe68032b1cd0bd8f8" +uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" +version = "1.13.0" + +[[deps.Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[deps.Distributions]] +deps = ["ChainRulesCore", "DensityInterface", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SparseArrays", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns", "Test"] +git-tree-sha1 = "5eeb2bd01e5065090ad591a205d8cad432ae6cb6" +uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" +version = "0.25.93" + +[[deps.DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.3" + +[[deps.DomainIntegrals]] +deps = ["CompositeTypes", "DomainSets", "FastGaussQuadrature", "GaussQuadrature", "HCubature", "IntervalSets", "LinearAlgebra", "QuadGK", "StaticArrays"] +git-tree-sha1 = "0b0425701a4b9b0b9da831d834e2580af35b321a" +uuid = "cc6bae93-f070-4015-88fd-838f9505a86c" +version = "0.4.3" + +[[deps.DomainSets]] +deps = ["CompositeTypes", "IntervalSets", "LinearAlgebra", "Random", "StaticArrays", "Statistics"] +git-tree-sha1 = "698124109da77b6914f64edd696be8dccf90229e" +uuid = "5b8099bc-c8ec-5219-889f-1d9e522a28bf" +version = "0.6.6" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.DualNumbers]] +deps = ["Calculus", "NaNMath", "SpecialFunctions"] +git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" +uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" +version = "0.6.8" + +[[deps.Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bad72f730e9e91c08d9427d5e8db95478a3c323d" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.4.8+0" + +[[deps.FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[deps.FFMPEG_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Pkg", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "74faea50c1d007c85837327f6775bea60b5492dd" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.4.2+2" + +[[deps.FastGaussQuadrature]] +deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"] +git-tree-sha1 = "0f478d8bad6f52573fb7658a263af61f3d96e43a" +uuid = "442a2c76-b920-505d-bb47-c5924d526838" +version = "0.5.1" + +[[deps.FileIO]] +deps = ["Pkg", "Requires", "UUIDs"] +git-tree-sha1 = "299dc33549f68299137e51e6d49a13b5b1da9673" +uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +version = "1.16.1" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FillArrays]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"] +git-tree-sha1 = "7072f1e3e5a8be51d525d64f63d3ec1287ff2790" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "0.13.11" + +[[deps.FiniteDiff]] +deps = ["ArrayInterface", "LinearAlgebra", "Requires", "Setfield", "SparseArrays", "StaticArrays"] +git-tree-sha1 = "6604e18a0220650dbbea7854938768f15955dd8e" +uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" +version = "2.20.0" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.4" + +[[deps.Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.93+0" + +[[deps.Formatting]] +deps = ["Printf"] +git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" +uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" +version = "0.4.2" + +[[deps.ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"] +git-tree-sha1 = "00e252f4d706b3d55a8863432e742bf5717b498d" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "0.10.35" + +[[deps.FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.10.4+0" + +[[deps.FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.10+0" + +[[deps.Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" + +[[deps.GLFW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] +git-tree-sha1 = "d972031d28c8c8d9d7b41a536ad7bb0c2579caca" +uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" +version = "3.3.8+0" + +[[deps.GR]] +deps = ["Artifacts", "Base64", "DelimitedFiles", "Downloads", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Preferences", "Printf", "Random", "Serialization", "Sockets", "TOML", "Tar", "Test", "UUIDs", "p7zip_jll"] +git-tree-sha1 = "d014972cd6f5afb1f8cd7adf000b7a966d62c304" +uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +version = "0.72.5" + +[[deps.GR_jll]] +deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "f670f269909a9114df1380cc0fcaa316fff655fb" +uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" +version = "0.72.5+0" + +[[deps.GaussQuadrature]] +deps = ["SpecialFunctions"] +git-tree-sha1 = "eb6f1f48aa994f3018cbd029a17863c6535a266d" +uuid = "d54b0c1a-921d-58e0-8e36-89d8069c0969" +version = "0.5.8" + +[[deps.Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[deps.Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "d3b3624125c1474292d0d8ed0f65554ac37ddb23" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.74.0+2" + +[[deps.GraphPPL]] +deps = ["MacroTools", "TupleTools"] +git-tree-sha1 = "36d1953626dcb87e87824488167a5a27e6046424" +uuid = "b3f8163a-e979-4e85-b43e-1f63d8c8b42c" +version = "3.1.0" + +[[deps.Graphite2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" +version = "1.3.14+0" + +[[deps.Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[deps.HCubature]] +deps = ["Combinatorics", "DataStructures", "LinearAlgebra", "QuadGK", "StaticArrays"] +git-tree-sha1 = "e95b36755023def6ebc3d269e6483efa8b2f7f65" +uuid = "19dc6840-f33b-545b-b366-655c7e3ffd49" +version = "1.5.1" + +[[deps.HTTP]] +deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] +git-tree-sha1 = "ba9eca9f8bdb787c6f3cf52cb4a404c0e349a0d1" +uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" +version = "1.9.5" + +[[deps.HarfBuzz_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] +git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" +version = "2.8.1+1" + +[[deps.HostCPUFeatures]] +deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"] +git-tree-sha1 = "734fd90dd2f920a2f1921d5388dcebe805b262dc" +uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0" +version = "0.1.14" + +[[deps.HypergeometricFunctions]] +deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] +git-tree-sha1 = "84204eae2dd237500835990bcade263e27674a93" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.16" + +[[deps.IfElse]] +git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" +uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" +version = "0.1.1" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.IntervalSets]] +deps = ["Dates", "Random", "Statistics"] +git-tree-sha1 = "16c0cc91853084cb5f58a78bd209513900206ce6" +uuid = "8197267c-284f-5f27-9208-e0e47529a953" +version = "0.7.4" + +[[deps.InverseFunctions]] +deps = ["Test"] +git-tree-sha1 = "6667aadd1cdee2c6cd068128b3d226ebc4fb0c67" +uuid = "3587e190-3f89-42d0-90ee-14403ec27112" +version = "0.1.9" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.2.2" + +[[deps.JLD2]] +deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "Pkg", "Printf", "Reexport", "Requires", "TranscodingStreams", "UUIDs"] +git-tree-sha1 = "42c17b18ced77ff0be65957a591d34f4ed57c631" +uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" +version = "0.4.31" + +[[deps.JLFzf]] +deps = ["Pipe", "REPL", "Random", "fzf_jll"] +git-tree-sha1 = "f377670cda23b6b7c1c0b3893e37451c5c1a2185" +uuid = "1019f520-868f-41f5-a6de-eb00f4b6a39c" +version = "0.1.5" + +[[deps.JLLWrappers]] +deps = ["Preferences"] +git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.4.1" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "6f2675ef130a300a112286de91973805fcc5ffbc" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "2.1.91+0" + +[[deps.LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.1+0" + +[[deps.LERC_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" +uuid = "88015f11-f218-50d7-93a8-a6af411a945d" +version = "3.0.0+1" + +[[deps.LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.1+0" + +[[deps.LaTeXStrings]] +git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.0" + +[[deps.Latexify]] +deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Printf", "Requires"] +git-tree-sha1 = "099e356f267354f46ba65087981a77da23a279b7" +uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +version = "0.16.0" + +[[deps.LayoutPointers]] +deps = ["ArrayInterface", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static", "StaticArrayInterface"] +git-tree-sha1 = "88b8f66b604da079a627b6fb2860d3704a6729a1" +uuid = "10f19ff3-798f-405d-979b-55457f8fc047" +version = "0.1.14" + +[[deps.LazyArrays]] +deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "MacroTools", "MatrixFactorizations", "SparseArrays", "StaticArrays"] +git-tree-sha1 = "7402f6be1a28a05516c6881596879e6d18d28039" +uuid = "5078a376-72f3-5289-bfd5-ec5146d43c02" +version = "0.22.18" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.3" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "7.84.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.10.2+0" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+1" + +[[deps.Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] +git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.7+0" + +[[deps.Libglvnd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] +git-tree-sha1 = "6f73d1dd803986947b2c750138528a999a6c7733" +uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" +version = "1.6.0+0" + +[[deps.Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.42.0+0" + +[[deps.Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c7cb1f5d892775ba13767a87c7ada0b980ea0a71" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.16.1+2" + +[[deps.Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.35.0+0" + +[[deps.Libtiff_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "3eb79b0ca5764d4799c06699573fd8f533259713" +uuid = "89763e89-9b03-5906-acba-b20f662cd828" +version = "4.4.0+0" + +[[deps.Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.36.0+0" + +[[deps.LineSearches]] +deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] +git-tree-sha1 = "7bbea35cec17305fc70a0e5b4641477dc0789d9d" +uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" +version = "7.2.0" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.LogExpFunctions]] +deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "0a1b7c2863e44523180fdb3146534e265a91870b" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.23" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.LoggingExtras]] +deps = ["Dates", "Logging"] +git-tree-sha1 = "cedb76b37bc5a6c702ade66be44f831fa23c681e" +uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" +version = "1.0.0" + +[[deps.LoopVectorization]] +deps = ["ArrayInterface", "ArrayInterfaceCore", "CPUSummary", "ChainRulesCore", "CloseOpenIntervals", "DocStringExtensions", "ForwardDiff", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "PrecompileTools", "SIMDTypes", "SLEEFPirates", "SpecialFunctions", "Static", "StaticArrayInterface", "ThreadingUtilities", "UnPack", "VectorizationBase"] +git-tree-sha1 = "3bb62b5003bc7d2d49f26663484267dc49fa1bf5" +uuid = "bdcacae8-1622-11e9-2a5c-532679323890" +version = "0.12.159" + +[[deps.MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "42324d08725e200c23d4dfb549e0d5d89dede2d2" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.10" + +[[deps.ManualMemory]] +git-tree-sha1 = "bcaef4fc7a0cfe2cba636d84cda54b5e4e4ca3cd" +uuid = "d125e4d3-2237-4719-b19c-fa641b8a4667" +version = "0.1.8" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MatrixFactorizations]] +deps = ["ArrayLayouts", "LinearAlgebra", "Printf", "Random"] +git-tree-sha1 = "0ff59b4b9024ab9a736db1ad902d2b1b48441c19" +uuid = "a3b82374-2e81-5b9e-98ce-41277c0e4c87" +version = "0.9.6" + +[[deps.MbedTLS]] +deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "Random", "Sockets"] +git-tree-sha1 = "03a9b9718f5682ecb107ac9f7308991db4ce395b" +uuid = "739be429-bea8-5141-9913-cc70e7f3736d" +version = "1.1.7" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.0+0" + +[[deps.Measures]] +git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102" +uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" +version = "0.3.2" + +[[deps.Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "f66bdc5de519e8f8ae43bdc598782d35a25b1272" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.1.0" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2022.2.1" + +[[deps.NLSolversBase]] +deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] +git-tree-sha1 = "a0b464d183da839699f4c79e7606d9d186ec172c" +uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" +version = "7.8.3" + +[[deps.NaNMath]] +deps = ["OpenLibm_jll"] +git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.0.2" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OffsetArrays]] +deps = ["Adapt"] +git-tree-sha1 = "82d7c9e310fe55aa54996e6f7f94674e2a38fcb4" +uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +version = "1.12.9" + +[[deps.Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+1" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.20+0" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+0" + +[[deps.OpenSSL]] +deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] +git-tree-sha1 = "51901a49222b09e3743c65b8847687ae5fc78eb2" +uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" +version = "1.4.1" + +[[deps.OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9ff31d101d987eb9d66bd8b176ac7c277beccd09" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "1.1.20+0" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" + +[[deps.Optim]] +deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] +git-tree-sha1 = "a89b11f0f354f06099e4001c151dffad7ebab015" +uuid = "429524aa-4258-5aef-a3af-852621145aeb" +version = "1.7.5" + +[[deps.Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + +[[deps.OrderedCollections]] +git-tree-sha1 = "d321bf2de576bf25ec4d3e4360faca399afca282" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.6.0" + +[[deps.PCRE2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" +version = "10.40.0+0" + +[[deps.PDMats]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "67eae2738d63117a196f497d7db789821bce61d1" +uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" +version = "0.11.17" + +[[deps.Parameters]] +deps = ["OrderedCollections", "UnPack"] +git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" +uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" +version = "0.12.3" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "a5aef8d4a6e8d81f171b2bd4be5265b01384c74c" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.5.10" + +[[deps.Pipe]] +git-tree-sha1 = "6842804e7867b115ca9de748a0cf6b364523c16d" +uuid = "b98c9c47-44ae-5843-9183-064241ee97a0" +version = "1.3.0" + +[[deps.Pixman_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.40.1+0" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.8.0" + +[[deps.PlotThemes]] +deps = ["PlotUtils", "Statistics"] +git-tree-sha1 = "1f03a2d339f42dca4a4da149c7e15e9b896ad899" +uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" +version = "3.1.0" + +[[deps.PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "Statistics"] +git-tree-sha1 = "f92e1315dadf8c46561fb9396e525f7200cdc227" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.3.5" + +[[deps.Plots]] +deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Preferences", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"] +git-tree-sha1 = "d03ef538114b38f89d66776f2d8fdc0280f90621" +uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +version = "1.38.12" + +[[deps.PolyesterWeave]] +deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] +git-tree-sha1 = "240d7170f5ffdb285f9427b92333c3463bf65bf6" +uuid = "1d0040c9-8b98-4ee7-8388-3f51789ca0ad" +version = "0.2.1" + +[[deps.PositiveFactorizations]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" +uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" +version = "0.2.4" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "259e206946c293698122f63e2b513a7c99a244e8" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.1.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "7eb1686b4f04b82f96ed7a4ea5890a4f0c7a09f1" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.0" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.ProgressMeter]] +deps = ["Distributed", "Printf"] +git-tree-sha1 = "d7a7aef8f8f2d537104f170139553b14dfe39fe9" +uuid = "92933f4c-e287-5a05-a399-4b506db050ca" +version = "1.7.2" + +[[deps.Qt5Base_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] +git-tree-sha1 = "0c03844e2231e12fda4d0086fd7cbe4098ee8dc5" +uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" +version = "5.15.3+2" + +[[deps.QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "6ec7ac8412e83d57e313393220879ede1740f9ee" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.8.2" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA", "Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.ReactiveMP]] +deps = ["DataStructures", "Distributions", "DomainIntegrals", "DomainSets", "FastGaussQuadrature", "ForwardDiff", "HCubature", "LazyArrays", "LinearAlgebra", "LoopVectorization", "MacroTools", "Optim", "PositiveFactorizations", "Random", "Requires", "Rocket", "SpecialFunctions", "StaticArrays", "StatsBase", "StatsFuns", "TinyHugeNumbers", "TupleTools", "Unrolled"] +git-tree-sha1 = "7a0e786deeee1d263b15a00be5d794444f770884" +uuid = "a194aa59-28ba-4574-a09c-4a745416d6e3" +version = "3.8.1" + +[[deps.RecipesBase]] +deps = ["PrecompileTools"] +git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.3.4" + +[[deps.RecipesPipeline]] +deps = ["Dates", "NaNMath", "PlotUtils", "PrecompileTools", "RecipesBase"] +git-tree-sha1 = "45cf9fd0ca5839d06ef333c8201714e888486342" +uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" +version = "0.6.12" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "90bc7a7c96410424509e4263e277e43250c05691" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "1.0.0" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.Rmath]] +deps = ["Random", "Rmath_jll"] +git-tree-sha1 = "f65dcb5fa46aee0cf9ed6274ccbd597adc49aa7b" +uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" +version = "0.7.1" + +[[deps.Rmath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6ed52fdd3382cf21947b15e8870ac0ddbff736da" +uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" +version = "0.4.0+0" + +[[deps.Rocket]] +deps = ["DataStructures", "Sockets", "Unrolled"] +git-tree-sha1 = "33e270ce5710d5315f28c205ec7d598c4fdf660d" +uuid = "df971d30-c9d6-4b37-b8ff-e965b2cb3a40" +version = "1.7.0" + +[[deps.RxInfer]] +deps = ["DataStructures", "Distributions", "DomainSets", "GraphPPL", "LinearAlgebra", "MacroTools", "Optim", "ProgressMeter", "Random", "ReactiveMP", "Reexport", "Rocket", "TupleTools"] +git-tree-sha1 = "21e2495fd23ff19fc77ed1c4e179d963ea4f44d4" +uuid = "86711068-29c9-4ff7-b620-ae75d7495b3d" +version = "2.10.4" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.SIMDTypes]] +git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" +uuid = "94e857df-77ce-4151-89e5-788b33177be4" +version = "0.1.0" + +[[deps.SLEEFPirates]] +deps = ["IfElse", "Static", "VectorizationBase"] +git-tree-sha1 = "4b8586aece42bee682399c4c4aee95446aa5cd19" +uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" +version = "0.6.39" + +[[deps.Scratch]] +deps = ["Dates"] +git-tree-sha1 = "30449ee12237627992a99d5e30ae63e4d78cd24a" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.2.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.Setfield]] +deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] +git-tree-sha1 = "e2cc6d8c88613c05e1defb55170bf5ff211fbeac" +uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" +version = "1.1.1" + +[[deps.Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[deps.SimpleBufferStream]] +git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" +uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" +version = "1.1.0" + +[[deps.SnoopPrecompile]] +deps = ["Preferences"] +git-tree-sha1 = "e760a70afdcd461cf01a575947738d359234665c" +uuid = "66db9d55-30c0-4569-8b51-7e840670fc0c" +version = "1.0.3" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "a4ada03f999bd01b3a25dcaa30b2d929fe537e00" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.1.0" + +[[deps.SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[deps.SpecialFunctions]] +deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "ef28127915f4229c971eb43f3fc075dd3fe91880" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.2.0" + +[[deps.Static]] +deps = ["IfElse"] +git-tree-sha1 = "dbde6766fc677423598138a5951269432b0fcc90" +uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" +version = "0.8.7" + +[[deps.StaticArrayInterface]] +deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "Requires", "SnoopPrecompile", "SparseArrays", "Static", "SuiteSparse"] +git-tree-sha1 = "33040351d2403b84afce74dae2e22d3f5b18edcb" +uuid = "0d7ed370-da01-4f52-bd93-41d350b8b718" +version = "1.4.0" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "Random", "StaticArraysCore", "Statistics"] +git-tree-sha1 = "8982b3607a212b070a5e46eea83eb62b4744ae12" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.5.25" + +[[deps.StaticArraysCore]] +git-tree-sha1 = "6b7ba252635a5eff6a0b0664a41ee140a1c9e72a" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.4.0" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[deps.StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "45a7769a04a3cf80da1c1c7c60caf932e6f4c9f7" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.6.0" + +[[deps.StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "d1bf48bfcc554a3761a133fe3a9bb01488e06916" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.33.21" + +[[deps.StatsFuns]] +deps = ["ChainRulesCore", "HypergeometricFunctions", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "f625d686d5a88bcd2b15cd81f18f98186fdc0c9a" +uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +version = "1.3.0" + +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.0" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.1" + +[[deps.TensorCore]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" +uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" +version = "0.1.1" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.ThreadingUtilities]] +deps = ["ManualMemory"] +git-tree-sha1 = "c97f60dd4f2331e1a495527f80d242501d2f9865" +uuid = "8290d209-cae3-49c0-8002-c8c24d57dab5" +version = "0.5.1" + +[[deps.TinyHugeNumbers]] +git-tree-sha1 = "d1bd5b57d45431fcbf2db38d3e17453a603e76ad" +uuid = "783c9a47-75a3-44ac-a16b-f1ab7b3acf04" +version = "1.0.0" + +[[deps.TranscodingStreams]] +deps = ["Random", "Test"] +git-tree-sha1 = "9a6ae7ed916312b41236fcef7e0af564ef934769" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.9.13" + +[[deps.TupleTools]] +git-tree-sha1 = "3c712976c47707ff893cf6ba4354aa14db1d8938" +uuid = "9d95972d-f1c8-5527-a6e0-b4b365fa01f6" +version = "1.3.0" + +[[deps.URIs]] +git-tree-sha1 = "074f993b0ca030848b897beff716d93aca60f06a" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.4.2" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.UnPack]] +git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" +uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" +version = "1.0.2" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.UnicodeFun]] +deps = ["REPL"] +git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" +uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" +version = "0.4.1" + +[[deps.Unrolled]] +deps = ["MacroTools"] +git-tree-sha1 = "6cc9d682755680e0f0be87c56392b7651efc2c7b" +uuid = "9602ed7d-8fef-5bc8-8597-8f21381861e8" +version = "0.1.5" + +[[deps.Unzip]] +git-tree-sha1 = "ca0969166a028236229f63514992fc073799bb78" +uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" +version = "0.2.0" + +[[deps.VectorizationBase]] +deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static", "StaticArrayInterface"] +git-tree-sha1 = "b182207d4af54ac64cbc71797765068fdeff475d" +uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" +version = "0.21.64" + +[[deps.Wayland_jll]] +deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "ed8d92d9774b077c53e1da50fd81a36af3744c1c" +uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" +version = "1.21.0+0" + +[[deps.Wayland_protocols_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4528479aa01ee1b3b4cd0e6faef0e04cf16466da" +uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" +version = "1.25.0+0" + +[[deps.XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] +git-tree-sha1 = "93c41695bc1c08c46c5899f4fe06d6ead504bb73" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.10.3+0" + +[[deps.XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[deps.Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.6.9+4" + +[[deps.Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.9+4" + +[[deps.Xorg_libXcursor_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" +uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" +version = "1.2.0+4" + +[[deps.Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.3+4" + +[[deps.Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.4+4" + +[[deps.Xorg_libXfixes_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" +uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" +version = "5.0.3+4" + +[[deps.Xorg_libXi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] +git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" +uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" +version = "1.7.10+4" + +[[deps.Xorg_libXinerama_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] +git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" +uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" +version = "1.1.4+4" + +[[deps.Xorg_libXrandr_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" +uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" +version = "1.5.2+4" + +[[deps.Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.10+4" + +[[deps.Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.0+3" + +[[deps.Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.13.0+3" + +[[deps.Xorg_libxkbfile_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" +uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" +version = "1.1.0+4" + +[[deps.Xorg_xcb_util_image_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" +uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] +git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" +uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_keysyms_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" +uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_renderutil_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" +uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" +version = "0.3.9+1" + +[[deps.Xorg_xcb_util_wm_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" +uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" +version = "0.4.1+1" + +[[deps.Xorg_xkbcomp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] +git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" +uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" +version = "1.4.2+4" + +[[deps.Xorg_xkeyboard_config_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] +git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" +uuid = "33bec58e-1273-512f-9401-5d533626f822" +version = "2.27.0+4" + +[[deps.Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.4.0+3" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.12+3" + +[[deps.Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "49ce682769cd5de6c72dcf1b94ed7790cd08974c" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.5+0" + +[[deps.fzf_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "868e669ccb12ba16eaf50cb2957ee2ff61261c56" +uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09" +version = "0.29.0+0" + +[[deps.libaom_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3a2ea60308f0996d26f1e5354e10c24e9ef905d4" +uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" +version = "3.4.0+0" + +[[deps.libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.15.1+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.1.1+0" + +[[deps.libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "2.0.2+0" + +[[deps.libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.38+0" + +[[deps.libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.48.0+0" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+0" + +[[deps.x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2021.5.5+0" + +[[deps.x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.5.0+0" + +[[deps.xkbcommon_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "9ebfc140cc56e8c2156a15ceac2f0302e327ac0a" +uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" +version = "1.4.1+0" diff --git a/src/Part1/Policy Inference.ipynb b/Part1/Policy_Inference.ipynb similarity index 91% rename from src/Part1/Policy Inference.ipynb rename to Part1/Policy_Inference.ipynb index 345ca21..45775af 100644 --- a/src/Part1/Policy Inference.ipynb +++ b/Part1/Policy_Inference.ipynb @@ -5,18 +5,10 @@ "execution_count": null, "id": "d06d6350", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], + "outputs": [], "source": [ - "using Pkg;Pkg.activate(\"../..\");Pkg.instantiate();\n", - "using RxInfer,ReactiveMP,GraphPPL,Rocket, LinearAlgebra, Distributions, Random\n", + "using Pkg;Pkg.activate(\"..\");Pkg.instantiate();\n", + "using RxInfer, LinearAlgebra, Distributions, Random\n", "Random.seed!(666)" ] }, @@ -33,7 +25,7 @@ "include(\"transition_mixture/in.jl\")\n", "include(\"transition_mixture/out.jl\")\n", "include(\"transition_mixture/switch.jl\")\n", - "include(\"goal_observation.jl\")\n", + "include(\"../goal_observation.jl\")\n", "include(\"helpers.jl\")" ] }, @@ -173,7 +165,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.8.5", + "display_name": "Julia 1.8.2", "language": "julia", "name": "julia-1.8" }, @@ -181,7 +173,7 @@ "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.8.5" + "version": "1.8.2" } }, "nbformat": 4, diff --git a/src/Part1/helpers.jl b/Part1/helpers.jl similarity index 64% rename from src/Part1/helpers.jl rename to Part1/helpers.jl index 0185f10..ccef26c 100644 --- a/src/Part1/helpers.jl +++ b/Part1/helpers.jl @@ -1,4 +1,7 @@ +using ReactiveMP + import LinearAlgebra: I + function softmax(x::Vector) r = x .- maximum(x) clamp!(r, -100,0.0) @@ -10,7 +13,6 @@ end const safelog = ReactiveMP.clamplog -# Stolen from the Epistemic Value paper function constructABCD(α::Float64, Cs,T) # Observation model A_1 = [0.5 0.5; @@ -42,29 +44,7 @@ function constructABCD(α::Float64, Cs,T) # 0's violate the domain of the Dirichlet distribution and breaks FE calculation A .+= tiny - # Transition model, Karls version - # - # B_1 = kron([1 0 0 1; # Row: can I move to 1? - # 0 1 0 0; - # 0 0 1 0; - # 0 0 0 0], I(2)) - - # B_2 = kron([0 0 0 0; - # 1 1 0 1; # Row: can I move to 2? - # 0 0 1 0; - # 0 0 0 0], I(2)) - - # B_3 = kron([0 0 0 0; - # 0 1 0 0; - # 1 0 1 1; # Row: can I move to 3? - # 0 0 0 0], I(2)) - - # B_4 = kron([0 0 0 0; - # 0 1 0 0; - # 0 0 1 0; - # 1 0 0 1], I(2)) # Row: can I move to 4? - - # Transition model, Thijs version + # Transition model B_1 = kron([1 1 1 1; # Row: can I move to 1? 0 0 0 0; 0 0 0 0; @@ -91,8 +71,6 @@ function constructABCD(α::Float64, Cs,T) C = [softmax(kron(ones(4), [0.0, 0.0, c, -c])) for c in Cs] # Initial state prior - # Note: in the epistemic value paper (Friston, 2015) there is a softmax over D. - # However, from the context as described in the paper this appears to be a notational error. D = kron([1.0, 0.0, 0.0, 0.0], [0.5, 0.5]) return (A, B, C, D) diff --git a/src/Part1/transition_mixture/in.jl b/Part1/transition_mixture/in.jl similarity index 100% rename from src/Part1/transition_mixture/in.jl rename to Part1/transition_mixture/in.jl diff --git a/src/Part1/transition_mixture/marginals.jl b/Part1/transition_mixture/marginals.jl similarity index 100% rename from src/Part1/transition_mixture/marginals.jl rename to Part1/transition_mixture/marginals.jl diff --git a/src/Part1/transition_mixture/out.jl b/Part1/transition_mixture/out.jl similarity index 100% rename from src/Part1/transition_mixture/out.jl rename to Part1/transition_mixture/out.jl diff --git a/src/Part1/transition_mixture/switch.jl b/Part1/transition_mixture/switch.jl similarity index 100% rename from src/Part1/transition_mixture/switch.jl rename to Part1/transition_mixture/switch.jl diff --git a/src/Part1/transition_mixture/testing_ground.jl b/Part1/transition_mixture/testing_ground.jl similarity index 100% rename from src/Part1/transition_mixture/testing_ground.jl rename to Part1/transition_mixture/testing_ground.jl diff --git a/src/Part1/transition_mixture/transition_mixture.jl b/Part1/transition_mixture/transition_mixture.jl similarity index 100% rename from src/Part1/transition_mixture/transition_mixture.jl rename to Part1/transition_mixture/transition_mixture.jl diff --git a/src/Part2/Rx/T-maze_Aggregate.ipynb b/Part2/T-maze_Aggregate.ipynb similarity index 92% rename from src/Part2/Rx/T-maze_Aggregate.ipynb rename to Part2/T-maze_Aggregate.ipynb index dabd6cb..2916aeb 100644 --- a/src/Part2/Rx/T-maze_Aggregate.ipynb +++ b/Part2/T-maze_Aggregate.ipynb @@ -15,8 +15,8 @@ "outputs": [], "source": [ "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" + "Pkg.activate(\"..\")\n", + "Pkg.instantiate()" ] }, { @@ -42,7 +42,7 @@ "metadata": {}, "outputs": [], "source": [ - "include(\"goal_observation.jl\")\n", + "include(\"../goal_observation.jl\")\n", "\n", "# Define the generative model\n", "@model function t_maze(A_s, D_s, x)\n", @@ -90,7 +90,7 @@ "# Define experimental setting\n", "α = 0.9; c = 2.0 # Reward probability and utility\n", "R = 100 # Number of runs\n", - "S = 30 # Number of trials\n", + "S = 30 # Number of trials per run\n", "seed = 666 # Randomizer seed\n", "\n", "include(\"helpers.jl\")\n", @@ -157,7 +157,7 @@ "# Load data from file\n", "using FileIO, JLD2, Plots, Statistics, Distributions\n", "\n", - "pairs = FileIO.load(\"figures/wins_100_30.jld2\")\n", + "pairs = FileIO.load(\"figures/wins_100_30.jld2\") # Load file with particular R and S\n", "wins = pairs[\"wins\"]\n", "params = pairs[\"params\"]\n", "R = pairs[\"R\"]\n", @@ -171,8 +171,8 @@ "metadata": {}, "outputs": [], "source": [ - "win_counts = Int64.(sum.(wins))\n", - "f_ideal = pdf.(Binomial(S, 0.9), 1:S).*R\n", + "win_counts = Int64.(sum.(wins)) # Count wins per run\n", + "f_ideal = pdf.(Binomial(S, 0.9), 1:S).*R # Ideal distribution for alpha=0.9\n", "\n", "# Plot histogram for number of wins per run\n", "histogram(win_counts, bins=-1:1:S, \n", @@ -196,7 +196,7 @@ "metadata": {}, "outputs": [], "source": [ - "m = mean(wins)\n", + "m = mean(wins) # Compute win average\n", "\n", "# Plot average wins per trial\n", "plot(1:S, m, ylim=(0,1),\n", @@ -207,7 +207,7 @@ " label=false, \n", " xlabel=\"Simulation Trial (s)\", \n", " ylabel=\"Win Average\")\n", - "plot!(1:S, 0.9.*ones(S), color=:black, linestyle=:dash, lw=2, label=false, legend=0)\n", + "plot!(1:S, 0.9.*ones(S), color=:black, linestyle=:dash, lw=2, label=false, legend=0) # Plot ideal win average for alpha=0.9\n", "\n", "savefig(\"figures/GFE_wins.png\")" ] diff --git a/src/Part2/Rx/T-maze_Bethe.ipynb b/Part2/T-maze_Bethe.ipynb similarity index 97% rename from src/Part2/Rx/T-maze_Bethe.ipynb rename to Part2/T-maze_Bethe.ipynb index 0f06adf..27923c1 100644 --- a/src/Part2/Rx/T-maze_Bethe.ipynb +++ b/Part2/T-maze_Bethe.ipynb @@ -15,8 +15,8 @@ "outputs": [], "source": [ "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" + "Pkg.activate(\"..\")\n", + "Pkg.instantiate()" ] }, { @@ -42,7 +42,7 @@ "metadata": {}, "outputs": [], "source": [ - "include(\"goal_observation.jl\")\n", + "include(\"../goal_observation.jl\")\n", "\n", "# Define the generative model\n", "@model function t_maze(A_s, D_s, x)\n", diff --git a/src/Part2/Rx/T-maze_Generalized.ipynb b/Part2/T-maze_Generalized.ipynb similarity index 97% rename from src/Part2/Rx/T-maze_Generalized.ipynb rename to Part2/T-maze_Generalized.ipynb index d51d38c..1558ce5 100644 --- a/src/Part2/Rx/T-maze_Generalized.ipynb +++ b/Part2/T-maze_Generalized.ipynb @@ -15,8 +15,8 @@ "outputs": [], "source": [ "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" + "Pkg.activate(\"..\")\n", + "Pkg.instantiate()" ] }, { @@ -42,7 +42,7 @@ "metadata": {}, "outputs": [], "source": [ - "include(\"goal_observation.jl\")\n", + "include(\"../goal_observation.jl\")\n", "\n", "# Define the generative model\n", "@model function t_maze(A_s, D_s, x)\n", @@ -162,7 +162,7 @@ "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.8.5" + "version": "1.8.2" } }, "nbformat": 4, diff --git a/src/Part2/Rx/agent.jl b/Part2/agent.jl similarity index 100% rename from src/Part2/Rx/agent.jl rename to Part2/agent.jl diff --git a/src/Part2/Rx/environment.jl b/Part2/environment.jl similarity index 100% rename from src/Part2/Rx/environment.jl rename to Part2/environment.jl diff --git a/Part2/figures/BFE_A.png b/Part2/figures/BFE_A.png new file mode 100644 index 0000000000000000000000000000000000000000..b2246e2f8053814e5fe7037cefc1c371c7f15c97 GIT binary patch literal 35911 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 ayUzP_+Tzd^8Mfk+&Yd}b#zjN>9sdt*#bm_* literal 0 HcmV?d00001 diff --git a/Part2/figures/BFE_FE.png b/Part2/figures/BFE_FE.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fa173cb9942cc673be63222c484113a6e89763 GIT binary patch literal 89510 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 literal 0 HcmV?d00001 diff --git a/Part2/figures/GFE_A.png b/Part2/figures/GFE_A.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9c81aae9812fd88bb9c0050605d59e42c935c0 GIT binary patch literal 41630 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 by?J+N(w#BAZ&&sgzPpjZ{5jY3R_y&>+Nvnh literal 0 HcmV?d00001 diff --git a/Part2/figures/GFE_FE.png b/Part2/figures/GFE_FE.png new file mode 100644 index 0000000000000000000000000000000000000000..5b9ae13e7bda3ad1df23cb033bd54cfb1daec4cd GIT binary patch literal 131838 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 literal 0 HcmV?d00001 diff --git a/Part2/figures/GFE_wins.png b/Part2/figures/GFE_wins.png new file mode 100644 index 0000000000000000000000000000000000000000..c12f9f337803d5bd65d74f24e815d43443c8583a GIT binary patch literal 53375 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 RUE$}pG+Vjkyouv4{|m2T3Yq`_ literal 0 HcmV?d00001 diff --git a/Part2/figures/wins_100_30.jld2 b/Part2/figures/wins_100_30.jld2 new file mode 100644 index 0000000000000000000000000000000000000000..df77e50629ba27e7849fd9fb5b70502331b0bd09 GIT binary patch literal 148651 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 ] +``` +Next, activate the virtual environment +``` +(v1.8) pkg> activate . +``` +and instantiate the required packages +``` +(SAIF) pkg> instantiate +``` +This will download and install the required packages in the virtual environment named SAIF. + +# Run the demos +Exit Julia, navigate to the root directory and start a Jupyter server +``` +~/SAIF$ jupyter notebook +``` +A browser window will open, and you can select the demo you wish to run. + +# License +MIT License, Copyright (c) 2023 BIASlab http://biaslab.org \ No newline at end of file diff --git a/archive/DiscreteLAIF.jl b/archive/DiscreteLAIF.jl deleted file mode 100644 index 139d359..0000000 --- a/archive/DiscreteLAIF.jl +++ /dev/null @@ -1,244 +0,0 @@ -using ForwardDiff: jacobian -using DomainSets: FullSpace -include("matrixlogpdf.jl") - -#TODO: make sure BetheMeta does not take any arbitrary thing -#TODO: Reproduced FL experiments -#TODO: Check that pipeline works for messages towards A. Do we still get q_A? - -# Use custom pipeline to get marginal and message on incoming edge -struct GFEPipeline{I,M} <: ReactiveMP.AbstractNodeFunctionalDependenciesPipeline - indices::I - init_message::M -end - -function ReactiveMP.message_dependencies(pipeline::GFEPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - # We simply override the messages dependencies with the provided indices - for index in pipeline.indices - output = ReactiveMP.messagein(nodeinterfaces[index]) - ReactiveMP.setmessage!(output, pipeline.init_message[index]) - end - return map(inds -> map(i -> @inbounds(nodeinterfaces[i]), inds), pipeline.indices) -end - -function ReactiveMP.marginal_dependencies(pipeline::GFEPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - # For marginals we require marginal on the same edges as in the provided indices - require_marginal = ReactiveMP.RequireMarginalFunctionalDependencies(pipeline.indices, map(_ -> nothing, pipeline.indices)) - return ReactiveMP.marginal_dependencies(require_marginal, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) -end - -# Helper functions -# We don't want log(0) to happen -safelog(x) = ReactiveMP.clamplog(x)#log(clamp(x,tiny,Inf)) -softmax(x) = exp.(x) ./ sum(exp.(x)) - -# Metas to change behaviour between BFE and GFE -struct PSubstitutionMeta end -struct UnobservedBetheMeta end - -# Optionally add data constraints -struct ObservedBetheMeta{I} - δ::I -end - -struct ObservedPSubstitutionMeta{I} - δ::I -end - - -struct DiscreteLAIF end -# Define node -@node DiscreteLAIF Stochastic [out,in, A] - -# Compute the h vector -_h(A) = -diag(A' * ReactiveMP.clamplog.(A)) -mean_h(A) = mean( _h.(rand(A,10))) - -### Unobserved PSubstitution -# GFE Energy -@average_energy DiscreteLAIF (q_out::Union{Dirichlet,PointMass}, q_in::Categorical, q_A::Union{PointMass,MatrixDirichlet},meta::PSubstitutionMeta) = begin - s = probvec(q_in) - A = mean(q_A) - c = mean(q_out) - - #-s' * diag(A' * safelog.(A)) + (A*s)'*(safelog.(A*s) .- safelog.(c)) - -s' * -mean_h(q_A) + (A*s)'*(safelog.(A*s) .- safelog.(c)) -end - - -# GFE Message towards A -@rule DiscreteLAIF(:A, Marginalisation) (q_out::Union{PointMass,Dirichlet}, m_in::Categorical, q_in::Categorical, q_A::MatrixDirichlet, m_A::Any, meta::PSubstitutionMeta) = begin - A_bar = mean(q_A) - c = mean(q_out) - s = probvec(q_in) - - # LogPdf - logpdf(A) = s' *( diag(A'*safelog.(A)) + A'*(safelog.(c) - safelog.(A_bar*s))) - return ContinuousMatrixvariateLogPdf(FullSpace(),logpdf) -end - -# GFE Message towards input -@rule DiscreteLAIF(:in, Marginalisation) (q_out::Union{Dirichlet,PointMass},m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass}, m_A::Any,meta::Any) = begin - # Ignore message from A for both the observed and unobserved cases - @call_rule typeof(DiscreteLAIF)(:in,Marginalisation) (q_out = q_out, m_in = m_in, q_in = q_in, q_A = q_A, meta=meta) -end - - -@rule DiscreteLAIF(:in, Marginalisation) (m_in::DiscreteNonParametric, q_out::Union{Dirichlet,PointMass}, q_in::DiscreteNonParametric, q_A::Union{MatrixDirichlet,PointMass}, meta::PSubstitutionMeta) = begin - - d = probvec(m_in) - s = probvec(q_in) - A = mean(q_A) - C = mean(q_out) - - # Newton iterations for stability - #g(s) = s - softmax(diag(A'*safelog.(A)) + A'*safelog.(C) - A'*safelog.(A*s) + safelog.(d)) - g(s) = s - softmax( -mean_h(q_A) + A'*safelog.(C) - A'*safelog.(A*s) + safelog.(d)) - - s_k = deepcopy(s) - for i in 1:20 # TODO make this user specified - s_k = s_k - inv(jacobian(g,s_k)) * g(s_k) - end - - ρ = s_k ./ (d .+ 1e-6) - - return Categorical(ρ ./ sum(ρ)) -end - - -# Message towards output (goal parameters) -@rule DiscreteLAIF(:out,Marginalisation) (m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass},m_A::Any,meta::PSubstitutionMeta) = begin - A = mean(q_A) - s = probvec(q_in) - return Dirichlet(A * s .+ 1.0) -end - -### Observed PSubstitution -# GFE Energy -@average_energy DiscreteLAIF (q_out::Union{Dirichlet,PointMass}, q_in::Categorical, q_A::Union{PointMass,MatrixDirichlet},meta::ObservedPSubstitutionMeta) = begin - x = meta.δ - s = probvec(q_in) - A = mean(q_A) - c = mean(q_out) - - -x' * (safelog.(A)*s + safelog.(c)) -end - - -# GFE Message towards A -@rule DiscreteLAIF(:A, Marginalisation) (q_out::Union{PointMass,Dirichlet}, m_in::Categorical, q_in::Categorical, q_A::MatrixDirichlet, m_A::Any, meta::ObservedPSubstitutionMeta) = begin - x = meta.δ - s = probvec(q_in) - - return MatrixDirichlet(x*s' .+ 1) -end - -# GFE Message towards input -@rule DiscreteLAIF(:in, Marginalisation) (q_out::Union{Dirichlet,PointMass},m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass},meta::ObservedPSubstitutionMeta) = begin - x = meta.δ - A = mean(q_A) - ρ = safelog.(A)' * x - - return Categorical(softmax(ρ)) -end - - -# Message towards output (goal parameters) -@rule DiscreteLAIF(:out,Marginalisation) (m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass},m_A::Any,meta::ObservedPSubstitutionMeta) = begin - x = meta.δ - return Dirichlet(x .+ 1) -end - -### Unobserved Bethe -# BFE Energy -@average_energy DiscreteLAIF (q_out::Union{Dirichlet,PointMass}, q_in::Categorical, q_A::Union{PointMass,MatrixDirichlet},meta::UnobservedBetheMeta) = begin - - s = probvec(q_in) - A = mean(q_A) - c = mean(q_out) - - # Compute internal marginal - x = softmax(safelog.(A) * s + safelog.(c)) - - -x' * (safelog.(A)*s + safelog.(c)) + x' * safelog.(x) -end - - -# BFE Message towards A -@rule DiscreteLAIF(:A, Marginalisation) (q_out::Union{PointMass,Dirichlet}, m_in::Categorical, q_in::Categorical, q_A::MatrixDirichlet, m_A::Any, meta::UnobservedBetheMeta) = begin - - c = mean(q_out) - s = probvec(q_in) - A = mean(q_A) - - # Compute internal marginal - x = softmax(safelog.(A) * s + safelog.(c)) - - return MatrixDirichlet(x*s' .+ 1) -end - -# BFE Message towards input -@rule DiscreteLAIF(:in, Marginalisation) (q_out::Union{Dirichlet,PointMass},m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass},meta::UnobservedBetheMeta) = begin - c = mean(q_out) - s = probvec(q_in) - A = mean(q_A) - - # Compute internal marginal - x = softmax(safelog.(A) * s + safelog.(c)) - - ρ = safelog.(A)' * x - - return Categorical(softmax(ρ)) -end - - -# BFE Message towards output (goal parameters) -@rule DiscreteLAIF(:out,Marginalisation) (m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass},m_A::Any, meta::UnobservedBetheMeta) = begin - c = mean(q_out) - s = probvec(q_in) - A = mean(q_A) - - # Compute internal marginal - x = softmax(safelog.(A) * s + safelog.(c)) - return Dirichlet(x .+ 1) -end - -### Observed Bethe -# BFE Energy -@average_energy DiscreteLAIF (q_out::Union{Dirichlet,PointMass}, q_in::Categorical, q_A::Union{PointMass,MatrixDirichlet},meta::ObservedBetheMeta) = begin - - s = probvec(q_in) - A = mean(q_A) - c = mean(q_out) - - x = meta.δ - - -x' * (safelog.(A)*s + safelog.(c)) + x' * safelog.(x) -end - - -# BFE Message towards A -@rule DiscreteLAIF(:A, Marginalisation) (q_out::Union{PointMass,Dirichlet}, m_in::Categorical, q_in::Categorical, q_A::MatrixDirichlet, m_A::Any, meta::ObservedBetheMeta) = begin - - s = probvec(q_in) - x = meta.δ - - return MatrixDirichlet(x*s' .+ 1) -end - -# BFE Message towards input -@rule DiscreteLAIF(:in, Marginalisation) (q_out::Union{Dirichlet,PointMass},m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass}, m_A::Any, meta::ObservedBetheMeta) = begin - A = mean(q_A) - x = meta.δ - - ρ = safelog.(A)' * x - - return Categorical(softmax(ρ)) -end - - -# BFE Message towards output (goal parameters) -@rule DiscreteLAIF(:out,Marginalisation) (m_in::Categorical, q_in::Categorical, q_A::Union{MatrixDirichlet,PointMass}, m_A::Any,meta::ObservedBetheMeta) = begin - x = meta.δ - return Dirichlet(x .+ 1) -end diff --git a/archive/GFECategorical.jl b/archive/GFECategorical.jl deleted file mode 100644 index 0b1a7ca..0000000 --- a/archive/GFECategorical.jl +++ /dev/null @@ -1,128 +0,0 @@ -using ForwardDiff: jacobian -using DomainSets: FullSpace -include("matrixlogpdf.jl") - -# Helper functions -# We don't want log(0) to happen -safelog(x) = log(clamp(x,tiny,Inf)) -softmax(x) = exp.(x) ./ sum(exp.(x)) - -ReactiveMP.mean(::typeof(safelog), p::PointMass) = safelog.(mean(p)) - -import ReactiveMP: AbstractFormConstraint - -struct PSubstitutionProduct <: AbstractFormConstraint end - -ReactiveMP.make_form_constraint(::Type{PSubstitutionProduct}) = PSubstitutionProduct() - -ReactiveMP.is_point_mass_form_constraint(::PSubstitutionProduct) = false -ReactiveMP.default_form_check_strategy(::PSubstitutionProduct) = FormConstraintCheckLast() -ReactiveMP.default_prod_constraint(::PSubstitutionProduct) = ProdGeneric() - -function ReactiveMP.constrain_form(::PSubstitutionProduct, distribution) - error("Unexpected") -end - -# Custom marginal struct for the goal edge inside composite node -struct WMarginal{A, I, P, Q} - m_a :: A # q(A) - m_in :: I # q(A) * q(z), Ā * z̄ - m_p :: P # Marginal over C - q :: Q # Edge Marginal -end - -ReactiveMP.probvec(dist::WMarginal) = ReactiveMP.probvec(dist.q) -Distributions.entropy(dist::WMarginal) = entropy(dist.q) - -function ReactiveMP.constrain_form(::PSubstitutionProduct, distribution::DistProduct) - return WMarginal(distribution.left[:A], distribution.left[:in], distribution.right[:p], distribution.left[:μ]) -end - -struct GFEPipeline{I} <: ReactiveMP.AbstractNodeFunctionalDependenciesPipeline - indices::I -end - -function ReactiveMP.message_dependencies(pipeline::GFEPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - # We simply override the messages dependencies with the provided indices - # for index in pipeline.indices - # output = ReactiveMP.messagein(nodeinterfaces[index]) - # ReactiveMP.setmessage!(output, Categorical(ones(8) ./ 8)) - # end - return map(inds -> map(i -> @inbounds(nodeinterfaces[i]), inds), pipeline.indices) -end - -function ReactiveMP.marginal_dependencies(pipeline::GFEPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - # For marginals we require marginal on the same edges as in the provided indices - require_marginal = ReactiveMP.RequireMarginalFunctionalDependencies(pipeline.indices, map(_ -> nothing, pipeline.indices)) - return ReactiveMP.marginal_dependencies(require_marginal, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) -end - -struct PSubstitutionMeta end - -@average_energy Transition (q_out::WMarginal, q_in::Categorical, q_a::PointMass, meta::PSubstitutionMeta) = begin - s = probvec(q_in) - A = mean(q_a) - c = probvec(q_out) - - -s' * diag(A' * safelog.(A)) - (A*s)'*safelog.(c) + (A*s)' * safelog.(A*s) -end - -@average_energy Categorical (q_out::WMarginal, q_p::Any, meta::PSubstitutionMeta) = begin - -sum(probvec(q_out) .* mean(ReactiveMP.clamplog, q_p)) -end - -@rule Transition(:out, Marginalisation) (m_in::Categorical, q_in::Categorical, q_a::Any, meta::PSubstitutionMeta) = begin - a = clamp.(exp.(mean(safelog, q_a) * probvec(q_in)), tiny, Inf) - μ = Categorical(a ./ sum(a)) - return (A = q_a, in = q_in, μ = μ) -end - -@rule Transition(:out, Marginalisation) (m_in::Categorical, q_in::Categorical, q_a::PointMass, meta::PSubstitutionMeta) = begin - a = mean(q_a) * probvec(q_in) - μ = Categorical(a ./ sum(a)) - return (A = q_a, in = q_in, μ = μ) -end - -# Message towards A -@rule Transition(:a, Marginalisation) (q_out::WMarginal, m_in::Categorical, q_a::Any, meta::PSubstitutionMeta) = begin - A_bar = mean(q_a) - c = mean(q_out.m_p) # This comes from the `Categorical` node as a named tuple TODO: bvdmitri double check - s = probvec(q_in) - # LogPdf - logpdf(A) = s' *( diag(A'*safelog.(A)) + A'*(safelog.(c) - safelog.(A_bar*s))) - return ContinuousMatrixvariateLogPdf(FullSpace(),logpdf) -end - -@rule Transition(:in, Marginalisation) (q_out::WMarginal, m_in::Categorical, q_in::Categorical, q_a::Any, meta::PSubstitutionMeta) = begin - - s = probvec(q_in) - d = probvec(m_in) - A = mean(q_a) - - # Grab the goal marginal - C = mean(q_out.m_p) # TODO: bvdmitri double check. Checks out --M - - # Newton iterations for stability - g(s) = s - softmax(safelog.(d) + diag(A' * safelog.(A)) + A' *(safelog.(C) - safelog.(A * s))) - - s_k = deepcopy(s) - for i in 1:20 # TODO make this user specified - s_k = s_k - inv(jacobian(g,s_k)) * g(s_k) - end - - ρ = s_k ./ (d .+ 1e-6) - return Categorical(ρ ./ sum(ρ)) -end - -# Rule towards "observations" -@rule Categorical(:out, Marginalisation) (q_p::Any, meta::PSubstitutionMeta) = begin - return (p = q_p, ) -end - -# Rule towards goal parameters -@rule Categorical(:p, Marginalisation) (q_out::WMarginal, meta::PSubstitutionMeta) = begin - A = mean(q_out.m_a) - s = probvec(q_out.m_in) - return Dirichlet(A * s .+ 1.0) -end - diff --git a/archive/GFECategorical_old.jl b/archive/GFECategorical_old.jl deleted file mode 100644 index e1a7fd4..0000000 --- a/archive/GFECategorical_old.jl +++ /dev/null @@ -1,108 +0,0 @@ -using ForwardDiff: jacobian -using DomainSets: FullSpace - -import Base: prod - -# Helper functions -# We don't want log(0) to happen -safelog(x) = log(clamp(x,tiny,Inf)) -#normalize(x) = x ./ sum(x) -softmax(x) = exp.(x) ./ sum(exp.(x)) - -# Meta object to replicate the classic EFE schedule -struct ForwardOnlyMeta end - -struct GFECategorical end -@node GFECategorical Stochastic [out,in,A] - -@average_energy GFECategorical (q_out::PointMass, q_in::Categorical,q_A::PointMass,) = begin - s = probvec(q_in) - A = mean(q_A) - c = probvec(q_out) - - -s' * diag(A' * safelog.(A)) + (A*s)'* safelog.(A*s) - (A*s)'*safelog.(c) -end - - -@rule GFECategorical(:in, Marginalisation) (m_out::PointMass, q_out::PointMass,m_in::DiscreteNonParametric, q_in::DiscreteNonParametric, m_A::PointMass, q_A::PointMass,) = begin - - z = probvec(q_in) - d = probvec(m_in) - A = mean(q_A) - - # We use the goal prior on an edge here - C = probvec(q_out) - - # Newton iterations for stability - g(s) = s - softmax(safelog.(d) + diag(A' * safelog.(A)) + A' *(safelog.(C) - safelog.(A * s))) - - z_min = z - for i in 1:20 # TODO make this user specified - z_k = z_min - inv(jacobian(g,z_min)) * g(z_min) - z_min = z_k - end - z_k = z_min - - ρ = z_k ./ (d .+ tiny) - return Categorical(ρ ./ sum(ρ)) -end - -@rule GFECategorical(:in, Marginalisation) (m_out::PointMass, q_out::PointMass,m_in::DiscreteNonParametric, q_in::DiscreteNonParametric, m_A::MatrixDirichlet, q_A::MatrixDirichlet,) = begin - @call_rule GFECategorical(:in, Marginalisation) (m_out = m_out, q_out = q_out, m_in = m_in, q_in = q_in, m_A = PointMass(mean(m_A)), q_A = PointMass(mean(q_A)),) -end - -# Block backwards rule if using ForwardOnlyMeta. Replicates standard EFE schedule -@rule GFECategorical(:in, Marginalisation) (m_out::PointMass, q_out::PointMass,m_in::DiscreteNonParametric, q_in::DiscreteNonParametric, m_A::PointMass, q_A::PointMass, meta::ForwardOnlyMeta) = begin - return missing -end - - - -# Message towards A -import Distributions.rand - - - -@rule GFECategorical(:A,Marginalisation) (m_out::PointMass, q_out::PointMass,m_in::DiscreteNonParametric, q_in::DiscreteNonParametric, m_A::MatrixDirichlet, q_A::MatrixDirichlet,) = begin - A_bar = mean(q_A) - c = probvec(m_out) - s = probvec(m_in) - - # LogPdf - logpdf(A) = s' *( diag(A'*safelog.(A)) + A'*(safelog.(c) - safelog.(A_bar*s))) - return ContinuousMatrixvariateLogPdf(FullSpace(),logpdf) - -end - - -# Draw sample from a Matrixvariate Dirichlet distribution with independent rows -# TODO: Find a way to not create a bunch of intermediate Dirichlet distributions -function rand(dist::MatrixDirichlet) - α = clamp.(dist.a,tiny,Inf) - # Sample from independent rowwise Dirichlet distributions and replace NaN's with 0.0. - # We replace NaN's to allow for rows of 0's which are common in AIF modelling - replace!(reduce(hcat, Distributions.rand.(Dirichlet.(eachrow(α))))', NaN => 0.0) -end - - -# We need a product of MatrixVariate Logpdf's and MatrixDirichlet to compute the marginal over the transition matrix. We approximate it using EVMP (Add citation to Semihs paper) -# TODO: Is this really ProdAnalytical? -# TODO: Check that the DomainSpace is right. Replace with "Unspecified" -import Base: prod -prod(::ProdAnalytical, left::MatrixDirichlet{Float64, Matrix{Float64}}, right::ContinuousMatrixvariateLogPdf{FullSpace{Float64}}) = begin - _logpdf = right.logpdf - - # Draw 50 samples - weights = [] - samples = [] - for n in 1:50 - A_hat = rand(left) - ρ_n = exp(_logpdf(A_hat)) - - push!(samples, A_hat) - push!(weights, ρ_n) - end - #Z = sum(weights) - #return MatrixDirichlet(sum(samples .* weights) / Z) - return SampleList(samples,weights) -end diff --git a/archive/GFEGaussian.jl b/archive/GFEGaussian.jl deleted file mode 100644 index 54052fe..0000000 --- a/archive/GFEGaussian.jl +++ /dev/null @@ -1,95 +0,0 @@ -using ForwardDiff: jacobian -using Plots -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions; -enable_autocomplete_brackets(false); -unicodeplots() - -### -TODO: -How to deal with the ratio of Gaussian distributions? -Approximate with moment matching? LaPlace? Something? -### - -# Helper functions -# We don't want log(0) to happen -safelog(x) = log(clamp(x,tiny,Inf)) -normalize(x) = x ./ sum(x) -softmax(x) = exp.(x) ./ sum(exp.(x)) - -struct ForwardOnlyMeta end - -struct GFEGaussian end -@node GFEGaussian Stochastic [out,in,Σ] - -@average_energy GFEGaussian (q_out::PointMass, q_in::MvNormalMeanVariance,q_A::PointMass,) = begin - s = probvec(q_in) - A = mean(q_A) - c = probvec(q_out) - - -s' * diag(A' * safelog.(A)) + (A*s)'* safelog.(A*s) - (A*s)'*safelog.(c) -end - - -@rule GFEGaussian(:in, Marginalisation) (m_out::MvNormalMeanPrecision, q_out::MvNormalMeanPrecision,m_in::MvNormalMeanPrecision, q_in::MvNormalMeanPrecision, m_Σ::PointMass,) = begin - - # We use the goal prior on an edge here - ξ_c,Λ_c = weightedmean_invcov(q_out) - - # incoming message - ξ_b,Λ_b = weightedmean_invcov(m_in) - - # Incoming marginal - ξ_s,Λ_s = weightedmean_invcov(q_in) - - - return MvNormalMeanVariance(ρ ./ sum(ρ)) -end - -# Block backwards rule -@rule GFEGaussian(:in, Marginalisation) (m_out::PointMass, q_out::PointMass,m_in::DiscreteNonParametric, q_in::DiscreteNonParametric, m_A::PointMass, q_A::PointMass, meta::ForwardOnlyMeta) = begin - return missing -end - - -using LinearAlgebra - -function posdef(n) - bob = rand(n) - bob * bob' + I(n) -end - -input = MvNormalMeanCovariance(zeros(3), posdef(3)) -# -μ_s,Σ_s = mean_invcov(input) -dims = size(Σ_s) - - -cov(MvNormalMeanCovariance(zeros(3),inv(Σ_s -posdef(3)))) - - - - -g(s) = inv(S_c)*μ_c + inv(S_b + S_s)* = -S_s = - - -unvec(bob) -bob = MvNormalMeanCovariance(ones(2),diageye(2)*2) -weightedmean_invcov(bob) -mean_invcov(bob) - -x_1 = MvNormalMeanCovariance(-rand(2)*10,posdef(2)*20) -x_2 = MvNormalMeanCovariance(rand(2)*4,posdef(2)) - - -n_samples = 3000 -storage = rand(x_1,n_samples) ./ rand(x_2,n_samples); -histogram(storage[1,:]) -histogram(storage[2,:]) - -plot(storage[1,:]) -plot(storage[2,:]) - -cov(storage[1,:]) -mean(storage[2,:]) -cov(storage[2,:]) diff --git a/archive/GFEtesting.jl b/archive/GFEtesting.jl deleted file mode 100644 index 0b1a7ca..0000000 --- a/archive/GFEtesting.jl +++ /dev/null @@ -1,128 +0,0 @@ -using ForwardDiff: jacobian -using DomainSets: FullSpace -include("matrixlogpdf.jl") - -# Helper functions -# We don't want log(0) to happen -safelog(x) = log(clamp(x,tiny,Inf)) -softmax(x) = exp.(x) ./ sum(exp.(x)) - -ReactiveMP.mean(::typeof(safelog), p::PointMass) = safelog.(mean(p)) - -import ReactiveMP: AbstractFormConstraint - -struct PSubstitutionProduct <: AbstractFormConstraint end - -ReactiveMP.make_form_constraint(::Type{PSubstitutionProduct}) = PSubstitutionProduct() - -ReactiveMP.is_point_mass_form_constraint(::PSubstitutionProduct) = false -ReactiveMP.default_form_check_strategy(::PSubstitutionProduct) = FormConstraintCheckLast() -ReactiveMP.default_prod_constraint(::PSubstitutionProduct) = ProdGeneric() - -function ReactiveMP.constrain_form(::PSubstitutionProduct, distribution) - error("Unexpected") -end - -# Custom marginal struct for the goal edge inside composite node -struct WMarginal{A, I, P, Q} - m_a :: A # q(A) - m_in :: I # q(A) * q(z), Ā * z̄ - m_p :: P # Marginal over C - q :: Q # Edge Marginal -end - -ReactiveMP.probvec(dist::WMarginal) = ReactiveMP.probvec(dist.q) -Distributions.entropy(dist::WMarginal) = entropy(dist.q) - -function ReactiveMP.constrain_form(::PSubstitutionProduct, distribution::DistProduct) - return WMarginal(distribution.left[:A], distribution.left[:in], distribution.right[:p], distribution.left[:μ]) -end - -struct GFEPipeline{I} <: ReactiveMP.AbstractNodeFunctionalDependenciesPipeline - indices::I -end - -function ReactiveMP.message_dependencies(pipeline::GFEPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - # We simply override the messages dependencies with the provided indices - # for index in pipeline.indices - # output = ReactiveMP.messagein(nodeinterfaces[index]) - # ReactiveMP.setmessage!(output, Categorical(ones(8) ./ 8)) - # end - return map(inds -> map(i -> @inbounds(nodeinterfaces[i]), inds), pipeline.indices) -end - -function ReactiveMP.marginal_dependencies(pipeline::GFEPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - # For marginals we require marginal on the same edges as in the provided indices - require_marginal = ReactiveMP.RequireMarginalFunctionalDependencies(pipeline.indices, map(_ -> nothing, pipeline.indices)) - return ReactiveMP.marginal_dependencies(require_marginal, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) -end - -struct PSubstitutionMeta end - -@average_energy Transition (q_out::WMarginal, q_in::Categorical, q_a::PointMass, meta::PSubstitutionMeta) = begin - s = probvec(q_in) - A = mean(q_a) - c = probvec(q_out) - - -s' * diag(A' * safelog.(A)) - (A*s)'*safelog.(c) + (A*s)' * safelog.(A*s) -end - -@average_energy Categorical (q_out::WMarginal, q_p::Any, meta::PSubstitutionMeta) = begin - -sum(probvec(q_out) .* mean(ReactiveMP.clamplog, q_p)) -end - -@rule Transition(:out, Marginalisation) (m_in::Categorical, q_in::Categorical, q_a::Any, meta::PSubstitutionMeta) = begin - a = clamp.(exp.(mean(safelog, q_a) * probvec(q_in)), tiny, Inf) - μ = Categorical(a ./ sum(a)) - return (A = q_a, in = q_in, μ = μ) -end - -@rule Transition(:out, Marginalisation) (m_in::Categorical, q_in::Categorical, q_a::PointMass, meta::PSubstitutionMeta) = begin - a = mean(q_a) * probvec(q_in) - μ = Categorical(a ./ sum(a)) - return (A = q_a, in = q_in, μ = μ) -end - -# Message towards A -@rule Transition(:a, Marginalisation) (q_out::WMarginal, m_in::Categorical, q_a::Any, meta::PSubstitutionMeta) = begin - A_bar = mean(q_a) - c = mean(q_out.m_p) # This comes from the `Categorical` node as a named tuple TODO: bvdmitri double check - s = probvec(q_in) - # LogPdf - logpdf(A) = s' *( diag(A'*safelog.(A)) + A'*(safelog.(c) - safelog.(A_bar*s))) - return ContinuousMatrixvariateLogPdf(FullSpace(),logpdf) -end - -@rule Transition(:in, Marginalisation) (q_out::WMarginal, m_in::Categorical, q_in::Categorical, q_a::Any, meta::PSubstitutionMeta) = begin - - s = probvec(q_in) - d = probvec(m_in) - A = mean(q_a) - - # Grab the goal marginal - C = mean(q_out.m_p) # TODO: bvdmitri double check. Checks out --M - - # Newton iterations for stability - g(s) = s - softmax(safelog.(d) + diag(A' * safelog.(A)) + A' *(safelog.(C) - safelog.(A * s))) - - s_k = deepcopy(s) - for i in 1:20 # TODO make this user specified - s_k = s_k - inv(jacobian(g,s_k)) * g(s_k) - end - - ρ = s_k ./ (d .+ 1e-6) - return Categorical(ρ ./ sum(ρ)) -end - -# Rule towards "observations" -@rule Categorical(:out, Marginalisation) (q_p::Any, meta::PSubstitutionMeta) = begin - return (p = q_p, ) -end - -# Rule towards goal parameters -@rule Categorical(:p, Marginalisation) (q_out::WMarginal, meta::PSubstitutionMeta) = begin - A = mean(q_out.m_a) - s = probvec(q_out.m_in) - return Dirichlet(A * s .+ 1.0) -end - diff --git a/archive/Project.toml b/archive/Project.toml deleted file mode 100644 index 81648c0..0000000 --- a/archive/Project.toml +++ /dev/null @@ -1 +0,0 @@ -[deps] diff --git a/archive/T-maze, GFE vs BFE.ipynb b/archive/T-maze, GFE vs BFE.ipynb deleted file mode 100644 index 8cca546..0000000 --- a/archive/T-maze, GFE vs BFE.ipynb +++ /dev/null @@ -1,298 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "afdbbb5a", - "metadata": {}, - "source": [ - "# Load packages #" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "e58f4cc1", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg; Pkg.activate(\"..\"); Pkg.instantiate()\n", - "using RxInfer,Distributions,Random,LinearAlgebra, ReactiveMP\n", - "\n", - "include(\"GFECategorical.jl\")\n", - "include(\"helpers.jl\")\n", - "Random.seed!(666)\n", - ";" - ] - }, - { - "cell_type": "markdown", - "id": "302be607", - "metadata": {}, - "source": [ - "# Construct the model #" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "1f13aa63", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "GFEPipeline{Tuple{Int64}}((2,))" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "\n", - "# Rule is missing from RxInfer\n", - "@rule Transition(:in, Marginalisation) (q_out::Any, q_a::Any) = begin\n", - " a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf)\n", - " return Categorical(a ./ sum(a))\n", - "end\n", - "\n", - "# Model for the T-maze experiment \n", - "@model function t_maze(A,B,C,T, pipeline = nothing)\n", - "\n", - " D_0 = datavar(Vector{Float64})\n", - " z_0 ~ Categorical(D_0)\n", - " # We use datavar here since x~ Pointmass is not a thing\n", - " x = datavar(Vector{Float64},T)\n", - " z = randomvar(T)\n", - " w = randomvar(T)\n", - "\n", - " # Requires changes in the ReactiveMP core, `@meta` does not support pipelines (yet)\n", - " pipeline = something(pipeline, ReactiveMP.DefaultFunctionalDependencies())\n", - "\n", - " z_prev = z_0\n", - "\n", - " for t in 1:T\n", - " z[t] ~ Transition(z_prev, B[t])\n", - " w[t] ~ Transition(z[t], A) where { pipeline = pipeline }\n", - " w[t] ~ Categorical(x[t])\n", - " z_prev = z[t]\n", - " end\n", - "end;\n", - "\n", - "# Edge Constraints\n", - "@constraints [ warn = false ] function gfeconstraints()\n", - " q(x, z, w, A) = q(x)q(w)q(z)q(A)\n", - " q(w) :: PSubstitutionProduct\n", - "end\n", - "\n", - "# Node constraints\n", - "@meta function gfemeta()\n", - " Transition(z, w) -> PSubstitutionMeta()\n", - " Categorical(x, w) -> PSubstitutionMeta()\n", - "end\n", - "\n", - "@constraints [ warn = false ] function bfeconstraints()\n", - " q(x, z, w, A) = q(x)q(w)q(z)q(A)\n", - "end\n", - "\n", - "# Custom pipeline so we can request incoming message only on the edge we need\n", - "gfepipeline = GFEPipeline((2,))\n", - ";" - ] - }, - { - "cell_type": "markdown", - "id": "7560444f", - "metadata": {}, - "source": [ - "# Set up priors and configure experiment" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "274cd6d5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(pipeline = GFEPipeline{Tuple{Int64}}((2,)), constraints = Constraints:\n", - " marginals form:\n", - " q(w) :: PSubstitutionProduct() [ prod_constraint = ProdGeneric(fallback = ProdAnalytical()) ]\n", - " messages form:\n", - " factorisation:\n", - " q(x, z, w, A) = q(x)q(w)q(z)q(A)\n", - "Options:\n", - " warn = false\n", - ", meta = Meta specification:\n", - " Transition(z, w) -> PSubstitutionMeta()\n", - " Categorical(x, w) -> PSubstitutionMeta()\n", - "Options:\n", - " warn = true)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get required matrices\n", - "A,B,C,D = constructABCD(0.9,[2.,2.],2);\n", - "\n", - "# Number of inference iterations\n", - "its = 5\n", - "\n", - "# Planning horizon\n", - "T = 2\n", - "\n", - "# Choose functional\n", - "gfe_setup = (\n", - " pipeline = gfepipeline,\n", - " constraints = gfeconstraints(),\n", - " meta = gfemeta()\n", - ")\n", - "\n", - "bfe_setup = (\n", - " pipeline = nothing,\n", - " constraints = bfeconstraints(),\n", - " meta = nothing\n", - ")\n", - "\n", - "\n", - "# Initialise marginals and messages\n", - "initmarginals = (\n", - " z = [Categorical(fill(1/8,8)) for t in 1:T],\n", - " );\n", - "\n", - "initmessages = (\n", - " z = [Categorical(fill(1/8,8)) for t in 1:T],\n", - " );\n", - "\n", - "\n", - "# Select between GFE and BFE experiments\n", - "current_setup = gfe_setup\n", - ";" - ] - }, - { - "cell_type": "markdown", - "id": "1455723f", - "metadata": {}, - "source": [ - "# Run experiment" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "40ebf728", - "metadata": {}, - "outputs": [], - "source": [ - "F = zeros(4,4);\n", - "for i in 1:4\n", - " for j in 1:4\n", - " Bs = (B[i],B[j])\n", - " global result = inference(model = t_maze(A,Bs,C,T, current_setup[:pipeline]),\n", - " data= (D_0 = D, x = C),\n", - " initmarginals = initmarginals,\n", - " initmessages = initmessages,\n", - " constraints = current_setup[:constraints],\n", - " meta = current_setup[:meta],\n", - " free_energy=true,\n", - " iterations = its)\n", - " F[i,j] = result.free_energy[end] / log(2)\n", - " end\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "79bfd471", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×4 Matrix{Float64}:\n", - " 10.5033 8.97439 8.97439 9.50325\n", - " 8.97439 8.97439 8.97439 8.97439\n", - " 8.97439 8.97439 8.97439 8.97439\n", - " 9.50325 8.30292 8.30292 8.50325" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Print free energy of all policies\n", - "F" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "918958bb", - "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "UndefVarError: os not defined", - "output_type": "error", - "traceback": [ - "UndefVarError: os not defined", - "", - "Stacktrace:", - " [1] top-level scope", - " @ In[8]:2", - " [2] eval", - " @ ./boot.jl:368 [inlined]", - " [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)", - " @ Base ./loading.jl:1428" - ] - } - ], - "source": [ - "include(\"FLSimulations/visualizations.jl\")\n", - "plotFreeEnergyMinimum(F, os, legend=115, ylim=(7,22))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "532c2494", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/archive/T-maze, GFE vs BFE.jl b/archive/T-maze, GFE vs BFE.jl deleted file mode 100644 index a574565..0000000 --- a/archive/T-maze, GFE vs BFE.jl +++ /dev/null @@ -1,116 +0,0 @@ -using Pkg; Pkg.activate(".."); Pkg.instantiate() -using RxInfer,Distributions,Random,LinearAlgebra, ReactiveMP, OhMyREPL -enable_autocomplete_brackets(false);colorscheme!("GruvboxDark") - -include("GFECategorical.jl") -include("helpers.jl") -Random.seed!(666) ; - - -# Rule is missing from RxInfer -@rule Transition(:in, Marginalisation) (q_out::Any, q_a::Any) = begin - a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -@rule Transition(:out, Marginalisation) (q_in::DiscreteNonParametric, q_a::PointMass, ) = begin - a = clamp.(exp.(mean(log, q_a) * probvec(q_in)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -# Model for the T-maze experiment -@model function t_maze(A,B,C,T, pipeline = nothing) - - D_0 = datavar(Vector{Float64}) - z_0 ~ Categorical(D_0) - # We use datavar here since x~ Pointmass is not a thing - x = datavar(Vector{Float64},T) - z = randomvar(T) - w = randomvar(T) - - # Requires changes in the ReactiveMP core, `@meta` does not support pipelines (yet) - pipeline = something(pipeline, ReactiveMP.DefaultFunctionalDependencies()) - - z_prev = z_0 - - for t in 1:T - z[t] ~ Transition(z_prev, B[t]) - w[t] ~ Transition(z[t], A) where { pipeline = pipeline } - w[t] ~ Categorical(x[t]) - z_prev = z[t] - end -end; - -# Edge Constraints -@constraints [ warn = false ] function gfeconstraints() - q(x, z, w, A) = q(x)q(w)q(z)q(A) - q(w) :: PSubstitutionProduct -end - -# Node constraints -@meta function gfemeta() - Transition(z, w) -> PSubstitutionMeta() - Categorical(x, w) -> PSubstitutionMeta() -end - -@constraints [ warn = false ] function bfeconstraints() - q(x, z, w, A) = q(x)q(w)q(z)q(A) -end - -# Custom pipeline so we can request incoming message only on the edge we need -gfepipeline = GFEPipeline((2,)); - -# Get required matrices -A,B,C,D = constructABCD(0.9,[2.,2.],2); - -# Number of inference iterations -its = 5 - -# Planning horizon -T = 2 - -# Choose functional -gfe_setup = ( - pipeline = gfepipeline, - constraints = gfeconstraints(), - meta = gfemeta() -); - -bfe_setup = ( - pipeline = nothing, - constraints = bfeconstraints(), - meta = nothing -); - - -# Initialise marginals and messages -initmarginals = ( - z = [Categorical(fill(1/8,8)) for t in 1:T], - ); - -initmessages = ( - z = [Categorical(fill(1/8,8)) for t in 1:T], - ); - - -# Select between GFE and BFE experiments -current_setup = gfe_setup; - -F = zeros(4,4); -for i in 1:4 - for j in 1:4 - Bs = (B[i],B[j]) - global result = inference(model = t_maze(A,Bs,C,T, current_setup[:pipeline]), - data= (D_0 = D, x = C), - initmarginals = initmarginals, - initmessages = initmessages, - constraints = current_setup[:constraints], - meta = current_setup[:meta], - free_energy=true, - iterations = its) - F[i,j] = result.free_energy[end] / log(2) - end -end - -# Print free energy of all policies -F diff --git a/archive/approx_marginal_categorical.jl b/archive/approx_marginal_categorical.jl deleted file mode 100644 index 6fa9bf2..0000000 --- a/archive/approx_marginal_categorical.jl +++ /dev/null @@ -1,40 +0,0 @@ -struct GFECategorical end - -# We use this to keep track of outgoing messages on the :in edge in order to compute the marginals we need -mutable struct GFEMeta - μ_in::Any -end - -@node GFECategorical Stochastic [out,in,A] - -@average_energy GFECategorical (q_out::PointMass, q_in::Categorical,q_A::PointMass,) = begin - σ = probvec(q_in) - A = mean(q_A) - c = probvec(q_out) - - -σ' * diag(A' * safelog.(A)) + (A*σ)'* (safelog.(A*σ - safelog.(c))) -end - -# We don't want log(0) to happen -safelog(x) = log(x +eps()) - - -# How do we get q_in?? -@rule GFECategorical(:in, Marginalisation) (q_out::PointMass, m_in::DiscreteNonParametric, q_A::PointMass, meta::GFEMeta,) = begin - # We store outgoing messages in meta since we can't access the edge marginal directly - μ_in = meta.μ_in - q_in = prod(ProdAnalytical(),m_in,μ_in) - - z = probvec(q_in) - A = mean(q_A) - # We use the goal prior on an edge here - C = probvec(q_out) - # q_out needs to be A*mean(incoming), hence this line - x = A * z - ρ = diag(A' * safelog.(A)) + A' * (safelog.(C) .- safelog.(x)) - m_out = Categorical(exp.(ρ) / sum(exp.(ρ))) - - meta.μ_in = m_out - return m_out -end - diff --git a/archive/backup.jl b/archive/backup.jl deleted file mode 100644 index c784d05..0000000 --- a/archive/backup.jl +++ /dev/null @@ -1,46 +0,0 @@ -using Pkg; Pkg.activate(".."); Pkg.instantiate() -using RxInfer,Distributions,Random,LinearAlgebra,OhMyREPL, ReactiveMP -enable_autocomplete_brackets(false);colorscheme!("GruvboxDark"); -#include("function.jl") -include("GFECategorical.jl") -include("helpers.jl") - -A,B,C,D = constructABCD(0.98,[2,2],2) - -@model function t_maze(A,B,C,T) - - z_0 = datavar(Vector{Float64}) - z = randomvar(T) - x = randomvar(T) - - z_prev = z_0 - - for t in 1:T - z[t] ~ Transition(z_prev,B[t]) - x[t] ~ GFECategorical(z[t], A) where {pipeline=ReactiveMP.RequireEverythingFunctionalDependencies(), meta=ForwardOnlyMeta,q=MeanField()} - x[t] ~ Dirichlet(C[t]) - z_prev = z[t] - end -end; - -T = 2 - -initmarginals = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - x = [PointMass(C[t]) for t in 1:T], - ); - -initmessages = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - x = [PointMass(C[t]) for t in 1:T], - ); - -its = 5 -i = j = 1 -Bs = (B[1],B[2]) -result = inference(model = t_maze(A,Bs,C,T), - data= (z_0 = D,), - initmarginals = initmarginals, - initmessages = initmessages, - free_energy=true, - iterations = its) diff --git a/archive/dirichlet_t_maze.jl b/archive/dirichlet_t_maze.jl deleted file mode 100644 index ca3c061..0000000 --- a/archive/dirichlet_t_maze.jl +++ /dev/null @@ -1,42 +0,0 @@ -using Pkg;Pkg.activate(".");Pkg.instantiate() -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions -enable_autocomplete_brackets(false) -include("transition_mixture.jl") -include("approx_marginal_categorical.jl") -include("helpers.jl") - -T = 2 - -A,B,C,D = constructABCD(0.9,2.0,T) - -# Try with all policies and evaluate EFE for each. -# Try with the EFE evaluation from the paper -@model function [default_factorisation=MeanField()] t_maze(Ac,D,T) - A = constvar(Ac) - z_0 ~ Categorical(D) - - z = randomvar(T) - - x = datavar(Vector{Float64}, T) - z_prev = z_0 - - B ~ MatrixDirichlet(diageye(8)) - for t in 1:T - z[t] ~ Transition(z_prev,B) - x[t] ~ GFECategorical(z[t], A) where {pipeline=RequireInbound(in = Categorical(fill(1. /8. ,8))), meta=GFEMeta(Categorical(fill(1. /8. ,8)))} - z_prev = z[t] - end -end - -imodel = Model(t_maze,A,D,T) -imarginals = ( - B = vague(MatrixDirichlet, 8, 8), -) - - -result = inference(model = imodel, data= (x = C,), initmarginals=imarginals) - -# Ignores first step, goes to cue on second -#probvec(result.posteriors[:switch][1][2]) -#probvec(result.posteriors[:z][1][1]) - diff --git a/archive/efe_from_gbfe.jl b/archive/efe_from_gbfe.jl deleted file mode 100644 index 3288821..0000000 --- a/archive/efe_from_gbfe.jl +++ /dev/null @@ -1,116 +0,0 @@ -using Pkg;Pkg.activate("..");Pkg.instantiate() -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions -import StatsBase: entropy -enable_autocomplete_brackets(false) - -include("forward/forward_transition.jl") -include("GFECategorical.jl") -include("helpers.jl") - -T = 2; - -A,B,C,D = constructABCD(0.9,[2.0,2.0],T); - -# Variatonal update rules for messing with VMP -@rule Transition(:in, Marginalisation) (q_out::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -@rule Transition(:out, Marginalisation) (q_in::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a) * probvec(q_in)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -# THERE HAS TO BE A BETTER WAY!!! -# Remove energy contributions from transition nodes -@average_energy Transition (q_out::Any, q_in::Any, q_a::MatrixDirichlet, meta::ForwardOnlyMeta) = begin - return 0. -end - -@average_energy Transition (q_out_in::Contingency, q_a::MatrixDirichlet, meta::ForwardOnlyMeta) = begin - return 0. -end - -@average_energy Transition (q_out_in::Contingency, q_a::PointMass, meta::ForwardOnlyMeta) = begin - return 0. -end - -@average_energy Transition (q_out::Any, q_in::Any, q_a::PointMass, meta::ForwardOnlyMeta) = begin - return 0. -end - -# Block edge entropies -entropy(d::DiscreteNonParametric) = 0. - - -# -#@model function t_maze(A,B,T) -# Ac = constvar(A) -# -# d = datavar(Vector{Float64}) -# -# x = datavar(Vector{Float64}, T) -# -# z_0 ~ Categorical(d) -# z = randomvar(T) -# -# x = randomvar(T) -# z_prev = z_0 -# for t in 1:T -# z[t] ~ Transition(z_prev,B[t]) where{meta=ForwardOnlyMeta()} -# x[t] ~ GFECategorical(z[t], A) where {pipeline=RequireEverythingFunctionalDependencies()} -# z_prev = z[t] -# end -#end - -@model function t_maze(A,D,B,T) - - z_0 ~ Categorical(D) - - z = randomvar(T) - - x = datavar(Vector{Float64}, T) - z_prev = z_0 - - for t in 1:T - z[t] ~ Transition(z_prev,B[t]) where{meta=ForwardOnlyMeta()} - x[t] ~ GFECategorical(z[t], A) where {pipeline=RequireEverythingFunctionalDependencies(),meta=ForwardOnlyMeta()} - z_prev = z[t] - end -end; - - -initmarginals = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - -initmessages = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - - -imodel = Model(t_maze,A,D,[B[i],B[j]],T) - -result = inference(model = imodel, data= (x = C,), initmarginals = initmarginals, initmessages = initmessages,free_energy=true, iterations = its) - - -# Try with all policies and evaluate EFE for each. -function evaluate_policies(B,its) - F = zeros(4,4) - for i in 1:4 - for j in 1:4 - imodel = Model(t_maze,A,D,[B[i],B[j]],T) - - result = inference(model = imodel, data= (x = C,), initmarginals = initmarginals, initmessages = initmessages,free_energy=true, iterations = its) - - F[i,j] =result.free_energy[end] ./log(2) - end - end -F -end - -Fmap = evaluate_policies(B,20) -argmin(Fmap) - - diff --git a/archive/fixed_t_maze.jl b/archive/fixed_t_maze.jl deleted file mode 100644 index 204ae32..0000000 --- a/archive/fixed_t_maze.jl +++ /dev/null @@ -1,77 +0,0 @@ -using Pkg;Pkg.activate(".");Pkg.instantiate() -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions -enable_autocomplete_brackets(false) - -include("GFECategorical.jl") -include("helpers.jl") - -T = 2; - -A,B,C,D = constructABCD(0.9,[2.0,2.0],T); - -# Variatonal update rules for messing with VMP -@rule Transition(:in, Marginalisation) (q_out::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -@rule Transition(:out, Marginalisation) (q_in::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a) * probvec(q_in)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - - -# TODO rewrite this for arbitrary T -@model function t_maze(A,B,C,T) - Ac = constvar(A) - - d = datavar(Vector{Float64}) - - z_0 ~ Categorical(d) - z = randomvar(T) - - #x = datavar(Vector{Float64}, T) - x_1 = constvar(C[1]) - x_2 = constvar(C[2]) - - #x = randomvar(T) - z_prev = z_0 - - z[1] ~ Transition(z_0,B[1]) - x_1 ~ GFECategorical(z[1], A) where {pipeline=RequireEverythingFunctionalDependencies()} - - z[2] ~ Transition(z[1],B[2]) - x_2 ~ GFECategorical(z[2], A) where {pipeline=RequireEverythingFunctionalDependencies()} - #for t in 1:T - # z[t] ~ Transition(z_prev,B[t]) - # x[t] ~ GFECategorical(z[t], A) where {pipeline=RequireEverythingFunctionalDependencies()} - # z_prev = z[t] - #end -end - -initmarginals = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - -initmessages = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - -# Try with all policies and evaluate EFE for each. -function evaluate_policies(B,its) - F = zeros(4,4) - for i in 1:4 - for j in 1:4 - imodel = Model(t_maze,A,[B[i],B[j]],C,T) - - result = inference(model = imodel, data= (d = D,), initmarginals = initmarginals, initmessages = initmessages,free_energy=true, iterations = its) - - F[i,j] =result.free_energy[end] ./log(2) - end - end -F -end - -Fmap = evaluate_policies(B,20) -argmin(Fmap) - diff --git a/archive/fixed_t_maze_2.jl b/archive/fixed_t_maze_2.jl deleted file mode 100644 index 6bdd646..0000000 --- a/archive/fixed_t_maze_2.jl +++ /dev/null @@ -1,77 +0,0 @@ -using Pkg;Pkg.activate("..");Pkg.instantiate() -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions -enable_autocomplete_brackets(false) - -include("GFECategorical.jl") -include("helpers.jl") - -T = 2; - -A,B,C,D = constructABCD(0.9,[2.0,2.0],T); - -# Variatonal update rules for messing with VMP -@rule Transition(:in, Marginalisation) (q_out::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -@rule Transition(:out, Marginalisation) (q_in::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a) * probvec(q_in)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - - -# TODO rewrite this for arbitrary T -@model function t_maze(A,B,C,T) - Ac = constvar(A) - - d = datavar(Vector{Float64}) - - z_0 ~ Categorical(d) - z = randomvar(T) - - #x = datavar(Vector{Float64}, T) - x_1 = constvar(C[1]) - x_2 = constvar(C[2]) - - #x = randomvar(T) - z_prev = z_0 - - z[1] ~ Transition(z_0,B[1]) - x_1 ~ GFECategorical(z[1], A) where {pipeline=RequireEverythingFunctionalDependencies()} - - z[2] ~ Transition(z[1],B[2]) - x_2 ~ GFECategorical(z[2], A) where {pipeline=RequireEverythingFunctionalDependencies()} - #for t in 1:T - # z[t] ~ Transition(z_prev,B[t]) - # x[t] ~ GFECategorical(z[t], A) where {pipeline=RequireEverythingFunctionalDependencies()} - # z_prev = z[t] - #end -end - -initmarginals = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - -initmessages = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - -# Try with all policies and evaluate EFE for each. -function evaluate_policies(B,its) - F = zeros(4,4) - for i in 1:4 - for j in 1:4 - imodel = Model(t_maze,A,[B[i],B[j]],C,T) - - result = inference(model = imodel, data= (d = D,), initmarginals = initmarginals, initmessages = initmessages,free_energy=true, iterations = its) - - F[i,j] =result.free_energy[end] ./log(2) - end - end -F -end - -Fmap = evaluate_policies(B,20) -argmin(Fmap) - diff --git a/archive/fixed_t_maze_novelty.jl b/archive/fixed_t_maze_novelty.jl deleted file mode 100644 index e0632e7..0000000 --- a/archive/fixed_t_maze_novelty.jl +++ /dev/null @@ -1,193 +0,0 @@ -using Pkg;Pkg.activate("..");Pkg.instantiate(); -using RxInfer,ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions; -using Random -Random.seed!(666) -enable_autocomplete_brackets(false),colorscheme!("GruvboxDark"); - - -# Need to make pointmass constraints for discrete vars -import RxInfer.default_point_mass_form_constraint_optimizer -import RxInfer.PointMassFormConstraint - - -function default_point_mass_form_constraint_optimizer( - ::Type{Univariate}, - ::Type{Discrete}, - constraint::PointMassFormConstraint, - distribution -) - - out = zeros( length(probvec(distribution))) - out[argmax(probvec(distribution))] = 1. - - PointMass(out) -end -# Any 0s in A break FE computation. Therefore we need to clamp all 0's to tinys instead - -# Functions we need to modify -import ReactiveMP: entropy, mean -import SpecialFunctions: loggamma, logabsgamma, digamma - - -safelog(x) = log(clamp(x,tiny,Inf)) - -# Logmean but with guard rails in place -ReactiveMP.mean(::typeof(safelog), dist::MatrixDirichlet) = digamma.(clamp.(dist.a,tiny,Inf)) .- digamma.(sum(clamp.(dist.a,tiny,Inf); dims = 1)) - - -## Standard entropy except 0s are set to tiny -function ReactiveMP.entropy(dist::MatrixDirichlet) - a = clamp.(dist.a, tiny,Inf) # <-- Change is here - return mapreduce(+, eachcol(a)) do column - scolumn = sum(column) - -sum((column .- 1.0) .* (digamma.(column) .- digamma.(scolumn))) - loggamma(scolumn) + sum(loggamma.(column)) - end -end - -# Overwrite energy to avoid 0s -@average_energy MatrixDirichlet (q_out::MatrixDirichlet, q_a::PointMass) = begin - H = mapreduce(+, zip(eachcol(clamp.(mean(q_a),tiny,Inf)), eachcol(mean(safelog, q_out)))) do (q_a_column, logmean_q_out_column) # Call to and a clamp safelog here - return -loggamma(sum(q_a_column)) + sum(loggamma.(q_a_column)) - sum((q_a_column .- 1.0) .* logmean_q_out_column) - end - return H -end - - -include("helpers.jl"); -include("DiscreteLAIF.jl"); - -@model function t_maze(θ_A,D,B,T) - - z_0 ~ Categorical(D) - - z = randomvar(T) - - x = datavar(Vector{Float64}, T) - z_prev = z_0 - A ~ MatrixDirichlet(θ_A) - - for t in 1:T - z[t] ~ Transition(z_prev,B[t]) - x[t] ~ DiscreteLAIF(z[t], A) where {q = MeanField(), pipeline = GFEPipeline((2,3),vague(Categorical,8))} - z_prev = z[t] - end -end; - - -@constraints function pointmass_q() - q(switch) :: PointMass -end - -# Node constraints -@meta function t_maze_meta() - DiscreteLAIF(x,z) -> PSubstitutionMeta() -end - -T = 2 -its = 10 - -A,B,C,D = constructABCD(0.9,[2.0 for t in 1:T],T); - -initmarginals = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], -# A = vague(MatrixDirichlet,(16,8)), - A = MatrixDirichlet(A + 1e-2*rand(size(A)...)), - ); - -Bs = (B[4],B[2]) -#TODO: FE calculation breaks on entropy of A -result = inference(model = t_maze(A,D,Bs,T), - data= (x = C,), - initmarginals = initmarginals, - meta= t_maze_meta(), - free_energy = true, -# addons = (AddonMemory(),), -# constraints=pointmass_q(), - iterations=its - ) - -result.free_energy - -# BEHOLD!!!! -probvec.(result.posteriors[:switch][end][1]) -probvec.(result.posteriors[:switch][end][2]) - -######################################################################## -# Below here is a giant mess of ongoing hacking, enter at your own risk! -######################################################################## - -bob = mean(result.posteriors[:A][1]) -bob = result.posteriors[:A][end] -probvec(result.posteriors[:z][end][1]) -probvec(result.posteriors[:z][end][end]) - -using ForneyLab -import ForneyLab: unsafeLogMean, labsgamma, ProbabilityDistribution, MatrixVariate, unsafeMean - -using Random -Random.seed!(123) -marg_out = ProbabilityDistribution(MatrixVariate, Dirichlet, a=A); -marg_a = ProbabilityDistribution(MatrixVariate,PointMass,m=A + 1e-2*rand(size(A)...)); - -eng = energy(marg_out,marg_a) - - -function energy(marg_out, marg_a) - (dims(marg_out) == dims(marg_a)) || error("Distribution dimensions must agree") - - log_mean_marg_out = unsafeLogMean(marg_out) - - H = 0.0 - for k = 1:dims(marg_out)[2] # For all columns - a_sum = sum(marg_a.params[:m][:,k]) - - H += -labsgamma(a_sum) + - sum(labsgamma.(marg_a.params[:m][:,k])) - - sum( (marg_a.params[:m][:,k] .- 1.0).*log_mean_marg_out[:,k] ) - end - - return H -end - -k = 2 -q_a_column = mean(q_a)[:,k] -a_sum = sum(q_a_column) -logmean_q_out_column = mean(safelog,q_out)[:,k] - -loggamma(sum(q_a_column)) -sum(loggamma.(q_a_column)) -sum((q_a_column .- 1.0) .* logmean_q_out_column) - -q_out = ReactiveMP.MatrixDirichlet(A) -mean(safelog,q_out) -Random.seed!(123) -q_a = ReactiveMP.PointMass(A + 1e-2*rand(size(A)...)) - -more_eng = more_energy(q_out,q_a) -eng - more_eng - -function energy(marg_out, marg_a) - (dims(marg_out) == dims(marg_a)) || error("Distribution dimensions must agree") - - log_mean_marg_out = unsafeLogMean(marg_out) - - H = 0.0 - for k = 1:dims(marg_out)[2] # For all columns - a_sum = sum(marg_a.params[:m][:,k]) - - H += -labsgamma(a_sum) + - sum(labsgamma.(marg_a.params[:m][:,k])) - - sum( (marg_a.params[:m][:,k] .- 1.0).*log_mean_marg_out[:,k] ) - end - - return H -end -# Overwrite energy to avoid 0s -function more_energy(q_out::MatrixDirichlet, q_a::ReactiveMP.PointMass) - H = mapreduce(+, zip(eachcol(mean(q_a)), eachcol(mean(safelog, q_out)))) do (q_a_column, logmean_q_out_column) - return -loggamma(sum(q_a_column)) + sum(loggamma.(q_a_column)) - sum((q_a_column .- 1.0) .* logmean_q_out_column) - end - return H -end - - diff --git a/archive/fl_results_remake.jl b/archive/fl_results_remake.jl deleted file mode 100644 index 5d4fa3d..0000000 --- a/archive/fl_results_remake.jl +++ /dev/null @@ -1,63 +0,0 @@ -using Pkg;Pkg.activate(".");Pkg.instantiate() -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions -enable_autocomplete_brackets(false) -include("categorical.jl") -include("helpers.jl") - -A,B,C,D = constructABCD(0.9,[2.0,2.0],T); - -# Variatonal update rules for messing with VMP -@rule Transition(:in, Marginalisation) (q_out::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -@rule Transition(:out, Marginalisation) (q_in::DiscreteNonParametric, q_a::PointMass) = begin - a = clamp.(exp.(mean(log, q_a) * probvec(q_in)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - - -@model function t_maze(A,B,D,T) - Ac = constvar(A) - - z_0 ~ Categorical(D) - z = randomvar(T) - - x = datavar(Vector{Float64}, T) - z_prev = z_0 - - for t in 1:T - z[t] ~ Transition(z_prev,B[t]) - x[t] ~ GFECategorical(z[t], A) where {pipeline=RequireEverythingFunctionalDependencies()} - z_prev = z[t] - end -end - -initmarginals = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T] - , - ); - -initmessages = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T] - , - ); - -# Try with all policies and evaluate GBFE for each. -function evaluate_policies(B,its) - F = zeros(4,4) - for i in 1:4 - for j in 1:4 - imodel = Model(t_maze,A,[B[i],B[j]],D,T) - - result = inference(model = imodel, data= (x = C,), initmarginals = initmarginals, initmessages = initmessages, free_energy=true, iterations=its) - - F[i,j] =result.free_energy[end] ./log(2) - end - end -F -end - -evaluate_policies(B,4) -argmin(evaluate_policies(B,1)) diff --git a/archive/gaussian.jl b/archive/gaussian.jl deleted file mode 100644 index c982d28..0000000 --- a/archive/gaussian.jl +++ /dev/null @@ -1,45 +0,0 @@ -struct GFEGaussian end -@node GFEGaussian Stochastic [out,in,A] - -@average_energy GFEGaussian (q_out::Gaussian, q_in::Gaussian,Σ::PointMass) = begin - # TODO -end - -# We don't want log(0) to happen -safelog(x) = log(x +eps()) - -#note, why is it m_in and not q_in??? -@rule GFEGaussian(:in, Marginalisation) (q_out::Gaussian,q_in::Gaussian,Σa::PointMass) = begin - - # Goal prior - mc,Σc = meancov(q_out) - # Incoming marginal - mx,Σx = meancov(q_in) - - - - - - z = probvec(q_in) - A = mean(q_A) - # We use the goal prior on an edge here - C = probvec(q_out) - # q_out needs to be A*mean(incoming), hence this line - x = A * z - ρ = diag(A' * safelog.(A)) + A' * (safelog.(C) .- safelog.(x)) - return Gaussian(exp.(ρ) / sum(exp.(ρ))) -end - -## -##@rule GFEGaussian(:in, Marginalisation) (q_out::PointMass, m_in::DiscreteNonParametric, q_A::PointMass, ) = begin -# -# z = probvec(m_in) -# A = mean(q_A) -# # We use the goal prior on an edge here -# C = probvec(q_out) -# # q_out needs to be A*mean(incoming), hence this line -# x = A * z -# ρ = diag(A' * safelog.(A)) + A' * (safelog.(C) .- safelog.(x)) -# return Gaussian(exp.(ρ) / sum(exp.(ρ))) -#end - diff --git a/archive/gfe_hmm_test.jl b/archive/gfe_hmm_test.jl deleted file mode 100644 index f3e7526..0000000 --- a/archive/gfe_hmm_test.jl +++ /dev/null @@ -1,62 +0,0 @@ -using Pkg;Pkg.activate(".");Pkg.instantiate() -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions -enable_autocomplete_brackets(false) -include("transition_mixture.jl") -include("categorical.jl") - -# Hack together some transition matrices -Bs = [zeros(4,4) for x in 1:4] -for i in 1:4 - Bs[i][i,:] .= 1. -end - -# Initial state -D = [1.,0,0,0] -# Likelihood -A = diageye(4) - -goal = [[0.,0.,0.5,0.5], - [1.,0.,0.0,0.0], - [0.,0.,0.3,0.7] ] - -#struct GFECategorical end -#@node GFECategorical Stochastic [out,in,A] -# -#safelog(x) = log(x +eps()) -#@rule GFECategorical(:in, Marginalisation) (q_out::PointMass,m_in::Categorical, q_A::PointMass) = begin -# z = probvec(m_in) -# A = mean(q_A) -# C = probvec(q_out) -# # q_out needs to be A*mean(incoming), hence this line -# x = A * z -# # Write this out in a nicer way. Vec is there to force the type to not be Matrix -# ρ = vec(sum(z .* A .* safelog.(A)',dims= 2)) + z.*A * (safelog.(C) - safelog.(x)) -# return Categorical(exp.(ρ) / sum(exp.(ρ))) -#end - - -@model function controlled_hmm(A,D,B1,B2,B3,B4,n) - - z_0 ~ Categorical(D) - - z = randomvar(n) - switch = randomvar(n) - - x = datavar(Vector{Float64}, n) - z_prev = z_0 - - for t in 1:n - switch[t] ~ Categorical(fill(1. /4. ,4)) - z[t] ~ TransitionMixture(z_prev,switch[t], B1,B2,B3,B4) - x[t] ~ GFECategorical(z[t], A) where {pipeline=RequireInbound(in = Categorical(fill(1. /4. ,4)))} - z_prev = z[t] - end -end - -imodel = Model(controlled_hmm,A,D,Bs[1],Bs[2],Bs[3],Bs[4],3) - -result = inference(model = imodel, data= (x = goal,)) - -probvec(result.posteriors[:switch][1][3]) - - diff --git a/archive/gfe_vs_vfe.jl b/archive/gfe_vs_vfe.jl deleted file mode 100644 index e6463ed..0000000 --- a/archive/gfe_vs_vfe.jl +++ /dev/null @@ -1,84 +0,0 @@ -using Pkg; Pkg.activate(".."); Pkg.instantiate() -using RxInfer,Distributions,Random,LinearAlgebra,OhMyREPL, ReactiveMP -enable_autocomplete_brackets(false);colorscheme!("GruvboxDark"); - -# TODO: Structure is correct now but the results are fucked -# include("GFECategorical.jl") -include("GFECategorical2.jl") -include("helpers.jl") - -gfepipeline = GFEPipeline((2,)) - -A,B,C,D = constructABCD(0.98,[2.,2.],2) - -@model function t_maze(A,B,C,T, pipeline = nothing) - - z_0 = datavar(Vector{Float64}) - # We use datavar here since x~ Pointmass is not a thing - x = datavar(Vector{Float64},T) - z = randomvar(T) - w = randomvar(T) - - # Requires changes in the ReactiveMP core, `@meta` does not support pipelines (yet) - pipeline = something(pipeline, ReactiveMP.DefaultFunctionalDependencies()) - - z_prev = z_0 - - for t in 1:T - z[t] ~ Transition(z_prev,B[t]) - w[t] ~ Transition(z[t], A) where { pipeline = pipeline } - w[t] ~ Categorical(x[t]) - z_prev = z[t] - end -end; - -# Edge Constraints -@constraints [ warn = false ] function t_maze_constraints() - q(x, z, w, A) = q(x)q(w)q(z)q(A) - q(w) :: EpistemicProduct -end - -# Node constraints -@meta function t_maze_meta() - Transition(z, w) -> EpistemicMeta() - Categorical(x, w) -> EpistemicMeta() -end - -T = 2 - -initmarginals = ( - z = [Categorical(fill(1/8,8)) for t in 1:T], - ); - -initmessages = ( - z = [Categorical(fill(1/8,8)) for t in 1:T], - ); - - -# TODO: Figure out why FE increases with number of iterations - but only for the best policy? -result = nothing -its = 50 -F = zeros(4,4); -results = Dict() -for i in 1:4 - for j in 1:4 - Bs = (B[i],B[j]) - global result = inference(model = t_maze(A,Bs,C,T, gfepipeline), - data= (z_0 = D, x=C), - initmarginals = initmarginals, - # initmessages = initmessages, - constraints = t_maze_constraints(), - meta = t_maze_meta(), - free_energy=true, - addons = (AddonMemory(),), - iterations = its) - results[(i, j)] = result - F[i,j] = result.free_energy[end] ./ log(2) - end -end - - - -# q_w is always one iteration behind -# Wmarginal.q stays flat? Initial message towards GFEnode never gets updated -# diff --git a/archive/gfe_vs_vfe_composite.jl b/archive/gfe_vs_vfe_composite.jl deleted file mode 100644 index edac9ce..0000000 --- a/archive/gfe_vs_vfe_composite.jl +++ /dev/null @@ -1,73 +0,0 @@ -using Pkg; Pkg.activate(".."); Pkg.instantiate() -using RxInfer,Distributions,Random,LinearAlgebra,OhMyREPL, ReactiveMP, Random -enable_autocomplete_brackets(false);colorscheme!("GruvboxDark"); -Random.seed!(666) - -include("DiscreteLAIF.jl") -include("helpers.jl") - -# Rule is missing from RxInfer -@rule Transition(:in, Marginalisation) (q_out::Any, q_a::Any) = begin - a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - - -@model function t_maze(θ_A,B,C,D,T) - - z_0 ~ Categorical(D) - # We use datavar here since x~ Pointmass is not a thing - x = datavar(Vector{Float64},T) - z = randomvar(T) - - z_prev = z_0 - # A ~ MatrixDirichlet(θ_A) - - for t in 1:T - z[t] ~ Transition(z_prev,B[t]) - # We use the pipeline to only initialise the messages we need. - x[t] ~ DiscreteLAIF(z[t], θ_A) where {q = MeanField(), pipeline = GFEPipeline((2,), (nothing, vague(Categorical,8) )) } - z_prev = z[t] - end - return z, z_0 -end; - - - -# Node constraints -@meta function t_maze_meta() - DiscreteLAIF(x,z) -> PSubstitutionMeta() -end - - -T = 2 -its=10 -# A has epsilons instead of 0's. Necessary because 0's are outside the domain of allowed parameters - -A,B,C,D = constructABCD(0.90,ones(T)*2,T); - -initmarginals = ( - z = [Categorical(fill(1/8,8)) for t in 1:T], - z_0 = [Categorical(fill(1/8,8))], -# A = MatrixDirichlet(A), - ); - - -F = zeros(4,4, its); - -for i in 1:4 - for j in 1:4 - Bs = (B[i],B[j]) - result = inference(model = t_maze(A,Bs,C,D,T), - data= (x=C,), - initmarginals = initmarginals, - meta = t_maze_meta(), - free_energy=true, - iterations = its) - #F[i,j] = mean(result.free_energy[10:end]) ./ log(2) - F[i,j, :] = result.free_energy ./ log(2) - end -end -using Plots, UnicodePlots -unicodeplots() -plot(F[2,3,:]) diff --git a/archive/matrixlogpdf.jl b/archive/matrixlogpdf.jl deleted file mode 100644 index 6922c93..0000000 --- a/archive/matrixlogpdf.jl +++ /dev/null @@ -1,89 +0,0 @@ -#Barebones implementation of matrixvariate logpdf for learning parameters with GFECategoricals -export ContinuousMatrixvariateLogPdf - -using Distributions -using ReactiveMP -import Distributions.rand -import StatsFuns: gammainvcdf -import DomainSets -using ReactiveMP: AbstractContinuousGenericLogPdf - -struct ContinuousMatrixvariateLogPdf{D <: DomainSets.Domain, F} <: AbstractContinuousGenericLogPdf - domain::D - logpdf::F - - #ContinuousMatrixvariateLogPdf(domain::D, logpdf::F) where {D, F} = begin - # @assert DomainSets.dimension(domain) == 1 "Cannot create ContinuousMatrixvariateLogPdf. Dimension of domain = $(domain) is not equal to 1." - # return new{D, F}(domain, logpdf) - #end -end - -variate_form(::Type{<:ContinuousMatrixvariateLogPdf}) = Matrixvariate -variate_form(::ContinuousMatrixvariateLogPdf) = Matrixvariate - -promote_variate_type(::Type{Matrixvariate}, ::Type{AbstractContinuousGenericLogPdf}) = ContinuousMatrixvariateLogPdf - -getdomain(dist::ContinuousMatrixvariateLogPdf) = dist.domain -getlogpdf(dist::ContinuousMatrixvariateLogPdf) = dist.logpdf - -ContinuousMatrixvariateLogPdf(f::Function) = ContinuousMatrixvariateLogPdf(DomainSets.FullSpace(), f) - -Base.show(io::IO, dist::ContinuousMatrixvariateLogPdf) = print(io, "ContinuousMatrixvariateLogPdf(", getdomain(dist), ")") -Base.show(io::IO, ::Type{<:ContinuousMatrixvariateLogPdf{D}}) where {D} = print(io, "ContinuousMatrixvariateLogPdf{", D, "}") - -Distributions.support(dist::ContinuousMatrixvariateLogPdf) = Distributions.RealInterval(DomainSets.infimum(getdomain(dist)), DomainSets.supremum(getdomain(dist))) - -# Fallback for various optimisation packages which may pass arguments as vectors -function Distributions.logpdf(dist::ContinuousMatrixvariateLogPdf, x::AbstractVector{<:Real}) - #@assert length(x) === 1 "`ContinuousMatrixvariateLogPdf` expects either float or a vector of a single float as an input for the `logpdf` function." - return logpdf(dist, first(x)) -end - -Base.convert(::Type{<:ContinuousMatrixvariateLogPdf}, domain::D, logpdf::F) where {D <: DomainSets.Domain, F} = ContinuousMatrixvariateLogPdf(domain, logpdf) - -convert_eltype(::Type{ContinuousMatrixvariateLogPdf}, ::Type{T}, dist::ContinuousMatrixvariateLogPdf) where {T <: Real} = convert(ContinuousMatrixvariateLogPdf, dist.domain, dist.logpdf) - -#vague(::Type{<:ContinuousMatrixvariateLogPdf}) = ContinuousMatrixvariateLogPdf(DomainSets.FullSpace(), (x) -> 1.0) - -# We do not check typeof of a different functions because in most of the cases lambdas have different types, but they can still be the same -function is_typeof_equal(::ContinuousMatrixvariateLogPdf{D, F1}, ::ContinuousMatrixvariateLogPdf{D, F2}) where {D, F1 <: Function, F2 <: Function} - return true -end - -function rand(dist::MatrixDirichlet) - #α = clamp.(dist.a,tiny,Inf) - # We replace NaN's to allow for rows of 0's which are common in AIF modelling -# replace!(reduce(hcat, Distributions.rand.(Dirichlet.(eachrow(α))))', NaN => 0.0) - sample = clamp.(gammainvcdf.(dist.a,1.0, rand(size(dist.a)...)), tiny,Inf) - sample ./ sum(sample, dims=1) -end - -function rand(dist::MatrixDirichlet, n::Int) - [rand(dist) for i in 1:n] -end - - -# We need a product of MatrixVariate Logpdf's and MatrixDirichlet to compute the marginal over the transition matrix. We approximate it using EVMP (Add citation to Semihs paper) -# TODO: Doublecheck with Semihs paper that this should really be a samplelist. Also make number of samples user specified somehow? -# TODO: SampleList requires 1D samples. Find a way to square that circle. In the meantime, replaced with MatrixDirichlet directly - -import Base: prod -prod(::ProdAnalytical, left::MatrixDirichlet{Float64, Matrix{Float64}}, right::ContinuousMatrixvariateLogPdf{FullSpace{Float64}}) = begin - _logpdf = right.logpdf - - # Draw 50 samples - weights = [] - samples = [] - for n in 1:50 - A_hat = rand(left) - ρ_n = exp(_logpdf(A_hat)) - - push!(samples, A_hat) - push!(weights, ρ_n) - end -# - Z = sum(weights) - # We clamp here to avoid 0 entries that violate the domain of a MatrixDirichlet. This should get cleaned up once a more permanent solution is in RxInfer - return MatrixDirichlet(clamp.(sum(samples .* weights) / Z, tiny,Inf)) - #return SampleList(samples,weights ./ sum(weights)) -end diff --git a/archive/stability_test.jl b/archive/stability_test.jl deleted file mode 100644 index bba6060..0000000 --- a/archive/stability_test.jl +++ /dev/null @@ -1,67 +0,0 @@ -using Pkg;Pkg.activate("."); Pkg.instantiate() -using OhMyREPL, ReactiveMP, LinearAlgebra -using ForwardDiff -enable_autocomplete_brackets(false) - -include("helpers.jl") -T = 2 -A,B,C,D = constructABCD(0.9,[2.0,2.0],T); -jac = ForwardDiff.jacobian - -#safelog(x) = log(x + exp(-16)) -# -#σ(x) = exp.(x) / sum(exp.(x)) -# -#σ(D) .* (1 .- σ(D)) -#A -#D = σ(rand(4)) -#function the_jac(z) -# n = size(D)[1] -# -# ρ_mat = σ(D) * σ(D)' -# ρ_mat[diagind(ρ_mat)] = σ(D) .* (1 .- σ(D)) -# -# A -# -# A'*A*D -# -# jacobian -# -# ForwardDiff.jacobian((x) -> log.(A*x), D) -# == -# 1 ./ A -# (D .+ exp(-16)) -# -# - - -A = [0.98 0.02; - 0.02 0.98] - -C = [0.5, 0.5] - -D = [0.1, 0.9] - -safelog(x) = log(x + tiny)#exp(-16)) - -function gfe_marginal(A,C,D,q_in) - - x = A * q_in - ρ = exp.(diag(A' * safelog.(A)) + A' *(safelog.(C) .- safelog.(x))) - - μ_out = clamp.(exp.(ρ),tiny,huge) / clamp.(sum(exp.(ρ)),tiny,huge) - - mvec = D .* μ_out - q_in = mvec ./ sum(mvec) -end - -n = 2 -q_in = ones(n) ./ n - -q_in = gfe_marginal(A,C[1],B[2]*D, q_in); -J = jac((x) -> gfe_marginal(A,C[1],B[2]*D, x), q_in); -eigvals(J) - -q_in = gfe_marginal(A,C,D, q_in) -J = jac((x) -> gfe_marginal(A,C,D, x), q_in) -eigvals(J) diff --git a/archive/t_maze.jl b/archive/t_maze.jl deleted file mode 100644 index 3cd6dcf..0000000 --- a/archive/t_maze.jl +++ /dev/null @@ -1,105 +0,0 @@ -using Pkg;Pkg.activate("..");Pkg.instantiate(); -using RxInfer,ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions, Random -Random.seed!(666) -enable_autocomplete_brackets(false),colorscheme!("GruvboxDark"); - -include("transition_mixture/transition_mixture.jl") -include("transition_mixture/marginals.jl") -include("transition_mixture/in.jl") -include("transition_mixture/out.jl") -include("transition_mixture/switch.jl") -include("DiscreteLAIF.jl") -include("helpers.jl") - - -# Need to make pointmass constraints for discrete vars -import RxInfer.default_point_mass_form_constraint_optimizer -import RxInfer.PointMassFormConstraint - -function default_point_mass_form_constraint_optimizer( - ::Type{Univariate}, - ::Type{Discrete}, - constraint::PointMassFormConstraint, - distribution -) - - out = zeros( length(probvec(distribution))) - out[argmax(probvec(distribution))] = 1. - - PointMass(out) -end - - -@model function t_maze(A,D,B1,B2,B3,B4,T) - - z_0 ~ Categorical(D) - - z = randomvar(T) - switch = randomvar(T) - - x = datavar(Vector{Float64}, T) - z_prev = z_0 - - for t in 1:T - switch[t] ~ Categorical(fill(1. /4. ,4)) - z[t] ~ TransitionMixture(z_prev,switch[t], B1,B2,B3,B4) - x[t] ~ DiscreteLAIF(z[t], A) where {q = MeanField(), - pipeline = GFEPipeline((2,), (nothing,vague(Categorical,8)) - ) - } - z_prev = z[t] - end -end; - - - -@constraints function pointmass_q() - q(switch) :: PointMass -end - -# Node constraints -@meta function t_maze_meta() - DiscreteLAIF(x,z) -> PSubstitutionMeta() -end - -T =2; -its = 10; -initmarginals = ( -# z_0 = Categorical(fill(1. /8. ,8)), - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - -A,B,C,D = constructABCD(0.9,[2.0 for t in 1:T],T); - -result = inference(model = t_maze(A,D,B[1],B[2],B[3],B[4],T), - data= (x = C,), - initmarginals = initmarginals, - meta= t_maze_meta(), - free_energy = true, -# constraints=pointmass_q(), - iterations=its, -# options=(limit_stack_depth=300,) - ) - - -# BEHOLD!!!! -probvec.(result.posteriors[:switch][end][1]) -probvec.(result.posteriors[:switch][end][2]) - -using Plots, UnicodePlots -unicodeplots() -plot(result.free_energy) - - -# Try without pointmass constraints, still works -result = inference(model = t_maze(A,D,B[1],B[2],B[3],B[4],T), - data= (x = C,), - initmarginals = initmarginals, - meta= t_maze_meta(), -# free_energy = true, - constraints=pointmass_q(), - iterations=its, -# options=(limit_stack_depth=300,) - ) -probvec(result.posteriors[:switch][end][1]) -probvec(result.posteriors[:switch][end][2]) diff --git a/archive/t_maze_novelty.jl b/archive/t_maze_novelty.jl deleted file mode 100644 index 429e76b..0000000 --- a/archive/t_maze_novelty.jl +++ /dev/null @@ -1,110 +0,0 @@ -using Pkg;Pkg.activate("..");Pkg.instantiate(); -using RxInfer,ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions; -enable_autocomplete_brackets(false),colorscheme!("GruvboxDark"); - - -# Need to make pointmass constraints for discrete vars -import RxInfer.default_point_mass_form_constraint_optimizer -import RxInfer.PointMassFormConstraint - - -function default_point_mass_form_constraint_optimizer( - ::Type{Univariate}, - ::Type{Discrete}, - constraint::PointMassFormConstraint, - distribution -) - - out = zeros( length(probvec(distribution))) - out[argmax(probvec(distribution))] = 1. - - PointMass(out) -end -# Any 0s in A break FE computation. Therefore we need to clamp all 0's to tinys instead - -# Functions we need to modify -import ReactiveMP: entropy, mean -import SpecialFunctions: loggamma, logabsgamma, digamma - -ReactiveMP.mean(::typeof(safelog), dist::MatrixDirichlet) = digamma.(clamp.(dist.a,tiny,Inf)) .- digamma.(sum(clamp.(dist.a,tiny,Inf); dims = 1)) - -# Standard entropy except 0s are set to tiny -function ReactiveMP.entropy(dist::MatrixDirichlet) - a = clamp.(dist.a, tiny,Inf) - return mapreduce(+, eachcol(a)) do column - scolumn = sum(column) - -sum((column .- 1.0) .* (digamma.(column) .- digamma.(scolumn))) - loggamma(scolumn) + sum(loggamma.(column)) - end -end - -# Overwrite energy to avoid 0s -@average_energy MatrixDirichlet (q_out::MatrixDirichlet, q_a::PointMass) = begin - H = mapreduce(+, zip(eachcol(clamp.(mean(q_a),tiny,Inf)), eachcol(mean(safelog, q_out)))) do (q_a_column, logmean_q_out_column) - return -loggamma(sum(q_a_column)) + sum(loggamma.(q_a_column)) - sum((q_a_column .- 1.0) .* logmean_q_out_column) - end - return H -end - - -include("transition_mixture.jl"); -include("helpers.jl"); -include("DiscreteLAIF.jl"); - -@model function t_maze(θ_A,D,B,T) - - z_0 ~ Categorical(D) - - z = randomvar(T) - switch = randomvar(T) - - x = datavar(Vector{Float64}, T) - z_prev = z_0 - A ~ MatrixDirichlet(θ_A) - - for t in 1:T - switch[t] ~ Categorical(fill(1. /4. ,4)) - z[t] ~ TransitionMixture(z_prev,switch[t], B[1],B[2],B[3],B[4]) - x[t] ~ DiscreteLAIF(z[t], A) where {q = MeanField(), pipeline = GFEPipeline((2,3),(Nothing,vague(Categorical,8),vague(MatrixDirichlet,size(θ_A)))) - } - z_prev = z[t] - end -end; - - -@constraints function pointmass_q() - q(switch) :: PointMass -end - -# Node constraints -@meta function t_maze_meta() - DiscreteLAIF(x,z) -> PSubstitutionMeta() -end - -T = 2 -its = 5 - -A,B,C,D = constructABCD(0.9,[2.0 for t in 1:T],T); - -initmarginals = ( - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - #A = vague(MatrixDirichlet,(16,8)), - A = MatrixDirichlet(A + 1e-2*rand(size(A)...)), - ); - -#TODO: FE calculation breaks on entropy of A -result = inference(model = t_maze(A,D,B,T), - data= (x = C,), - initmarginals = initmarginals, - meta= t_maze_meta(), - free_energy = true, -# addons = (AddonMemory(),), -# constraints=pointmass_q(), - iterations=its - ) - - -# BEHOLD!!!! -probvec.(result.posteriors[:switch][end][1]) -probvec.(result.posteriors[:switch][end][2]) -bob = mean(result.posteriors[:A][end]) -bob = result.posteriors[:A][end] diff --git a/archive/test_hmm.jl b/archive/test_hmm.jl deleted file mode 100644 index ffc8c20..0000000 --- a/archive/test_hmm.jl +++ /dev/null @@ -1,97 +0,0 @@ -using Pkg;Pkg.activate(".");Pkg.instantiate() -using OhMyREPL -enable_autocomplete_brackets(false) - -using Rocket, ReactiveMP, GraphPPL -using Random, BenchmarkTools, Distributions, LinearAlgebra -using Plots - -function rand_vec(rng, distribution::Categorical) - k = ncategories(distribution) - s = zeros(k) - s[ rand(rng, distribution) ] = 1.0 - s -end - -function generate_data(n_samples; seed = 124) - - rng = MersenneTwister(seed) - - # Transition probabilities (some transitions are impossible) - A = [0.9 0.0 0.1; 0.1 0.9 0.0; 0.0 0.1 0.9] - # Observation noise - B = [0.9 0.05 0.05; 0.05 0.9 0.05; 0.05 0.05 0.9] - # Initial state - s_0 = [1.0, 0.0, 0.0] - # Generate some data - s = Vector{Vector{Float64}}(undef, n_samples) # one-hot encoding of the states - x = Vector{Vector{Float64}}(undef, n_samples) # one-hot encoding of the observations - - s_prev = s_0 - - for t = 1:n_samples - a = A * s_prev - s[t] = rand_vec(rng, Categorical(a ./ sum(a))) - b = B * s[t] - x[t] = rand_vec(rng, Categorical(b ./ sum(b))) - s_prev = s[t] - end - - return x, s -end - -# Model specification -@model function hidden_markov_model(n,Ac,Bc) - - #A ~ MatrixDirichlet(ones(3, 3)) - A = constvar(Ac) - - #B ~ MatrixDirichlet([ 10.0 1.0 1.0; 1.0 10.0 1.0; 1.0 1.0 10.0 ]) - B = constvar(Bc) - - s_0 ~ Categorical(fill(1.0 / 3.0, 3)) - - s = randomvar(n) - x = datavar(Vector{Float64}, n) - - s_prev = s_0 - - for t in 1:n - s[t] ~ Transition(s_prev, A) - x[t] ~ Transition(s[t], B) - s_prev = s[t] - end - -end - -@constraints function hidden_markov_model_constraints() - q(s_0, s) = q(s_0, s) -end - -N = 100 -A = [0.9 0.0 0.1; 0.1 0.9 0.0; 0.0 0.1 0.9] -B = [0.9 0.05 0.05; 0.05 0.9 0.05; 0.05 0.05 0.9] - -x_data, s_data = generate_data(N) - -idata = (x = x_data, ) - -imodel = Model(hidden_markov_model, N,A,B) - -imarginals = ( - s = vague(Categorical, 3), -) - -ireturnvars = ( - s = KeepLast(), -) - -result = inference( - model = imodel, - data = idata, - #constraints = hidden_markov_model_constraints(), - initmarginals = imarginals, - returnvars = ireturnvars, - iterations = 20, - free_energy = true -) diff --git a/archive/testing.jl b/archive/testing.jl deleted file mode 100644 index edb4665..0000000 --- a/archive/testing.jl +++ /dev/null @@ -1,47 +0,0 @@ -using Pkg;Pkg.activate(".");Pkg.instantiate() -using ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions -enable_autocomplete_brackets(false) -include("transition_mixture.jl") - -# Hack together some transition matrices -Bs = [zeros(4,4) for x in 1:4] -for i in 1:4 - Bs[i][i,:] .= 1. -end - -# Initial state -D = [1.,0.,0,0] -# Likelihood -A = diageye(4) - -goal = [[0.,0.,0.,1.], - [1.,0.,0.,0.], - [0.,0.,0.,1.] ] - - -@model function controlled_hmm(A,D,B1,B2,B3,B4,n) - - z_0 ~ Categorical(D) - - z = randomvar(n) - switch = randomvar(n) - x = datavar(Vector{Float64}, n) - - z_prev = z_0 - - for t in 1:n - switch[t] ~ Categorical(fill(1. /4. ,4)) - z[t] ~ TransitionMixture(z_prev,switch[t], B1,B2,B3,B4) - x[t] ~ Transition(z[t], A) - z_prev = z[t] - end - -end - -imodel = Model(controlled_hmm,A,D,Bs[1],Bs[2],Bs[3],Bs[4],3) - -result = inference(model = imodel, data= (x = goal,)) - -probvec(result.posteriors[:switch][1][3]) - - diff --git a/archive/testing_grounds.jl b/archive/testing_grounds.jl deleted file mode 100644 index 5ac7622..0000000 --- a/archive/testing_grounds.jl +++ /dev/null @@ -1,116 +0,0 @@ -using Pkg; Pkg.activate(".."); Pkg.instantiate() -using RxInfer,Distributions,Random,LinearAlgebra,OhMyREPL, ReactiveMP -import Distributions.entropy -import SpecialFunctions: digamma, loggamma -enable_autocomplete_brackets(false);colorscheme!("GruvboxDark"); - -include("DiscreteLAIF.jl") -include("helpers.jl") - -# We need to get rid of zero entries in MatrixDirichlets to not break FE calculation -function Distributions.entropy(dist::MatrixDirichlet) - return mapreduce(+, eachcol(dist.a)) do column - # This isn't pretty but it gets the job done - col = clamp.(column, tiny, Inf) - scol = sum(col) - -sum((col .- 1.0) .* (digamma.(col) .- digamma.(scol))) - loggamma(scol) + sum(loggamma.(col)) - end -end - - -@average_energy MatrixDirichlet (q_out::MatrixDirichlet, q_a::PointMass) = begin - # Hacky McHackface - q_out = MatrixDirichlet(clamp.(mean(q_out), tiny, Inf)) - q_a = MatrixDirichlet(clamp.(mean(q_a), tiny, Inf)) - H = mapreduce(+, zip(eachcol(mean(q_a)), eachcol(mean(log, q_out)))) do (q_a_column, logmean_q_out_column) - return -loggamma(sum(q_a_column)) + sum(loggamma.(q_a_column)) - sum((q_a_column .- 1.0) .* logmean_q_out_column) - end - return H -end - - -# Rule is missing from RxInfer -@rule Transition(:in, Marginalisation) (q_out::Any, q_a::Any) = begin - a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf) - return Categorical(a ./ sum(a)) -end - -@model function t_maze(θ_A,B,C,D,T) - - z_0 ~ Categorical(D) - # We use datavar here since x~ Pointmass is not a thing - x = datavar(Vector{Float64},T) - z = randomvar(T) - A ~ MatrixDirichlet(θ_A) - - z_prev = z_0 - - for t in 1:T - z[t] ~ Transition(z_prev,B[t]) - # We use the pipeline to only initialise the messages we need - x[t] ~ DiscreteLAIF(z[t], A) where {q = MeanField(), pipeline = GFEPipeline((2,3),(Nothing, - vague(Categorical,8), - MatrixDirichlet(θ_A) - ))} - z_prev = z[t] - end - return z, z_0 -end; - -# Node constraints -@meta function t_maze_meta() - DiscreteLAIF(x,z) -> PSubstitutionMeta() -end - - -T = 2 -A,B,C,D = constructABCD(0.90,ones(T)*2,T); - - -initmarginals = ( - z = [Categorical(fill(1/8,8)) for t in 1:T], - z_0 = [Categorical(fill(1/8,8))], - #A = MatrixDirichlet(A), - A = vague(MatrixDirichlet,size(A)) - ); - - -its=50 -using Random -Random.seed!(123) - -i = 4 -j = 2 -Bs = (B[i],B[j]) -result = inference(model = t_maze(A,Bs,C,D,T), - data= (x=C,), - initmarginals = initmarginals, - meta = t_maze_meta(), -# constraints = nonzero(), - free_energy=true, - iterations = its) - -Ahat = result.posteriors[:A][end] -mean(Ahat) - - - -# Instead of adding jitters, we should go through the constraints specification -# -#@constraints function nonzero() -# q(A):: NonZeroConstraint() -#end - - -#struct NonZeroConstraint <: AbstractFormConstraint end -# -#ReactiveMP.is_point_mass_form_constraint(::NonZeroConstraint) = false -#ReactiveMP.default_form_check_strategy(::NonZeroConstraint) = FormConstraintCheckLast() -#ReactiveMP.default_prod_constraint(::NonZeroConstraint) = ProdGeneric() -# -## Adds a bit of jiter to avoid zeros -#function ReactiveMP.constrain_form(::NonZeroConstraint, distribution) -# m = mean(distribution) -# return MatrixDirichlet(m .+ tiny) -#end -# diff --git a/archive/tm.jl b/archive/tm.jl deleted file mode 100644 index 2d636b0..0000000 --- a/archive/tm.jl +++ /dev/null @@ -1,102 +0,0 @@ -struct TransitionMixture end - -@node TransitionMixture Stochastic [out,in,z,B1,B2,B3,B4,] - -# Average energy functional -#function averageEnergy(::Type{TransitionMixture}, -# dist_out_in1_switch::Distribution{Multivariate, Contingency}, -# dist_factors::Vararg{Distribution}) -# -# n_factors = length(dist_factors) -# U = 0.0 -# for k = 1:n_factors -# U += -tr(dist_out_in1_switch.params[:p][k]'*unsafeLogMean(dist_factors[k])) -# end -# -# return U -#end - -#@average_eneergy TransitionMixture(blah) = begin -# TODO -#end - - -# m_x means message_x, q_x means marginal x. So we use this to dispatch on SP/VB rules -@rule TransitionMixture(:out, Marginalisation) (m_in::DiscreteNonParametric,m_z::DiscreteNonParametric,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - z = probvec(m_z) - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - inp = probvec(m_in) - - # Hack some more... - p = zeros(size(B1*inp)[1]) - for k in 1:4 - p += z[k] * Bs[k] * inp - end - - return Categorical(p ./ sum(p)) -end - -@rule TransitionMixture(:in, Marginalisation) (m_out::DiscreteNonParametric,m_z::DiscreteNonParametric,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - z = probvec(m_z) - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - out = probvec(m_out) - - # This is ugly.. - p = zeros(size(B1'*out)[1]) - for k in 1:4 - p += z[k] * Bs[k]' * out - end - - return Categorical(p ./ sum(p)) -end - -@rule TransitionMixture(:z, Marginalisation) (m_out::DiscreteNonParametric,m_in::DiscreteNonParametric,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - out = probvec(m_out) - inp = probvec(m_in) - - p = zeros(4) - for k in 1:4 - p[k] += out' * Bs[k] * inp - end - - return Categorical(p ./ sum(p)) -end - -@rule TransitionMixture(:out, Marginalisation) (m_in::DiscreteNonParametric,m_z::PointMass,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - - z = argmax(m_z.point) - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - p = Bs[z] * probvec(m_in) - - return Categorical(p ./ sum(p)) -end - diff --git a/archive/tm_back.jl b/archive/tm_back.jl deleted file mode 100644 index 2d636b0..0000000 --- a/archive/tm_back.jl +++ /dev/null @@ -1,102 +0,0 @@ -struct TransitionMixture end - -@node TransitionMixture Stochastic [out,in,z,B1,B2,B3,B4,] - -# Average energy functional -#function averageEnergy(::Type{TransitionMixture}, -# dist_out_in1_switch::Distribution{Multivariate, Contingency}, -# dist_factors::Vararg{Distribution}) -# -# n_factors = length(dist_factors) -# U = 0.0 -# for k = 1:n_factors -# U += -tr(dist_out_in1_switch.params[:p][k]'*unsafeLogMean(dist_factors[k])) -# end -# -# return U -#end - -#@average_eneergy TransitionMixture(blah) = begin -# TODO -#end - - -# m_x means message_x, q_x means marginal x. So we use this to dispatch on SP/VB rules -@rule TransitionMixture(:out, Marginalisation) (m_in::DiscreteNonParametric,m_z::DiscreteNonParametric,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - z = probvec(m_z) - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - inp = probvec(m_in) - - # Hack some more... - p = zeros(size(B1*inp)[1]) - for k in 1:4 - p += z[k] * Bs[k] * inp - end - - return Categorical(p ./ sum(p)) -end - -@rule TransitionMixture(:in, Marginalisation) (m_out::DiscreteNonParametric,m_z::DiscreteNonParametric,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - z = probvec(m_z) - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - out = probvec(m_out) - - # This is ugly.. - p = zeros(size(B1'*out)[1]) - for k in 1:4 - p += z[k] * Bs[k]' * out - end - - return Categorical(p ./ sum(p)) -end - -@rule TransitionMixture(:z, Marginalisation) (m_out::DiscreteNonParametric,m_in::DiscreteNonParametric,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - out = probvec(m_out) - inp = probvec(m_in) - - p = zeros(4) - for k in 1:4 - p[k] += out' * Bs[k] * inp - end - - return Categorical(p ./ sum(p)) -end - -@rule TransitionMixture(:out, Marginalisation) (m_in::DiscreteNonParametric,m_z::PointMass,q_B1::PointMass,q_B2::PointMass,q_B3::PointMass,q_B4::PointMass,) = begin - - z = argmax(m_z.point) - - # Hacky McHackface - B1 = mean(q_B1) - B2 = mean(q_B2) - B3 = mean(q_B3) - B4 = mean(q_B4) - Bs = [B1,B2,B3,B4] - - p = Bs[z] * probvec(m_in) - - return Categorical(p ./ sum(p)) -end - diff --git a/archive/tm_test.jl b/archive/tm_test.jl deleted file mode 100644 index 4705988..0000000 --- a/archive/tm_test.jl +++ /dev/null @@ -1,79 +0,0 @@ -using Pkg;Pkg.activate("..");Pkg.instantiate(); -using RxInfer,ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions; -enable_autocomplete_brackets(false),colorscheme!("GruvboxDark"); - - -# Need to make pointmass constraints for discrete vars -import RxInfer.default_point_mass_form_constraint_optimizer -import RxInfer.PointMassFormConstraint - -function default_point_mass_form_constraint_optimizer( - ::Type{Univariate}, - ::Type{Discrete}, - constraint::PointMassFormConstraint, distribution -) - - out = zeros( length(probvec(distribution))) - out[argmax(probvec(distribution))] = 1. - - PointMass(out) -end - - -include("transition_mixture/transition_mixture.jl"); -include("transition_mixture/marginals.jl"); -include("transition_mixture/in.jl"); -include("transition_mixture/out.jl"); -include("transition_mixture/switch.jl"); -include("helpers.jl"); - -@model function t_maze(A,D,B1,B2,B3,B4,T) - - z_0 ~ Categorical(D) - - z = randomvar(T) - switch = randomvar(T) - - x = datavar(Vector{Float64}, T) - z_prev = z_0 - - for t in 1:T - switch[t] ~ Categorical(fill(1. /4. ,4)) - z[t] ~ TransitionMixture(z_prev,switch[t], B1,B2,B3,B4) - #x[t] ~ DiscreteLAIF(z[t], A) where {q = MeanField(), pipeline = GFEPipeline((2,),vague(Categorical,8))} - x[t] ~ Transition(z[t],A) - z_prev = z[t] - end -end; - - - - -#@constraints function pointmass_q() -# q(switch) :: PointMass -#end - -T =2; - -A,B,C,D = constructABCD(0.9,[2.0 for t in 1:T],T); -D = [1,0,0,0] -B1 =zeros(4,4) ; B1[1,:] .= 1. -B2 =zeros(4,4) ; B2[2,:] .= 1. -B3 =zeros(4,4) ; B3[3,:] .= 1. -B4 =zeros(4,4) ; B4[4,:] .= 1. -B = [B1,B2,B3,B4] - -C[1] = [0,1,0,0] -C[2] = [0,0,1,0] -A = diageye(4) - - -result = inference(model = t_maze(A,D,B[1],B[2],B[3],B[4],T), - data= (x = C,), - free_energy = true, -# constraints=pointmass_q(), - iterations=10, - ) -# BEHOLD!!!! -probvec.(result.posteriors[:switch][end][1]) -probvec.(result.posteriors[:switch][end][2]) diff --git a/src/Part1/distributions.jl b/distributions.jl similarity index 100% rename from src/Part1/distributions.jl rename to distributions.jl diff --git a/src/Part2/Rx/goal_observation.jl b/goal_observation.jl similarity index 100% rename from src/Part2/Rx/goal_observation.jl rename to goal_observation.jl diff --git a/src/.ipynb_checkpoints/T-maze, GFE vs BFE-checkpoint.ipynb b/src/.ipynb_checkpoints/T-maze, GFE vs BFE-checkpoint.ipynb deleted file mode 100644 index 4f98c59..0000000 --- a/src/.ipynb_checkpoints/T-maze, GFE vs BFE-checkpoint.ipynb +++ /dev/null @@ -1,239 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "afb7d8a4", - "metadata": {}, - "source": [ - "# Load packages #" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "e58f4cc1", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - }, - { - "data": { - "text/plain": [ - "constructABCD (generic function with 1 method)" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using Pkg; Pkg.activate(\"..\"); Pkg.instantiate()\n", - "using RxInfer,Distributions,Random,LinearAlgebra,OhMyREPL, ReactiveMP\n", - "enable_autocomplete_brackets(false);colorscheme!(\"GruvboxDark\");\n", - "\n", - "# TODO: Structure is correct now but the results are fucked\n", - "# include(\"GFECategorical.jl\")\n", - "include(\"GFECategorical2.jl\")\n", - "include(\"helpers.jl\")" - ] - }, - { - "cell_type": "markdown", - "id": "48546e8a", - "metadata": {}, - "source": [ - "# Construct the model #" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2a33db20", - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# Rule is missing from RxInfer\n", - "@rule Transition(:in, Marginalisation) (q_out::Any, q_a::Any) = begin\n", - " a = clamp.(exp.(mean(log, q_a)' * probvec(q_out)), tiny, Inf)\n", - " return Categorical(a ./ sum(a))\n", - "end\n", - "\n", - "# Model for the T-maze experiment \n", - "@model function t_maze(A,B,C,T, pipeline = nothing)\n", - "\n", - " D_0 = datavar(Vector{Float64})\n", - " z_0 ~ Categorical(D_0)\n", - " # We use datavar here since x~ Pointmass is not a thing\n", - " x = datavar(Vector{Float64},T)\n", - " z = randomvar(T)\n", - " w = randomvar(T)\n", - "\n", - " # Requires changes in the ReactiveMP core, `@meta` does not support pipelines (yet)\n", - " pipeline = something(pipeline, ReactiveMP.DefaultFunctionalDependencies())\n", - "\n", - " z_prev = z_0\n", - "\n", - " for t in 1:T\n", - " z[t] ~ Transition(z_prev, B[t])\n", - " w[t] ~ Transition(z[t], A) where { pipeline = pipeline }\n", - " w[t] ~ Categorical(x[t])\n", - " z_prev = z[t]\n", - " end\n", - "end;\n", - "\n", - "# Edge Constraints\n", - "@constraints [ warn = false ] function gfeconstraints()\n", - " q(x, z, w, A) = q(x)q(w)q(z)q(A)\n", - " q(w) :: PSubstitutionProduct\n", - "end\n", - "\n", - "# Node constraints\n", - "@meta function gfemeta()\n", - " Transition(z, w) -> PSubstitutionMeta()\n", - " Categorical(x, w) -> PSubstitutionMeta()\n", - "end\n", - "\n", - "@constraints [ warn = false ] function bfeconstraints()\n", - " q(x, z, w, A) = q(x)q(w)q(z)q(A)\n", - "end\n", - "\n", - "# Custom pipeline\n", - "gfepipeline = GFEPipeline((2,))\n" - ] - }, - { - "cell_type": "markdown", - "id": "48c11b1f", - "metadata": {}, - "source": [ - "# Set up priors and configure experiment" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "274cd6d5", - "metadata": {}, - "outputs": [], - "source": [ - "# Get required matrices\n", - "A,B,C,D = constructABCD(0.9,[2.,2.],2);\n", - "\n", - "# Number of inference iterations\n", - "its = 5\n", - "\n", - "# Planning horizon\n", - "T = 2\n", - "\n", - "# Choose functional\n", - "gfe_setup = (\n", - " pipeline = gfepipeline,\n", - " constraints = gfeconstraints(),\n", - " meta = gfemeta()\n", - ")\n", - "\n", - "bfe_setup = (\n", - " pipeline = nothing,\n", - " constraints = bfeconstraints(),\n", - " meta = nothing\n", - ")\n", - "\n", - "\n", - "# Initialise marginals and messages\n", - "\n", - "initmarginals = (\n", - " z = [Categorical(fill(1/8,8)) for t in 1:T],\n", - " );\n", - "\n", - "initmessages = (\n", - " z = [Categorical(fill(1/8,8)) for t in 1:T],\n", - " );\n", - "\n", - "\n", - "# Select between GFE and BFE experiments\n", - "current_setup = gfe_setup" - ] - }, - { - "cell_type": "markdown", - "id": "76519931", - "metadata": {}, - "source": [ - "# Run experiment" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "40ebf728", - "metadata": {}, - "outputs": [], - "source": [ - "F = zeros(4,4);\n", - "for i in 1:4\n", - " for j in 1:4\n", - " Bs = (B[i],B[j])\n", - " global result = inference(model = t_maze(A,Bs,C,T, current_setup[:pipeline]),\n", - " data= (D_0 = D, x = C),\n", - " initmarginals = initmarginals,\n", - " initmessages = initmessages,\n", - " constraints = current_setup[:constraints],\n", - " meta = current_setup[:meta],\n", - " free_energy=true,\n", - " # addons = (AddonMemory(),),\n", - " iterations = its)\n", - " F[i,j] = result.free_energy[end] / log(2)\n", - " end\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "79bfd471", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×4 Matrix{Float64}:\n", - " 10.5033 8.97439 8.97439 9.50325\n", - " 8.97439 8.97439 8.97439 8.97439\n", - " 8.97439 8.97439 8.97439 8.97439\n", - " 9.50325 8.30292 8.30292 8.50325" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Print results\n", - "F" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE-checkpoint.ipynb deleted file mode 100644 index 1c13ad5..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE-checkpoint.ipynb +++ /dev/null @@ -1,247 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "┌ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]\n", - "└ @ Base loading.jl:1664\n", - "\u001b[36m\u001b[1m[ \u001b[22m\u001b[39m\u001b[36m\u001b[1mInfo: \u001b[22m\u001b[39mGR\n" - ] - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], A, # Choose Generalized or Bethe constraint\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], A, ids=[:Y, :X, :A])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of trials\n", - "seed = 1234 # Randomizer seed\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "rs = generateGoalSequence(seed, S) # Sets random seed and returns reproducible goal sequence\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gs = [Vector{Matrix}(undef, 3) for si=1:S] # Free energy values per time\n", - "as = [Vector{Int64}(undef, 2) for si=1:S] # Actions per time\n", - "os = [Vector{Vector}(undef, 2) for si=1:S] # Observations (one-hot) per time\n", - "for si = 1:S # Simulations start at s=0\n", - " reset(si) # Reset world\n", - " for ti=1:2 # Time starts at t=0\n", - " (Gs[si][ti], _) = infer(ti-1, as[si], os[si])\n", - " as[si][ti] = act(ti-1, Gs[si][ti])\n", - " execute(as[si][ti])\n", - " os[si][ti] = observe()\n", - " end\n", - " (Gs[si][3], As[si]) = infer(2, as[si], os[si]) # Learn at t=2\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sum([as[si].==rs[si]'*[2, 3] for si=1:S]) # Correct visits per timepoint" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "include(\"visualizations.jl\")\n", - "plotObservationStatistics(As[S], A_0)\n", - "savefig(\"figures/GFE_A\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "include(\"visualizations.jl\")\n", - "plotFreeEnergyMinimum(Gs, os, legend=115, ylim=(7,22))\n", - "savefig(\"figures/GFE_FE.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# include(\"visualizations.jl\")\n", - "# for si=1:S\n", - "# plotFreeEnergies(Gs[si], as[si], os[si], rs[si], title=\"s=$(si-1)\")\n", - "# savefig(\"figures/GFE_$(si-1).png\")\n", - "# end" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-Copy1-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-Copy1-checkpoint.ipynb deleted file mode 100644 index 6412fe3..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-Copy1-checkpoint.ipynb +++ /dev/null @@ -1,529 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k),\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], ids=[:Y, :X])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Cat(p=[5.69e-11, 5.69e-11, 0.00, 0.00, 0.00, 0.00, 0.72, 0.28, 0.00, 0.00, 1.24e-11, 1.24e-11, 1.24e-11, 1.24e-11, 0.00, 0.00])\n" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "marginals[:y_2]" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function stepY!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - "\n", - "messages[1] = ruleVBDiscreteObservationGeneralizedY(marginals[:y_2], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "messages[2] = ruleVBDiscreteObservationGeneralizedY(marginals[:y_1], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "\n", - "marginals[:y_1] = messages[2].dist\n", - "marginals[:y_2] = messages[1].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function initX()\n", - "\n", - "messages = Array{Message}(undef, 10)\n", - "\n", - "messages[5] = Message(vague(Categorical, (8,)))\n", - "messages[8] = Message(vague(Categorical, (8,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function stepX!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 10))\n", - "\n", - "messages[1] = ruleVBDiscreteObservationGeneralizedS(marginals[:y_1], messages[8], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "messages[2] = ruleVBCategoricalOut(nothing, Distribution(Multivariate, PointMass, m=data[:D_s]))\n", - "messages[3] = ruleSVBTransitionOutVCD(nothing, messages[2], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "messages[4] = ruleSPEqualityCategorical(messages[3], messages[1], nothing)\n", - "messages[5] = ruleSVBTransitionOutVCD(nothing, messages[4], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[6] = ruleVBDiscreteObservationGeneralizedS(marginals[:y_2], messages[5], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "messages[7] = ruleSVBTransitionIn1CVD(messages[6], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[8] = ruleSPEqualityCategorical(messages[3], nothing, messages[7])\n", - "messages[9] = ruleSPEqualityCategorical(nothing, messages[1], messages[7])\n", - "messages[10] = ruleSVBTransitionIn1CVD(messages[9], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "\n", - "marginals[:x_0] = messages[2].dist * messages[10].dist\n", - "marginals[:x_1] = messages[3].dist * messages[9].dist\n", - "marginals[:x_2] = messages[5].dist * messages[6].dist\n", - "marginals[:x_1_x_0] = ruleMTransitionCCD(messages[9], messages[2], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "marginals[:x_2_x_1] = ruleMTransitionCCD(messages[6], messages[4], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(Categorical, marginals[:x_0], Distribution(Multivariate, PointMass, m=data[:D_s]))\n", - "F += averageEnergy(DiscreteObservation{Generalized}, marginals[:y_1], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "F += averageEnergy(DiscreteObservation{Generalized}, marginals[:y_2], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "F += averageEnergy(Transition, marginals[:x_1_x_0], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "F += averageEnergy(Transition, marginals[:x_2_x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "F -= -1*differentialEntropy(marginals[:x_1])\n", - "F -= differentialEntropy(marginals[:x_1_x_0])\n", - "F -= differentialEntropy(marginals[:x_2_x_1])\n", - "F -= differentialEntropy(marginals[:y_1])\n", - "F -= differentialEntropy(marginals[:y_2])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - " println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "10-element Vector{Message}:\n", - " #undef\n", - " #undef\n", - " #undef\n", - " #undef\n", - " Message: Cat(p=[0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12])\n", - "\n", - " #undef\n", - " #undef\n", - " Message: Cat(p=[0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12])\n", - "\n", - " #undef\n", - " #undef" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of trials\n", - "seed = 1234 # Randomizer seed\n", - "n_its = 50\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "pol = (4,2)\n", - "\n", - "data = Dict(:u => [B[pol[1]], B[pol[2]]],\n", - " :A => A,\n", - " :C => C,\n", - " :D_s => D_0)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_0 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - "# Define unobserved marginals\n", - "marginals[:y_1] = Distribution(Univariate, Categorical, p=asym(16))\n", - "marginals[:y_2] = Distribution(Univariate, Categorical, p=asym(16))\n", - "\n", - "messages = initX()\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Cat(p=[0.12, 0.12, 0.12, 0.13, 0.12, 0.13, 0.13, 0.13])\n" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "marginals[:x_1]" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "8.461620404516369" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Gis = zeros(n_its)\n", - "\n", - "\n", - "stepX!(data, marginals, messages)\n", - "stepY!(data, marginals)\n", - "freeEnergy(data, marginals)/log(2)" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Cat(p=[0.89, 0.11, 6.83e-12, 6.83e-12, 6.83e-12, 6.83e-12, 6.83e-12, 6.83e-12])\n" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "marginals[:x_0]" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - " \n", - "Gis = zeros(n_its)\n", - "for i=1:n_its\n", - " stepX!(data, marginals, messages)\n", - " stepY!(data, marginals)\n", - " Gis[i] = freeEnergy(data, marginals)/log(2)\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot(1:n_its, Gis, color=:black, linewidth=2, xlabel=\"Iteration\", ylabel=\"Free Energy [bits]\", label=false, title=\"Policy: $pol\")\n", - "\n", - "#savefig(\"figures/policy.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot(Gis[2:end])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-checkpoint.ipynb deleted file mode 100644 index 984d7b4..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/T-maze_GFE_planning-checkpoint.ipynb +++ /dev/null @@ -1,249 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k),\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], ids=[:Y, :X])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of trials\n", - "seed = 1234 # Randomizer seed\n", - "n_its = 50\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "pol = (4,2)\n", - "\n", - "data = Dict(:u => [B[pol[1]], B[pol[2]]],\n", - " :A => A,\n", - " :C => C,\n", - " :D_s => D_0)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_0 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - "# Define unobserved marginals\n", - "marginals[:y_1] = Distribution(Univariate, Categorical, p=asym(16))\n", - "marginals[:y_2] = Distribution(Univariate, Categorical, p=asym(16))\n", - "\n", - "messages = initX()\n", - " \n", - "Gis = zeros(n_its)\n", - "for i=1:n_its\n", - " stepX!(data, marginals, messages)\n", - " stepY!(data, marginals)\n", - " Gis[i] = freeEnergy(data, marginals)/log(2)\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "SystemError: opening file \"/home/mkoudahl/biaslab/repos/EpistemicMessagePassing/src/FLSimulations/figures/policy.png\": No such file or directory", - "output_type": "error", - "traceback": [ - "SystemError: opening file \"/home/mkoudahl/biaslab/repos/EpistemicMessagePassing/src/FLSimulations/figures/policy.png\": No such file or directory", - "", - "Stacktrace:", - " [1] systemerror(p::String, errno::Int32; extrainfo::Nothing)", - " @ Base ./error.jl:176", - " [2] #systemerror#80", - " @ ./error.jl:175 [inlined]", - " [3] systemerror", - " @ ./error.jl:175 [inlined]", - " [4] open(fname::String; lock::Bool, read::Nothing, write::Nothing, create::Nothing, truncate::Bool, append::Nothing)", - " @ Base ./iostream.jl:293", - " [5] open(fname::String, mode::String; lock::Bool)", - " @ Base ./iostream.jl:356", - " [6] open(fname::String, mode::String)", - " @ Base ./iostream.jl:355", - " [7] open(::Plots.var\"#334#335\"{Plots.Plot{Plots.GRBackend}}, ::String, ::Vararg{String}; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})", - " @ Base ./io.jl:382", - " [8] open", - " @ ./io.jl:381 [inlined]", - " [9] png(plt::Plots.Plot{Plots.GRBackend}, fn::String)", - " @ Plots ~/.config/julia/packages/Plots/io9zQ/src/output.jl:6", - " [10] savefig(plt::Plots.Plot{Plots.GRBackend}, fn::String)", - " @ Plots ~/.config/julia/packages/Plots/io9zQ/src/output.jl:149", - " [11] savefig(fn::String)", - " @ Plots ~/.config/julia/packages/Plots/io9zQ/src/output.jl:154", - " [12] top-level scope", - " @ In[7]:3", - " [13] eval", - " @ ./boot.jl:368 [inlined]", - " [14] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)", - " @ Base ./loading.jl:1428" - ] - } - ], - "source": [ - "plot(1:n_its, Gis, color=:black, linewidth=2, xlabel=\"Iteration\", ylabel=\"Free Energy [bits]\", label=false, title=\"Policy: $pol\")\n", - "\n", - "savefig(\"figures/policy.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/T-maze_interactive-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/T-maze_interactive-checkpoint.ipynb deleted file mode 100644 index d71d73d..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/T-maze_interactive-checkpoint.ipynb +++ /dev/null @@ -1,935 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete GFE-constrained SSM.\n", - "\n", - "TODO: parameter estimation" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Regulator Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg_plan = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "y = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " DiscreteObservation(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k), \n", - " placeholder(:C, dims=(16,), index=k, var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "q_plan = PosteriorFactorization(fg_plan)\n", - "algo_plan = messagePassingAlgorithm(x_t_min, id=:Plan, free_energy=true)\n", - "code_plan = algorithmSourceCode(algo_plan, free_energy=true)\n", - "eval(Meta.parse(code_plan))\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Estimator Model" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "fg_slide = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "y = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV x_t ~ Transition(x_t_min, placeholder(:B_t, dims=(8,8)))\n", - "@RV y_t ~ Transition(x_t, placeholder(:A, dims=(16,8)))\n", - "placeholder(y_t, :o_t, dims=(16,))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "q_slide = PosteriorFactorization(fg_slide)\n", - "algo_slide = messagePassingAlgorithm(x_t, id=:Slide)\n", - "code_slide = algorithmSourceCode(algo_slide)\n", - "eval(Meta.parse(code_slide))\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "N = 2 # Number of moves per simulation\n", - "S = 10 # Number of simulations\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - " \n", - "# for s = 1:S\n", - " (execute, observe) = initializeWorld(A, B, C, D) # Let there be a world\n", - " (plan, act, slide) = initializeAgent(A, B, C, D) # Let there be a constrained agent\n", - "\n", - " # Step through the experimental protocol\n", - " G_ts = Vector{Matrix}(undef, N)\n", - " a = Vector{Int64}(undef, N)\n", - " for t = 1:N\n", - " G_ts[t] = plan()\n", - " a[t] = act(G_ts[t])\n", - " execute(a[t])\n", - " (o_t, r_t) = observe()\n", - " slide(a[t], o_t)\n", - " end\n", - "# end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotResults(G_ts[1], clim=(11,19), highlight=minimum)" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotResults(G_ts[2], clim=(11,19), highlight=minimum)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[4, 1]\n" - ] - } - ], - "source": [ - "println(a) # Back to one?" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.0", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/T-maze_interactive_2-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/T-maze_interactive_2-checkpoint.ipynb deleted file mode 100644 index d1f515c..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/T-maze_interactive_2-checkpoint.ipynb +++ /dev/null @@ -1,294 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete GFE-constrained SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "┌ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]\n", - "└ @ Base loading.jl:1662\n", - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mbackend `GR` is not installed.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Plots ~/.config/julia/packages/Plots/M4dfL/src/backends.jl:37\u001b[39m\n", - "\u001b[36m\u001b[1m[ \u001b[22m\u001b[39m\u001b[36m\u001b[1mInfo: \u001b[22m\u001b[39mGR\n" - ] - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=1$" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t1 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "DiscreteObservation(x[1], \n", - " A,\n", - " placeholder(:C, dims=(16,), var_id=:C_1),\n", - " n_factors=8)\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "DiscreteObservation(x[2], \n", - " A,\n", - " placeholder(:C, dims=(16,), var_id=:C_2),\n", - " n_factors=8)\n", - "# Algorithm\n", - "q_t1 = PosteriorFactorization([x_0; x], A, ids=[:X, :A])\n", - "algo_t1 = messagePassingAlgorithm(q_t1, id=:t1, free_energy=true)\n", - "code_t1 = algorithmSourceCode(algo_t1, free_energy=true)\n", - "eval(Meta.parse(code_t1))\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=2$" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t2 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "@RV y[1] ~ Transition(x[1], A)\n", - "placeholder(y[1], :y, index=1, dims=(16,))\n", - "\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "DiscreteObservation(x[2], \n", - " A,\n", - " placeholder(:C, dims=(16,), var_id=:C_2),\n", - " n_factors=8)\n", - "# Algorithm\n", - "q_t2 = PosteriorFactorization([x_0; x], A, ids=[:X, :A])\n", - "algo_t2 = messagePassingAlgorithm(q_t2, id=:t2, free_energy=true)\n", - "code_t2 = algorithmSourceCode(algo_t2, free_energy=true)\n", - "eval(Meta.parse(code_t2))\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=3$ (Learning)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t3 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "@RV y[1] ~ Transition(x[1], A)\n", - "placeholder(y[1], :y, index=1, dims=(16,))\n", - "\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "@RV y[2] ~ Transition(x[2], A)\n", - "placeholder(y[2], :y, index=2, dims=(16,))\n", - "\n", - "# Algorithm\n", - "q_t3 = PosteriorFactorization([x_0; x], A, ids=[:X, :A])\n", - "algo_t3 = messagePassingAlgorithm(q_t3, id=:t3, free_energy=true)\n", - "code_t3 = algorithmSourceCode(algo_t3, free_energy=true)\n", - "eval(Meta.parse(code_t3))\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 20 # Number of simulations\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent_2.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "A_0 = constructAPrior() # Construct prior statistics for A\n", - "\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gts = [[Matrix(undef, 4, 4), Vector(undef, 4)] for s=1:S] # Free energy values\n", - "ats = [Vector{Int64}(undef, 2) for s=1:S] # Actions\n", - "ots = [Vector{Vector}(undef, 2) for s=1:S] # Observations (1-of-K)\n", - "rts = [Vector{Float64}(undef, 2) for s=1:S] # Probability of reward\n", - "for s = 1:S\n", - " reset() # Reset world\n", - " for t = 1:2\n", - " Gts[s][t] = infer(t, ats[s], ots[s])\n", - " ats[s][t] = act(Gts[s][t])\n", - " execute(ats[s][t])\n", - " (ots[s][t], rts[s][t]) = observe()\n", - " end\n", - " As[s] = infer(3, ats[s], ots[s]) # Learn\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "round.(As[S] - A_0, digits=1) # Inspect difference in observation statistics" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "include(\"visualizations.jl\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.0", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/T-maze_planning_GBFE-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/T-maze_planning_GBFE-checkpoint.ipynb deleted file mode 100644 index 96f6e7e..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/T-maze_planning_GBFE-checkpoint.ipynb +++ /dev/null @@ -1,718 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with GBFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k],id=:x_*k)\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " DiscreteObservation(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k), \n", - " placeholder(:C, dims=(16,), index=k, var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(fg)\n", - "algo = messagePassingAlgorithm(x_t_min, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function init()\n", - "\n", - "messages = Array{Message}(undef, 10)\n", - "\n", - "messages[5] = Message(vague(Categorical, (8,)))\n", - "messages[8] = Message(vague(Categorical, (8,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function step!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 10))\n", - "\n", - "messages[1] = ruleSPDiscreteObservationOutDPP(messages[8], marginals[:x_1], Message(MatrixVariate, PointMass, m=data[:A]), Message(Multivariate, PointMass, m=data[:C][1]))\n", - "messages[2] = ruleSPCategoricalOutNP(nothing, Message(Multivariate, PointMass, m=data[:D_t_min]))\n", - "messages[3] = ruleSPTransitionOutNCP(nothing, messages[2], Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "messages[4] = ruleSPEqualityCategorical(messages[3], messages[1], nothing)\n", - "messages[5] = ruleSPTransitionOutNCP(nothing, messages[4], Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[6] = ruleSPDiscreteObservationOutDPP(messages[5], marginals[:x_2], Message(MatrixVariate, PointMass, m=data[:A]), Message(Multivariate, PointMass, m=data[:C][2]))\n", - "messages[7] = ruleSPTransitionIn1CNP(messages[6], nothing, Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[8] = ruleSPEqualityCategorical(messages[3], nothing, messages[7])\n", - "messages[9] = ruleSPEqualityCategorical(nothing, messages[1], messages[7])\n", - "messages[10] = ruleSPTransitionIn1CNP(messages[9], nothing, Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "\n", - "marginals[:x_1] = messages[3].dist * messages[9].dist\n", - "marginals[:x_2] = messages[5].dist * messages[6].dist\n", - "marginals[:x_t_min] = messages[2].dist * messages[10].dist\n", - "marginals[:x_1_x_t_min] = ruleMTransitionCCN(messages[9], messages[2], Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "marginals[:x_2_x_1] = ruleMTransitionCCN(messages[6], messages[4], Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(Categorical, marginals[:x_t_min], Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][1]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][2]))\n", - "F += averageEnergy(Transition, marginals[:x_1_x_t_min], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "F += averageEnergy(Transition, marginals[:x_2_x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "F -= -1*differentialEntropy(marginals[:x_1])\n", - "F -= differentialEntropy(marginals[:x_1_x_t_min])\n", - "F -= differentialEntropy(marginals[:x_2_x_1])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - "println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Single policy\n", - "pi = [4, 2]\n", - "\n", - "n_its = 10\n", - "G = zeros(n_its)\n", - "\n", - "data = Dict(:u => [B[pi[1]], B[pi[2]]],\n", - " :A => A,\n", - " :C => C_t,\n", - " :D_t_min => D)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - "messages = init()\n", - "\n", - "for k=1:n_its\n", - " step!(data, marginals, messages)\n", - " G[k] = freeEnergy(data, marginals)\n", - "end\n", - " \n", - "G = G./log(2) # Convert to bits\n", - "\n", - "plot(1:n_its, G, color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Iteration\", ylabel=\"GFE [bits]\")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# GBFE for all policies\n", - "GBFE = evaluatePoliciesGBFE(A, B, C_t, D, n_its=n_its)\n", - "plotResults(GBFE, clim=(8.0,11.0), dpi=300, highlight=minimum)\n", - "#savefig(\"GBFE_c_$(c)_a_$(α).png\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.0", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/multi_T-maze_GFE-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/multi_T-maze_GFE-checkpoint.ipynb deleted file mode 100644 index 88e557f..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/multi_T-maze_GFE-checkpoint.ipynb +++ /dev/null @@ -1,244 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], A, # Choose Generalized or Bethe constraint\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], A, ids=[:Y, :X, :A])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32mProgress: 3%|█▎ | ETA: 0:48:24\u001b[39m" - ] - } - ], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 20 # Number of trials\n", - "R = 100 # Number of runs\n", - "seed = 1234 # Randomizer seed\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"visualizations.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "wins = [Vector{Float64}(undef, S) for ri=1:R]\n", - "\n", - "@showprogress for ri=1:R\n", - " rs = generateGoalSequence(S) # Returns random goal sequence\n", - " (reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - " (infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - " # Step through the experimental protocol\n", - " As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - " Gs = [Vector{Matrix}(undef, 3) for si=1:S] # Free energy values per time\n", - " as = [Vector{Int64}(undef, 2) for si=1:S] # Actions per time\n", - " os = [Vector{Vector}(undef, 2) for si=1:S] # Observations (one-hot) per time\n", - " for si = 1:S # Simulations start at s=0\n", - " reset(si) # Reset world\n", - " for ti=1:2 # Time starts at t=0\n", - " (Gs[si][ti], _) = infer(ti-1, as[si], os[si])\n", - " as[si][ti] = act(ti-1, Gs[si][ti])\n", - " execute(as[si][ti])\n", - " os[si][ti] = observe()\n", - " end\n", - " (Gs[si][3], As[si]) = infer(2, as[si], os[si]) # Learn at t=2\n", - " end\n", - " wins[ri] = extractWins(os)\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "using FileIO, JLD2\n", - "FileIO.save(\"figures/wins.jld2\",\"wins\",wins,\"R\",R,\"S\",S)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ms = mean(wins)\n", - "sds = sqrt.(var(wins))\n", - "\n", - "plot(0:S-1, ms, ylim=(0,1), \n", - " color=:black, \n", - " lw=2, \n", - " legend=false, \n", - " xlabel=\"Simulation Trial (s)\", \n", - " ylabel=\"Win Average\")\n", - "\n", - "# savefig(\"figures/GFE_wins.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/param_direct-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/param_direct-checkpoint.ipynb deleted file mode 100644 index e73a994..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/param_direct-checkpoint.ipynb +++ /dev/null @@ -1,612 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "mean (generic function with 1 method)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForwardDiff: jacobian\n", - "\n", - "da = 0.05\n", - "as = 0:da:1\n", - "n = length(as)\n", - "function muAbw(A_bar)\n", - " fA = zeros(n,n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " A = [as[j] as[k]; 1-as[j] 1-as[k]]\n", - " fA[j,k] = exp.( x_bar'*diag(A'*log.(A .+ eps())) + (A*x_bar)'*(log_c_bar - log.(A*x_bar .+ eps()) ) )\n", - " end\n", - " end\n", - " \n", - " return fA ./ sum(fA)\n", - "end\n", - "\n", - "function mean(p)\n", - " X = Matrix{Vector}(undef, n, n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " X[j,k] = [as[j], as[k]]\n", - " end\n", - " end\n", - " a_bar = sum(p.*X)\n", - " return [a_bar[1] a_bar[2]; 1-a_bar[1] 1-a_bar[2]]\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using Plots; gr()\n", - "\n", - "B_fw = 2*ones(2, 2)\n", - "x_bar = [0.5, 0.5]\n", - "log_c_bar = log.([0.5, 0.5])\n", - "\n", - "K = 5\n", - "A_bar = [0.5 0.5; 0.5 0.5]\n", - "mu = muAbw(A_bar)\n", - "\n", - "plt = plot(as,\n", - " as,\n", - " mu',\n", - " st=:contour,\n", - " fill=true,\n", - " dpi=100,\n", - " aspect_ratio=:equal, \n", - " xlim=(0,1), \n", - " ylim=(0,1), \n", - " xlabel=\"a11\",\n", - " ylabel=\"a12\",\n", - " title=\"mu_bw(A)\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.0", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - }, - "vscode": { - "interpreter": { - "hash": "31b90ea2ee662646d8e5466ef4be593ab702f85e022a25e857ef13a3c4d04a00" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/.ipynb_checkpoints/param_iterate-checkpoint.ipynb b/src/FLSimulations/.ipynb_checkpoints/param_iterate-checkpoint.ipynb deleted file mode 100644 index 1431d5a..0000000 --- a/src/FLSimulations/.ipynb_checkpoints/param_iterate-checkpoint.ipynb +++ /dev/null @@ -1,640 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "mean (generic function with 1 method)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForwardDiff: jacobian\n", - "\n", - "da = 0.05\n", - "as = 0:da:1\n", - "n = length(as)\n", - "function qA(A_bar)\n", - " fA = zeros(n,n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " A = [as[j] as[k]; 1-as[j] 1-as[k]]\n", - " fA[j,k] = exp.( x_bar'*diag(A'*log.(A .+ eps())) + (A*x_bar)'*(log_c_bar - log.(A*x_bar .+ eps()) ) + tr( (B_fw' .- 1)*log.(A .+ eps()) ) )\n", - " end\n", - " end\n", - " \n", - " return fA ./ sum(fA)\n", - "end\n", - "\n", - "function muAfw(B_fw)\n", - " fAfw = zeros(n,n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " A = [as[j] as[k]; 1-as[j] 1-as[k]]\n", - " fAfw[j,k] = exp.(tr((B_fw' .- 1)*log.(A .+ eps())))\n", - " end\n", - " end\n", - "\n", - " return fAfw ./ sum(fAfw)\n", - "end\n", - "\n", - "function mean(p)\n", - " X = Matrix{Vector}(undef, n, n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " X[j,k] = [as[j], as[k]]\n", - " end\n", - " end\n", - " a_bar = sum(p.*X)\n", - " return [a_bar[1] a_bar[2]; 1-a_bar[1] 1-a_bar[2]]\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5]" - ] - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using Plots; gr()\n", - "\n", - "B_fw = 2*ones(2, 2)\n", - "x_bar = [0.5, 0.5]\n", - "log_c_bar = log.([0.5, 0.5])\n", - "\n", - "K = 5\n", - "A_bar_k_min = [0.5 0.5; 0.5 0.5]\n", - "q_k = zeros(n, n)\n", - "for k=1:K\n", - " q_k = qA(A_bar_k_min)\n", - " A_bar_k = mean(q_k)\n", - " print(round.(A_bar_k, digits=2))\n", - "\n", - " A_bar_k_min = A_bar_k\n", - "end\n", - "\n", - "muAbw = q_k ./ muAfw(B_fw)\n", - "\n", - "plt = plot(as,\n", - " as,\n", - " muAbw',\n", - " st=:contour,\n", - " fill=true,\n", - " dpi=100,\n", - " aspect_ratio=:equal, \n", - " xlim=(0,1), \n", - " ylim=(0,1), \n", - " xlabel=\"a11\",\n", - " ylabel=\"a12\",\n", - " title=\"mu_bw(A)\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.0", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - }, - "vscode": { - "interpreter": { - "hash": "31b90ea2ee662646d8e5466ef4be593ab702f85e022a25e857ef13a3c4d04a00" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/T-maze_GFE_planning-Copy1.ipynb b/src/FLSimulations/T-maze_GFE_planning-Copy1.ipynb deleted file mode 100644 index 3da2686..0000000 --- a/src/FLSimulations/T-maze_GFE_planning-Copy1.ipynb +++ /dev/null @@ -1,671 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "┌ Info: Precompiling Plots [91a5bcdd-55d7-5caf-9e0b-520d859cae80]\n", - "└ @ Base loading.jl:1664\n" - ] - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "using Random\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k),\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], ids=[:Y, :X])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function stepY!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - "\n", - "messages[1] = ruleVBDiscreteObservationGeneralizedY(marginals[:y_2], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "messages[2] = ruleVBDiscreteObservationGeneralizedY(marginals[:y_1], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "\n", - "marginals[:y_1] = messages[2].dist\n", - "marginals[:y_2] = messages[1].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function initX()\n", - "\n", - "messages = Array{Message}(undef, 10)\n", - "\n", - "messages[5] = Message(vague(Categorical, (8,)))\n", - "messages[8] = Message(vague(Categorical, (8,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function stepX!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 10))\n", - "\n", - "messages[1] = ruleVBDiscreteObservationGeneralizedS(marginals[:y_1], messages[8], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "messages[2] = ruleVBCategoricalOut(nothing, Distribution(Multivariate, PointMass, m=data[:D_s]))\n", - "messages[3] = ruleSVBTransitionOutVCD(nothing, messages[2], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "messages[4] = ruleSPEqualityCategorical(messages[3], messages[1], nothing)\n", - "messages[5] = ruleSVBTransitionOutVCD(nothing, messages[4], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[6] = ruleVBDiscreteObservationGeneralizedS(marginals[:y_2], messages[5], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "messages[7] = ruleSVBTransitionIn1CVD(messages[6], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[8] = ruleSPEqualityCategorical(messages[3], nothing, messages[7])\n", - "messages[9] = ruleSPEqualityCategorical(nothing, messages[1], messages[7])\n", - "messages[10] = ruleSVBTransitionIn1CVD(messages[9], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "\n", - "marginals[:x_0] = messages[2].dist * messages[10].dist\n", - "marginals[:x_1] = messages[3].dist * messages[9].dist\n", - "marginals[:x_2] = messages[5].dist * messages[6].dist\n", - "marginals[:x_1_x_0] = ruleMTransitionCCD(messages[9], messages[2], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "marginals[:x_2_x_1] = ruleMTransitionCCD(messages[6], messages[4], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(Categorical, marginals[:x_0], Distribution(Multivariate, PointMass, m=data[:D_s]))\n", - "F += averageEnergy(DiscreteObservation{Generalized}, marginals[:y_1], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "F += averageEnergy(DiscreteObservation{Generalized}, marginals[:y_2], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C]))\n", - "F += averageEnergy(Transition, marginals[:x_1_x_0], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "F += averageEnergy(Transition, marginals[:x_2_x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "F -= -1*differentialEntropy(marginals[:x_1])\n", - "F -= differentialEntropy(marginals[:x_1_x_0])\n", - "F -= differentialEntropy(marginals[:x_2_x_1])\n", - "F -= differentialEntropy(marginals[:y_1])\n", - "F -= differentialEntropy(marginals[:y_2])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - " println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "using Random" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "10-element Vector{Message}:\n", - " #undef\n", - " #undef\n", - " #undef\n", - " #undef\n", - " Message: Cat(p=[0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12])\n", - "\n", - " #undef\n", - " #undef\n", - " Message: Cat(p=[0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12])\n", - "\n", - " #undef\n", - " #undef" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of trials\n", - "#Random.seed! = 1234 # Randomizer seed\n", - "n_its = 2\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "pol = (4,2)\n", - "\n", - "data = Dict(:u => [B[pol[1]], B[pol[2]]],\n", - " :A => A,\n", - " :C => C,\n", - " :D_s => D_0)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_0 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - "# Define unobserved marginals\n", - "marginals[:y_1] = Distribution(Univariate, Categorical, p=asym(16))\n", - "marginals[:y_2] = Distribution(Univariate, Categorical, p=asym(16))\n", - "\n", - "messages = initX()\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "10-element Vector{Message}:\n", - " #undef\n", - " #undef\n", - " #undef\n", - " #undef\n", - " Message: Cat(p=[0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12])\n", - "\n", - " #undef\n", - " #undef\n", - " Message: Cat(p=[0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12])\n", - "\n", - " #undef\n", - " #undef" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Cat(p=[0.12, 0.13, 0.12, 0.13, 0.12, 0.13, 0.12, 0.13])\n" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "marginals[:x_1]" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I am s: [0.12495467054373983, 0.1250391498095245, 0.12498303608121678, 0.125020440663928, 0.12495084030691886, 0.12503471572404107, 0.12498898937670185, 0.125028157493929]\n", - "I am d: [0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125]\n", - "I am logC: [-3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836]\n", - "\n", - "\n", - "I am s: [0.12504255892118632, 0.1250385202617946, 0.12495147331513475, 0.12497140322074698, 0.12498560589413055, 0.1250287813804603, 0.12498240849744119, 0.12499924850910524]\n", - "I am d: [1.7437724210137946e-11, 1.7437724210137946e-11, 0.49999999998056205, 0.49999999998056205, 9.999999999930004e-13, 9.999999999930004e-13, 9.999999999930004e-13, 9.999999999930004e-13]\n", - "I am logC: [-3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836]\n", - "\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "8.461620404516369" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Gis = zeros(n_its)\n", - "\n", - "\n", - "stepX!(data, marginals, messages)\n", - "stepY!(data, marginals)\n", - "freeEnergy(data, marginals)/log(2)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Cat(p=[1.18e-11, 1.18e-11, 1.18e-11, 1.18e-11, 1.18e-11, 1.18e-11, 0.89, 0.11])\n" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "marginals[:x_1]" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "10-element Vector{Message}:\n", - " Message: Cat(p=[0.09, 0.09, 0.26, 0.03, 0.03, 0.26, 0.12, 0.12])\n", - "\n", - " Message: Cat(p=[0.50, 0.50, 1.00e-12, 1.00e-12, 1.00e-12, 1.00e-12, 1.00e-12, 1.00e-12])\n", - "\n", - " Message: Cat(p=[3.00e-12, 3.00e-12, 1.00e-12, 1.00e-12, 1.00e-12, 1.00e-12, 0.50, 0.50])\n", - "\n", - " Message: Cat(p=[8.22e-12, 8.22e-12, 8.22e-12, 8.22e-12, 8.22e-12, 8.22e-12, 0.50, 0.50])\n", - "\n", - " Message: Cat(p=[1.74e-11, 1.74e-11, 0.50, 0.50, 1.00e-12, 1.00e-12, 1.00e-12, 1.00e-12])\n", - "\n", - " Message: Cat(p=[0.22, 0.22, 0.22, 0.03, 0.02, 0.16, 0.07, 0.07])\n", - "\n", - " Message: Cat(p=[0.16, 0.02, 0.16, 0.16, 0.16, 0.16, 0.16, 0.02])\n", - "\n", - " Message: Cat(p=[1.10e-11, 1.10e-11, 1.10e-11, 1.10e-11, 1.10e-11, 1.10e-11, 0.89, 0.11])\n", - "\n", - " Message: Cat(p=[0.11, 0.01, 0.31, 0.04, 0.04, 0.31, 0.15, 0.02])\n", - "\n", - " Message: Cat(p=[0.26, 0.03, 0.18, 0.02, 0.18, 0.02, 0.26, 0.03])\n" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "16-element Vector{Float64}:\n", - " 0.02624839635087663\n", - " 0.02624839635087663\n", - " 0.19395087314359397\n", - " 0.0035523341546527592\n", - " 0.02624839635087663\n", - " 0.02624839635087663\n", - " 0.19395087314359397\n", - " 0.0035523341546527592\n", - " 0.02624839635087663\n", - " 0.02624839635087663\n", - " 0.19395087314359397\n", - " 0.0035523341546527592\n", - " 0.02624839635087663\n", - " 0.02624839635087663\n", - " 0.19395087314359397\n", - " 0.0035523341546527592" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "C" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I am s: [1.1765784868979485e-11, 1.1765784868979485e-11, 1.1765784868979485e-11, 1.1765784868979485e-11, 1.1765784868979485e-11, 1.1765784868979485e-11, 0.8856931432751671, 0.11430685665423802]\n", - "I am d: [1.095290923503698e-11, 1.095290923503698e-11, 1.095290923503698e-11, 1.095290923503698e-11, 1.095290923503698e-11, 1.095290923503698e-11, 0.8856931432794869, 0.11430685665479554]\n", - "I am logC: [-3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836]\n", - "\n", - "\n", - "I am s: [3.0310728425801e-11, 3.0310728425801e-11, 0.8856931432585293, 0.11430685664857741, 8.067904642006173e-12, 8.067904642006173e-12, 8.067904642006173e-12, 8.067904642006173e-12]\n", - "I am d: [2.5477231115396225e-11, 2.5477231115396225e-11, 0.2643006275899523, 0.7356993723550929, 9.999999999930007e-13, 9.999999999930007e-13, 9.999999999930007e-13, 9.999999999930007e-13]\n", - "I am logC: [-3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836]\n", - "\n", - "\n", - "I am s: [2.6924278247887596e-11, 2.6924278247887596e-11, 2.6924278247887596e-11, 2.6924278247887596e-11, 2.6924278247887596e-11, 2.6924278247887596e-11, 0.795074749586772, 0.2049252502516824]\n", - "I am d: [1.0491860571128379e-11, 1.0491860571128379e-11, 1.0491860571128379e-11, 1.0491860571128379e-11, 1.0491860571128379e-11, 1.0491860571128379e-11, 0.9152526160310062, 0.08474738390604264]\n", - "I am logC: [-3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836]\n", - "\n", - "\n", - "I am s: [6.795168201662887e-11, 6.795168201662887e-11, 0.7950747495808301, 0.20492525023562239, 1.1910948686401029e-11, 1.1910948686401029e-11, 1.1910948686401029e-11, 1.1910948686401029e-11]\n", - "I am d: [2.2983924910253923e-11, 2.298392491025392e-11, 0.233303309524559, 0.7666966904254728, 9.999999999930009e-13, 9.999999999930009e-13, 9.999999999930009e-13, 9.999999999930009e-13]\n", - "I am logC: [-3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836, -3.6401503832058357, -3.6401503832058357, -1.6401503832058357, -5.640150383205836]\n", - "\n", - "\n" - ] - } - ], - "source": [ - " \n", - "Gis = zeros(n_its)\n", - "for i=1:n_its\n", - " stepX!(data, marginals, messages)\n", - " stepY!(data, marginals)\n", - " Gis[i] = freeEnergy(data, marginals)/log(2)\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot(1:n_its, Gis, color=:black, linewidth=2, xlabel=\"Iteration\", ylabel=\"Free Energy [bits]\", label=false, title=\"Policy: $pol\")\n", - "\n", - "#savefig(\"figures/policy.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot(Gis[2:end])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/FLSimulations/archive/.ipynb_checkpoints/T-maze_planning_BFE-checkpoint.ipynb b/src/FLSimulations/archive/.ipynb_checkpoints/T-maze_planning_BFE-checkpoint.ipynb deleted file mode 100644 index 95a6a1f..0000000 --- a/src/FLSimulations/archive/.ipynb_checkpoints/T-maze_planning_BFE-checkpoint.ipynb +++ /dev/null @@ -1,171 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with BFE" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "y = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k],id=:x_*k)\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ Transition(x[k], placeholder(:A, dims=(16,8), var_id=:A_*k))\n", - " Categorical(y[k], placeholder(:C, dims=(16,), index=k, var_id=:C_*k))\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(fg)\n", - "algo = messagePassingAlgorithm(x_t_min, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# GBFE for all policies\n", - "BFE = evaluatePoliciesBFE(A, B, C_t, D)\n", - "plotResults(BFE, clim=(8.0,11.0), dpi=300, highlight=minimum)\n", - "#savefig(\"BFE_c_$(c)_a_$(α).png\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part1/goal_observation.jl b/src/Part1/goal_observation.jl deleted file mode 100644 index 4e78f63..0000000 --- a/src/Part1/goal_observation.jl +++ /dev/null @@ -1,270 +0,0 @@ -using ForwardDiff: jacobian -using TupleTools: deleteat -using ReactiveMP: AbstractNodeFunctionalDependenciesPipeline, RequireMarginalFunctionalDependencies, messagein, setmessage!, get_samples, get_weights -import ReactiveMP: message_dependencies, marginal_dependencies - -include("distributions.jl") - - -struct GoalObservation end - -@node GoalObservation Stochastic [c, z, A] - - -#---------- -# Modifiers -#---------- - -# Metas -struct BetheMeta{P} # Meta parameterized by x type for rule overloading - x::P # Pointmass value for observation -end -BetheMeta() = BetheMeta(missing) # Absent observation - -struct GeneralizedMeta{P} - x::P # Pointmass value for observation - newton_iterations::Int64 -end -GeneralizedMeta() = GeneralizedMeta(missing, 20) -GeneralizedMeta(point) = GeneralizedMeta(point, 20) - -# Pipelines -struct BethePipeline <: AbstractNodeFunctionalDependenciesPipeline end -struct GeneralizedPipeline <: AbstractNodeFunctionalDependenciesPipeline - init_message::Categorical -end - -function message_dependencies(::BethePipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - return () -end - -# Bethe update rules for goal-observation node require marginals on all edges -function marginal_dependencies(::BethePipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - return nodelocalmarginals -end - -# Generalized update rule for state requires inbound message -function message_dependencies(pipeline::GeneralizedPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - if iindex === 2 # Message towards state - input = ReactiveMP.messagein(nodeinterfaces[iindex]) - ReactiveMP.setmessage!(input, pipeline.init_message) # Predefine breaker message - return (nodeinterfaces[iindex],) # Include inbound message on state - else - return () - end -end - - -# Generalized update rule for state requires inbound marginal -function marginal_dependencies(::GeneralizedPipeline, nodeinterfaces, nodelocalmarginals, varcluster, cindex, iindex) - if (iindex === 2) || (iindex === 3) # Message towards state or parameter - return nodelocalmarginals # Include all marginals - else - return deleteat(nodelocalmarginals, cindex) # Include default marginals - end -end - - -#------------------------------ -# Unobserved Bethe Update Rules -#------------------------------ - -@rule GoalObservation(:c, Marginalisation) (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::BetheMeta{Missing}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - log_A = mean(log, q_A) - - # Compute internal marginal - x = softmax(log_A*z + log_c) - - return Dirichlet(x .+ 1) -end - -@rule GoalObservation(:z, Marginalisation) (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::BetheMeta{Missing}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - log_A = mean(log, q_A) - - # Compute internal marginal - x = softmax(log_A*z + log_c) - - return Categorical(softmax(log_A'*x)) -end - -@rule GoalObservation(:A, Marginalisation) (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::BetheMeta{Missing}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - log_A = mean(log, q_A) - - # Compute internal marginal - x = softmax(log_A*z + log_c) - - return MatrixDirichlet(x*z' .+ 1) -end - -@average_energy GoalObservation (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::BetheMeta{Missing}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - log_A = mean(log, q_A) - - # Compute internal marginal - x = softmax(log_A*z + log_c) - - return -x'*(log_A*z + log_c - safelog.(x)) -end - - -#---------------------------- -# Observed Bethe Update Rules -#---------------------------- - -@rule GoalObservation(:c, Marginalisation) (q_c::Union{Dirichlet, PointMass}, # Unused - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::BetheMeta{<:AbstractVector}) = begin - return Dirichlet(meta.x .+ 1) -end - -@rule GoalObservation(:z, Marginalisation) (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, # Unused - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::BetheMeta{<:AbstractVector}) = begin - log_A = mean(log, q_A) - - return Categorical(softmax(log_A'*meta.x)) -end - -@rule GoalObservation(:A, Marginalisation) (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, # Unused - meta::BetheMeta{<:AbstractVector}) = begin - z = probvec(q_z) - - return MatrixDirichlet(meta.x*z' .+ 1) -end - -@average_energy GoalObservation (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::BetheMeta{<:AbstractVector}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - log_A = mean(log, q_A) - - return -meta.x'*(log_A*z + log_c) -end - - -#------------------------------------ -# Unobserved Generalized Update Rules -#------------------------------------ - -@rule GoalObservation(:c, Marginalisation) (q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::GeneralizedMeta{Missing}) = begin - z = probvec(q_z) - A = mean(q_A) - - return Dirichlet(A*z .+ 1) -end - -@rule GoalObservation(:z, Marginalisation) (m_z::Categorical, - q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::GeneralizedMeta{Missing}) = begin - d = probvec(m_z) - log_c = mean(log, q_c) - z_0 = probvec(q_z) - (A, h_A) = mean_h(q_A) - - # Root-finding problem for marginal statistics - g(z) = z - softmax(-h_A + A'*log_c - A'*safelog.(A*z) + safelog.(d)) - - z_k = deepcopy(z_0) - for k=1:meta.newton_iterations - z_k = z_k - inv(jacobian(g, z_k))*g(z_k) # Newton step for multivariate root finding - end - - # Compute outbound message statistics - rho = softmax(safelog.(z_k) - log.(d .+ 1e-6)) - - return Categorical(rho) -end - -@rule GoalObservation(:A, Marginalisation) (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::GeneralizedMeta{Missing}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - A_bar = mean(q_A) - - log_mu(A) = (A*z)'*(log_c - safelog.(A_bar*z)) - z'*h(A) - - return ContinuousMatrixvariateLogPdf(log_mu) -end - -@average_energy GoalObservation (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::GeneralizedMeta{Missing}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - (A, h_A) = mean_h(q_A) - - return z'*h_A - (A*z)'*(log_c - safelog.(A*z)) -end - - -#---------------------------------- -# Observed Generalized Update Rules -#---------------------------------- - -@rule GoalObservation(:c, Marginalisation) (q_z::Categorical, # Unused - q_A::Union{SampleList, MatrixDirichlet, PointMass}, # Unused - meta::GeneralizedMeta{<:AbstractVector}) = begin - return Dirichlet(meta.x .+ 1) -end - -@rule GoalObservation(:z, Marginalisation) (m_z::Categorical, # Unused - q_c::Union{Dirichlet, PointMass}, # Unused - q_z::Categorical, # Unused - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::GeneralizedMeta{<:AbstractVector}) = begin - log_A = mean(log, q_A) - - return Categorical(softmax(log_A'*meta.x)) -end - -@rule GoalObservation(:A, Marginalisation) (q_c::Union{Dirichlet, PointMass}, # Unused - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, # Unused - meta::GeneralizedMeta{<:AbstractVector}) = begin - z = probvec(q_z) - - return MatrixDirichlet(meta.x*z' .+ 1) -end - -@average_energy GoalObservation (q_c::Union{Dirichlet, PointMass}, - q_z::Categorical, - q_A::Union{SampleList, MatrixDirichlet, PointMass}, - meta::GeneralizedMeta{<:AbstractVector}) = begin - log_c = mean(log, q_c) - z = probvec(q_z) - log_A = mean(log, q_A) - - return -meta.x'*(log_A*z + log_c) -end diff --git a/src/Part1/t_maze.jl b/src/Part1/t_maze.jl deleted file mode 100644 index fec5097..0000000 --- a/src/Part1/t_maze.jl +++ /dev/null @@ -1,99 +0,0 @@ -using Pkg;Pkg.activate("/home/mkoudahl/biaslab/repos/EpistemicMessagePassing");Pkg.instantiate(); -using RxInfer,ReactiveMP,GraphPPL,Rocket, LinearAlgebra, OhMyREPL, Distributions, Random -Random.seed!(666) -enable_autocomplete_brackets(false),colorscheme!("GruvboxDark"); - -include("transition_mixture/transition_mixture.jl") -include("transition_mixture/marginals.jl") -include("transition_mixture/in.jl") -include("transition_mixture/out.jl") -include("transition_mixture/switch.jl") -include("goal_observation.jl") -include("helpers.jl") - - -# Need to make pointmass constraints for discrete vars -import RxInfer.default_point_mass_form_constraint_optimizer -import RxInfer.PointMassFormConstraint - -function default_point_mass_form_constraint_optimizer( - ::Type{Univariate}, - ::Type{Discrete}, - constraint::PointMassFormConstraint, - distribution -) - - out = zeros( length(probvec(distribution))) - out[argmax(probvec(distribution))] = 1. - - PointMass(out) -end - - -@model function t_maze(A,D,B1,B2,B3,B4,T) - - z_0 ~ Categorical(D) - - z = randomvar(T) - switch = randomvar(T) - - c = datavar(Vector{Float64}, T) - z_prev = z_0 - - for t in 1:T - switch[t] ~ Categorical(fill(1. /4. ,4)) - z[t] ~ TransitionMixture(z_prev,switch[t], B1,B2,B3,B4) - c[t] ~ GoalObservation(z[t], A) where {pipeline = GeneralizedPipeline(vague(Categorical, 8)) } - z_prev = z[t] - end -end; - - - -@constraints function pointmass_q() - q(switch) :: PointMass -end - -# Node constraints -@meta function t_maze_meta() - GoalObservation(c,z) -> GeneralizedMeta() -end - -T =2; -its = 10; -initmarginals = ( -# z_0 = Categorical(fill(1. /8. ,8)), - z = [Categorical(fill(1. /8. ,8)) for t in 1:T], - ); - -A,B,C,D = constructABCD(0.9,[2.0 for t in 1:T],T); - -result = inference(model = t_maze(A,D,B[1],B[2],B[3],B[4],T), - data= (c = C,), - initmarginals = initmarginals, - meta= t_maze_meta(), - free_energy = true, - iterations=its, - options=(limit_stack_depth=300,) - ) - - -# BEHOLD!!!! -probvec.(result.posteriors[:switch][end][1]) -probvec.(result.posteriors[:switch][end][2]) - -using Plots, UnicodePlots -unicodeplots() -plot(result.free_energy) - -# Try without pointmass constraints, still works -result = inference(model = t_maze(A,D,B[1],B[2],B[3],B[4],T), - data= (c = C,), - initmarginals = initmarginals, - meta= t_maze_meta(), - constraints=pointmass_q(), - iterations=its, - ) - -probvec(result.posteriors[:switch][end][1]) -probvec(result.posteriors[:switch][end][2]) diff --git a/src/Part2/FL/Project.toml b/src/Part2/FL/Project.toml deleted file mode 100644 index 5691ee2..0000000 --- a/src/Part2/FL/Project.toml +++ /dev/null @@ -1,8 +0,0 @@ -[deps] -ForneyLab = "9fc3f58a-c2cc-5bff-9419-6a294fefdca9" -ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" -LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" diff --git a/src/Part2/FL/T-maze_BFE.ipynb b/src/Part2/FL/T-maze_BFE.ipynb deleted file mode 100644 index 848a97a..0000000 --- a/src/Part2/FL/T-maze_BFE.ipynb +++ /dev/null @@ -1,897 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Bethe}(x[k], A, # Choose Generalized or Bethe constraint\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], A, ids=[:Y, :X, :A])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of trials\n", - "seed = 1234 # Randomizer seed\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "rs = generateGoalSequence(seed, S) # Sets random seed and returns reproducible goal sequence\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gs = [Vector{Matrix}(undef, 3) for s=1:S] # Free energy values per time\n", - "as = [Vector{Int64}(undef, 2) for s=1:S] # Actions per time\n", - "os = [Vector{Vector}(undef, 2) for s=1:S] # Observations (one-hot) per time\n", - "for s = 1:S\n", - " reset(s) # Reset world\n", - " for t=1:2\n", - " (Gs[s][t], _) = infer(t, as[s], os[s])\n", - " as[s][t] = act(t, Gs[s][t])\n", - " execute(as[s][t])\n", - " os[s][t] = observe()\n", - " end\n", - " (Gs[s][3], As[s]) = infer(3, as[s], os[s]) # Learn at t=3\n", - "end\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Int64}:\n", - " 0\n", - " 0" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([as[s].==rs[s]'*[2, 3] for s=1:S]) # Correct visits per timepoint" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotObservationStatistics(As[S], A_0)\n", - "# savefig(\"figures/BFE_A\")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotFreeEnergyMinimum(Gs, os, legend=13, ylim=(5,22))\n", - "# savefig(\"figures/BFE_FE.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# include(\"visualizations.jl\")\n", - "# for s=1:S\n", - "# plotFreeEnergies(Gs[s], as[s], os[s], rs[s], title=\"s=$s\")\n", - "# savefig(\"figures/BFE_$s.png\")\n", - "# end" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/T-maze_GFE.ipynb b/src/Part2/FL/T-maze_GFE.ipynb deleted file mode 100644 index 6b86475..0000000 --- a/src/Part2/FL/T-maze_GFE.ipynb +++ /dev/null @@ -1,917 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 223, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 224, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 225, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], A, # Choose Generalized or Bethe constraint\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 226, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], A, ids=[:Y, :X, :A])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 227, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 228, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of trials\n", - "seed = 1234 # Randomizer seed\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "rs = generateGoalSequence(seed, S) # Sets random seed and returns reproducible goal sequence\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gs = [Vector{Matrix}(undef, 3) for s=1:S] # Free energy values per time\n", - "as = [Vector{Int64}(undef, 2) for s=1:S] # Actions per time\n", - "os = [Vector{Vector}(undef, 2) for s=1:S] # Observations (one-hot) per time\n", - "for s = 1:S\n", - " reset(s) # Reset world\n", - " for t=1:2\n", - " (Gs[s][t], _) = infer(t, as[s], os[s])\n", - " as[s][t] = act(t, Gs[s][t])\n", - " execute(as[s][t])\n", - " os[s][t] = observe()\n", - " end\n", - " (Gs[s][3], As[s]) = infer(3, as[s], os[s]) # Learn at t=3\n", - "end\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 229, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Int64}:\n", - " 0\n", - " 100" - ] - }, - "execution_count": 229, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([as[s].==rs[s]'*[2, 3] for s=1:S]) # Correct visits per timepoint" - ] - }, - { - "cell_type": "code", - "execution_count": 230, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 230, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotObservationStatistics(As[S], A_0)\n", - "# savefig(\"figures/GFE_A\")" - ] - }, - { - "cell_type": "code", - "execution_count": 231, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 231, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotFreeEnergyMinimum(Gs, os, legend=45, ylim=(5,22))\n", - "# savefig(\"figures/GFE_FE.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 232, - "metadata": {}, - "outputs": [], - "source": [ - "# include(\"visualizations.jl\")\n", - "# for s=1:S\n", - "# plotFreeEnergies(Gs[s], as[s], os[s], rs[s], title=\"s=$s\")\n", - "# savefig(\"figures/GFE_$s.png\")\n", - "# end" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/T-maze_GFE_planning.ipynb b/src/Part2/FL/T-maze_GFE_planning.ipynb deleted file mode 100644 index 8e365ef..0000000 --- a/src/Part2/FL/T-maze_GFE_planning.ipynb +++ /dev/null @@ -1,240 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k),\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], ids=[:Y, :X])\n", - "# q = PosteriorFactorization(y, x_0, x; ids=[:Y, :X0, :X])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "n_its = 10\n", - "Gs = Matrix{Float64}(undef, 4, 4)\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "pols = [(1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)]\n", - "\n", - "for (i,j) in pols\n", - " data = Dict(:u => [B[i], B[j]],\n", - " :A => A,\n", - " :C => C,\n", - " :D_s => D_0)\n", - "\n", - " marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_0 => ProbabilityDistribution(Univariate, Categorical, p=D_0),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - " # Define unobserved marginals\n", - " marginals[:y_1] = Distribution(Univariate, Categorical, p=asym(16))\n", - " marginals[:y_2] = Distribution(Univariate, Categorical, p=asym(16))\n", - "\n", - " messages = initX()\n", - " \n", - " for i=1:n_its\n", - " # stepX0!(data, marginals)\n", - " stepX!(data, marginals, messages)\n", - " stepY!(data, marginals)\n", - " end\n", - " Gs[i,j] = freeEnergy(data, marginals)/log(2)\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "# plot(1:n_its, Gis, color=:black, linewidth=2, xlabel=\"Iteration\", ylabel=\"Free Energy [bits]\", label=false, title=\"Policy: $pol\")\n", - "\n", - "# savefig(\"figures/policy.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×4 Matrix{Float64}:\n", - " 10.5033 8.97439 8.97439 9.50325\n", - " 8.97439 0.0 0.0 3.60827e-9\n", - " 8.97439 3.60827e-9 3.60827e-9 0.0\n", - " 9.50325 8.3088 8.3088 8.50325" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Gs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/T-maze_GFE_policy.ipynb b/src/Part2/FL/T-maze_GFE_policy.ipynb deleted file mode 100644 index 94e6bfd..0000000 --- a/src/Part2/FL/T-maze_GFE_policy.ipynb +++ /dev/null @@ -1,337 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 170, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 171, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 172, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], A,\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 173, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], A, ids=[:Y, :X, :A])\n", - "# q = PosteriorFactorization(y, x_0, x; ids=[:Y, :X0, :X])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 174, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 175, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING: redefinition of constant default_n_samples. This may fail, cause incorrect answers, or produce other errors.\n" - ] - } - ], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "n_its = 50\n", - "G = Vector{Float64}(undef, n_its)\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "A_0 = 10.0*A .+ 0.01\n", - "\n", - "pol = (4,2)\n", - "\n", - "data = Dict(:u => [B[pol[1]], B[pol[2]]],\n", - " :A_s => A_0,\n", - " :C => C,\n", - " :D_s => D_0)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_0 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_0)))\n", - "\n", - "# Define unobserved marginals\n", - "marginals[:y_1] = Distribution(Univariate, Categorical, p=asym(16))\n", - "marginals[:y_2] = Distribution(Univariate, Categorical, p=asym(16))\n", - "\n", - "messages = initX()\n", - " \n", - "for i=1:n_its\n", - " # stepX0!(data, marginals)\n", - " stepX!(data, marginals, messages)\n", - " stepA!(data, marginals)\n", - " stepY!(data, marginals)\n", - " G[i] = freeEnergy(data, marginals)/log(2)\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 176, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 176, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot(1:n_its, G, color=:black, linewidth=2, xlabel=\"Iteration\", ylabel=\"Free Energy [bits]\", label=false, title=\"Policy: $pol\", ylim=(6,8))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/agent.jl b/src/Part2/FL/agent.jl deleted file mode 100644 index e2c2af0..0000000 --- a/src/Part2/FL/agent.jl +++ /dev/null @@ -1,106 +0,0 @@ -function constructPriors() - eps = 0.1 - - # Position 1 surely does not offer disambiguation - A_0_1 = [10.0 10.0; - 10.0 10.0; - eps eps; - eps eps] - - # But the other positions might - A_0_X = [1.0 eps; - eps 1.0; - eps eps; - eps eps] - - A_0 = eps*ones(16, 8) # Vague prior on everything else - - A_0[1:4, 1:2] = A_0_1 - A_0[5:8, 3:4] = A_0_X - A_0[9:12, 5:6] = A_0_X - A_0[13:16, 7:8] = A_0_X - - # Agent knows it starts at position 1 - D_0 = zeros(8) - D_0[1:2] = [0.5, 0.5] - - return (A_0, D_0) -end - -function initializeAgent(A_0, B, C, D_0) - n_its = 50 # Iterations of variational algorithm - A_s = deepcopy(A_0) - D_s = deepcopy(D_0) - function infer(t::Int64, a::Vector, o::Vector) - # Define possible policies - G = Matrix{Union{Float64, Missing}}(undef, 4, 4) - if t == 1 - pols = [(1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)] - elseif t == 2 - a1 = a[1] # Register first move - if a1 in [2, 3] - pols = [(a1,1)] # Mandatory move to 1 - else - pols = [(a1,1), (a1,2), (a1,3), (a1,4)] - end - elseif t == 3 - a1 = a[1] # Register both moves - a2 = a[2] - pols = [(a1, a2)] - end - - for (i, j) in pols - data = Dict(:u => [B[i], B[j]], - :A_s => A_s, - :C => C, - :D_s => D_s) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_0 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_s))) - - # Define (un)observed marginals - for k=1:2 - if isassigned(o, k) - # Observed - marginals[:y_*k] = Distribution(Multivariate, PointMass, m=o[k]) - else - # Unobserved - marginals[:y_*k] = Distribution(Univariate, Categorical, p=asym(16)) - end - end - - messages = initX() - - Gis = zeros(n_its) - for i=1:n_its - stepX!(data, marginals, messages) - stepA!(data, marginals) - stepY!(data, marginals) - Gis[i] = freeEnergy(data, marginals) - end - - G[i, j] = mean(Gis[10:n_its])./log(2) # Average to smooth fluctuations and convert to bits - if t == 3 # Update posterior statistics after learning - A_s = deepcopy(marginals[:A].params[:a]) - end - end - - return (G, A_s) - end - - function act(t, G) - # We include policy selection in the act function for clearer code; procedurally, policy selection belongs in the plan step - idx = findall((!).(ismissing.(G))) # Find coordinates of non-missing entries - Gvec = G[idx] # Convert to vector of valid entries - p = softmax(-100.0*Gvec) - s = sample(ProbabilityDistribution(Categorical, p=p)) # Sample a one-hot representation - c = first(idx[s.==1.0]) # Select coordinate (policy) by sample - - return c[t] # Return current action - end - - return (infer, act) -end \ No newline at end of file diff --git a/src/Part2/FL/archive/T-maze_BFE.ipynb b/src/Part2/FL/archive/T-maze_BFE.ipynb deleted file mode 100644 index f22a5bc..0000000 --- a/src/Part2/FL/archive/T-maze_BFE.ipynb +++ /dev/null @@ -1,277 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Bethe}(x[k], A, # Choose Generalized or Bethe constraint\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], A, ids=[:Y, :X, :A])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of simulations\n", - "seed = 1234 # Randomizer seed\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "rs = generateGoalSequence(seed, S) # Sets random seed and returns reproducible goal sequence\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gs = [Vector{Matrix}(undef, 3) for s=1:S] # Free energy values per time\n", - "as = [Vector{Int64}(undef, 2) for s=1:S] # Actions per time\n", - "os = [Vector{Vector}(undef, 2) for s=1:S] # Observations (1-of-K) per time\n", - "for s = 1:S\n", - " reset(s) # Reset world\n", - " for t=0:1 # Time starts at 0\n", - " (Gs[s][t+1], _) = infer(t, as[s], os[s])\n", - " as[s][t+1] = act(t, Gs[s][t+1])\n", - " execute(as[s][t+1])\n", - " os[s][t+1] = observe()\n", - " end\n", - " (Gs[s][3], As[s]) = infer(2, as[s], os[s]) # Learn\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Int64}:\n", - " 0\n", - " 0" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([as[s].==rs[s]'*[2, 3] for s=1:S]) # Correct visits per timepoint" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n" - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotObservationStatistics(As[S], A_0)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotFreeEnergyMinimum(Gs, os, legend=12, title=\"BFE\")\n", - "# savefig(\"figures/BFE.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s = 21\n", - "include(\"visualizations.jl\")\n", - "plotFreeEnergies(Gs[s], as[s], os[s], rs[s], title=\"s=$s\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_full_GBFE.ipynb b/src/Part2/FL/archive/T-maze_full_GBFE.ipynb deleted file mode 100644 index 444d66a..0000000 --- a/src/Part2/FL/archive/T-maze_full_GBFE.ipynb +++ /dev/null @@ -1,231 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with GBFE" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "\n", - "A_0 = 10.0*(A .+ 0.01)\n", - "C_0 = 100.0*(C .+ 0.01)\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A_t ~ Dirichlet(A_0)\n", - "@RV c_t ~ Dirichlet(C_0)\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k],id=:x_*k)\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " DiscreteObservation(x[k], A_t, c_t, n_factors=8)\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization([x_t_min; x], A_t, c_t, ids=[:X, :A, :C])\n", - "algo = messagePassingAlgorithm(x_t_min, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 68, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Single policy\n", - "pi = [4, 2]\n", - "\n", - "n_its = 20\n", - "G = zeros(n_its)\n", - "\n", - "data = Dict(:u => [B[pi[1]], B[pi[2]]],\n", - " :A => A,\n", - " :C => [C, C],\n", - " :D_t_min => D)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :A_t => ProbabilityDistribution(MatrixVariate, Dirichlet, a=A_0),\n", - " :c_t => ProbabilityDistribution(Multivariate, Dirichlet, a=C_0))\n", - "\n", - "messages = initX()\n", - "\n", - "for k=1:n_its\n", - " stepX!(data, marginals, messages)\n", - " stepC!(data, marginals, messages)\n", - " stepA!(data, marginals, messages)\n", - " G[k] = freeEnergy(data, marginals)\n", - "end\n", - " \n", - "G = G./log(2) # Convert to bits\n", - "\n", - "range = 5:n_its\n", - "G_bar = mean(G[range]) # Average over final iterations\n", - "\n", - "plot(1:n_its, G, color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Iteration\", ylabel=\"GFE [bits]\")\n", - "plot!(range, G_bar*ones(length(range)), color=:red, linewidth=2)" - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n" - }, - "execution_count": 69, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# GBFE for all policies\n", - "GBFE = evaluatePoliciesFullGBFE(A, B, C, D, n_its=n_its)\n", - "plotResults(GBFE, clim=(8.0,11.0), dpi=300, highlight=minimum)\n", - "#savefig(\"GBFE_c_$(c)_a_$(α).png\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_interactive.ipynb b/src/Part2/FL/archive/T-maze_interactive.ipynb deleted file mode 100644 index c240cc7..0000000 --- a/src/Part2/FL/archive/T-maze_interactive.ipynb +++ /dev/null @@ -1,282 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete GFE-constrained SSM.\n", - "\n", - "TODO: parameter estimation" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Regulator Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg_plan = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "y = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " DiscreteObservation(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k), \n", - " placeholder(:C, dims=(16,), index=k, var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "q_plan = PosteriorFactorization(fg_plan)\n", - "algo_plan = messagePassingAlgorithm(x_t_min, id=:Plan, free_energy=true)\n", - "code_plan = algorithmSourceCode(algo_plan, free_energy=true)\n", - "eval(Meta.parse(code_plan))\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Estimator Model" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "fg_slide = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "y = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV x_t ~ Transition(x_t_min, placeholder(:B_t, dims=(8,8)))\n", - "@RV y_t ~ Transition(x_t, placeholder(:A, dims=(16,8)))\n", - "placeholder(y_t, :o_t, dims=(16,))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "q_slide = PosteriorFactorization(fg_slide)\n", - "algo_slide = messagePassingAlgorithm(x_t, id=:Slide)\n", - "code_slide = algorithmSourceCode(algo_slide)\n", - "eval(Meta.parse(code_slide))\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "N = 2 # Number of moves per simulation\n", - "S = 10 # Number of simulations\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - " \n", - "# for s = 1:S\n", - " (execute, observe) = initializeWorld(A, B, C, D) # Let there be a world\n", - " (plan, act, slide) = initializeAgent(A, B, C, D) # Let there be a constrained agent\n", - "\n", - " # Step through the experimental protocol\n", - " G_ts = Vector{Matrix}(undef, N)\n", - " a = Vector{Int64}(undef, N)\n", - " for t = 1:N\n", - " G_ts[t] = plan()\n", - " a[t] = act(G_ts[t])\n", - " execute(a[t])\n", - " (o_t, r_t) = observe()\n", - " slide(a[t], o_t)\n", - " end\n", - "# end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotResults(G_ts[1], clim=(11,19), highlight=minimum)" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotResults(G_ts[2], clim=(11,19), highlight=minimum)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[4, 1]\n" - ] - } - ], - "source": [ - "println(a) # Back to one?" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_interactive_2.ipynb b/src/Part2/FL/archive/T-maze_interactive_2.ipynb deleted file mode 100644 index d0b401c..0000000 --- a/src/Part2/FL/archive/T-maze_interactive_2.ipynb +++ /dev/null @@ -1,539 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete GFE-constrained SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 563, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 564, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using Random\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - "\n", - "Random.seed!(1234)\n", - "# Random.seed!(42)\n", - "# Random.seed!(123) # Does not learn all key entries\n", - "# Random.seed!(678) # Does not learn all key entries\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=1$" - ] - }, - { - "cell_type": "code", - "execution_count": 565, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t1 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "DiscreteObservation(x[1], \n", - " A,\n", - " placeholder(:C, dims=(16,), var_id=:C_1),\n", - " n_factors=8)\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "DiscreteObservation(x[2], \n", - " A,\n", - " placeholder(:C, dims=(16,), var_id=:C_2),\n", - " n_factors=8)\n", - "# Algorithm\n", - "q_t1 = PosteriorFactorization([x_0; x], A, ids=[:X, :A])\n", - "algo_t1 = messagePassingAlgorithm(q_t1, id=:t1, free_energy=true)\n", - "code_t1 = algorithmSourceCode(algo_t1, free_energy=true)\n", - "eval(Meta.parse(code_t1))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 566, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "averageEnergyDecomp (generic function with 1 method)" - ] - }, - "execution_count": 566, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "function averageEnergyDecomp(::Type{DiscreteObservation},\n", - " marg_out::Distribution{Univariate},\n", - " marg_A::Distribution{MatrixVariate},\n", - " marg_c::Distribution{Multivariate})\n", - "\n", - " s = unsafeMean(marg_out)\n", - " A = unsafeMean(marg_A)\n", - " log_c = unsafeLogMean(marg_c)\n", - "\n", - " risk = (A*s)'*(safelog.(A*s) - log_c)\n", - " amb = -s'*diag(A'*safelog.(A)) \n", - "\n", - " return (risk, amb)\n", - "end\n" - ] - }, - { - "cell_type": "code", - "execution_count": 567, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "freeEnergyDecompt1 (generic function with 1 method)" - ] - }, - "execution_count": 567, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "function freeEnergyDecompt1(data::Dict, marginals::Dict)\n", - " F = 0.0\n", - " risk = 0.0\n", - " amb = 0.0\n", - " nov = 0.0\n", - " \n", - " F += averageEnergy(Categorical, marginals[:x_0], Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - " nov += averageEnergy(Dirichlet, marginals[:A], Distribution(MatrixVariate, PointMass, m=data[:A_s]))\n", - " (risk_1, amb_1) = averageEnergyDecomp(DiscreteObservation, marginals[:x_1], marginals[:A], Distribution(Multivariate, PointMass, m=data[:C]))\n", - " (risk_2, amb_2) = averageEnergyDecomp(DiscreteObservation, marginals[:x_2], marginals[:A], Distribution(Multivariate, PointMass, m=data[:C]))\n", - " risk += risk_1 + risk_2\n", - " amb += amb_1 + amb_2\n", - " F += averageEnergy(Transition, marginals[:x_1_x_0], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - " F += averageEnergy(Transition, marginals[:x_2_x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - " \n", - " nov -= differentialEntropy(marginals[:A])\n", - " F -= -1*differentialEntropy(marginals[:x_1])\n", - " F -= differentialEntropy(marginals[:x_1_x_0])\n", - " F -= differentialEntropy(marginals[:x_2_x_1])\n", - "\n", - " return (risk/log(2), amb/log(2), nov/log(2))\n", - "end" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=2$" - ] - }, - { - "cell_type": "code", - "execution_count": 568, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t2 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "@RV y[1] ~ Transition(x[1], A)\n", - "placeholder(y[1], :y, index=1, dims=(16,))\n", - "\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "DiscreteObservation(x[2], \n", - " A,\n", - " placeholder(:C, dims=(16,), var_id=:C_2),\n", - " n_factors=8)\n", - "# Algorithm\n", - "q_t2 = PosteriorFactorization([x_0; x], A, ids=[:X, :A])\n", - "algo_t2 = messagePassingAlgorithm(q_t2, id=:t2, free_energy=true)\n", - "code_t2 = algorithmSourceCode(algo_t2, free_energy=true)\n", - "eval(Meta.parse(code_t2))\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=3$ (Learning)" - ] - }, - { - "cell_type": "code", - "execution_count": 569, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t3 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "@RV y[1] ~ Transition(x[1], A)\n", - "placeholder(y[1], :y, index=1, dims=(16,))\n", - "\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "@RV y[2] ~ Transition(x[2], A)\n", - "placeholder(y[2], :y, index=2, dims=(16,))\n", - "\n", - "# Algorithm\n", - "q_t3 = PosteriorFactorization([x_0; x], A, ids=[:X, :A])\n", - "algo_t3 = messagePassingAlgorithm(q_t3, id=:t3, free_energy=true)\n", - "code_t3 = algorithmSourceCode(algo_t3, free_energy=true)\n", - "eval(Meta.parse(code_t3))\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 570, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 50 # Number of simulations\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent_2.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "A_0 = constructAPrior() # Construct prior statistics for A\n", - "\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gts = [[Matrix(undef, 4, 4), Vector(undef, 4), undef] for s=1:S] # Free energy values\n", - "riskts = [[Matrix(undef, 4, 4), Vector(undef, 4), undef] for s=1:S] # Free energy values\n", - "ambts = [[Matrix(undef, 4, 4), Vector(undef, 4), undef] for s=1:S] # Free energy values\n", - "novts = [[Matrix(undef, 4, 4), Vector(undef, 4), undef] for s=1:S] # Free energy values\n", - "ats = [Vector{Int64}(undef, 2) for s=1:S] # Actions\n", - "polts = [[Vector{Int64}(undef, 2), undef] for s=1:S] # Policies\n", - "gamts = [[Vector{Float64}(undef, 16), Vector{Float64}(undef, 16)] for s=1:S] # Policies\n", - "ots = [Vector{Vector}(undef, 2) for s=1:S] # Observations (1-of-K)\n", - "rs = Vector{Int64}(undef, S) # Hidden reward positions\n", - "for s = 1:S\n", - " rs[s] = reset() # Reset world\n", - " for t = 1:2\n", - " if t == 1\n", - " (Gts[s][t], riskts[s][t], ambts[s][t], novts[s][t]) = infer(t, ats[s], ots[s])\n", - " elseif t == 2\n", - " Gts[s][t] = infer(t, ats[s], ots[s])\n", - " end\n", - " (ats[s][t], polts[s][t]) = act(Gts[s][t])\n", - " execute(ats[s][t])\n", - " ots[s][t] = observe()\n", - " end\n", - " (Gts[s][3], As[s]) = infer(3, ats[s], ots[s]) # Learn\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 571, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Int64}:\n", - " 0\n", - " 96" - ] - }, - "execution_count": 571, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([ats[s].==rs[s] for s=1:S]) # Correct vists per timepoint" - ] - }, - { - "cell_type": "code", - "execution_count": 572, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×8 SparseMatrixCSC{Float64, Int64} with 12 stored entries:\n", - " 0.5 0.5 ⋅ ⋅ ⋅ ⋅ 43.0 4.0\n", - " 0.5 0.5 ⋅ ⋅ ⋅ ⋅ ⋅ 53.0\n", - " ⋅ ⋅ 41.0 ⋅ 1.0 46.0 ⋅ ⋅ \n", - " ⋅ ⋅ ⋅ 5.0 ⋅ 5.0 ⋅ ⋅ " - ] - }, - "execution_count": 572, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotObservationStatistics(As[S], A_0)" - ] - }, - { - "cell_type": "code", - "execution_count": 573, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×8 SparseMatrixCSC{Float64, Int64} with 3 stored entries:\n", - " ⋅ 0.5 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ \n", - " ⋅ 0.5 ⋅ ⋅ ⋅ ⋅ ⋅ 1.0\n", - " ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ \n", - " ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ " - ] - }, - "execution_count": 573, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "\n", - "s=4\n", - "plotObservationStatistics(As[s], As[s-1])" - ] - }, - { - "cell_type": "code", - "execution_count": 574, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 574, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotFreeEnergyMinimum(Gts)" - ] - }, - { - "cell_type": "code", - "execution_count": 575, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 575, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotDecomposition(polts, riskts, ambts, novts)" - ] - }, - { - "cell_type": "code", - "execution_count": 576, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 576, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s = 7\n", - "plotFreeEnergies(Gts[s], ats[s], ots[s], rs[s])" - ] - }, - { - "cell_type": "code", - "execution_count": 577, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "100×2 Matrix{Any}:\n", - " [4, 1] 2\n", - " [4, 2] 3\n", - " [4, 2] 2\n", - " [4, 1] 3\n", - " [4, 3] 2\n", - " [4, 2] 2\n", - " [4, 2] 2\n", - " [4, 3] 3\n", - " [4, 2] 2\n", - " [4, 2] 2\n", - " [4, 3] 3\n", - " [4, 3] 3\n", - " [4, 2] 2\n", - " ⋮ \n", - " [4, 2] 2\n", - " [4, 2] 2\n", - " [4, 2] 2\n", - " [4, 3] 3\n", - " [4, 3] 3\n", - " [4, 3] 3\n", - " [4, 3] 3\n", - " [4, 3] 3\n", - " [4, 2] 2\n", - " [4, 3] 3\n", - " [4, 3] 3\n", - " [4, 3] 3" - ] - }, - "execution_count": 577, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "hcat(ats, rs)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_interactive_3.ipynb b/src/Part2/FL/archive/T-maze_interactive_3.ipynb deleted file mode 100644 index f11720d..0000000 --- a/src/Part2/FL/archive/T-maze_interactive_3.ipynb +++ /dev/null @@ -1,382 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete BFE-constrained SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "# using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=1$" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t1 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "@RV y[1] ~ Transition(x[1], A)\n", - "Categorical(y[1], \n", - " placeholder(:C, dims=(16,), var_id=:C_1))\n", - "\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "@RV y[2] ~ Transition(x[2], A)\n", - "Categorical(y[2], \n", - " placeholder(:C, dims=(16,), var_id=:C_2))\n", - "\n", - "# Algorithm\n", - "q_t1 = PosteriorFactorization([x_0; x; y], A, ids=[:X, :A])\n", - "algo_t1 = messagePassingAlgorithm(q_t1, id=:t1, free_energy=true)\n", - "code_t1 = algorithmSourceCode(algo_t1, free_energy=true)\n", - "eval(Meta.parse(code_t1))\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=2$" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t2 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "@RV y[1] ~ Transition(x[1], A)\n", - "placeholder(y[1], :y, index=1, dims=(16,))\n", - "\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "@RV y[2] ~ Transition(x[2], A)\n", - "Categorical(y[2], \n", - " placeholder(:C, dims=(16,), var_id=:C_2))\n", - "\n", - "# Algorithm\n", - "q_t2 = PosteriorFactorization([x_0; x; y[2]], A, ids=[:X, :A])\n", - "algo_t2 = messagePassingAlgorithm(q_t2, id=:t2, free_energy=true)\n", - "code_t2 = algorithmSourceCode(algo_t2, free_energy=true)\n", - "eval(Meta.parse(code_t2))\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm for $t=3$ (Learning)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "fg_t3 = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "# Slice k=0\n", - "@RV x_0 ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "# Slice k=1\n", - "@RV u[1]\n", - "@RV x[1] ~ Transition(x_0, u[1])\n", - "placeholder(u[1], :u, index=1, dims=(8,8))\n", - "@RV y[1] ~ Transition(x[1], A)\n", - "placeholder(y[1], :y, index=1, dims=(16,))\n", - "\n", - "# Slice k=2\n", - "@RV u[2]\n", - "@RV x[2] ~ Transition(x[1], u[2])\n", - "placeholder(u[2], :u, index=2, dims=(8,8))\n", - "@RV y[2] ~ Transition(x[2], A)\n", - "placeholder(y[2], :y, index=2, dims=(16,))\n", - "\n", - "# Algorithm\n", - "q_t3 = PosteriorFactorization([x_0; x], A, ids=[:X, :A])\n", - "algo_t3 = messagePassingAlgorithm(q_t3, id=:t3, free_energy=true)\n", - "code_t3 = algorithmSourceCode(algo_t3, free_energy=true)\n", - "eval(Meta.parse(code_t3))\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 50 # Number of simulations\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent_3.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "A_0 = constructAPrior() # Construct prior statistics for A\n", - "\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gts = [[Matrix(undef, 4, 4), Vector(undef, 4), undef] for s=1:S] # Free energy values\n", - "ats = [Vector{Int64}(undef, 2) for s=1:S] # Actions\n", - "ots = [Vector{Vector}(undef, 2) for s=1:S] # Observations (1-of-K)\n", - "rs = Vector{Int64}(undef, S) # Hidden reward positions\n", - "for s = 1:S\n", - " rs[s] = reset() # Reset world\n", - " for t = 1:2\n", - " Gts[s][t] = infer(t, ats[s], ots[s])\n", - " ats[s][t] = act(Gts[s][t])\n", - " execute(ats[s][t])\n", - " ots[s][t] = observe()\n", - " end\n", - " (Gts[s][3], As[s]) = infer(3, ats[s], ots[s]) # Learn\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×8 SparseMatrixCSC{Float64, Int64} with 6 stored entries:\n", - " 0.5 ⋅ ⋅ ⋅ ⋅ ⋅ 45.0 ⋅ \n", - " 0.5 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 52.0\n", - " ⋅ ⋅ ⋅ ⋅ 0.2 ⋅ ⋅ ⋅ \n", - " ⋅ ⋅ ⋅ ⋅ 1.8 ⋅ ⋅ ⋅ " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "\n", - "plotObservationStatistics(As, A_0)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plotFreeEnergyMinimum(Gts)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s = 1\n", - "plotFreeEnergies(Gts[s], ats[s], ots[s], rs[s])" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "50-element Vector{Vector{Int64}}:\n", - " [1, 3]\n", - " [4, 3]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " ⋮\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]\n", - " [4, 4]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ats" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_planning_BFE.ipynb b/src/Part2/FL/archive/T-maze_planning_BFE.ipynb deleted file mode 100644 index 7594d79..0000000 --- a/src/Part2/FL/archive/T-maze_planning_BFE.ipynb +++ /dev/null @@ -1,242 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with BFE" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "y = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k],id=:x_*k)\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ Transition(x[k], placeholder(:A, dims=(16,8), var_id=:A_*k))\n", - " Categorical(y[k], placeholder(:C, dims=(16,), index=k, var_id=:C_*k))\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(fg)\n", - "algo = messagePassingAlgorithm(x_t_min, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function step!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 14))\n", - "\n", - "messages[1] = ruleSPCategoricalOutNP(nothing, Message(Multivariate, PointMass, m=data[:C][1]))\n", - "messages[2] = ruleSPTransitionIn1CNP(messages[1], nothing, Message(MatrixVariate, PointMass, m=data[:A]))\n", - "messages[3] = ruleSPCategoricalOutNP(nothing, Message(Multivariate, PointMass, m=data[:D_t_min]))\n", - "messages[4] = ruleSPTransitionOutNCP(nothing, messages[3], Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "messages[5] = ruleSPEqualityCategorical(messages[4], messages[2], nothing)\n", - "messages[6] = ruleSPTransitionOutNCP(nothing, messages[5], Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[7] = ruleSPTransitionOutNCP(nothing, messages[6], Message(MatrixVariate, PointMass, m=data[:A]))\n", - "messages[8] = ruleSPCategoricalOutNP(nothing, Message(Multivariate, PointMass, m=data[:C][2]))\n", - "messages[9] = ruleSPTransitionIn1CNP(messages[8], nothing, Message(MatrixVariate, PointMass, m=data[:A]))\n", - "messages[10] = ruleSPTransitionIn1CNP(messages[9], nothing, Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[11] = ruleSPEqualityCategorical(messages[4], nothing, messages[10])\n", - "messages[12] = ruleSPTransitionOutNCP(nothing, messages[11], Message(MatrixVariate, PointMass, m=data[:A]))\n", - "messages[13] = ruleSPEqualityCategorical(nothing, messages[2], messages[10])\n", - "messages[14] = ruleSPTransitionIn1CNP(messages[13], nothing, Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "\n", - "marginals[:x_1] = messages[4].dist * messages[13].dist\n", - "marginals[:x_2] = messages[6].dist * messages[9].dist\n", - "marginals[:x_t_min] = messages[3].dist * messages[14].dist\n", - "marginals[:y_1] = messages[12].dist * messages[1].dist\n", - "marginals[:y_2] = messages[7].dist * messages[8].dist\n", - "marginals[:x_1_x_t_min] = ruleMTransitionCCN(messages[13], messages[3], Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "marginals[:x_2_x_1] = ruleMTransitionCCN(messages[9], messages[5], Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "marginals[:y_1_x_1] = ruleMTransitionCCN(messages[1], messages[11], Message(MatrixVariate, PointMass, m=data[:A]))\n", - "marginals[:y_2_x_2] = ruleMTransitionCCN(messages[8], messages[6], Message(MatrixVariate, PointMass, m=data[:A]))\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(Categorical, marginals[:x_t_min], Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - "F += averageEnergy(Categorical, marginals[:y_1], Distribution(Multivariate, PointMass, m=data[:C][1]))\n", - "F += averageEnergy(Categorical, marginals[:y_2], Distribution(Multivariate, PointMass, m=data[:C][2]))\n", - "F += averageEnergy(Transition, marginals[:y_1_x_1], Distribution(MatrixVariate, PointMass, m=data[:A]))\n", - "F += averageEnergy(Transition, marginals[:y_2_x_2], Distribution(MatrixVariate, PointMass, m=data[:A]))\n", - "F += averageEnergy(Transition, marginals[:x_1_x_t_min], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "F += averageEnergy(Transition, marginals[:x_2_x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "F -= -2*differentialEntropy(marginals[:x_1])\n", - "F -= differentialEntropy(marginals[:x_1_x_t_min])\n", - "F -= -1*differentialEntropy(marginals[:x_2])\n", - "F -= differentialEntropy(marginals[:x_2_x_1])\n", - "F -= differentialEntropy(marginals[:y_1_x_1])\n", - "F -= differentialEntropy(marginals[:y_2_x_2])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - "println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# GBFE for all policies\n", - "BFE = evaluatePoliciesBFE(A, B, C_t, D)\n", - "plotResults(BFE, clim=(8.0,11.0), dpi=300, highlight=minimum)\n", - "#savefig(\"BFE_c_$(c)_a_$(α).png\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_planning_EFE.ipynb b/src/Part2/FL/archive/T-maze_planning_EFE.ipynb deleted file mode 100644 index 4574e5f..0000000 --- a/src/Part2/FL/archive/T-maze_planning_EFE.ipynb +++ /dev/null @@ -1,111 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with EFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using Plots\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n" - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# GBFE for all policies\n", - "EFE = evaluatePoliciesEFE(A, B, C_t, D)\n", - "plotResults(EFE, clim=(8.0,11.0), dpi=300, highlight=minimum)\n", - "#savefig(\"EFE_c_$(c)_a_$(α).png\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_planning_EFE_from_GMFE.ipynb b/src/Part2/FL/archive/T-maze_planning_EFE_from_GMFE.ipynb deleted file mode 100644 index f264b8d..0000000 --- a/src/Part2/FL/archive/T-maze_planning_EFE_from_GMFE.ipynb +++ /dev/null @@ -1,287 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with EFE Reduced From GMFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k],id=:x_*k)\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " DiscreteObservation(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k), \n", - " placeholder(:C, dims=(16,), index=k, var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(x_t_min, x[1], x[2], ids=[:X0, :X1, :X2])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code) # Uncomment to inspect auto-generated code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define Reduced Algorithm From Generated Code\n", - "\n", - "Definitions below comment lines from the auto-generated GMFE algorithm to recover the EFE algorithm." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "freeEnergy (generic function with 1 method)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "function stepX0!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - " messages[1] = ruleVBCategoricalOut(nothing, Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - " # messages[2] = ruleVBTransitionIn1(marginals[:x_1], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "\n", - " marginals[:x_t_min] = messages[1].dist # * messages[2].dist\n", - "\n", - " return marginals\n", - "end\n", - "\n", - "function stepX1!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 5))\n", - " messages[1] = ruleVBTransitionOut(nothing, marginals[:x_t_min], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - " # messages[2] = ruleVBTransitionIn1(marginals[:x_2], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - " # messages[3] = ruleSPEqualityCategorical(messages[1], nothing, messages[2])\n", - " # messages[4] = ruleVBDiscreteObservationOut(messages[3], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][1]))\n", - " # messages[5] = ruleSPEqualityCategorical(nothing, messages[4], messages[2])\n", - "\n", - " marginals[:x_1] = messages[1].dist # * messages[5].dist\n", - "\n", - " return marginals\n", - "end\n", - "\n", - "function stepX2!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - " messages[1] = ruleVBTransitionOut(nothing, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - " # messages[2] = ruleVBDiscreteObservationOut(messages[1], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][2]))\n", - "\n", - " marginals[:x_2] = messages[1].dist # * messages[2].dist\n", - "\n", - " return marginals\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - " F = 0.0\n", - "\n", - " # F += averageEnergy(Categorical, marginals[:x_t_min], Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - " F += averageEnergy(DiscreteObservation, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][1]))\n", - " F += averageEnergy(DiscreteObservation, marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][2]))\n", - " # F += averageEnergy(Transition, marginals[:x_1], marginals[:x_t_min], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - " # F += averageEnergy(Transition, marginals[:x_2], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - " # F -= differentialEntropy(marginals[:x_1])\n", - " # F -= differentialEntropy(marginals[:x_2])\n", - " # F -= differentialEntropy(marginals[:x_t_min])\n", - "\n", - " return F\n", - "end" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "8.972123158069055" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Single policy\n", - "pi = [4, 2]\n", - "\n", - "data = Dict(:u => [B[pi[1]], B[pi[2]]],\n", - " :A => A,\n", - " :C => C_t,\n", - " :D_t_min => D)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - "# Single iteration\n", - "stepX0!(data, marginals)\n", - "stepX1!(data, marginals)\n", - "stepX2!(data, marginals)\n", - "G = freeEnergy(data, marginals)\n", - " \n", - "G/log(2) # Convert to bits" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n" - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# GMFE for all policies\n", - "GMFE = evaluatePoliciesGMFE(A, B, C_t, D, n_its=1) # Single iteration of (adjusted) GMFE\n", - "plotResults(GMFE, clim=(8.0,11.0), dpi=300, highlight=minimum)\n", - "#savefig(\"GMFE_c_$(c)_a_$(α).png\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_planning_GBFE.ipynb b/src/Part2/FL/archive/T-maze_planning_GBFE.ipynb deleted file mode 100644 index 765e6d9..0000000 --- a/src/Part2/FL/archive/T-maze_planning_GBFE.ipynb +++ /dev/null @@ -1,284 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with GBFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k],id=:x_*k)\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " DiscreteObservation(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k), \n", - " placeholder(:C, dims=(16,), index=k, var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(fg)\n", - "algo = messagePassingAlgorithm(x_t_min, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function init()\n", - "\n", - "messages = Array{Message}(undef, 10)\n", - "\n", - "messages[5] = Message(vague(Categorical, (8,)))\n", - "messages[8] = Message(vague(Categorical, (8,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function step!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 10))\n", - "\n", - "messages[1] = ruleSPDiscreteObservationOutDPP(messages[8], marginals[:x_1], Message(MatrixVariate, PointMass, m=data[:A]), Message(Multivariate, PointMass, m=data[:C][1]))\n", - "messages[2] = ruleSPCategoricalOutNP(nothing, Message(Multivariate, PointMass, m=data[:D_t_min]))\n", - "messages[3] = ruleSPTransitionOutNCP(nothing, messages[2], Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "messages[4] = ruleSPEqualityCategorical(messages[3], messages[1], nothing)\n", - "messages[5] = ruleSPTransitionOutNCP(nothing, messages[4], Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[6] = ruleSPDiscreteObservationOutDPP(messages[5], marginals[:x_2], Message(MatrixVariate, PointMass, m=data[:A]), Message(Multivariate, PointMass, m=data[:C][2]))\n", - "messages[7] = ruleSPTransitionIn1CNP(messages[6], nothing, Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[8] = ruleSPEqualityCategorical(messages[3], nothing, messages[7])\n", - "messages[9] = ruleSPEqualityCategorical(nothing, messages[1], messages[7])\n", - "messages[10] = ruleSPTransitionIn1CNP(messages[9], nothing, Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "\n", - "marginals[:x_1] = messages[3].dist * messages[9].dist\n", - "marginals[:x_2] = messages[5].dist * messages[6].dist\n", - "marginals[:x_t_min] = messages[2].dist * messages[10].dist\n", - "marginals[:x_1_x_t_min] = ruleMTransitionCCN(messages[9], messages[2], Message(MatrixVariate, PointMass, m=data[:u][1]))\n", - "marginals[:x_2_x_1] = ruleMTransitionCCN(messages[6], messages[4], Message(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(Categorical, marginals[:x_t_min], Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][1]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][2]))\n", - "F += averageEnergy(Transition, marginals[:x_1_x_t_min], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "F += averageEnergy(Transition, marginals[:x_2_x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "F -= -1*differentialEntropy(marginals[:x_1])\n", - "F -= differentialEntropy(marginals[:x_1_x_t_min])\n", - "F -= differentialEntropy(marginals[:x_2_x_1])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - "println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Single policy\n", - "pi = [4, 2]\n", - "\n", - "n_its = 10\n", - "G = zeros(n_its)\n", - "\n", - "data = Dict(:u => [B[pi[1]], B[pi[2]]],\n", - " :A => A,\n", - " :C => C_t,\n", - " :D_t_min => D)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - "messages = init()\n", - "\n", - "for k=1:n_its\n", - " step!(data, marginals, messages)\n", - " G[k] = freeEnergy(data, marginals)\n", - "end\n", - " \n", - "G = G./log(2) # Convert to bits\n", - "\n", - "plot(1:n_its, G, color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Iteration\", ylabel=\"GFE [bits]\")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n" - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# GBFE for all policies\n", - "GBFE = evaluatePoliciesGBFE(A, B, C_t, D, n_its=n_its)\n", - "plotResults(GBFE, clim=(8.0,11.0), dpi=300, highlight=minimum)\n", - "#savefig(\"GBFE_c_$(c)_a_$(α).png\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/T-maze_planning_GMFE.ipynb b/src/Part2/FL/archive/T-maze_planning_GMFE.ipynb deleted file mode 100644 index 00ebe20..0000000 --- a/src/Part2/FL/archive/T-maze_planning_GMFE.ipynb +++ /dev/null @@ -1,303 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Inference for Planning with GMFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/biaslab/repos/EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "T = 2\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, T)\n", - "x = Vector{Variable}(undef, T)\n", - "\n", - "@RV x_t_min ~ Categorical(placeholder(:D_t_min, dims=(8,)))\n", - "\n", - "x_k_min = x_t_min\n", - "for k=1:T\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k],id=:x_*k)\n", - "\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " DiscreteObservation(x[k], \n", - " placeholder(:A, dims=(16,8), var_id=:A_*k), \n", - " placeholder(:C, dims=(16,), index=k, var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k]\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(x_t_min, x[1], x[2], ids=[:X0, :X1, :X2])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function stepX0!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - "\n", - "messages[1] = ruleVBCategoricalOut(nothing, Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - "messages[2] = ruleVBTransitionIn1(marginals[:x_1], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "\n", - "marginals[:x_t_min] = messages[1].dist * messages[2].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function initX2()\n", - "\n", - "messages = Array{Message}(undef, 2)\n", - "\n", - "messages[1] = Message(vague(Categorical, (8,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function stepX2!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - "\n", - "messages[1] = ruleVBTransitionOut(nothing, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[2] = ruleVBDiscreteObservationOut(messages[1], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][2]))\n", - "\n", - "marginals[:x_2] = messages[1].dist * messages[2].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function initX1()\n", - "\n", - "messages = Array{Message}(undef, 5)\n", - "\n", - "messages[3] = Message(vague(Categorical, (8,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function stepX1!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 5))\n", - "\n", - "messages[1] = ruleVBTransitionOut(nothing, marginals[:x_t_min], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "messages[2] = ruleVBTransitionIn1(marginals[:x_2], nothing, Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "messages[3] = ruleSPEqualityCategorical(messages[1], nothing, messages[2])\n", - "messages[4] = ruleVBDiscreteObservationOut(messages[3], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][1]))\n", - "messages[5] = ruleSPEqualityCategorical(nothing, messages[4], messages[2])\n", - "\n", - "marginals[:x_1] = messages[1].dist * messages[5].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(Categorical, marginals[:x_t_min], Distribution(Multivariate, PointMass, m=data[:D_t_min]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][1]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_2], Distribution(MatrixVariate, PointMass, m=data[:A]), Distribution(Multivariate, PointMass, m=data[:C][2]))\n", - "F += averageEnergy(Transition, marginals[:x_1], marginals[:x_t_min], Distribution(MatrixVariate, PointMass, m=data[:u][1]))\n", - "F += averageEnergy(Transition, marginals[:x_2], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=data[:u][2]))\n", - "\n", - "F -= differentialEntropy(marginals[:x_1])\n", - "F -= differentialEntropy(marginals[:x_2])\n", - "F -= differentialEntropy(marginals[:x_t_min])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - "println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Reward probability and utility, uncomment scenario of interest\n", - "α = 0.9; c = 2.0\n", - "\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"helpers.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "C_t = [C, C] # Goal prior sequence\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Single policy\n", - "pi = [4, 2]\n", - "\n", - "n_its = 10\n", - "G = zeros(n_its)\n", - "\n", - "data = Dict(:u => [B[pi[1]], B[pi[2]]],\n", - " :A => A,\n", - " :C => C_t,\n", - " :D_t_min => D)\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D),\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)))\n", - "\n", - "for k=1:n_its\n", - " stepX0!(data, marginals)\n", - " stepX1!(data, marginals)\n", - " stepX2!(data, marginals)\n", - " G[k] = freeEnergy(data, marginals)\n", - "end\n", - " \n", - "G = G./log(2) # Convert to bits\n", - "\n", - "plot(1:n_its, G, color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Iteration\", ylabel=\"GFE [bits]\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n" - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# GMFE for all policies\n", - "GMFE = evaluatePoliciesGMFE(A, B, C_t, D, n_its=n_its)\n", - "plotResults(GMFE, clim=(9.0,12.0), dpi=300, highlight=minimum)\n", - "#savefig(\"GMFE_c_$(c)_a_$(α).png\")" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/agent.jl b/src/Part2/FL/archive/agent.jl deleted file mode 100644 index def82f6..0000000 --- a/src/Part2/FL/archive/agent.jl +++ /dev/null @@ -1,215 +0,0 @@ -import ForneyLab: softmax, tiny - -function softmax(v::Vector) - r = v .- maximum(v) - clamp!(r, -100.0, 0.0) - exp.(r)./sum(exp.(r)) -end - -# Symmetry breaking for initial statistics -function asym(n::Int64) - p = ones(n) .+ 1e-3*rand(n) - return p./sum(p) -end - -function evaluatePoliciesGBFE(A, B, C_t, D; n_its=10) - # Evaluate all policies - G = zeros(4,4) - for i in 1:4 # First move - for j = 1:4 # Second move - data = Dict(:u => [B[i], B[j]], - :A => A, - :C => C_t, - :D_t_min => D) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8))) - - messages = init() - - for k=1:n_its - step!(data, marginals, messages) - end - - G[i, j] = freeEnergy(data, marginals) - end - end - - return G./log(2) # Convert to bits -end - -# Evaluation includes parameter estimate -function evaluatePoliciesFullGBFE(A, B, C, D; n_its=10) - # Evaluate all policies - G = zeros(4,4) - for i in 1:4 # First move - for j = 1:4 # Second move - data = Dict(:u => [B[i], B[j]], - :A => A, - :C => [C, C], - :D_t_min => D) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A_t => ProbabilityDistribution(MatrixVariate, Dirichlet, a=A_0), - :c_t => ProbabilityDistribution(Multivariate, Dirichlet, a=C_0)) - - messages = initX() - - Gs = zeros(n_its) - for k=1:n_its - stepX!(data, marginals, messages) - stepC!(data, marginals, messages) - stepA!(data, marginals, messages) - - Gs[k] = freeEnergy(data, marginals) - end - - G[i, j] = mean(Gs[5:n_its]) - end - end - - return G./log(2) # Convert to bits -end - -function evaluatePoliciesEFE(A, B, C_t, D) - # Construct priors - D_t_min = D - - # Evaluate all policies - Q = zeros(4,4) - for i in 1:4 # First move - x_t_hat = B[i]*D_t_min # Expected state - y_t_hat = A*x_t_hat # Expected outcome - - # We follow Eq. D.2 in da Costa (2021) "Active inference on discrete state-spaces: a synthesis" - predicted_uncertainty_t = diag(A' * log.(A .+ tiny))' * x_t_hat # Friston (for reference): ones(16)' * (A.*log.(A .+ tiny)) * x_t_hat - predicted_divergence_t = transpose( log.(y_t_hat .+ tiny) - log.(C_t[1] .+ tiny) ) * y_t_hat - Q_t = predicted_uncertainty_t - predicted_divergence_t - - for j in 1:4 # Second move - x_t_plus_hat = B[j]*x_t_hat # Expected state - y_t_plus_hat = A*x_t_plus_hat # Expected outcome - - predicted_uncertainty_t_plus = diag(A' * log.(A .+ tiny))' * x_t_plus_hat - predicted_divergence_t_plus = transpose( log.(y_t_plus_hat .+ tiny) - log.(C_t[2] .+ tiny) ) * y_t_plus_hat - Q_t_plus = predicted_uncertainty_t_plus - predicted_divergence_t_plus - - Q[i, j] = Q_t + Q_t_plus - end - end - - return -Q./log(2) # Return expected free energy per policy in bits -end - -function evaluatePoliciesGMFE(A, B, C_t, D; n_its=10) - # Evaluate all policies - G = zeros(4,4) - for i in 1:4 # First move - for j = 1:4 # Second move - data = Dict(:u => [B[i], B[j]], - :A => A, - :C => C_t, - :D_t_min => D) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8))) - - for k=1:n_its - stepX0!(data, marginals) - stepX1!(data, marginals) - stepX2!(data, marginals) - end - - G[i, j] = freeEnergy(data, marginals) - end - end - - return G./log(2) # Convert to bits -end - -function evaluatePoliciesBFE(A, B, C_t, D) - # Evaluate all policies - F = zeros(4,4) - for i in 1:4 # First move - for j = 1:4 # Second move - data = Dict(:u => [B[i], B[j]], - :A => A, - :C => C_t, - :D_t_min => D) - - marginals = step!(data) - - F[i, j] = freeEnergy(data, marginals) - end - end - - return F./log(2) # Convert to bits -end - -function initializeAgent(A, B, C, D) - n_its = 10 - function plan() - # Evaluate all policies - G = zeros(4,4) - for i in 1:4 # First move - for j = 1:4 # Second move - data = Dict(:u => [B[i], B[j]], - :A => A, - :C => C_t, - :D_t_min => D_t_min) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8))) - - messages = initPlan() - - Gs = zeros(n_its) - for k=1:n_its - stepPlan!(data, marginals, messages) - Gs[k] = freeEnergyPlan(data, marginals) - end - Gs = Gs./log(2) # Convert to bits - - G[i, j] = mean(Gs[5:n_its]) # Average to smooth fluctuations - end - end - - return G./log(2) # Return free energy in bits - end - - function act(G::Matrix{Float64}) - # We include policy selection in the act function for clearer code; procedurally, policy selection belongs in the plan step - p = softmax(vec(-100*G)) # Determine policy probabilities with high precision (max selection) - S = reshape(sample(ProbabilityDistribution(Categorical, p=p)), 4, 4) # Reshaped policy sample - (_, pol) = findmax(S) - - return pol[1] # Return first action of policy - end - - D_t_min = D - C_t = [C, C] - function slide(a_t::Int64, o_t::Vector{Float64}) - # Estimate state - data = Dict(:B_t => B[a_t], - :A => A, - :o_t => o_t, - :D_t_min => D_t_min) - marginals = stepSlide!(data) - D_t_min = ForneyLab.unsafeMean(marginals[:x_t]) # Reset prior state statistics - - # Shift goals for next move - C_t = circshift(C_t, -1) - C_t[end] = C - end - - return (plan, act, slide) -end \ No newline at end of file diff --git a/src/Part2/FL/archive/agent_2.jl b/src/Part2/FL/archive/agent_2.jl deleted file mode 100644 index 5e6a1ca..0000000 --- a/src/Part2/FL/archive/agent_2.jl +++ /dev/null @@ -1,147 +0,0 @@ -function constructAPrior() - eps = 0.01 - - # A_0_X = [1.5 0.5; - # 0.5 1.5; - # 1.0 1.0; - # 1.0 1.0] # Sum of probabilities in A - - A_0_4 = [10.0 eps; - eps 10.0; - eps eps; - eps eps] - - A_0 = eps*ones(16, 8) - - # A_0[1:4, 1:2] = A_0_X - # A_0[5:8, 3:4] = A_0_X - # A_0[9:12, 5:6] = A_0_X - A_0[13:16, 7:8] = A_0_4 - - return A_0 -end - -function initializeAgent(A_0, B, C, D) - D_t_min = deepcopy(D) - n_its = 10 - A_s = deepcopy(A_0) - function infer(t::Int64, a::Vector, o::Vector) - # Evaluate all policies - if t == 1 - G = Matrix{Union{Float64, Missing}}(undef, 4, 4) - risk = Matrix{Union{Float64, Missing}}(undef, 4, 4) - amb = Matrix{Union{Float64, Missing}}(undef, 4, 4) - nov = Matrix{Union{Float64, Missing}}(undef, 4, 4) - pols = [(1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)] - for (i, j) in pols - data = Dict(:u => [B[i], B[j]], - :A_s => A_s, - :C => C, - :D_t_min => D_t_min) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_s))) - - messages = initt1X() - - Gks = zeros(n_its) - riskks = zeros(n_its) - ambks = zeros(n_its) - novks = zeros(n_its) - for k=1:n_its - stept1X!(data, marginals, messages) - stept1A!(data, marginals) - Gks[k] = freeEnergyt1(data, marginals)/log(2) # Convert to bits - (riskks[k], ambks[k], novks[k]) = freeEnergyDecompt1(data, marginals) # Already returned in bits - end - - G[i, j] = mean(Gks[5:n_its]) # Average to smooth fluctuations - risk[i, j] = mean(riskks[5:n_its]) - amb[i, j] = mean(ambks[5:n_its]) - nov[i, j] = mean(novks[5:n_its]) - end - - return (G, risk, amb, nov) # Return free energy - elseif t == 2 - G = Vector{Union{Float64, Missing}}(undef, 4) - if a[1] in [2, 3] - pols = [1] # Mandatory move to 1 - else - pols = [1, 2, 3, 4] - end - - for j in pols # Second move - data = Dict(:u => [B[a[1]], B[j]], - :y => o, - :A_s => A_s, - :C => C, - :D_t_min => D_t_min) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_s))) - - messages = initt2X() - - Gs = zeros(n_its) - for k=1:n_its - stept2X!(data, marginals, messages) - stept2A!(data, marginals) - Gs[k] = freeEnergyt2(data, marginals)/log(2) # Convert to bits - Gs[k] += averageEnergy(Categorical, - Distribution(Multivariate, PointMass, m=o[1]), - Distribution(Multivariate, PointMass, m=C))/log(2) - end - - G[j] = mean(Gs[5:n_its]) # Average to smooth fluctuations - end - - return G - elseif t == 3 - data = Dict(:u => [B[a[1]], B[a[2]]], - :y => o, - :A_s => A_s, - :C => C, - :D_t_min => D_t_min) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_s))) - - for k=1:n_its - stept3X!(data, marginals) - stept3A!(data, marginals) - end - G = freeEnergyt3(data, marginals)/log(2) # Convert to bits - G += averageEnergy(Categorical, - Distribution(Multivariate, PointMass, m=o[1]), - Distribution(Multivariate, PointMass, m=C))/log(2) - G += averageEnergy(Categorical, - Distribution(Multivariate, PointMass, m=o[2]), - Distribution(Multivariate, PointMass, m=C))/log(2) - A_s = deepcopy(marginals[:A].params[:a]) # Reset for next simulation - - return (G, A_s) # Return free energy and posterior statistics - end - end - - function act(G) - # We include policy selection in the act function for clearer code; procedurally, policy selection belongs in the plan step - idx = findall((!).(ismissing.(G))) # Find coordinates of non-missing entries - Gvec = G[idx] # Convert to vector of valid entries - p = softmax(-100.0*Gvec) - s = sample(ProbabilityDistribution(Categorical, p=p)) # Sample a 1-of-K representation - c = first(idx[s.==1.0]) # Select coordinate (policy) by sample - - return (c[1], c) # Return first action from policy - end - - return (infer, act) -end \ No newline at end of file diff --git a/src/Part2/FL/archive/agent_3.jl b/src/Part2/FL/archive/agent_3.jl deleted file mode 100644 index 87f90cc..0000000 --- a/src/Part2/FL/archive/agent_3.jl +++ /dev/null @@ -1,124 +0,0 @@ -function constructAPrior() - eps = 0.1 - - A_0_4 = [1.0 0.0; - 0.0 1.0; - 0.0 0.0; - 0.0 0.0] - - A_0 = eps*ones(16, 8) - A_0[13:16, 7:8] = A_0_4 .+ eps # Hint that position 4 resolves information - - return A_0 -end - -function initializeAgent(A_0, B, C, D) - D_t_min = deepcopy(D) - n_its = 10 - A_s = deepcopy(A_0) - function infer(t::Int64, a::Vector, o::Vector) - # Evaluate all policies - if t == 1 - G = Matrix{Union{Float64, Missing}}(undef, 4, 4) - pols = [(1,1), (1,2), (1,3), (1,4), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4)] - for (i, j) in pols - data = Dict(:u => [B[i], B[j]], - :A_s => A_s, - :C => C, - :D_t_min => D_t_min) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_s))) - - Gks = zeros(n_its) - for k=1:n_its - stept1X!(data, marginals) - stept1A!(data, marginals) - Gks[k] = freeEnergyt1(data, marginals)/log(2) # Convert to bits - end - - G[i, j] = mean(Gks[5:n_its]) # Average to smooth fluctuations - end - - return G # Return free energy - elseif t == 2 - G = Vector{Union{Float64, Missing}}(undef, 4) - if a[1] in [2, 3] - pols = [1] # Mandatory move to 1 - else - pols = [1, 2, 3, 4] - end - - for j in pols # Second move - data = Dict(:u => [B[a[1]], B[j]], - :y => o, - :A_s => A_s, - :C => C, - :D_t_min => D_t_min) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_s))) - - Gs = zeros(n_its) - for k=1:n_its - stept2X!(data, marginals) - stept2A!(data, marginals) - Gs[k] = freeEnergyt2(data, marginals)/log(2) # Convert to bits - Gs[k] += averageEnergy(Categorical, - Distribution(Multivariate, PointMass, m=o[1]), - Distribution(Multivariate, PointMass, m=C))/log(2) - end - - G[j] = mean(Gs[5:n_its]) # Average to smooth fluctuations - end - - return G - elseif t == 3 - data = Dict(:u => [B[a[1]], B[a[2]]], - :y => o, - :A_s => A_s, - :C => C, - :D_t_min => D_t_min) - - marginals = Dict{Symbol, ProbabilityDistribution}( - :x_t_min => ProbabilityDistribution(Univariate, Categorical, p=D), - :x_1 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :x_2 => ProbabilityDistribution(Univariate, Categorical, p=asym(8)), - :A => ProbabilityDistribution(MatrixVariate, Dirichlet, a=asym(A_s))) - - for k=1:n_its - stept3X!(data, marginals) - stept3A!(data, marginals) - end - G = freeEnergyt3(data, marginals)/log(2) # Convert to bits - G += averageEnergy(Categorical, - Distribution(Multivariate, PointMass, m=o[1]), - Distribution(Multivariate, PointMass, m=C))/log(2) - G += averageEnergy(Categorical, - Distribution(Multivariate, PointMass, m=o[2]), - Distribution(Multivariate, PointMass, m=C))/log(2) - A_s = deepcopy(marginals[:A].params[:a]) # Reset for next simulation - - return (G, A_s) # Return free energy and posterior statistics - end - end - - function act(G) - # We include policy selection in the act function for clearer code; procedurally, policy selection belongs in the plan step - idx = findall((!).(ismissing.(G))) # Find coordinates of non-missing entries - Gvec = G[idx] # Convert to vector of valid entries - p = softmax(-100*Gvec) - s = sample(ProbabilityDistribution(Categorical, p=p)) # Sample a 1-of-K representation - c = first(idx[s.==1.0]) # Select coordinate (policy) by sample - - return c[1] # Return first action from policy - end - - return (infer, act) -end \ No newline at end of file diff --git a/src/Part2/FL/archive/ep_distribution.ipynb b/src/Part2/FL/archive/ep_distribution.ipynb deleted file mode 100644 index 126610c..0000000 --- a/src/Part2/FL/archive/ep_distribution.ipynb +++ /dev/null @@ -1,149 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using Plots\n", - "\n", - "da = 0.05\n", - "as = 0:da:1\n", - "n = length(as)\n", - "\n", - "function pdf(f, s, b)\n", - " fA = zeros(n,n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " A_jk = [as[j] as[k]; 1-as[j] 1-as[k]]\n", - " fA[j,k] = f(A_jk, s, b)\n", - " end\n", - " end\n", - " \n", - " return fA ./ sum(fA)\n", - "end;" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [], - "source": [ - "# Parameters\n", - "s = [0.9, 0.1]\n", - "b = [2.0, 2.0];" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 80, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Joint Distribution\n", - "f_joint(A, s, b) = exp.(s'*diag(A'*log.(A .+ eps())) + (A*s)'*b)\n", - "pdf_joint = pdf(f_joint, s, b)\n", - "\n", - "plt = plot(as,\n", - " as,\n", - " pdf_joint',\n", - " st=:contour,\n", - " fill=true,\n", - " dpi=100,\n", - " aspect_ratio=:equal, \n", - " xlim=(0,1), \n", - " ylim=(0,1), \n", - " xlabel=\"a11\",\n", - " ylabel=\"a12\",\n", - " title=\"p_joint(A)\")" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 81, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# IID Distribution\n", - "f_iid(A, s, b) = exp.(s[1]*A[:,1]'*log.(A[:,1].+eps()) + s[1]*A[:,1]'*b + s[2]*A[:,2]'*log.(A[:,2].+eps()) + s[2]*A[:,2]'*b)\n", - "pdf_iid = pdf(f_iid, s, b)\n", - "\n", - "plt = plot(as,\n", - " as,\n", - " pdf_iid',\n", - " st=:contour,\n", - " fill=true,\n", - " dpi=100,\n", - " aspect_ratio=:equal, \n", - " xlim=(0,1), \n", - " ylim=(0,1), \n", - " xlabel=\"a11\",\n", - " ylabel=\"a12\",\n", - " title=\"p_iid(A)\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/ep_kl.ipynb b/src/Part2/FL/archive/ep_kl.ipynb deleted file mode 100644 index b257d26..0000000 --- a/src/Part2/FL/archive/ep_kl.ipynb +++ /dev/null @@ -1,152 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using Plots\n", - "\n", - "dx = 0.01\n", - "xs = dx:dx:(1-dx)\n", - "n = length(xs)\n", - "\n", - "function pdf_ep(s, d, b)\n", - " f_ep = zeros(n)\n", - " for j = 1:n\n", - " x_j = [xs[j], 1-xs[j]]\n", - " f_ep[j] = exp.(s*x_j'*log.(x_j.+eps()) + s*x_j'*d + (b .- 1.0)'*log.(x_j.+eps()))\n", - " end\n", - " \n", - " return f_ep ./ sum(f_ep)\n", - "end\n", - "\n", - "function pdf_dir(β)\n", - " f_dir = zeros(n)\n", - " for j = 1:n\n", - " x_j = [xs[j], 1-xs[j]]\n", - " f_dir[j] = exp.((β .- 1.0)'*log.(x_j.+eps()))\n", - " end\n", - " \n", - " return f_dir ./ sum(f_dir)\n", - "end\n", - "\n", - "function softmax(v::Vector)\n", - " r = v .- maximum(v)\n", - " clamp!(r, -100.0, 0.0)\n", - " exp.(r)./sum(exp.(r))\n", - "end;" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[854.0183132656466, 1589.7400505030569]\n" - ] - }, - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using SpecialFunctions\n", - "using ForwardDiff: jacobian\n", - "\n", - "# Parameters\n", - "s = 0.5\n", - "d = [10.0, 1.0]\n", - "b = [1.0, 1.0]\n", - "K = length(d)\n", - "\n", - "# Compute beta\n", - "function g(β)\n", - " β_0 = sum(β)\n", - " b_0 = sum(b)\n", - " d_0 = sum(d)\n", - "\n", - " return ((1 - s/β_0)*β - b).*trigamma.(β) .-\n", - " (β_0 - s - b_0)*trigamma(β_0) .+\n", - " (s/β_0^2)*(β'*digamma.(β) .- β_0*(digamma.(β) .+ d .- d_0) .+ K .- 1)\n", - "end\n", - "\n", - "β_k = b\n", - "for k=1:10\n", - " β_k = β_k - inv(jacobian(g, β_k))*g(β_k) # Newton step for multivariate root finding\n", - " for j in 1:K\n", - " β_k[j] = clamp(β_k[j], 0.01, Inf)\n", - " end\n", - "end\n", - "\n", - "println(β_k)\n", - "\n", - "# Univariate Distribution\n", - "plt = plot(xs,\n", - " pdf_ep(s, d, b),\n", - " dpi=100,\n", - " xlim=(0,1), \n", - " ylim=(0,0.05),\n", - " xlabel=\"a1\",\n", - " ylabel=\"p(a)\",\n", - " color=\"black\",\n", - " label=\"\",\n", - " lw=2)\n", - "plot!(xs, pdf_dir(β_k), lw=2, label=\"\", color=\"red\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/ep_laplace.ipynb b/src/Part2/FL/archive/ep_laplace.ipynb deleted file mode 100644 index 41b4fab..0000000 --- a/src/Part2/FL/archive/ep_laplace.ipynb +++ /dev/null @@ -1,141 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using Plots\n", - "\n", - "da = 0.01\n", - "as = da:da:(1-da)\n", - "n = length(as)\n", - "\n", - "function pdf_ep(s, d)\n", - " f_ep = zeros(n)\n", - " for j = 1:n\n", - " a_j = [as[j], 1-as[j]]\n", - " f_ep[j] = exp.(s*a_j'*log.(a_j.+eps()) + s*a_j'*d)\n", - " end\n", - " \n", - " return f_ep ./ sum(f_ep)\n", - "end\n", - "\n", - "function pdf_dir(b)\n", - " f_dir = zeros(n)\n", - " for j = 1:n\n", - " a_j = [as[j], 1-as[j]]\n", - " f_dir[j] = exp.((b .- 1.0)'*log.(a_j.+eps()))\n", - " end\n", - " \n", - " return f_dir ./ sum(f_dir)\n", - "end\n", - "\n", - "function softmax(v::Vector)\n", - " r = v .- maximum(v)\n", - " clamp!(r, -100.0, 0.0)\n", - " exp.(r)./sum(exp.(r))\n", - "end;" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[-3.658429314905327e305, -8.951881381162527e307]\n", - "-39.0\n" - ] - }, - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Parameters\n", - "s = 0.5\n", - "d = [10.0, -1.0]\n", - "K = length(d)\n", - "\n", - "x_star = softmax(-s*d)\n", - "b_k = zeros(K)\n", - "b_k_min = [1.5, 1.5] #softmax(-s*d)\n", - "for k=1:10\n", - " b_k = 1.0 .- (x_star./s)*(sum(b_k_min) - K).^2\n", - " b_k_min = deepcopy(b_k)\n", - "end\n", - "println(b_k)\n", - "\n", - "D = (2/s - 1)^2 + (4/s)*K*(1 - K/s)\n", - "println(D)\n", - "\n", - "# Univariate Distribution\n", - "plt = plot(as,\n", - " pdf_ep(s, d),\n", - " dpi=100,\n", - " xlim=(0,1), \n", - " ylim=(0,0.05),\n", - " xlabel=\"a1\",\n", - " ylabel=\"p(a)\",\n", - " color=\"black\",\n", - " label=\"\",\n", - " lw=2)\n", - "plot!(as, pdf_dir(b_k), lw=2, label=\"\", color=\"red\")\n", - "# plot!(as, pdf_dir(softmax(s*d)), lw=2, label=\"\", color=\"red\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/instability.ipynb b/src/Part2/FL/archive/instability.ipynb deleted file mode 100644 index e108468..0000000 --- a/src/Part2/FL/archive/instability.ipynb +++ /dev/null @@ -1,515 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Stability Analysis of GFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using Plots\n", - "\n", - "function softmax(v::Vector)\n", - " r = v .- maximum(v)\n", - " clamp!(r, -100.0, 0.0)\n", - " exp.(r)./sum(exp.(r))\n", - "end\n", - "\n", - "tiny = 1e-12\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "A = [0.98 0.02; \n", - " 0.02 0.98]\n", - "\n", - "c = [0.5, 0.5]\n", - "\n", - "d = [0.2, 0.8]\n", - "\n", - "s_0 = [0.9, 0.1] # Initial coordinate\n", - "\n", - "f(s) = softmax(log.(d .+ tiny) + diag(A'*log.(A) .+ tiny) + A'*log.(c .+ tiny) - A'*log.(A*s .+ tiny))\n", - "F(s) = -s'*log.(d .+ tiny) + s'*log.(s .+ tiny) - s'*diag(A'*log.(A) .+ tiny) - (A*s)'*log.(c .+ tiny) + (A*s)'*log.(A*s .+ tiny)\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "n_its = 5\n", - "G = zeros(n_its)\n", - "p = Vector{Float64}(undef, n_its) # Coordinates\n", - "\n", - "G_0 = F(s_0)\n", - "s_k_min = s_0\n", - "for k=1:n_its\n", - " s_k = f(s_k_min)\n", - "\n", - " p[k] = s_k[1]\n", - " G[k] = F(s_k)\n", - "\n", - " s_k_min = s_k\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot(0:n_its, [G_0; G], color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Coordinate Increment\", ylabel=\"GFE [nats]\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Landscape" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "ps = 0.0:0.05:1.0\n", - "m = length(ps)\n", - "Gs = zeros(m)\n", - "for i = 1:m\n", - " Gs[i] = F([ps[i], 1.0-ps[i]])\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plt = plot(ps,\n", - " Gs,\n", - " dpi=100,\n", - " xlabel=\"s\",\n", - " ylabel=\"GFE [nats]\", color=:black, linewidth=2)\n", - "\n", - "p_0 = s_0[1]\n", - "plot!([p_0; p], [G_0; G], color=:green, marker=:o, linewidth=2, legend=false)\n", - "\n", - "for k=1:n_its+1\n", - " ann = ([p_0; p][k], [G_0; G][k], text(k-1, 12, :red, :center))\n", - " annotate!(ann, linecolor=:red)\n", - "end\n", - "\n", - "plt" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using ForwardDiff\n", - "\n", - "h(p) = norm(ForwardDiff.jacobian(f, [p, 1.0-p])) # Frobenius norm of Jacobian\n", - "plt = plot(ps, h.(ps), color=:black, linewidth=2, legend=false, xlabel=\"s\", ylabel=\"instability\")\n", - "plot!([0.0, 1.0], [1.0, 1.0], color=:red, linewidth=2, legend=false)\n", - "scatter!([p_0; p], h.([p_0; p]), color=:green, marker=:o, linewidth=2, legend=false)\n", - "for k=1:n_its+1\n", - " p_k = [p_0; p][k]\n", - " ann = (p_k, h(p_k), text(k-1, 12, :red, :center))\n", - " annotate!(ann, linecolor=:red)\n", - "end\n", - "\n", - "plt" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.0", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - }, - "vscode": { - "interpreter": { - "hash": "31b90ea2ee662646d8e5466ef4be593ab702f85e022a25e857ef13a3c4d04a00" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/landscape_kl.ipynb b/src/Part2/FL/archive/landscape_kl.ipynb deleted file mode 100644 index 1686c57..0000000 --- a/src/Part2/FL/archive/landscape_kl.ipynb +++ /dev/null @@ -1,227 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "metadata": {}, - "outputs": [], - "source": [ - "using SpecialFunctions\n", - "\n", - "# import SpecialFunctions: logbeta\n", - "# logbeta(x) = sum(loggamma.(x)) - loggamma(sum(x))\n", - " \n", - "# Parameters\n", - "s = 0.7\n", - "d = [1.0, 2.0]\n", - "b = [1.0, 1.0]\n", - "K = length(b)\n", - "\n", - "# Divergence\n", - "function F(β1, β2)\n", - " β = [β1, β2]\n", - " β0 = sum(β)\n", - " b0 = sum(b)\n", - "\n", - " β = [β1, β2]\n", - " β0 = sum(β)\n", - " b0 = sum(b)\n", - "\n", - " return -logbeta(β1, β2) + \n", - " ((1 - s/β0)*β - b)'*digamma.(β) - \n", - " (β0 - s - b0)*digamma(β0) -\n", - " (s/β0)*(β'*d + K - 1)\n", - "end\n", - "\n", - "# Gradient\n", - "S = 0.1 # Plot scale\n", - "function delβF(β1, β2)\n", - " β = [β1, β2]\n", - " β0 = sum(β)\n", - " b0 = sum(b)\n", - "\n", - " C = (s/β0^2)*(β'*digamma.(β) + β'd + K - 1) -\n", - " (β0 - s - b0)*trigamma(β0)\n", - " del = -(s/β0)*digamma.(β) +\n", - " (1 - s/β0)*β.*trigamma.(β) -\n", - " b.*trigamma.(β) -\n", - " (s/β0)*d .+ C\n", - "\n", - " return S*del # Scaled gradient\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 88, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using Plots; gr()\n", - "\n", - "B = 2 # Max plotting range\n", - "\n", - "βs = LinRange(0, B, 50)\n", - "contour(βs, βs, F,\n", - " aspect_ratio=:equal, \n", - " xlim=(0,B), \n", - " ylim=(0,B), \n", - " xlabel=\"β1\",\n", - " ylabel=\"β2\")\n", - "\n", - "delβs = LinRange(0, B, 20)\n", - "meshgrid(x, y) = (repeat(x, outer=length(y)),\n", - " repeat(y, inner=length(x)))\n", - "B1, B2 = meshgrid(delβs, delβs)\n", - "quiver!(B1, B2, quiver=delβF, color=:blue)" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1.0609679431822323, 1.8636161326570044]\n" - ] - } - ], - "source": [ - "using ForwardDiff: jacobian\n", - "\n", - "delβFVec(β) = delβF(β[1], β[2])\n", - "\n", - "# Multivariate root-finding\n", - "# β_k = d\n", - "# for k=1:10\n", - "# β_k = β_k - inv(jacobian(delβFVec, β_k))*delβFVec(β_k) # Newton step\n", - "# β_k = clamp.(β_k, 0.01, Inf)\n", - "# end\n", - "\n", - "# Gradient descent\n", - "γ = 0.1\n", - "β_k = d\n", - "for k=1:100\n", - " β_k = β_k - γ*delβFVec(β_k) # Gradient step\n", - " β_k = clamp.(β_k, 0.01, Inf)\n", - "end\n", - "\n", - "println(β_k)" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 90, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dx = 0.01\n", - "xs = dx:dx:(1-dx)\n", - "n = length(xs)\n", - "\n", - "# Distributions\n", - "function pdf_ep(s, d, b)\n", - " f_ep = zeros(n)\n", - " for j = 1:n\n", - " x_j = [xs[j], 1-xs[j]]\n", - " f_ep[j] = exp.(s*x_j'*log.(x_j.+eps()) + s*x_j'*d + (b .- 1.0)'*log.(x_j.+eps()))\n", - " end\n", - "\n", - " return f_ep ./ sum(f_ep)\n", - "end\n", - " \n", - "function pdf_dir(β)\n", - " f_dir = zeros(n)\n", - " for j = 1:n\n", - " x_j = [xs[j], 1-xs[j]]\n", - " f_dir[j] = exp.((β .- 1.0)'*log.(x_j.+eps()))\n", - " end\n", - "\n", - " return f_dir ./ sum(f_dir)\n", - "end\n", - "\n", - "# Univariate Distribution\n", - "plt = plot(xs,\n", - " pdf_ep(s, d, b),\n", - " dpi=100,\n", - " xlim=(0,1), \n", - " ylim=(0,0.05),\n", - " xlabel=\"x\",\n", - " ylabel=\"p(x)\",\n", - " color=\"black\",\n", - " label=\"\",\n", - " lw=2)\n", - "plot!(xs, pdf_dir(β_k), lw=2, label=\"\", color=\"red\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "31b90ea2ee662646d8e5466ef4be593ab702f85e022a25e857ef13a3c4d04a00" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/minimal_planning.ipynb b/src/Part2/FL/archive/minimal_planning.ipynb deleted file mode 100644 index 55527c6..0000000 --- a/src/Part2/FL/archive/minimal_planning.ipynb +++ /dev/null @@ -1,450 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Minimal Inference for Planning with GFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "\n", - "include(\"factor_nodes/DiscreteObservation.jl\")\n", - "include(\"update_rules/DiscreteObservation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "A = [0.98 0.02; \n", - " 0.02 0.98]\n", - "\n", - "C = [0.5, 0.5]\n", - "\n", - "D = [0.1, 0.9]\n", - "\n", - "@RV x ~ Categorical(D)\n", - "DiscreteObservation(x, A, C)\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(fg)\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function init()\n", - "\n", - "messages = Array{Message}(undef, 2)\n", - "\n", - "messages[1] = Message(vague(Categorical, (2,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function step!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - "\n", - "messages[1] = ruleSPCategoricalOutNP(nothing, Message(Multivariate, PointMass, m=[0.1, 0.9]))\n", - "messages[2] = ruleSPDiscreteObservationOutDPP(messages[1], marginals[:x], Message(MatrixVariate, PointMass, m=[0.98 0.02; 0.02 0.98]), Message(Multivariate, PointMass, m=[0.5, 0.5]))\n", - "\n", - "marginals[:x] = messages[1].dist * messages[2].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(Categorical, marginals[:x], Distribution(Multivariate, PointMass, m=[0.1, 0.9]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x], Distribution(MatrixVariate, PointMass, m=[0.98 0.02; 0.02 0.98]), Distribution(Multivariate, PointMass, m=[0.5, 0.5]))\n", - "\n", - "F -= differentialEntropy(marginals[:x])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - "println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "n_its = 5\n", - "G = zeros(n_its)\n", - "p_0 = 0.9 # Initial coordinate\n", - "p = Vector{Float64}(undef, n_its) # Coordinates\n", - "\n", - "data = Dict()\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x => ProbabilityDistribution(Univariate, Categorical, p=[p_0, 1.0 - p_0]))\n", - "\n", - "G_0 = freeEnergy(data, marginals)\n", - "for k=1:n_its\n", - " step!(data, marginals)\n", - " p[k] = marginals[:x].params[:p][1]\n", - " G[k] = freeEnergy(data, marginals)\n", - "end\n", - ";\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "text/html": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plot(0:n_its, [G_0; G], color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Coordinate Increment\", ylabel=\"GFE [nats]\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Landscape" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "xs = 0.0:0.05:1.0\n", - "m = length(xs)\n", - "Gs = zeros(m)\n", - "for i = 1:m\n", - " data = Dict()\n", - " m_x = Distribution(Univariate, Categorical, p=[xs[i], 1.0 - xs[i]])\n", - " margs = Dict{Symbol, ProbabilityDistribution}(:x => m_x)\n", - " Gs[i] = freeEnergy(data, margs)\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "text/html": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt = plot(xs,\n", - " Gs,\n", - " dpi=100,\n", - " xlabel=\"x\",\n", - " ylabel=\"GFE [nats]\", color=:black, linewidth=2)\n", - "\n", - "plot!([p_0; p], [G_0; G], color=:green, marker=:o, linewidth=2, legend=false)\n", - "\n", - "for k=1:n_its+1\n", - " ann = ([p_0; p][k], [G_0; G][k], text(k-1, 12, :red, :center))\n", - " annotate!(ann, linecolor=:red)\n", - "end\n", - "\n", - "plt" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.6.4", - "language": "julia", - "name": "julia-1.6" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.6.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/minimal_planning_newton.ipynb b/src/Part2/FL/archive/minimal_planning_newton.ipynb deleted file mode 100644 index 3be2499..0000000 --- a/src/Part2/FL/archive/minimal_planning_newton.ipynb +++ /dev/null @@ -1,595 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# GFE Optimization by Newton's Method" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using PositiveFactorizations\n", - "using ForwardDiff: jacobian\n", - "using Plots\n", - "\n", - "function softmax(v::Vector)\n", - " r = v .- maximum(v)\n", - " clamp!(r, -100.0, 0.0)\n", - " exp.(r)./sum(exp.(r))\n", - "end\n", - "\n", - "tiny = 1e-12\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [], - "source": [ - "A = [0.98 0.02; \n", - " 0.02 0.98]\n", - "\n", - "c = [0.5, 0.5]\n", - "\n", - "d = [0.2, 0.8]\n", - "\n", - "s_0 = [0.9, 0.1] # Initial coordinate\n", - "\n", - "g(s) = s - softmax(log.(d .+ tiny) + diag(A'*log.(A) .+ tiny) + A'*log.(c .+ tiny) - A'*log.(A*s .+ tiny)) # Convert fixed-point equation to root-finding problem\n", - "F(s) = -s'*log.(d .+ tiny) + s'*log.(s .+ tiny) - s'*diag(A'*log.(A) .+ tiny) - (A*s)'*log.(c .+ tiny) + (A*s)'*log.(A*s .+ tiny)\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [], - "source": [ - "n_its = 5\n", - "G = zeros(n_its)\n", - "p = Vector{Float64}(undef, n_its) # Coordinates\n", - "\n", - "G_0 = F(s_0)\n", - "s_k_min = s_0\n", - "for k=1:n_its\n", - " s_k = s_k_min - inv(jacobian(g, s_k_min))*g(s_k_min) # Newton step for multivariate root finding\n", - "\n", - " p[k] = s_k[1]\n", - " G[k] = F(s_k)\n", - "\n", - " s_k_min = s_k\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/html": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plot(0:n_its, [G_0; G], color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Coordinate Increment\", ylabel=\"GFE [nats]\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Landscape" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [], - "source": [ - "ps = 0.0:0.05:1.0\n", - "m = length(ps)\n", - "Gs = zeros(m)\n", - "for i = 1:m\n", - " Gs[i] = F([ps[i], 1.0-ps[i]])\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "text/html": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt = plot(ps,\n", - " Gs,\n", - " dpi=100,\n", - " xlabel=\"s\",\n", - " ylabel=\"GFE [nats]\", color=:black, linewidth=2)\n", - "\n", - "p_0 = s_0[1]\n", - "plot!([p_0; p], [G_0; G], color=:green, marker=:o, linewidth=2, legend=false)\n", - "\n", - "for k=1:n_its+1\n", - " ann = ([p_0; p][k], [G_0; G][k], text(k-1, 12, :red, :center))\n", - " annotate!(ann, linecolor=:red)\n", - "end\n", - "\n", - "plt" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.8.0", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.0" - }, - "vscode": { - "interpreter": { - "hash": "31b90ea2ee662646d8e5466ef4be593ab702f85e022a25e857ef13a3c4d04a00" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/param_direct.ipynb b/src/Part2/FL/archive/param_direct.ipynb deleted file mode 100644 index 13ee33e..0000000 --- a/src/Part2/FL/archive/param_direct.ipynb +++ /dev/null @@ -1,137 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "mean (generic function with 1 method)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForwardDiff: jacobian\n", - "\n", - "da = 0.05\n", - "as = 0:da:1\n", - "n = length(as)\n", - "function muAbw(A_bar)\n", - " fA = zeros(n,n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " A = [as[j] as[k]; 1-as[j] 1-as[k]]\n", - " fA[j,k] = exp.( x_bar'*diag(A'*log.(A .+ eps())) + (A*x_bar)'*(log_c_bar - log.(A_bar*x_bar .+ eps()) ) )\n", - " end\n", - " end\n", - " \n", - " return fA ./ sum(fA)\n", - "end\n", - "\n", - "function mean(p)\n", - " X = Matrix{Vector}(undef, n, n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " X[j,k] = [as[j], as[k]]\n", - " end\n", - " end\n", - " a_bar = sum(p.*X)\n", - " return [a_bar[1] a_bar[2]; 1-a_bar[1] 1-a_bar[2]]\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using Plots; gr()\n", - "\n", - "B_fw = 2*ones(2, 2)\n", - "x_bar = [0.5, 0.5]\n", - "log_c_bar = log.([0.5, 0.5])\n", - "\n", - "K = 5\n", - "A_bar = [0.5 0.5; 0.5 0.5]\n", - "mu = muAbw(A_bar)\n", - "\n", - "plt = plot(as,\n", - " as,\n", - " mu',\n", - " st=:contour,\n", - " fill=true,\n", - " dpi=100,\n", - " aspect_ratio=:equal, \n", - " xlim=(0,1), \n", - " ylim=(0,1), \n", - " xlabel=\"a11\",\n", - " ylabel=\"a12\",\n", - " title=\"mu_bw(A)\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "31b90ea2ee662646d8e5466ef4be593ab702f85e022a25e857ef13a3c4d04a00" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/param_iterate.ipynb b/src/Part2/FL/archive/param_iterate.ipynb deleted file mode 100644 index 3578437..0000000 --- a/src/Part2/FL/archive/param_iterate.ipynb +++ /dev/null @@ -1,165 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\"../..\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "mean (generic function with 1 method)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForwardDiff: jacobian\n", - "\n", - "da = 0.05\n", - "as = 0:da:1\n", - "n = length(as)\n", - "function qA(A_bar)\n", - " fA = zeros(n,n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " A = [as[j] as[k]; 1-as[j] 1-as[k]]\n", - " fA[j,k] = exp.( x_bar'*diag(A'*log.(A .+ eps())) + (A*x_bar)'*(log_c_bar - log.(A_bar*x_bar .+ eps()) ) + tr( (B_fw' .- 1)*log.(A .+ eps()) ) )\n", - " end\n", - " end\n", - " \n", - " return fA ./ sum(fA)\n", - "end\n", - "\n", - "function muAfw(B_fw)\n", - " fAfw = zeros(n,n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " A = [as[j] as[k]; 1-as[j] 1-as[k]]\n", - " fAfw[j,k] = exp.(tr((B_fw' .- 1)*log.(A .+ eps())))\n", - " end\n", - " end\n", - "\n", - " return fAfw ./ sum(fAfw)\n", - "end\n", - "\n", - "function mean(p)\n", - " X = Matrix{Vector}(undef, n, n)\n", - " for j = 1:n\n", - " for k = 1:n\n", - " X[j,k] = [as[j], as[k]]\n", - " end\n", - " end\n", - " a_bar = sum(p.*X)\n", - " return [a_bar[1] a_bar[2]; 1-a_bar[1] 1-a_bar[2]]\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5][0.5 0.5; 0.5 0.5]" - ] - }, - { - "data": { - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using Plots; gr()\n", - "\n", - "B_fw = 2*ones(2, 2)\n", - "x_bar = [0.5, 0.5]\n", - "log_c_bar = log.([0.5, 0.5])\n", - "\n", - "K = 5\n", - "A_bar_k_min = [0.5 0.5; 0.5 0.5]\n", - "q_k = zeros(n, n)\n", - "for k=1:K\n", - " q_k = qA(A_bar_k_min)\n", - " A_bar_k = mean(q_k)\n", - " print(round.(A_bar_k, digits=2))\n", - "\n", - " A_bar_k_min = A_bar_k\n", - "end\n", - "\n", - "muAbw = q_k ./ muAfw(B_fw)\n", - "\n", - "plt = plot(as,\n", - " as,\n", - " muAbw',\n", - " st=:contour,\n", - " fill=true,\n", - " dpi=100,\n", - " aspect_ratio=:equal, \n", - " xlim=(0,1), \n", - " ylim=(0,1), \n", - " xlabel=\"a11\",\n", - " ylabel=\"a12\",\n", - " title=\"mu_bw(A)\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.1", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.1" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "31b90ea2ee662646d8e5466ef4be593ab702f85e022a25e857ef13a3c4d04a00" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/archive/simple_planning.ipynb b/src/Part2/FL/archive/simple_planning.ipynb deleted file mode 100644 index e569c1c..0000000 --- a/src/Part2/FL/archive/simple_planning.ipynb +++ /dev/null @@ -1,930 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simple Inference for Planning with GFE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mThe call to compilecache failed to create a usable precompiled cache file for ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4]\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m exception = Required dependency Compat [34da2185-b29b-5c13-b0c7-acf172513d20] failed to load from a cache file.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1055\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17412579331703 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17412579331703 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mThe call to compilecache failed to create a usable precompiled cache file for SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b]\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m exception = Required dependency Compat [34da2185-b29b-5c13-b0c7-acf172513d20] failed to load from a cache file.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1055\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mThe call to compilecache failed to create a usable precompiled cache file for ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4]\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m exception = Required dependency Compat [34da2185-b29b-5c13-b0c7-acf172513d20] failed to load from a cache file.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1055\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17429290887610 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17429290887610 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17425249880909 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17425249880909 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17425249880909 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17425249880909 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17425249880909 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule LogExpFunctions with build ID 17433059784514 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean LogExpFunctions [2ab3a3ac-af41-5b50-aa03-7779005ae688] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "┌ Warning: The call to compilecache failed to create a usable precompiled cache file for ForneyLab [9fc3f58a-c2cc-5bff-9419-6a294fefdca9]\n", - "│ exception = ErrorException(\"Required dependency DataStructures [864edb3b-99cc-5e75-8d2d-829cb0a9cfe8] failed to load from a cache file.\")\n", - "└ @ Base loading.jl:1055\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mThe call to compilecache failed to create a usable precompiled cache file for ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4]\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m exception = Required dependency Compat [34da2185-b29b-5c13-b0c7-acf172513d20] failed to load from a cache file.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1055\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17478330468103 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17478330468103 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "┌ Warning: The call to compilecache failed to create a usable precompiled cache file for SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b]\n", - "│ exception = ErrorException(\"Required dependency Compat [34da2185-b29b-5c13-b0c7-acf172513d20] failed to load from a cache file.\")\n", - "└ @ Base loading.jl:1055\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "┌ Warning: The call to compilecache failed to create a usable precompiled cache file for ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4]\n", - "│ exception = ErrorException(\"Required dependency Compat [34da2185-b29b-5c13-b0c7-acf172513d20] failed to load from a cache file.\")\n", - "└ @ Base loading.jl:1055\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mPackage Compat does not have Base64 in its dependencies:\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- If you have Compat checked out for development and have\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m added Base64 as a dependency but haven't updated your primary\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m environment's manifest file, try `Pkg.resolve()`.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39m- Otherwise you may need to report an issue with Compat\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39mLoading Base64 into Compat from project dependency, future warnings for Compat are suppressed.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17496707893534 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule ChainRulesCore with build ID 17496707893534 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean ChainRulesCore [d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule LogExpFunctions with build ID 17502077755638 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean LogExpFunctions [2ab3a3ac-af41-5b50-aa03-7779005ae688] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule SpecialFunctions with build ID 17491503349333 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule PlotUtils with build ID 17583056270202 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean PlotUtils [995b91a9-d308-5afd-9ec6-746e21dbc043] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[33m\u001b[1m┌ \u001b[22m\u001b[39m\u001b[33m\u001b[1mWarning: \u001b[22m\u001b[39mModule PlotUtils with build ID 17583056270202 is missing from the cache.\n", - "\u001b[33m\u001b[1m│ \u001b[22m\u001b[39mThis may mean PlotUtils [995b91a9-d308-5afd-9ec6-746e21dbc043] does not support precompilation but is imported by a module that does.\n", - "\u001b[33m\u001b[1m└ \u001b[22m\u001b[39m\u001b[90m@ Base loading.jl:1030\u001b[39m\n" - ] - } - ], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "\n", - "include(\"factor_nodes/DiscreteObservation.jl\")\n", - "include(\"update_rules/DiscreteObservation.jl\")\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Model" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "include(\"environment.jl\")\n", - "\n", - "fg = FactorGraph()\n", - "\n", - "A = [0.9 0.1; \n", - " 0.1 0.9]\n", - "\n", - "B = [0.9 0.1;\n", - " 0.1 0.9]\n", - "\n", - "C = [0.5, 0.5]\n", - "\n", - "@RV x_1\n", - "DiscreteObservation(x_1, A, C)\n", - "@RV x_2 ~ Transition(x_1, B)\n", - "DiscreteObservation(x_2, A, C)\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(x_1, x_2, ids=[:X1, :X2])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "eval(Meta.parse(code))\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "begin\n", - "\n", - "function initX2()\n", - "\n", - "messages = Array{Message}(undef, 2)\n", - "\n", - "messages[1] = Message(vague(Categorical, (2,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function stepX2!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - "\n", - "messages[1] = ruleVBTransitionOut(nothing, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=[0.9 0.1; 0.1 0.9]))\n", - "messages[2] = ruleVBDiscreteObservationOut(messages[1], marginals[:x_2], Distribution(MatrixVariate, PointMass, m=[0.9 0.1; 0.1 0.9]), Distribution(Multivariate, PointMass, m=[0.5, 0.5]))\n", - "\n", - "marginals[:x_2] = messages[1].dist * messages[2].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function initX1()\n", - "\n", - "messages = Array{Message}(undef, 2)\n", - "\n", - "messages[1] = Message(vague(Categorical, (2,)))\n", - "\n", - "return messages\n", - "\n", - "end\n", - "\n", - "function stepX1!(data::Dict, marginals::Dict=Dict(), messages::Vector{Message}=Array{Message}(undef, 2))\n", - "\n", - "messages[1] = ruleVBTransitionIn1(marginals[:x_2], nothing, Distribution(MatrixVariate, PointMass, m=[0.9 0.1; 0.1 0.9]))\n", - "messages[2] = ruleVBDiscreteObservationOut(messages[1], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=[0.9 0.1; 0.1 0.9]), Distribution(Multivariate, PointMass, m=[0.5, 0.5]))\n", - "\n", - "marginals[:x_1] = messages[2].dist * messages[1].dist\n", - "\n", - "return marginals\n", - "\n", - "end\n", - "\n", - "function freeEnergy(data::Dict, marginals::Dict)\n", - "\n", - "F = 0.0\n", - "\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_1], Distribution(MatrixVariate, PointMass, m=[0.9 0.1; 0.1 0.9]), Distribution(Multivariate, PointMass, m=[0.5, 0.5]))\n", - "F += averageEnergy(DiscreteObservation, marginals[:x_2], Distribution(MatrixVariate, PointMass, m=[0.9 0.1; 0.1 0.9]), Distribution(Multivariate, PointMass, m=[0.5, 0.5]))\n", - "F += averageEnergy(Transition, marginals[:x_2], marginals[:x_1], Distribution(MatrixVariate, PointMass, m=[0.9 0.1; 0.1 0.9]))\n", - "\n", - "F -= differentialEntropy(marginals[:x_1])\n", - "F -= differentialEntropy(marginals[:x_2])\n", - "\n", - "return F\n", - "\n", - "end\n", - "\n", - "end # block\n" - ] - } - ], - "source": [ - "println(code)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "ename": "UndefVarError", - "evalue": "UndefVarError: softmax not defined", - "output_type": "error", - "traceback": [ - "UndefVarError: softmax not defined\n", - "\n", - "Stacktrace:\n", - " [1] (::var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}})(s::Vector{ForwardDiff.Dual{ForwardDiff.Tag{var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, Float64}, Float64, 2}})\n", - " @ Main d:\\Articles\\EpistemicMessagePassing\\src\\FLSimulations\\update_rules\\DiscreteObservation.jl:112\n", - " [2] vector_mode_dual_eval!\n", - " @ C:\\Users\\tvdlaar\\.julia\\packages\\ForwardDiff\\wAaVJ\\src\\apiutils.jl:37 [inlined]\n", - " [3] vector_mode_jacobian(f::var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, Float64}, Float64, 2, Vector{ForwardDiff.Dual{ForwardDiff.Tag{var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, Float64}, Float64, 2}}})\n", - " @ ForwardDiff C:\\Users\\tvdlaar\\.julia\\packages\\ForwardDiff\\wAaVJ\\src\\jacobian.jl:148\n", - " [4] jacobian(f::Function, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, Float64}, Float64, 2, Vector{ForwardDiff.Dual{ForwardDiff.Tag{var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, Float64}, Float64, 2}}}, ::Val{true})\n", - " @ ForwardDiff C:\\Users\\tvdlaar\\.julia\\packages\\ForwardDiff\\wAaVJ\\src\\jacobian.jl:21\n", - " [5] jacobian(f::Function, x::Vector{Float64}, cfg::ForwardDiff.JacobianConfig{ForwardDiff.Tag{var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, Float64}, Float64, 2, Vector{ForwardDiff.Dual{ForwardDiff.Tag{var\"#g#13\"{Vector{Float64}, Matrix{Float64}, Vector{Float64}}, Float64}, Float64, 2}}}) (repeats 2 times)\n", - " @ ForwardDiff C:\\Users\\tvdlaar\\.julia\\packages\\ForwardDiff\\wAaVJ\\src\\jacobian.jl:19\n", - " [6] msgDiscreteObservationOut(d::Vector{Float64}, s_0::Vector{Float64}, A::Matrix{Float64}, c::Vector{Float64}, n_iterations::Int64)\n", - " @ Main d:\\Articles\\EpistemicMessagePassing\\src\\FLSimulations\\update_rules\\DiscreteObservation.jl:116\n", - " [7] ruleVBDiscreteObservationOut(msg_out::Message{Categorical, Univariate}, marg_out::Distribution{Univariate, Categorical}, marg_A::Distribution{MatrixVariate, PointMass}, marg_c::Distribution{Multivariate, PointMass}; n_iterations::Int64)\n", - " @ Main d:\\Articles\\EpistemicMessagePassing\\src\\FLSimulations\\update_rules\\DiscreteObservation.jl:74\n", - " [8] ruleVBDiscreteObservationOut\n", - " @ d:\\Articles\\EpistemicMessagePassing\\src\\FLSimulations\\update_rules\\DiscreteObservation.jl:69 [inlined]\n", - " [9] stepX1!(data::Dict{Any, Any}, marginals::Dict{Symbol, Distribution}, messages::Vector{Message})\n", - " @ Main .\\none:37\n", - " [10] stepX1!(data::Dict{Any, Any}, marginals::Dict{Symbol, Distribution})\n", - " @ Main .\\none:36\n", - " [11] top-level scope\n", - " @ d:\\Articles\\EpistemicMessagePassing\\src\\FLSimulations\\simple_planning.ipynb:15" - ] - } - ], - "source": [ - "n_its = 5\n", - "n_iits = 5\n", - "G = zeros(n_its*2)\n", - "p_0 = [0.9, 0.9]\n", - "p = Vector{Vector{Float64}}(undef, n_its*2) # Coordinates\n", - "\n", - "data = Dict()\n", - "\n", - "marginals = Dict{Symbol, ProbabilityDistribution}(\n", - " :x_1 => ProbabilityDistribution(Univariate, Categorical, p=[p_0[1], 1.0 - p_0[1]]),\n", - " :x_2 => ProbabilityDistribution(Univariate, Categorical, p=[p_0[2], 1.0 - p_0[2]]))\n", - "\n", - "for k=1:n_its\n", - " for l=1:n_iits\n", - " stepX1!(data, marginals)\n", - " end\n", - " p[2*k - 1] = [marginals[:x_1].params[:p][1], marginals[:x_2].params[:p][1]]\n", - " G[2*k - 1] = freeEnergy(data, marginals)\n", - " for l=1:n_iits\n", - " stepX2!(data, marginals)\n", - " end\n", - " p[2*k] = [marginals[:x_1].params[:p][1], marginals[:x_2].params[:p][1]]\n", - " G[2*k] = freeEnergy(data, marginals)\n", - "end\n", - ";\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlgAAAGQCAIAAAD9V4nPAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nO3dd3wUdf7H8W+ym2x6J6RIKEEQMFKFQDiaoFQpUqQ8NIeIiMgdFkTxd4cgXBHDqYCSQ7BL90CCEMBIUUroxVASCEkIJIGEtE3ZMr8/5vdbQ0hyQHazJt/X86+Z73xn9rPDDu9Md1AURQAAICtHexcAAIA9EYQAAKkRhAAAqRGEAACpEYQAAKkRhAAAqRGEAACpEYQAAKkRhAAAqRGEAACp1dcgLC8vP336tL2rsDKTyWTvEhoI1qS1mM1me5fQQCiKwsq0Fqtv4PU1CLOysoYMGWLvKqxMr9fbu4QGgjVpLaWlpfz3bRUmk6m8vNzeVTQQVt/A62sQAgBgFQQhAEBqBCEAQGoEIQBAarYKwo8//njSpEldu3ZNSEiosoPBYJg1a1aTJk3atWv35ZdfWtqPHDnSs2fP4ODgESNGZGZm2qg8AABUtgrCCxcuREZGXrt2LS8vr8oOMTEx+/fvP3ToUGxs7MyZM0+ePCmEKC8vf/LJJydMmPDrr78GBwdPnjzZRuUBAKCyVRAuWbJkxowZXl5e1XWIjY19++23Q0JCoqKinn766ZUrVwohvv/+e09Pz+nTp/v6+i5cuPDHH39MTU21UYUAAAh7nSMsKyu7fPlyx44d1dEOHTokJSUJIZKSkiyNfn5+TZo0OXfunF0qBABIQmuXT71586aiKJb9RW9v75ycHLXd09PT0s3Hx+fGjRvVLSQvL8/X19cyeujQoeDgYJuVXBeKiorsXUIDwZq0lpKSEoPB4OjIVXW1ZTQajUajwWCwdyENwT1t4G5ubhqNpuY+9glCNcAKCwt9fHyEEAUFBQEBAWr79evXLd3y8/P9/f2rW4iPj8+pU6cso97e3g1gc634dwBqgzVpFRqNxsXFpQFsWXanBqGLi4u9C2kgrLuB2+f37erqGhoa+uuvv6qjSUlJ4eHhQoiWLVtaGgsLCzMyMtT2Kjk4OPhWwLYKALgPtgqPa9euXbp0qby8PCsr69KlS6WlpUKIPXv2LFiwQO0QHR29ePHi0tLSS5cuffPNN9HR0UKI4cOHp6enb9myxWw2v//++507d27VqpWNKgQAQNguCF977bUBAwaYzebFixcPGDDg7NmzQoiMjIxDhw6pHd58801/f//AwMBHH330tdde69GjhxDC3d197dq1f/7znz09Pbdv37569WoblQcAgMpBURQ7fryiKA4ODnffbpGenh4VFZWWlmaz0uygsLCQM1tWwZq0Fr1ezzlCq+AcoRVZfQO38++7urSrOQUBALAW/tADAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEiNIAQASI0gBABIjSAEAEhNa6PlmkymxYsXf//99/7+/nPmzOnevXulDu+9915iYqJlNCgo6MMPPxRCzJo16+rVq2pj27Zt582bZ6MKAQAQtgvCmJiYr7/+OjY29vTp04MGDUpKSgoODq7YISoqqlmzZurwkiVLPD091eEdO3ZMmDChdevWQohGjRrZqDwAAFQ2CUJFUZYtW7Z8+fLIyMjIyMi4uLjPPvvszTffrNinR48e6kBJScnUqVPfe+89y6S+fftGRUXZojAAACqxSRDm5eVduXKlW7du6mi3bt2OHz9eXed169YFBgZaclEIsXDhQjc3t44dO86cOdOypwgAgC3YJAizsrIcHBx8fHzUUT8/v6ysrOo6r1q1asqUKQ4ODupodHR0eHi4oigff/zxpk2bDh486OTkVOWM+fn5HTt2tIxu3Lixvh9KLSoqsncJDQRr0lpKSkoMBoOjI1fV1ZbRaDQajQaDwd6FNAT3tIG7ublpNJqa+9gkCL28vBRFKSkp8fDwEEIUFxd7e3tX2fPixYsHDhxYs2aNpWX27NnqwJAhQ5o0abJv375+/fpVOa+7u/vKlSstow888ICz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3snJ6cSJEw899NDp06fV9nnz5sXFxR09evTo0aMXLlywUXkAAKhstUe4cOHCf/zjH1OmTFEUJTIycu3atX/84x8rdli/fr2Hh4c6rNfrP/3003/961/q6OzZs6OiomxUGAAAFdlkj7C4uPjw4cODBg0SQjg4OAwcOPDHH3+s1MeSgioXFxfL8A8//LBs2bIDBw7YojYAACqyyR5hZmamECIwMFAdbdy48f79+6vrvG/fvh07dpw4cUIdbdOmTV5eXm5u7vz580eMGLFixYrqZiwuLp4yZYpl9N133/Xx8bHOF7CT0tJSJycne1fRELAmraW0tFQI4ejIVXW1ZTQajUajvatoIO5pA3d2dv6vP2CbBKFGoxFCmM1mddRkMlVX9JkzZ8aOHbt69epmzZqpLRs3blQH5syZ89BDD73wwgudOnWqcl6tVtu5c2fLqIuLi/q59ZdGo6nvX+F3gjVpLeqaJAhrT1EURVH4WVrFPW3gDg4O/7WPTYIwODjYwcEhMzOzefPmQojMzMzg4OA7u50/f37gwIExMTEjR468c2pYWFiLFi0uXrxYXRDqdLoXX3zRupXbl5OTE/sxVsGatBZ1TRKEtefg4ODg4MDP0iqsvoHb5Pft6urar1+/TZs2CSEMBsP3338/ZMgQIURpaenBgwdNJpMQIjk5uX///n/961/Hjx9vmdFgMCiKog6npKSkpKQ89NBDtqgQAACVra4anTdv3pNPPnn+/Plz5875+PgMHz5cCHH58uXu3bvn5eX5+Pg899xzer1+3bp169atE0J07959/vz5J0+enDRpUrdu3RRF2bp16/Tp09u3b2+jCgEAEEI4WPbArC49PX337t1+fn4DBw50dnYWQuj1+sOHD/fs2VOr1R4+fLigoMDSuVGjRu3btzeZTImJiefPn9dqtR07dmzbtm0NC4+KikpLS7NR8XZRWFjo6elp7yoaAtaktej1ehcXFw6N1p56sUzFy+Nx36y+gdswCG2KIEQNWJPWQhBaC0FoRVbfwPl9AwCkRhACAKRGEAIApEYQAgCkRhACAKRGEAIApEYQAgCkRhACAKRGEAIApEYQAgCkRhACAKRGEAIApEYQAgCkRhACAKRGEAIApEYQAgCkRhACAKRGEAIApEYQAgCkRhACAKRGEAIApEYQAgCkRhACAKRGEAIApEYQAgCkRhACAKRG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", - "image/svg+xml": "\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "text/html": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plot(1:n_its*2, G, color=:black, grid=true, linewidth=2, legend=false, xlabel=\"Coordinate Increment\", ylabel=\"GFE [nats]\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Landscape" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "xs_1 = 0.0:0.1:1.0\n", - "m = length(xs_1)\n", - "xs_2 = 0.0:0.1:1.0\n", - "n = length(xs_2)\n", - "Gs = zeros(m, n)\n", - "for i = 1:m\n", - " for j = 1:n\n", - " data = Dict()\n", - "\n", - " p_x_1 = [xs_1[i], 1.0 - xs_1[i]]\n", - " m_x_1 = Distribution(Univariate, Categorical, p=p_x_1)\n", - " p_x_2 = [xs_2[j], 1.0 - xs_2[j]]\n", - " m_x_2 = Distribution(Univariate, Categorical, p=p_x_2)\n", - " marginals = Dict{Symbol, ProbabilityDistribution}(:x_1 => m_x_1, :x_2 => m_x_2)\n", - " Gs[i, j] = freeEnergy(data, marginals)\n", - " end\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "ename": "UndefRefError", - "evalue": "UndefRefError: access to undefined reference", - "output_type": "error", - "traceback": [ - "UndefRefError: access to undefined reference\n", - "\n", - "Stacktrace:\n", - " [1] getindex\n", - " @ .\\array.jl:805 [inlined]\n", - " [2] iterate (repeats 2 times)\n", - " @ .\\array.jl:781 [inlined]\n", - " [3] top-level scope\n", - " @ d:\\Articles\\EpistemicMessagePassing\\src\\FLSimulations\\simple_planning.ipynb:16" - ] - } - ], - "source": [ - "plt = plot(xs_1,\n", - " xs_2,\n", - " Gs',\n", - " st=:contour,\n", - " fill=true,\n", - " dpi=100,\n", - " aspect_ratio=:equal, \n", - " xlim=(-0.01,1.01), \n", - " ylim=(-0.01,1.01), \n", - " xlabel=\"x_1\",\n", - " ylabel=\"x_2\",\n", - " title=\"GFE [nats]\")\n", - "\n", - "p_1 = [p_0[1]]\n", - "p_2 = [p_0[2]]\n", - "for p_k in p\n", - " push!(p_1, p_k[1])\n", - " push!(p_2, p_k[2])\n", - "end\n", - "plot!(p_1, p_2, color=:green, marker=:o, linewidth=2, legend=false)\n", - "\n", - "for k=1:n_its*2+1\n", - " ann = (p_1[k], p_2[k], text(k-1, 12, :red, :center))\n", - " annotate!(ann, linecolor=:red)\n", - "end\n", - "\n", - "plt" - ] - } - ], - "metadata": { - "@webio": { - "lastCommId": "a2bcb982c5944cd58b530bf08df4f47d", - "lastKernelId": "24c0452e-5458-464f-9023-95b2e0fcac7e" - }, - "kernelspec": { - "display_name": "Julia 1.6.4", - "language": "julia", - "name": "julia-1.6" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.6.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/environment.jl b/src/Part2/FL/environment.jl deleted file mode 100644 index 20f6687..0000000 --- a/src/Part2/FL/environment.jl +++ /dev/null @@ -1,115 +0,0 @@ -using Random - -function constructABCD(α::Float64, c::Float64) - # Observation model - A_1 = [0.5 0.5; - 0.5 0.5; - 0.0 0.0; - 0.0 0.0] - - A_2 = [0.0 0.0; - 0.0 0.0; - α 1-α; - 1-α α ] - - A_3 = [0.0 0.0; - 0.0 0.0; - 1-α α ; - α 1-α] - - A_4 = [1.0 0.0; - 0.0 1.0; - 0.0 0.0; - 0.0 0.0] - - A = zeros(16, 8) - A[1:4, 1:2] = A_1 - A[5:8, 3:4] = A_2 - A[9:12, 5:6] = A_3 - A[13:16, 7:8] = A_4 - - # Transition model (with forced move back after reward-arm visit) - B_1 = kron([1 1 1 1; # Row: can I move to 1? - 0 0 0 0; - 0 0 0 0; - 0 0 0 0], I(2)) - - B_2 = kron([0 1 1 0; - 1 0 0 1; # Row: can I move to 2? - 0 0 0 0; - 0 0 0 0], I(2)) - - B_3 = kron([0 1 1 0; - 0 0 0 0; - 1 0 0 1; # Row: can I move to 3? - 0 0 0 0], I(2)) - - B_4 = kron([0 1 1 0; - 0 0 0 0; - 0 0 0 0; - 1 0 0 1], I(2)) # Row: can I move to 4? - - B = [B_1, B_2, B_3, B_4] - - # Goal prior - C = softmax(kron(ones(4), [0.0, 0.0, c, -c])) - - # Initial state prior - # Note: in the epistemic value paper (Friston, 2015) there is a softmax over D. - # However, from the context as described in the paper this appears to be a notational error. - D = kron([1.0, 0.0, 0.0, 0.0], [0.5, 0.5]) - - return (A, B, C, D) -end - -function generateGoalSequence(S::Int64) - rs = Vector{Vector}(undef, S) - for si=1:S - if rand() > 0.5 - rs[si] = [0, 1] - else - rs[si] = [1, 0] - end - end - - return rs -end - -function generateGoalSequence(seed::Int64, S::Int64) - Random.seed!(seed) - generateGoalSequence(S) -end - - -function initializeWorld(A, B, C, D, rs) - function reset(s) - x_0 = zeros(8) - x_0[1:2] = rs[s] - x_t_min = x_0 - o_t = A*x_0 - - return Int64(r'*[2, 3]) # Hidden reward position - end - - # Set reward position - r = [0, 1] - - # Initial state - x_0 = zeros(8) - x_0[1:2] = r # Start from position 1 - - # Execute a move to position a_t - x_t_min = x_0 - function execute(a_t::Int64) - x_t = B[a_t]*x_t_min # State transition - o_t = A*x_t # Observation - - x_t_min = x_t # Reset state for next step - end - - o_t = A*x_0 - observe() = sample(Distribution(Univariate, Categorical, p=o_t)) - - return (reset, execute, observe) -end -; \ No newline at end of file diff --git a/src/Part2/FL/factor_nodes/discrete_observation.jl b/src/Part2/FL/factor_nodes/discrete_observation.jl deleted file mode 100644 index 0a03249..0000000 --- a/src/Part2/FL/factor_nodes/discrete_observation.jl +++ /dev/null @@ -1,103 +0,0 @@ -using ForneyLab: SoftFactor, generateId, @ensureVariables, addNode!, associate!, removePrefix -import ForneyLab: slug, averageEnergy, requiresBreaker, breakerParameters, ApproximationMethod - -export DiscreteObservation - -abstract type EpistemicFactor <: SoftFactor end -abstract type Generalized <: ApproximationMethod end -abstract type Bethe <: ApproximationMethod end - -""" -Description: - - Composite node for discrete observation model - - out ∈ {0, 1}^d where Σ_k out_k = 1 - A ∈ R^{m × n} observation matrix - c ∈ R^m goal prior statistics - - f(y, s, A, c) - -Interfaces: - - 1. y (internal edge exposed) - 2. s - 3. A - 4. c - -Construction: - - DiscreteObservation{T}(id=:some_id) -""" -mutable struct DiscreteObservation{T<:ApproximationMethod} <: EpistemicFactor - id::Symbol - interfaces::Vector{Interface} - i::Dict{Symbol,Interface} - - n_factors::Int64 # Number of categories in s (for initialization) - n_iterations::Union{Int64, Nothing} # Number of Newton iterations - - function DiscreteObservation{T}(y, s, A, c; - id=generateId(DiscreteObservation), - n_factors=2, - n_iterations=nothing) where T<:ApproximationMethod - @ensureVariables(y, s, A, c) - self = new(id, Array{Interface}(undef, 4), Dict{Symbol,Interface}(), n_factors, n_iterations) - addNode!(currentGraph(), self) - self.i[:y] = self.interfaces[1] = associate!(Interface(self), y) - self.i[:s] = self.interfaces[2] = associate!(Interface(self), s) - self.i[:A] = self.interfaces[3] = associate!(Interface(self), A) - self.i[:c] = self.interfaces[4] = associate!(Interface(self), c) - - return self - end -end - -slug(::Type{DiscreteObservation{T}}) where T<:ApproximationMethod = "DO{$(removePrefix(T))}" - -# A breaker message is required if interface is partnered with a DO node out interface -requiresBreaker(interface::Interface, partner_interface::Interface, partner_node::DiscreteObservation{Generalized}) = (partner_interface == partner_node.interfaces[2]) - -breakerParameters(interface::Interface, partner_interface::Interface, partner_node::DiscreteObservation{Generalized}) = (Message{Categorical, Univariate}, (partner_node.n_factors,)) # Defaults to two factors - -# Average energy functionals -function averageEnergy(::Type{DiscreteObservation{Generalized}}, - ::Distribution{Univariate, Categorical}, # Unconstrained observation (not used) - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - marg_c::Distribution) - - s = unsafeMean(marg_s) - (A, amb_A) = unsafeMeanAmb(marg_A) - log_c = unsafeLogMean(marg_c) - - s'*amb_A - (A*s)'*log_c # + (A*s)'*safelog.(A*s) # Entropy term is included by algorithm -end - -function averageEnergy(::Type{DiscreteObservation{Bethe}}, - marg_y::Distribution{Univariate, Categorical}, # Unconstrained observation - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - marg_c::Distribution) - - y = unsafeMean(marg_y) - s = unsafeMean(marg_s) - log_A = unsafeLogMean(marg_A) - log_c = unsafeLogMean(marg_c) - - -y'*(log_A*s + log_c) # + y'*log_y # Entropy term is included by algorithm -end - -function averageEnergy(::Type{<:DiscreteObservation}, # Holds for Generalized and Bethe - marg_y::Distribution{Multivariate, PointMass}, # Constrained observation - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - marg_c::Distribution) - - y_hat = unsafeMean(marg_y) - s = unsafeMean(marg_s) - log_A = unsafeLogMean(marg_A) - log_c = unsafeLogMean(marg_c) - - -y_hat'*(log_A*s + log_c) -end diff --git a/src/Part2/FL/helpers.jl b/src/Part2/FL/helpers.jl deleted file mode 100644 index 1fa061e..0000000 --- a/src/Part2/FL/helpers.jl +++ /dev/null @@ -1,94 +0,0 @@ -using StatsFuns: gammainvcdf, loggamma -import ForneyLab: ruleSPEqualityDirichlet, sample, logPdf, sampleWeightsAndEntropy, sample, unsafeMean, unsafeLogMean, VariateType, differentialEntropy, softmax, tiny - -differentialEntropy(::Distribution{<:VariateType, PointMass}) = 0.0 # Define entropy of pointmass as zero - -# Edit: add tiny to x -logPdf(dist::Distribution{MatrixVariate, Dirichlet}, x) = sum(sum((dist.params[:a].-1).*log.(x .+ tiny),dims=1) - sum(loggamma.(dist.params[:a]), dims=1) + loggamma.(sum(dist.params[:a],dims=1))) - -# Custom update that outputs a Function message as result of Dirichlet-Function message product -ruleSPEqualityDirichlet(msg_1::Message{<:Function}, msg_2::Message{<:Dirichlet}, msg_3::Nothing) = Message(prodDirFn!(msg_1.dist, msg_2.dist)) -ruleSPEqualityDirichlet(msg_1::Message{<:Function}, msg_2::Nothing, msg_3::Message{<:Dirichlet}) = Message(prodDirFn!(msg_1.dist, msg_3.dist)) -ruleSPEqualityDirichlet(msg_1::Nothing, msg_2::Message{<:Function}, msg_3::Message{<:Dirichlet}) = Message(prodDirFn!(msg_2.dist, msg_3.dist)) -ruleSPEqualityDirichlet(msg_1::Message{<:Dirichlet}, msg_2::Message{<:Function}, msg_3::Nothing) = Message(prodDirFn!(msg_2.dist, msg_1.dist)) -ruleSPEqualityDirichlet(msg_1::Message{<:Dirichlet}, msg_2::Nothing, msg_3::Message{<:Function}) = Message(prodDirFn!(msg_3.dist, msg_1.dist)) -ruleSPEqualityDirichlet(msg_1::Nothing, msg_2::Message{<:Dirichlet}, msg_3::Message{<:Function}) = Message(prodDirFn!(msg_3.dist, msg_2.dist)) - -prodDirFn!(dist_fn::Distribution{MatrixVariate, Function}, dist_dir::Distribution{MatrixVariate, Dirichlet}) = - Distribution(MatrixVariate, Function, log_pdf=(A)->logPdf(dist_dir, A)+dist_fn.params[:log_pdf](A)) - -ruleSPEqualityDirichlet(msg_1::Message{<:Function}, msg_2::Message{<:Function}, msg_3::Nothing) = Message(prod!(msg_1.dist, msg_2.dist)) -ruleSPEqualityDirichlet(msg_1::Message{<:Function}, msg_2::Nothing, msg_3::Message{<:Function}) = Message(prod!(msg_1.dist, msg_3.dist)) -ruleSPEqualityDirichlet(msg_1::Nothing, msg_2::Message{<:Function}, msg_3::Message{<:Function}) = Message(prod!(msg_2.dist, msg_3.dist)) - -# Edit number of default samples -function sampleWeightsAndEntropy(x::Distribution, y::Distribution{<:VariateType, <:Function}) - n_samples = 10 # Number of samples is fixed - samples = sample(x, n_samples) - - # Apply log-pdf functions to the samples - log_samples_x = logPdf.([x], samples) - log_samples_y = logPdf.([y], samples) - - # Extract the sample weights - w_raw = exp.(log_samples_y) # Unnormalized weights - w_sum = sum(w_raw) - weights = w_raw./w_sum # Normalize the raw weights - - # Compute the separate contributions to the entropy - H_y = log(w_sum) - log(n_samples) - H_x = -sum( weights.*(log_samples_x + log_samples_y) ) - entropy = H_x + H_y - - # Inform next step about the proposal and integrand to be used in entropy calculation in smoothing - logproposal = (samples) -> logPdf.([x], samples) - logintegrand = (samples) -> logPdf.([y], samples) - - return (samples, weights, w_raw, logproposal, logintegrand, entropy) -end - -# Helper function to prevent log of 0 -safelog(x) = log(clamp(x,tiny,Inf)) - -# Ambiguity weight vector -amb(A) = -diag(A'*safelog.(A)) - -function sample(dist::Distribution{MatrixVariate, Dirichlet}) - A = dist.params[:a] - U = rand(size(A)...) - S = gammainvcdf.(A, 1.0, U) - - return S./sum(S, dims=1) # Normalize columns -end - -function unsafeLogMean(dist::Distribution{MatrixVariate, SampleList}) - sum = zeros(size(dist.params[:s][1])) - for i=1:length(dist.params[:s]) - sum = sum .+ log.(dist.params[:s][i] .+ tiny).*dist.params[:w][i] - end - return sum -end - -unsafeMeanAmb(dist::Distribution{MatrixVariate, PointMass}) = (dist.params[:m], amb(dist.params[:m])) - -function unsafeMeanAmb(dist::Distribution{MatrixVariate, Dirichlet}) - n_samples = 10 # Number of samples is fixed - s = sample(dist, n_samples) - (sum(s)./n_samples, sum(amb.(s))./n_samples) -end - -unsafeMeanAmb(dist::Distribution{MatrixVariate, SampleList}) = (sum(dist.params[:s].*dist.params[:w]), sum(amb.(dist.params[:s]).*dist.params[:w])) - -function softmax(v::Vector) - r = v .- maximum(v) - clamp!(r, -100.0, 0.0) - exp.(r)./sum(exp.(r)) -end - -# Symmetry breaking for initial statistics -function asym(n::Int64) - p = ones(n) .+ 1e-3*rand(n) - return p./sum(p) -end - -asym(A::Matrix) = A + 1e-2*rand(size(A)...) \ No newline at end of file diff --git a/src/Part2/FL/multi_T-maze_GFE.ipynb b/src/Part2/FL/multi_T-maze_GFE.ipynb deleted file mode 100644 index 30d7634..0000000 --- a/src/Part2/FL/multi_T-maze_GFE.ipynb +++ /dev/null @@ -1,817 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Interactive Simulation\n", - "\n", - "This notebook executes the action-perception loop for a discrete SSM." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra\n", - "using ForneyLab\n", - "using Plots\n", - "using ForwardDiff: hessian\n", - "using ProgressMeter\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|\n", - "\n", - "include(\"factor_nodes/discrete_observation.jl\")\n", - "include(\"update_rules/discrete_observation.jl\")\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generative Model" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [], - "source": [ - "fg = FactorGraph()\n", - "\n", - "u = Vector{Variable}(undef, 2)\n", - "x = Vector{Variable}(undef, 2)\n", - "y = Vector{Variable}(undef, 2)\n", - "\n", - "@RV x_0 ~ Categorical(placeholder(:D_s, dims=(8,)))\n", - "@RV A ~ Dirichlet(placeholder(:A_s, dims=(16,8)))\n", - "\n", - "x_k_min = x_0\n", - "for k=1:2\n", - " @RV u[k]\n", - " @RV x[k] ~ Transition(x_k_min, u[k])\n", - " placeholder(u[k], :u, index=k, dims=(8,8))\n", - " @RV y[k] ~ DiscreteObservation{Generalized}(x[k], A, # Choose Generalized or Bethe constraint\n", - " placeholder(:C, dims=(16,), var_id=:C_*k),\n", - " n_factors=8)\n", - " \n", - " x_k_min = x[k] # For next slice\n", - "end\n", - ";" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Algorithm" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [], - "source": [ - "q = PosteriorFactorization(y, [x_0; x], A, ids=[:Y, :X, :A])\n", - "algo = messagePassingAlgorithm(q, free_energy=true)\n", - "code = algorithmSourceCode(algo, free_energy=true)\n", - "initX() = Array{Message}(undef, 9) # Predefine\n", - "eval(Meta.parse(code)) # Overwrites initX for Generalized constraint\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [], - "source": [ - "# println(code)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Action-Perception Loop" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 30 # Number of trials\n", - "R = 100 # Number of runs\n", - "seed = 1234 # Randomizer seed\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32mProgress: 100%|█████████████████████████████████████████| Time: 1:21:41\u001b[39m\n" - ] - } - ], - "source": [ - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "include(\"visualizations.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "wins = [Vector{Float64}(undef, S) for ri=1:R]\n", - "params = Vector{Matrix}(undef, R)\n", - "\n", - "@showprogress for r=1:R\n", - " rs = generateGoalSequence(S) # Returns random goal sequence\n", - " (reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - " (infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - " # Step through the experimental protocol\n", - " As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - " Gs = [Vector{Matrix}(undef, 3) for s=1:S] # Free energy values per time\n", - " as = [Vector{Int64}(undef, 2) for s=1:S] # Actions per time\n", - " os = [Vector{Vector}(undef, 2) for s=1:S] # Observations (one-hot) per time\n", - " for s = 1:S\n", - " reset(s) # Reset world\n", - " for t=1:2\n", - " (Gs[s][t], _) = infer(t, as[s], os[s])\n", - " as[s][t] = act(t, Gs[s][t])\n", - " execute(as[s][t])\n", - " os[s][t] = observe()\n", - " end\n", - " (Gs[s][3], As[s]) = infer(3, as[s], os[s]) # Learn at t=3\n", - " end\n", - " wins[r] = extractWins(os)\n", - " params[r] = deepcopy(As[end])\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [], - "source": [ - "using FileIO, JLD2\n", - "FileIO.save(\"figures/wins.jld2\",\"wins\",wins,\"params\",params,\"R\",R,\"S\",S)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING: using Distributions.params in module Main conflicts with an existing identifier.\n" - ] - } - ], - "source": [ - "# Load data from file\n", - "using FileIO, JLD2, Plots, Statistics, Distributions\n", - "pairs = FileIO.load(\"figures/wins.jld2\")\n", - "wins = pairs[\"wins\"]\n", - "params = pairs[\"params\"]\n", - "R = pairs[\"R\"]\n", - "S = pairs[\"S\"]\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Binomial{Float64}(n=30, p=0.811)" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dist" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "# Fit Binomial\n", - "\n", - "win_counts = Int64.(sum.(wins))\n", - "dist = fit_mle(Binomial, S, win_counts)\n", - "p = Distributions.params(dist)[end]\n", - "f = pdf.(dist, 1:S).*R\n", - "f_ideal = pdf.(Binomial(S, α), 1:S).*R\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 65, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Plot histogram for number of wins per run\n", - "histogram(win_counts, bins=-1:1:S, \n", - " dpi=300,\n", - " size=(400,250),\n", - " color=:gray, \n", - " label=false, \n", - " xlabel=\"Wins per Run\", \n", - " ylabel=\"Run Count\",\n", - " legend=120,\n", - " xticks=((0:10:30).-0.5, 0:10:30))\n", - "\n", - "plot!((1:S).-0.5, f_ideal, linestyle=:dash, lw=2, color=:black, label=false)\n", - "\n", - "# savefig(\"figures/GFE_hist.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 66, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Plot average wins per trial\n", - "m = mean(wins)\n", - "\n", - "plot(1:S, m, ylim=(0,1),\n", - " dpi=300,\n", - " size=(400,250),\n", - " color=:black, \n", - " lw=2, \n", - " label=false, \n", - " xlabel=\"Simulation Trial (s)\", \n", - " ylabel=\"Win Average\")\n", - "plot!(1:S, α.*ones(S), color=:black, linestyle=:dash, lw=2, label=false, legend=0)\n", - "\n", - "# savefig(\"figures/GFE_wins.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [], - "source": [ - "# i_bot = findall(sum.(wins) .<= 20)" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [], - "source": [ - "# r = 40\n", - "# plotObservationStatistics(params[r], A_0, title=\"Score: $(round(mean(wins[r]), digits=2))\")" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [], - "source": [ - "# include(\"visualizations.jl\")\n", - "# for r=1:R\n", - "# plotObservationStatistics(params[r], A_0, title=\"Score: $(mean(wins[r]))\")\n", - "# savefig(\"figures/params_$r.png\")\n", - "# end\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "@webio": { - "lastCommId": null, - "lastKernelId": null - }, - "kernelspec": { - "display_name": "Julia 1.8.2", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/FL/update_rules/discrete_observation.jl b/src/Part2/FL/update_rules/discrete_observation.jl deleted file mode 100644 index 1e16144..0000000 --- a/src/Part2/FL/update_rules/discrete_observation.jl +++ /dev/null @@ -1,321 +0,0 @@ -import ForneyLab: collectSumProductNodeInbounds, collectNaiveVariationalNodeInbounds - -using ForneyLab: isClamped, assembleClamp!, unsafeMean, unsafeLogMean -using ForwardDiff: jacobian - -using LinearAlgebra: diag - - -#----------------------- -# Messages towards state -#----------------------- - -@naiveVariationalRule(:node_type => DiscreteObservation{Generalized}, - :outbound_type => Message{Categorical}, - :inbound_types => (Distribution, Nothing, Distribution, Distribution), - :name => VBDiscreteObservationGeneralizedS) - -@naiveVariationalRule(:node_type => DiscreteObservation{Bethe}, - :outbound_type => Message{Categorical}, - :inbound_types => (Distribution, Nothing, Distribution, Distribution), - :name => VBDiscreteObservationBetheS) - -# Generalized Unobserved -function ruleVBDiscreteObservationGeneralizedS( - ::Distribution{Univariate, Categorical}, # Unconstrained observation (not used) - msg_s::Message{Categorical, Univariate}, - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - marg_c::Distribution{Multivariate}; - n_iterations=20) - - d = msg_s.dist.params[:p] - s_0 = unsafeMean(marg_s) - (A, amb_A) = unsafeMeanAmb(marg_A) - log_c = unsafeLogMean(marg_c) - - # Root-finding problem for marginal statistics - g(s) = s - softmax(-amb_A + A'*log_c - A'*safelog.(A*s) + safelog.(d)) - - s_k = deepcopy(s_0) - for k=1:n_iterations - s_k = s_k - inv(jacobian(g, s_k))*g(s_k) # Newton step for multivariate root finding - end - - # Compute unnormalized outbound message statistics - rho = s_k./(d .+ 1e-6) - - Message(Univariate, Categorical, p=rho./sum(rho)) -end - -# Generalized Observed -function ruleVBDiscreteObservationGeneralizedS( - marg_y::Distribution{Multivariate, PointMass}, # Constrained observation - ::Message, # State message not used - ::Any, - marg_A::Distribution{MatrixVariate}, - ::Any; # Goal marginal not used - n_iterations=20) # Iterations not used - - y_hat = unsafeMean(marg_y) - log_A = unsafeLogMean(marg_A) - - Message(Univariate, Categorical, p=softmax(log_A'*y_hat)) -end - -# Bethe -function ruleVBDiscreteObservationBetheS( - marg_y::Distribution, # Observed and Unobserved - ::Any, - marg_A::Distribution{MatrixVariate}, - ::Any) # Goal marginal not used - - y = unsafeMean(marg_y) - log_A = unsafeLogMean(marg_A) - - Message(Univariate, Categorical, p=softmax(log_A'*y)) -end - - -#---------------------- -# Messages towards goal -#---------------------- - -@naiveVariationalRule(:node_type => DiscreteObservation{Generalized}, - :outbound_type => Message{Dirichlet}, - :inbound_types => (Distribution, Distribution, Distribution, Nothing), - :name => VBDiscreteObservationGeneralizedC) - -@naiveVariationalRule(:node_type => DiscreteObservation{Bethe}, - :outbound_type => Message{Dirichlet}, - :inbound_types => (Distribution, Distribution, Distribution, Nothing), - :name => VBDiscreteObservationBetheC) - -# Generalized Unobserved -function ruleVBDiscreteObservationGeneralizedC( - ::Distribution{Univariate, Categorical}, # Unconstrained observation (not used) - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - marg_c::Any) - - s = unsafeMean(marg_s) - A = unsafeMean(marg_A) - - Message(Multivariate, Dirichlet, a=A*s .+ 1) -end - -# Generalized Observed -function ruleVBDiscreteObservationGeneralizedC( - marg_y::Distribution{Multivariate, PointMass}, # Constrained observation - ::Any, # State marginal not used - ::Any, # Parameter marginal not used - ::Any) - - y_hat = unsafeMean(marg_y) - - Message(Multivariate, Dirichlet, a=y_hat .+ 1) -end - -# Bethe -function ruleVBDiscreteObservationBetheC( - marg_y::Distribution, # Observed and unobserved - ::Any, # State marginal not used - ::Any, # Parameter marginal not used - ::Any) - - y = unsafeMean(marg_y) - - Message(Multivariate, Dirichlet, a=y .+ 1) -end - - -#--------------------------- -# Messages towards parameter -#--------------------------- - -@naiveVariationalRule(:node_type => DiscreteObservation{Generalized}, - :outbound_type => Message{Dirichlet}, # Returns Function message in unconstrained case - :inbound_types => (Distribution, Distribution, Nothing, Distribution), - :name => VBDiscreteObservationGeneralizedA) - -@naiveVariationalRule(:node_type => DiscreteObservation{Bethe}, - :outbound_type => Message{Dirichlet}, - :inbound_types => (Distribution, Distribution, Nothing, Distribution), - :name => VBDiscreteObservationBetheA) - -# Generalized Unobserved -function ruleVBDiscreteObservationGeneralizedA( - ::Distribution{Univariate, Categorical}, # Unconstrained observation (not used) - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - marg_c::Distribution) - - s = unsafeMean(marg_s) - A = unsafeMean(marg_A) - log_c = unsafeLogMean(marg_c) - - log_mu_A(Z) = -s'*amb(Z) + (Z*s)'*log_c - (Z*s)'*safelog.(A*s) - - Message(MatrixVariate, Function, log_pdf=log_mu_A) # Returns Function message -end - -# Generalized Observed -function ruleVBDiscreteObservationGeneralizedA( - marg_y::Distribution{Multivariate, PointMass}, # Constrained observation - marg_s::Distribution{Univariate}, - ::Any, - ::Any) # Goal marginal not used - - y_hat = unsafeMean(marg_y) - s = unsafeMean(marg_s) - - Message(MatrixVariate, Dirichlet, a=y_hat*s' .+ 1) # Returns Dirichlet message -end - -# Bethe -function ruleVBDiscreteObservationBetheA( - marg_y::Distribution, # Observed and unobserved - marg_s::Distribution{Univariate}, - ::Any, - ::Any) # Goal marginal not used - - y = unsafeMean(marg_y) - s = unsafeMean(marg_s) - - Message(MatrixVariate, Dirichlet, a=y*s' .+ 1) -end - - -#----------------------------- -# Messages towards observation -#----------------------------- - -@naiveVariationalRule(:node_type => DiscreteObservation{Generalized}, - :outbound_type => Message{Categorical}, - :inbound_types => (Nothing, Distribution, Distribution, Distribution), - :name => VBDiscreteObservationGeneralizedY) - -@naiveVariationalRule(:node_type => DiscreteObservation{Bethe}, - :outbound_type => Message{Categorical}, - :inbound_types => (Nothing, Distribution, Distribution, Distribution), - :name => VBDiscreteObservationBetheY) - -# Generalized Unobserved -function ruleVBDiscreteObservationGeneralizedY( - ::Distribution{Univariate, Categorical}, - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - ::Any) # Goal marginal not used - - s = unsafeMean(marg_s) - A = unsafeMean(marg_A) - - Message(Univariate, Categorical, p=A*s) -end - -# Generalized Observed -function ruleVBDiscreteObservationGeneralizedY( - marg_y::Distribution{Multivariate, PointMass}, - ::Any, # State marginal not used - ::Any, # Parameter marginal not used - ::Any) # Goal marginal not used - - y_hat = unsafeMean(marg_y) - - Message(Multivariate, PointMass, m=y_hat) # Clamped marginal remains clamped -end - -# Bethe Unobserved -function ruleVBDiscreteObservationBetheY( - ::Distribution{Univariate, Categorical}, - marg_s::Distribution{Univariate}, - marg_A::Distribution{MatrixVariate}, - marg_c::Distribution) - - s = unsafeMean(marg_s) - log_A = unsafeLogMean(marg_A) - log_c = unsafeLogMean(marg_c) - - Message(Univariate, Categorical, p=softmax(log_A*s + log_c)) -end - -# Bethe Observed -function ruleVBDiscreteObservationBetheY( - marg_y::Distribution{Multivariate, PointMass}, - ::Any, # State marginal not used - ::Any, # Parameter marginal not used - ::Any) # Goal marginal not used - - y_hat = unsafeMean(marg_y) - - Message(Multivariate, PointMass, m=y_hat) # Clamped marginal remains clamped -end - - -#--------------------------- -# Custom inbounds collectors -#--------------------------- - -function collectNaiveVariationalNodeInbounds(node::DiscreteObservation{Generalized}, entry::ScheduleEntry) - algo = currentInferenceAlgorithm() - interface_to_schedule_entry = algo.interface_to_schedule_entry - target_to_marginal_entry = algo.target_to_marginal_entry - - inbounds = Any[] - for node_interface in entry.interface.node.interfaces - inbound_interface = ultimatePartner(node_interface) - if node_interface === entry.interface === node.interfaces[2] - # Outbound message for s: collect inbound message and marginal - push!(inbounds, interface_to_schedule_entry[inbound_interface]) - push!(inbounds, target_to_marginal_entry[node_interface.edge.variable]) - elseif node_interface === node.interfaces[1] - # Marginal for y is always included (for rule overloading) - push!(inbounds, target_to_marginal_entry[node_interface.edge.variable]) - elseif (node_interface === node.interfaces[3]) && !isClamped(inbound_interface) - # Marginal for A is always included (for dependency) - push!(inbounds, target_to_marginal_entry[node_interface.edge.variable]) - elseif node_interface === entry.interface - # Otherwise do not collect inbounds for remaining outbound messages - push!(inbounds, nothing) - elseif isClamped(inbound_interface) - # Hard-code marginal of constant node in schedule - push!(inbounds, assembleClamp!(inbound_interface.node, Distribution)) - else - # Collect entry from marginal schedule - push!(inbounds, target_to_marginal_entry[node_interface.edge.variable]) - end - end - - # Push custom arguments if defined - if (node.n_iterations !== nothing) - push!(inbounds, Dict{Symbol, Any}(:n_iterations => node.n_iterations, - :keyword => true)) - end - - return inbounds -end - -function collectNaiveVariationalNodeInbounds(node::DiscreteObservation{Bethe}, entry::ScheduleEntry) - algo = currentInferenceAlgorithm() - target_to_marginal_entry = algo.target_to_marginal_entry - - inbounds = Any[] - for node_interface in entry.interface.node.interfaces - inbound_interface = ultimatePartner(node_interface) - if node_interface === node.interfaces[1] - # Marginal for y is always included (for rule overloading) - push!(inbounds, target_to_marginal_entry[node_interface.edge.variable]) - elseif node_interface === entry.interface - # Ignore marginal of outbound edge - push!(inbounds, nothing) - elseif isClamped(inbound_interface) - # Hard-code marginal of constant node in schedule - push!(inbounds, assembleClamp!(inbound_interface.node, Distribution)) - else - # Collect entry from marginal schedule - push!(inbounds, target_to_marginal_entry[node_interface.edge.variable]) - end - end - - return inbounds -end diff --git a/src/Part2/FL/visualizations.jl b/src/Part2/FL/visualizations.jl deleted file mode 100644 index ea4bfab..0000000 --- a/src/Part2/FL/visualizations.jl +++ /dev/null @@ -1,206 +0,0 @@ -using LaTeXStrings -using SparseArrays - -function plotFreeEnergies(Gt::Vector, at::Vector, ot::Vector, r::Vector; title=title) - min1 = floor(minimum(skipmissing(Gt[1]))) - max1 = ceil(maximum(skipmissing(Gt[1]))) - min2 = floor(minimum(skipmissing(Gt[2]))) - max2 = ceil(maximum(skipmissing(Gt[2]))) - - p1 = plotG1(Gt[1], at, ot, r, clim=(min1,max1+0.5), title=title) - p2 = plotG2(Gt[2], at, clim=(min2,max2+0.5)) - - plot(p1, p2, layout=grid(2,1,heights=[0.8,0.2]), size=(300, 400), dpi=300) -end - -function plotG1(F::Matrix, at::Vector, ot::Vector, r::Vector; - clim=(4.0,8.0), title="", highlight=minimum) - ticks = ([1,2,3,4], ["O","L","R","C"]) - p = heatmap(F, - dpi=300, - color=:grays, - aspect_ratio=:equal, - colorbar=false, - xlim=(0.5,4.5), - ylim=(0.5,4.5), - title=title, - clim=clim, - xticks=false, - yticks=ticks, - xtickfontsize=12, - ytickfontsize=12, - xguidefontsize=14, - yguidefontsize=14) - - F_round = round.(F, digits=1) - if highlight !== nothing - extremum = highlight(skipmissing(F_round)) - else - extremum = NaN - end - - for i=1:4 - for j=1:4 - ismissing(F[i,j]) && continue - - # Annotate number - if F[i,j] >= clim[2]-0.3 - colour = :black - else - colour = :white - end - - if extremum == F_round[i,j] - ann = (j, i, text("$(F_round[i,j])*", 15, :red, :center)) # Annotate extremum - else - ann = (j, i, text(F_round[i,j], 15, colour, :center)) - end - annotate!(ann, linecolor=colour) - end - end - - obs_mask = kron(ones(Int64, 4), [1, 2, 3, 4]) - obs_dict = Dict{Int, String}(1 => "CL", - 2 => "CR", - 3 => "RW", - 4 => "NR") - sta_mask = kron([1, 2, 3, 4], ones(Int64, 4)) - sta_dict = Dict{Int, String}(1 => "O", - 2 => "L", - 3 => "R", - 4 => "C") - - obs = dot.([obs_mask], ot) # Observation - sta = dot.([sta_mask], ot) # State - - txt = join([sta_dict[s_t] for s_t in sta], " ") - ann = (3, 2.8, text(txt, 18, :black, :center)) - annotate!(ann, linecolor=:black) - - txt = join([obs_dict[o_t] for o_t in obs], " ") - ann = (3, 2.2, text(txt, 18, :black, :center)) - annotate!(ann, linecolor=:black) - - return p -end - -function plotG2(F::Matrix, at::Vector; clim=(4.0,8.0), title="", highlight=minimum) - ticks = ([1,2,3,4], ["O","L","R","C"]) - F = reshape(F[at[1], :], 1, 4) - p = heatmap(F, - dpi=300, - color=:grays, - aspect_ratio=:equal, - colorbar=false, - xlim=(0.5,4.5), - ylim=(0.5,1.5), - title=title, - clim=clim, - xticks=ticks, - yticks=([1.0], ticks[2][at[1]]), - xtickfontsize=12, - ytickfontsize=12, - xguidefontsize=14, - yguidefontsize=14) - - F_round = round.(F, digits=1) - if highlight !== nothing - extremum = highlight(skipmissing(F_round)) - else - extremum = NaN - end - - for j=1:4 - ismissing(F[j]) && continue - - # Annotate number - if F[j] >= clim[2]-0.3 - colour = :black - else - colour = :white - end - - if extremum == F_round[j] - ann = (j, 1, text("$(F_round[j])*", 15, :red, :center)) # Annotate extremum - else - ann = (j, 1, text(F_round[j], 15, colour, :center)) - end - annotate!(ann, linecolor=colour) - end - - return p -end - -function plotFreeEnergyMinimum(Gs, os; args...) - S = length(Gs) - - # Plot free energies over simulations - G1_mins = [minimum(skipmissing(Gs[s][1])) for s=1:S] - G2_mins = [minimum(skipmissing(Gs[s][2])) for s=1:S] - G3s = [minimum(skipmissing(Gs[s][3])) for s=1:S] - - empty_ticks = ([0,25,50,75,100],["","","","",""]) - p1 = plot(1:S, G1_mins, xticks=empty_ticks, ylabel="Free Energy Minimum [bits]", label="t=1", lw=2, linestyle=:dashdot; args...) - plot!(p1, 1:S, G2_mins, label="t=2", lw=2, linestyle=:dash) - plot!(p1, 1:S, G3s, label="t=3", lw=2) - - wins = extractWins(os) - p2 = scatter(1:S, 1 .- wins, xlabel="Simulation Trial (s)", yticks=([0, 1], ["win", "loss"]), color=:black, legend=false, ylim=(-0.1, 1.1), markersize=2.5) # Plot non-reward - - plot(p1, p2, layout=grid(2,1,heights=[0.8,0.2]), dpi=300) -end - -function extractWins(os) - win_mask = kron(ones(Int64, 4), [0,0,1,0]) - wins = Vector{Float64}(undef, S) - for s=1:S - win_1 = win_mask'*os[s][1] - win_2 = win_mask'*os[s][2] - wins[s] = win_1 + win_2 - end - - return wins -end - -function plotObservationStatistics(A::Matrix, A_0::Matrix; title="") - # Inspect difference in observation statistics - # dA = sparse(round.(A - A_0, digits=1)) - dA = Matrix{Union{Missing,Float64}}(A - A_0) - zs = (dA .< 0.01) - dA[zs] .= missing - dA_1 = dA[1:4, 1:2] - dA_2 = dA[5:8, 3:4] - dA_3 = dA[9:12, 5:6] - dA_4 = dA[13:16, 7:8] - cmax = maximum(skipmissing(dA)) - - yticks = ([1, 2, 3, 4], ["CL", "CR", "RW", "NR"]) - empty = ([1, 2, 3, 4], ["", "", "", ""]) - xticks = ([1, 2], ["RL", "RR"]) - cg = cgrad(:grays, rev = true) - p1 = heatmap(dA_1, title=L"O", yflip=true, c=cg, colorbar=false, clim=(0, 55), color=:grays, xticks=xticks, yticks=yticks) - p2 = heatmap(dA_2, title=L"L", yflip=true, c=cg, colorbar=false, clim=(0, 55), color=:grays, xticks=xticks, yticks=empty) - p3 = heatmap(dA_3, title=L"R", yflip=true, c=cg, colorbar=false, clim=(0, 55), color=:grays, xticks=xticks, yticks=empty) - p4 = heatmap(dA_4, title=L"C", yflip=true, c=cg, colorbar=false, clim=(0, 55), xticks=xticks, yticks=empty) - - for (px, dA_x) in [(p1,dA_1), (p2,dA_2), (p3,dA_3), (p4,dA_4)] - for i=1:4 - for j=1:2 - ismissing(dA_x[i,j]) && continue - - # Annotate number - if dA_x[i,j] <= 30 - colour = :black - else - colour = :white - end - - ann = (j, i, text(Int64(round(dA_x[i,j], digits=0)), 10, colour, :center)) - - annotate!(px, ann, linecolor=colour) - end - end - end - - plot(p1, p2, p3, p4, layout=grid(1,4,widths=[0.25,0.25,0.25,0.25]), size=(500,220), dpi=300, plot_title=title, plot_titlevspan=0.1) -end \ No newline at end of file diff --git a/src/Part2/Rx/.ipynb_checkpoints/T-maze_Aggregate-checkpoint.ipynb b/src/Part2/Rx/.ipynb_checkpoints/T-maze_Aggregate-checkpoint.ipynb deleted file mode 100644 index 438bef1..0000000 --- a/src/Part2/Rx/.ipynb_checkpoints/T-maze_Aggregate-checkpoint.ipynb +++ /dev/null @@ -1,680 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Aggregate Simulations with Generalized FE" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing\\src\\Part2\\Rx`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "using RxInfer, LinearAlgebra, ProgressMeter, Plots\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Agent" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "structured (generic function with 1 method)" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"goal_observation.jl\")\n", - "\n", - "# Define the generative model\n", - "@model function t_maze(A_s, D_s, x)\n", - " u = datavar(Matrix{Int64}, 2) # Policy for evaluations\n", - " z = randomvar(2) # Latent states\n", - " c = datavar(Vector{Float64}, 2) # Goal prior statistics\n", - "\n", - " z_0 ~ Categorical(D_s) # State prior\n", - " A ~ MatrixDirichlet(A_s) # Observation matrix prior\n", - "\n", - " z_k_min = z_0\n", - " for k=1:2\n", - " z[k] ~ Transition(z_k_min, u[k])\n", - " c[k] ~ GoalObservation(z[k], A) where {\n", - " meta=GeneralizedMeta(x[k]), \n", - " pipeline=GeneralizedPipeline(vague(Categorical,8))} # With breaker message\n", - "\n", - " z_k_min = z[k] # Reset for next slice\n", - " end\n", - "end\n", - "\n", - "# Define constraints on the variational density\n", - "@constraints function structured(approximate::Bool)\n", - " q(z_0, z, A) = q(z_0, z)q(A)\n", - " if approximate # Sampling approximation on parameter required for t<3\n", - " q(A) :: SampleList(20)\n", - " end\n", - "end" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Simulation" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32mProgress: 100%|█████████████████████████████████████████| Time: 1:42:38\u001b[39m\n" - ] - } - ], - "source": [ - "# Define experimental setting\n", - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "R = 100 # Number of runs\n", - "S = 30 # Number of trials\n", - "seed = 666 # Randomizer seed\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"visualizations.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "wins = [Vector{Float64}(undef, S) for ri=1:R]\n", - "params = Vector{Matrix}(undef, R)\n", - "\n", - "@showprogress for r=1:R\n", - " rs = generateGoalSequence(S) # Returns random goal sequence\n", - " (reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - " (infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - " # Step through the experimental protocol\n", - " As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - " Gs = [Vector{Matrix}(undef, 3) for s=1:S] # Free energy values per time\n", - " as = [Vector{Int64}(undef, 2) for s=1:S] # Actions per time\n", - " os = [Vector{Vector}(undef, 2) for s=1:S] # Observations (one-hot) per time\n", - " for s = 1:S\n", - " reset(s) # Reset world\n", - " for t=1:2\n", - " (Gs[s][t], _) = infer(t, as[s], os[s])\n", - " as[s][t] = act(t, Gs[s][t])\n", - " execute(as[s][t])\n", - " os[s][t] = observe()\n", - " end\n", - " (Gs[s][3], As[s]) = infer(3, as[s], os[s]) # Learn at t=3\n", - " end\n", - " wins[r] = extractWins(os)\n", - " params[r] = deepcopy(As[end])\n", - "end\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "using FileIO, JLD2\n", - "FileIO.save(\"figures/wins_$(R)_$(S).jld2\",\"wins\",wins,\"params\",params,\"R\",R,\"S\",S)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "# Load data from file\n", - "using FileIO, JLD2, Plots, Statistics, Distributions\n", - "pairs = FileIO.load(\"figures/wins_$(R)_$(S).jld2\")\n", - "wins = pairs[\"wins\"]\n", - "params = pairs[\"params\"]\n", - "R = pairs[\"R\"]\n", - "S = pairs[\"S\"]\n", - ";" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "win_counts = Int64.(sum.(wins))\n", - "f_ideal = pdf.(Binomial(S, α), 1:S).*R\n", - "\n", - "# Plot histogram for number of wins per run\n", - "histogram(win_counts, bins=-1:1:S, \n", - " dpi=300,\n", - " size=(400,250),\n", - " color=:gray, \n", - " label=false, \n", - " xlabel=\"Wins per Run\", \n", - " ylabel=\"Run Count\",\n", - " legend=120,\n", - " xticks=((0:10:30).-0.5, 0:10:30))\n", - "\n", - "plot!((1:S).-0.5, f_ideal, linestyle=:dash, lw=2, color=:black, label=false)\n", - "\n", - "# savefig(\"figures/GFE_hist.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12-element Vector{Int64}:\n", - " 3\n", - " 5\n", - " 18\n", - " 29\n", - " 35\n", - " 44\n", - " 53\n", - " 57\n", - " 74\n", - " 87\n", - " 88\n", - " 97" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Inspect failing runs\n", - "failing_runs = findall(sum.(wins).<20)" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Inspect learned parameters for a failing run\n", - "plotObservationStatistics(params[18], A_0)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/Rx/.ipynb_checkpoints/T-maze_Generalized-checkpoint.ipynb b/src/Part2/Rx/.ipynb_checkpoints/T-maze_Generalized-checkpoint.ipynb deleted file mode 100644 index e31020d..0000000 --- a/src/Part2/Rx/.ipynb_checkpoints/T-maze_Generalized-checkpoint.ipynb +++ /dev/null @@ -1,644 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# T-Maze Perception-Action Cycle with Generalized FE" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `c:\\Simulations\\EpistemicMessagePassing\\src\\Part2\\Rx`\n" - ] - } - ], - "source": [ - "using Pkg\n", - "Pkg.activate(\".\")\n", - "# Pkg.instantiate()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "using RxInfer, LinearAlgebra, Plots\n", - "\n", - "# T-maze layout\n", - "# [2| |3]\n", - "# | |\n", - "# |1|\n", - "# |4|" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Agent" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "structured (generic function with 1 method)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"goal_observation.jl\")\n", - "\n", - "# Define the generative model\n", - "@model function t_maze(A_s, D_s, x)\n", - " u = datavar(Matrix{Int64}, 2) # Policy for evaluations\n", - " z = randomvar(2) # Latent states\n", - " c = datavar(Vector{Float64}, 2) # Goal prior statistics\n", - "\n", - " z_0 ~ Categorical(D_s) # State prior\n", - " A ~ MatrixDirichlet(A_s) # Observation matrix prior\n", - "\n", - " z_k_min = z_0\n", - " for k=1:2\n", - " z[k] ~ Transition(z_k_min, u[k])\n", - " c[k] ~ GoalObservation(z[k], A) where {\n", - " meta=GeneralizedMeta(x[k]), \n", - " pipeline=GeneralizedPipeline(vague(Categorical,8))} # With breaker message\n", - "\n", - " z_k_min = z[k] # Reset for next slice\n", - " end\n", - "end\n", - "\n", - "# Define constraints on the variational density\n", - "@constraints function structured(approximate::Bool)\n", - " q(z_0, z, A) = q(z_0, z)q(A)\n", - " if approximate # Sampling approximation on parameter required for t<3\n", - " q(A) :: SampleList(20)\n", - " end\n", - "end" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Simulation" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Define experimental setting\n", - "α = 0.9; c = 2.0 # Reward probability and utility\n", - "S = 100 # Number of trials\n", - "seed = 666 # Randomizer seed\n", - "\n", - "include(\"helpers.jl\")\n", - "include(\"environment.jl\")\n", - "include(\"agent.jl\")\n", - "\n", - "(A, B, C, D) = constructABCD(α, c)\n", - "(A_0, D_0) = constructPriors() # Construct prior statistics for A and D\n", - "\n", - "rs = generateGoalSequence(seed, S) # Sets random seed and returns reproducible goal sequence\n", - "(reset, execute, observe) = initializeWorld(A, B, C, D, rs) # Let there be a world\n", - "(infer, act) = initializeAgent(A_0, B, C, D_0) # Let there be a constrained agent\n", - "\n", - "# Step through the experimental protocol\n", - "As = Vector{Matrix}(undef, S) # Posterior statistics for A\n", - "Gs = [Vector{Matrix}(undef, 3) for s=1:S] # Free energy values per time\n", - "as = [Vector{Int64}(undef, 2) for s=1:S] # Actions per time\n", - "os = [Vector{Vector}(undef, 2) for s=1:S] # Observations (one-hot) per time\n", - "for s = 1:S\n", - " reset(s) # Reset world\n", - " for t=1:2\n", - " (Gs[s][t], _) = infer(t, as[s], os[s])\n", - " as[s][t] = act(t, Gs[s][t])\n", - " execute(as[s][t])\n", - " os[s][t] = observe()\n", - " end\n", - " (Gs[s][3], As[s]) = infer(3, as[s], os[s]) # Learn at t=3\n", - "end\n", - ";" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Int64}:\n", - " 0\n", - " 99" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum([as[s].==rs[s]'*[2, 3] for s=1:S]) # Correct visits per timepoint" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotObservationStatistics(As[S], A_0)\n", - "# savefig(\"figures/GFE_A\")" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "include(\"visualizations.jl\")\n", - "plotFreeEnergyMinimum(Gs, os, legend=100, ylim=(5,25))\n", - "# savefig(\"figures/GFE_FE.png\")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# include(\"visualizations.jl\")\n", - "# for s=1:S\n", - "# plotFreeEnergies(Gs[s], as[s], os[s], rs[s], title=\"s=$s\")\n", - "# savefig(\"figures/GFE_$s.png\")\n", - "# end" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.8.5", - "language": "julia", - "name": "julia-1.8" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.8.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/Part2/Rx/Project.toml b/src/Part2/Rx/Project.toml deleted file mode 100644 index 8bdee4d..0000000 --- a/src/Part2/Rx/Project.toml +++ /dev/null @@ -1,12 +0,0 @@ -[deps] -DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf" -FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" -ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" -JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" -ReactiveMP = "a194aa59-28ba-4574-a09c-4a745416d6e3" -RxInfer = "86711068-29c9-4ff7-b620-ae75d7495b3d" -StatsFuns = "4c63d2b9-4356-54db-8cca-17b64c39e42c" -TupleTools = "9d95972d-f1c8-5527-a6e0-b4b365fa01f6" diff --git a/src/Part2/Rx/README.md b/src/Part2/Rx/README.md deleted file mode 100644 index a03b109..0000000 --- a/src/Part2/Rx/README.md +++ /dev/null @@ -1,35 +0,0 @@ -This file contains minimal instructions to get the accompanying demos running with Jupyter Notebook, Julia and RxInfer. - -# Install Julia -In order to install the Julia language (v1.8 or higher), follow the platform-specific instructions at https://julialang.org/downloads/platform.html - -# Install Jupyter Notebook -Jupyter notebook is a framework for running Julia (among other languages) in a browser environment. It is especially well suited for showing demo applications and interactive experimentation (i.e. playing around). In order to install Jupyter Notebook, follow the instructions at https://jupyter.readthedocs.io/en/latest/install.html - -# Install required packages -The demos require some packages to be imported in Julia. Open Julia -``` -$ julia -``` -and enter the package prompt by typing a closing bracket -``` -julia> ] -``` -Next, activate the virtual environment -``` -(v1.8) pkg> activate . -``` -and instantiate the required packages -``` -(Rx) pkg> instantiate -``` - -# Run the demo -Exit Julia, navigate to the root directory and start a Jupyter server -``` -~/Rx$ jupyter notebook -``` -A browser window will open, and you can select the demo you wish to run. - -# License -(c) 2023 BIASlab \ No newline at end of file diff --git a/src/Part2/Rx/distributions.jl b/src/Part2/Rx/distributions.jl deleted file mode 100644 index 33d50d0..0000000 --- a/src/Part2/Rx/distributions.jl +++ /dev/null @@ -1,108 +0,0 @@ -using DomainSets: Domain -using StatsFuns: gammainvcdf, loggamma -using ReactiveMP: AbstractContinuousGenericLogPdf, GenericLogPdfVectorisedProduct, UnspecifiedDomain, approximate_prod_with_sample_list -using RxInfer: AutoProposal, SampleListFormConstraint -using Random - -import Base: prod, rand, eltype, size -import Distributions: logpdf, mean -import Random: rand, rand! -import ReactiveMP: getdomain, getlogpdf -import RxInfer: __approximate - - -h(A) = -diag(A'*safelog.(A)) - -mean_h(d::PointMass) = (d.point, h(d.point)) - - -#------------------------------ -# ContinuousMatrixvariateLogPdf -#------------------------------ - -struct ContinuousMatrixvariateLogPdf{D <: Domain, F} <: AbstractContinuousGenericLogPdf - domain::D - logpdf::F -end - -ContinuousMatrixvariateLogPdf(f::Function) = ContinuousMatrixvariateLogPdf(UnspecifiedDomain(), f) - -getdomain(d::ContinuousMatrixvariateLogPdf) = d.domain -getlogpdf(d::ContinuousMatrixvariateLogPdf) = d.logpdf - - -#----------- -# SampleList -#----------- - -function __approximate(constraint::SampleListFormConstraint{N, R, S, M}, left::ContinuousMatrixvariateLogPdf, right) where {N, R, S <: AutoProposal, M} - return approximate_prod_with_sample_list(constraint.rng, constraint.method, right, left, N) -end - -function __approximate(constraint::SampleListFormConstraint{N, R, S, M}, left, right::ContinuousMatrixvariateLogPdf) where {N, R, S <: AutoProposal, M} - return approximate_prod_with_sample_list(constraint.rng, constraint.method, left, right, N) -end - -function __approximate(constraint::SampleListFormConstraint{N, R, S, M}, left::GenericLogPdfVectorisedProduct, right) where {N, R, S <: AutoProposal, M} - return approximate_prod_with_sample_list(constraint.rng, constraint.method, right, left, N) -end - -function __approximate(constraint::SampleListFormConstraint{N, R, S, M}, left, right::GenericLogPdfVectorisedProduct) where {N, R, S <: AutoProposal, M} - return approximate_prod_with_sample_list(constraint.rng, constraint.method, left, right, N) -end - -# These are hacks to make _rand! work with matrix variate logpfds -eltype(::GenericLogPdfVectorisedProduct) = Float64 -eltype(::ContinuousMatrixvariateLogPdf) = Float64 - -function mean_h(d::SampleList) - s = get_samples(d) - w = get_weights(d) - - return (sum(s.*w), sum(h.(s).*w)) -end - - -#---------------- -# MatrixDirichlet -#---------------- - -size(d::MatrixDirichlet) = size(d.a) - -function logpdf(d::MatrixDirichlet, x::AbstractMatrix) - return sum(sum((d.a.-1).*log.(x),dims=1) - sum(loggamma.(d.a), dims=1) + loggamma.(sum(d.a,dims=1))) -end - -# Average energy definition for SampleList marginal -@average_energy MatrixDirichlet (q_out::SampleList, q_a::PointMass) = begin - H = mapreduce(+, zip(eachcol(mean(q_a)), eachcol(mean(log, q_out)))) do (q_a_column, logmean_q_out_column) - return -loggamma(sum(q_a_column)) + sum(loggamma.(q_a_column)) - sum((q_a_column .- 1.0) .* logmean_q_out_column) - end - return H -end - -# In-place operations for sampling -function rand!(rng::AbstractRNG, d::MatrixDirichlet, container::Array{Float64, 3}) - s = size(d) - for i in 1:size(container, 3) - M = view(container, :, :, i) - sample = rand(rng, d) - copyto!(M, sample) - end - - return container -end - -# Custom sampling implementation -function rand(rng::AbstractRNG, d::MatrixDirichlet) - U = rand(rng, size(d.a)...) - S = gammainvcdf.(d.a, 1.0, U) - return S./sum(S, dims=1) # Normalize columns -end - -function mean_h(d::MatrixDirichlet) - n_samples = 20 # Fixed number of samples - s = [rand(d) for i=1:n_samples] - - return (sum(s)./n_samples, sum(h.(s))./n_samples) -end \ No newline at end of file diff --git a/src/forward/forward_transition.jl b/src/forward/forward_transition.jl deleted file mode 100644 index 4e056a9..0000000 --- a/src/forward/forward_transition.jl +++ /dev/null @@ -1,82 +0,0 @@ -""" -Contains modified rules for the transition node to block backwards flow of messages. -Useful for replicating the standard AIF algorithm in Reactive -""" - -struct ForwardOnlyMeta end - -# Incoming edges -@rule Transition(:in, Marginalisation) (q_out::Any, q_a::MatrixDirichlet, meta::ForwardOnlyMeta) = begin - return missing -end - -@rule Transition(:in, Marginalisation) (m_out::Categorical, q_a::MatrixDirichlet, meta::ForwardOnlyMeta) = begin - return missing -end - -@rule Transition(:in, Marginalisation) (m_out::Categorical, q_a::PointMass, meta::ForwardOnlyMeta) = begin - return missing -end - -@rule Transition(:in, Marginalisation) (q_out::PointMass, q_a::PointMass, meta::ForwardOnlyMeta) = begin - return missing -end - -@rule Transition(:in, Marginalisation) (m_out::Categorical, m_a::PointMass, meta::ForwardOnlyMeta) = begin - return missing -end - -@rule Transition(:in, Marginalisation) (m_out::Missing, q_a::PointMass, meta::ForwardOnlyMeta) = begin - return missing -end - -@marginalrule Transition(:out_in) (m_out::Missing, m_in::DiscreteNonParametric, q_a::PointMass, meta::ForwardOnlyMeta) = - begin - return missing -end - - -# Outgoing edges -@rule Transition(:out, Marginalisation) (q_in::Categorical, q_a::MatrixDirichlet, meta::ForwardOnlyMeta) = begin - return @call_rule Transition(:out, Marginalisation) (q_in = q_in, q_a = q_a) -end - -@rule Transition(:out, Marginalisation) (m_in::Categorical, q_a::MatrixDirichlet, meta::ForwardOnlyMeta) = begin - return @call_rule Transition(:out, Marginalisation) (m_in = m_in, q_a = q_a) -end - -@rule Transition(:out, Marginalisation) (m_in::DiscreteNonParametric, q_a::PointMass, meta::Any) = begin - return @call_rule Transition(:out, Marginalisation) (m_in = m_in, m_a = q_a, meta = meta) -end - -@rule Transition(:out, Marginalisation) (q_in::PointMass, q_a::PointMass, meta::ForwardOnlyMeta) = begin - return @call_rule Transition(:out, Marginalisation) (q_in = q_in, q_a = q_a) -end - -@rule Transition(:out, Marginalisation) (m_in::Categorical, m_a::PointMass, meta::ForwardOnlyMeta) = begin - return @call_rule Transition(:out, Marginalisation) (m_in = m_in, m_a = m_a) -end - - -# Edge towards transition matrix -@rule Transition(:a, Marginalisation) (q_out::Any, q_in::Categorical, meta::ForwardOnlyMeta) = begin - return @call_rule Transition(:a, Marginalisation) (q_out = q_out, q_in = q_in) -end - -# TODO: Fix this rule -#@rule Transition(:a, Marginalisation) (q_out_in::Contingency, meta::ForwardOnlyMeta) = begin -# return @call_rule Transition(:a, Marginalisation) (q_out_in = q_out_in) -#end - -# Marginals -@marginalrule Transition(:out_in) (m_out::Categorical, m_in::Categorical, q_a::MatrixDirichlet, meta::ForwardOnlyMeta) = begin - return @call_marginalrule Transition(:out_in) (m_out = m_out, m_in = m_in, q_a = q_a) -end - -@marginalrule Transition(:out_in) (m_out::Categorical, m_in::Categorical, q_a::PointMass, meta::ForwardOnlyMeta) = begin - return @call_marginalrule Transition(:out_in) (m_out = m_out, m_in = m_in, q_a = q_a) -end - -@marginalrule Transition(:out_in_a) (m_out::Categorical, m_in::Categorical, m_a::PointMass, meta::ForwardOnlyMeta) = begin - return @call_marginalrule Transition(:out_in_a) (m_out = m_out, m_in = m_in, m_a = m_a) -end