diff --git a/benchmarks/Linear Multivariate Gaussian State Space Model Benchmark.ipynb b/benchmarks/Linear Multivariate Gaussian State Space Model Benchmark.ipynb index ea41440ad..b8071ef9b 100644 --- a/benchmarks/Linear Multivariate Gaussian State Space Model Benchmark.ipynb +++ b/benchmarks/Linear Multivariate Gaussian State Space Model Benchmark.ipynb @@ -220,7 +220,7 @@ "function reactivemp_inference_smoothing(observations, A, B, P, Q)\n", " n = length(observations) \n", " \n", - " result = inference(\n", + " result = infer(\n", " model = linear_gaussian_ssm_smoothing(n, A, B, P, Q),\n", " data = (y = observations, ),\n", " options = (limit_stack_depth = 500, )\n", @@ -237,7 +237,7 @@ " x_min_t_mean, x_min_t_cov = mean_cov(q(x_t))\n", " end\n", " \n", - " result = rxinference(\n", + " result = infer(\n", " model = linear_gaussian_ssm_filtering(A, B, P, Q),\n", " data = (y_t = observations, ),\n", " autoupdates = autoupdates,\n", diff --git a/benchmarks/Tiny Benchmark.ipynb b/benchmarks/Tiny Benchmark.ipynb index 7d4a5fa7a..c656d301a 100644 --- a/benchmarks/Tiny Benchmark.ipynb +++ b/benchmarks/Tiny Benchmark.ipynb @@ -121,7 +121,7 @@ " x_prior_mean, x_prior_var = mean_var(q(x_next))\n", " end\n", "\n", - " return rxinference(\n", + " return infer(\n", " model = filtering(c = 1.0, v = v),\n", " datastream = datastream,\n", " autoupdates = autoupdates,\n", @@ -460,7 +460,7 @@ ], "source": [ "function run_smoothing(data, n, v)\n", - " return inference(\n", + " return infer(\n", " model = smoothing(n, c = 1.0, v = v), \n", " data = (y = data, ), \n", " returnvars = KeepLast(),\n", diff --git a/docs/make.jl b/docs/make.jl index 529326f7a..da03de180 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -115,7 +115,7 @@ makedocs(; "Model specification" => "manuals/model-specification.md", "Constraints specification" => "manuals/constraints-specification.md", "Meta specification" => "manuals/meta-specification.md", - "Inference specification" => ["Overview" => "manuals/inference/overview.md", "Static dataset" => "manuals/inference/inference.md", "Real-time dataset / reactive inference" => "manuals/inference/rxinference.md", "Inference results postprocessing" => "manuals/inference/postprocess.md", "Manual inference specification" => "manuals/inference/manual.md"], + "Inference specification" => ["Overview" => "manuals/inference/overview.md", "Static vs Streamline inference" => "manuals/inference/infer.md", "Inference results postprocessing" => "manuals/inference/postprocess.md", "Manual inference specification" => "manuals/inference/manual.md"], "Inference customization" => ["Defining a custom node and rules" => "manuals/custom-node.md"], "Debugging" => "manuals/debugging.md", "Delta node" => "manuals/delta-node.md" diff --git a/docs/src/library/bethe-free-energy.md b/docs/src/library/bethe-free-energy.md index dd9b2ba3d..9fec6ee7c 100644 --- a/docs/src/library/bethe-free-energy.md +++ b/docs/src/library/bethe-free-energy.md @@ -53,7 +53,7 @@ which internalizes the factors of the model. The last two terms specify entropi Crucially, the BFE can be iteratively optimized for each individual variational distribution in turn. Optimization of the BFE is thus more manageable than direct optimization of the VFE. -For iterative optimization of the BFE, the variational distributions must first be initialized. The `initmarginals` keyword argument to the [`inference`](@ref) and [`rxinference`](@ref) functions initializes the variational distributions of the BFE. +For iterative optimization of the BFE, the variational distributions must first be initialized. The `initmarginals` keyword argument to the [`infer`](@ref) function initializes the variational distributions of the BFE. For disambiguation, note that the initialization of the variational distribution is a different design consideration than the choice of priors. A prior specifies a factor in the model definition, while initialization concerns factors in the variational distribution. diff --git a/docs/src/manuals/constraints-specification.md b/docs/src/manuals/constraints-specification.md index 86e557e06..12ec40c43 100644 --- a/docs/src/manuals/constraints-specification.md +++ b/docs/src/manuals/constraints-specification.md @@ -162,4 +162,4 @@ end model, returnval = create_model(my_model(arguments...); constraints = constraints) ``` -Alternatively, it is possible to use constraints directly in the automatic [`inference`](@ref) and [`rxinference`](@ref) functions that accepts `constraints` keyword argument. \ No newline at end of file +Alternatively, it is possible to use constraints directly in the automatic [`infer`](@ref) function that accepts `constraints` keyword argument. \ No newline at end of file diff --git a/docs/src/manuals/custom-node.md b/docs/src/manuals/custom-node.md index db34b8e04..be8f3e5c0 100644 --- a/docs/src/manuals/custom-node.md +++ b/docs/src/manuals/custom-node.md @@ -279,7 +279,7 @@ end Finally, we can run inference with this model and the generated dataset: ```@example create-node -result_mybernoulli = inference( +result_mybernoulli = infer( model = coin_model_mybernoulli(length(dataset)), data = (y = dataset, ), ) @@ -312,7 +312,7 @@ As a sanity check, we can create the same model with the `RxInfer` built-in node end -result_bernoulli = inference( +result_bernoulli = infer( model = coin_model(length(dataset)), data = (y = dataset, ), ) diff --git a/docs/src/manuals/debugging.md b/docs/src/manuals/debugging.md index 322ec5498..ac1a3c1e6 100644 --- a/docs/src/manuals/debugging.md +++ b/docs/src/manuals/debugging.md @@ -36,7 +36,7 @@ dataset = convert.(Int64, rand(Bernoulli(θ_real), n)) end -result = inference( +result = infer( model = coin_model(length(dataset)), data = (x = dataset, ), ); @@ -56,7 +56,7 @@ vline!([θ_real], label="Real θ", title = "Inference results") We can figure out what's wrong by looking at the Memory Addon. To obtain the trace, we have to add `addons = (AddonMemory(),)` as an argument to the inference function. ```@example addoncoin -result = inference( +result = infer( model = coin_model(length(dataset)), data = (x = dataset, ), addons = (AddonMemory(),) @@ -93,7 +93,7 @@ All the observations (purple, green, pink, blue) have much smaller rate paramete end -result = inference( +result = infer( model = coin_model(length(dataset)), data = (x = dataset, ), ); diff --git a/docs/src/manuals/delta-node.md b/docs/src/manuals/delta-node.md index 313d127af..d9f5530ea 100644 --- a/docs/src/manuals/delta-node.md +++ b/docs/src/manuals/delta-node.md @@ -63,7 +63,7 @@ end To execute the inference procedure: ```@example delta_node_example -inference(model = delta_node_example(), meta=delta_meta, data = (z = 1.0,)) +infer(model = delta_node_example(), meta=delta_meta, data = (z = 1.0,)) ``` This methodology is consistent even when the delta node is associated with multiple nodes. For instance: diff --git a/docs/src/manuals/getting-started.md b/docs/src/manuals/getting-started.md index 59fad5b62..c17140172 100644 --- a/docs/src/manuals/getting-started.md +++ b/docs/src/manuals/getting-started.md @@ -121,7 +121,7 @@ As you can see, `RxInfer` offers a model specification syntax that resembles clo Once we have defined our model, the next step is to use `RxInfer` API to infer quantities of interests. To do this we can use a generic `inference` function that supports static datasets. ```@example coin -result = inference( +result = infer( model = coin_model(length(dataset)), data = (y = dataset, ) ) diff --git a/docs/src/manuals/inference/infer.md b/docs/src/manuals/inference/infer.md new file mode 100644 index 000000000..4b1e7facc --- /dev/null +++ b/docs/src/manuals/inference/infer.md @@ -0,0 +1,17 @@ +# [Automatic Inference Specification](@id user-guide-inference) + +`RxInfer` provides the `infer` function for quickly running and testing your model with both static and streaming datasets. To enable streaming behavior, the `infer` function accepts an `autoupdates` argument, which specifies how to update your priors for future states based on newly updated posteriors. + +It's important to note that while this function covers most capabilities of the inference engine, advanced use cases may require resorting to the [Manual Inference Specification](@ref user-guide-inference-execution-manual-specification). + +For details on manual inference specification, see the [Manual Inference](@ref user-guide-manual-inference) section. + +```@docs +infer +InferenceResult +RxInfer.start +RxInfer.stop +@autoupdates +RxInferenceEngine +RxInferenceEvent +``` \ No newline at end of file diff --git a/docs/src/manuals/inference/inference.md b/docs/src/manuals/inference/inference.md deleted file mode 100644 index 9132db198..000000000 --- a/docs/src/manuals/inference/inference.md +++ /dev/null @@ -1,11 +0,0 @@ -# [Automatic inference specification on static datasets](@id user-guide-inference) - -`RxInfer` exports the `inference` function to quickly run and test you model with static datasets. Note, however, that this function does cover almost all capabilities of the inference engine, but for advanced use cases you may want to resort to the [manual inference specification](@ref user-guide-inference-execution-manual-specification). - -For running inference on real-time datasets see the [Reactive Inference](@ref user-guide-rxinference) section. -For manual inference specification see the [Manual Inference](@ref user-guide-manual-inference) section. - -```@docs -inference -InferenceResult -``` diff --git a/docs/src/manuals/inference/overview.md b/docs/src/manuals/inference/overview.md index 51445b92d..44672b013 100644 --- a/docs/src/manuals/inference/overview.md +++ b/docs/src/manuals/inference/overview.md @@ -11,12 +11,12 @@ The inference engine itself isn't aware of different algorithm types and simply ## [Automatic inference specification on static datasets](@id user-guide-inference-execution-automatic-specification-static) -`RxInfer` exports the `inference` function to quickly run and test you model with static datasets. See more information about the `inference` function on the separate [documentation section](@ref user-guide-inference). +`RxInfer` exports the `infer` function to quickly run and test you model with static datasets. See more information about the `infer` function on the separate [documentation section](@ref user-guide-inference). ## [Automatic inference specification on real-time datasets](@id user-guide-inference-execution-automatic-specification-realtime) -`RxInfer` exports the `rxinference` function to quickly run and test you model with dynamic and potentially real-time datasets. See more information about the `rxinference` function on the separate [documentation section](@ref user-guide-rxinference). +`RxInfer` supports running inference the with dynamic and potentially real-time datasets with enabled `autoupdates` keyword. See more information about the `infer` function on the separate [documentation section](@ref user-guide-inference). ## [Manual inference specification](@id user-guide-inference-execution-manual-specification) -While both `inference` and `rxinference` use most of the `RxInfer` inference engine capabilities in some situations it might be beneficial to write inference code manually. The [Manual inference](@ref user-guide-manual-inference) documentation section explains how to write your custom inference routines. \ No newline at end of file +While `infer` uses most of the `RxInfer` inference engine capabilities in some situations it might be beneficial to write inference code manually. The [Manual inference](@ref user-guide-manual-inference) documentation section explains how to write your custom inference routines. \ No newline at end of file diff --git a/docs/src/manuals/inference/postprocess.md b/docs/src/manuals/inference/postprocess.md index 3ca6910c5..681c5ae92 100644 --- a/docs/src/manuals/inference/postprocess.md +++ b/docs/src/manuals/inference/postprocess.md @@ -1,7 +1,6 @@ # [Inference results postprocessing](@id user-guide-inference-postprocess) -Both [`inference`](@ref) and [`rxinference`](@ref) allow users to postprocess -the inference result with the `postprocess = ...` keyword argument. The inference engine +[`infer`](@ref) allow users to postprocess the inference result with the `postprocess = ...` keyword argument. The inference engine operates on __wrapper__ types to distinguish between marginals and messages. By default these wrapper types are removed from the inference results if no addons option is present. Together with the enabled addons, however, the wrapper types are preserved in the diff --git a/docs/src/manuals/inference/rxinference.md b/docs/src/manuals/inference/rxinference.md deleted file mode 100644 index 256a5e4f1..000000000 --- a/docs/src/manuals/inference/rxinference.md +++ /dev/null @@ -1,15 +0,0 @@ -# [Automatic inference specification on real-time datasets](@id user-guide-rxinference) - -`RxInfer` exports the `rxinference` function to quickly run and test you model with dynamic and potentially real-time datasets. Note, however, that this function does cover almost all capabilities of the __reactive__ inference engine, but for advanced use cases you may want to resort to the [manual inference specification](@ref user-guide-inference-execution-manual-specification). - -For running inference on static datasets see the [Static Inference](@ref user-guide-inference) section. -For manual inference specification see the [Manual Inference](@ref user-guide-manual-inference) section. - -```@docs -rxinference -RxInfer.start -RxInfer.stop -@autoupdates -RxInferenceEngine -RxInferenceEvent -``` \ No newline at end of file diff --git a/docs/src/manuals/meta-specification.md b/docs/src/manuals/meta-specification.md index c0f1d0f1b..e50d68cdc 100644 --- a/docs/src/manuals/meta-specification.md +++ b/docs/src/manuals/meta-specification.md @@ -90,16 +90,10 @@ end model, returnval = create_model(my_model(arguments...); meta = my_meta) ``` -Alternatively, it is possible to use meta directly in the automatic [`inference`](@ref) and [`rxinference`](@ref) functions that accepts `meta` keyword argument: +Alternatively, it is possible to use meta directly in the automatic [`infer`](@ref) function that accepts `meta` keyword argument: ```julia -inferred_result = inference( - model = my_model(arguments...), - meta = my_meta, - ... -) - -inferred_result = rxinference( +inferred_result = infer( model = my_model(arguments...), meta = my_meta, ... @@ -116,7 +110,7 @@ inferred_result = rxinference( ... end ``` -If you add node-specific meta to your model this way, then you do not need to use the `meta` keyword argument in the `inference` and `rxinference` functions. +If you add node-specific meta to your model this way, then you do not need to use the `meta` keyword argument in the `infer` function. ## Create your own meta @@ -179,7 +173,7 @@ y_data = 4.0 end #do inference -inference_result = inference( +inference_result = infer( model = gaussian_model(), data = (y = y_data,) ) diff --git a/examples/advanced_examples/Active Inference Mountain car.ipynb b/examples/advanced_examples/Active Inference Mountain car.ipynb index cf50442b5..61fceb4b2 100644 --- a/examples/advanced_examples/Active Inference Mountain car.ipynb +++ b/examples/advanced_examples/Active Inference Mountain car.ipynb @@ -11,17 +11,61 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "fcbc7485", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/.julia/dev/RxInfer/examples`\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m\u001b[1mPrecompiling\u001b[22m\u001b[39m " + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "project...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m ✓ \u001b[39m\u001b[90mShiftedArrays\u001b[39m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m ✓ \u001b[39m\u001b[90mStatsModels\u001b[39m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m ✓ \u001b[39mGLM\n", + " 3 dependencies successfully precompiled in 6 seconds. 374 already precompiled.\n" + ] + } + ], "source": [ "import Pkg; Pkg.activate(\"..\"); Pkg.instantiate();" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "5e3fda93", "metadata": {}, "outputs": [], @@ -69,10 +113,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "49986f41", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "create_world (generic function with 1 method)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "import HypergeometricFunctions: _₂F₁\n", "\n", @@ -142,10 +196,122 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "78a3026d", "metadata": {}, - "outputs": [], + "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" + ], + "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" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "engine_force_limit = 0.04\n", "friction_coefficient = 0.1\n", @@ -179,7 +345,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "02e7940f", "metadata": {}, "outputs": [], @@ -343,7 +509,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "037c0d5b", "metadata": {}, "outputs": [], @@ -418,18 +584,28 @@ "3. **Slide**:\n", " After updating its internal belief, the agent moves to the next time step and uses the inferred action $u_t$ in the previous time step to interact with the environment. \n", "\n", - "In the cell below, we create the agent through the `create_agent` function, which includes `infer`, `act`, `slide` and `future` functions:\n", + "In the cell below, we create the agent through the `create_agent` function, which includes `compute`, `act`, `slide` and `future` functions:\n", "- The `act` function selects the next action based on the inferred policy. On the other hand, the `future` function predicts the next $T$ positions based on the current action. These two function implement the **Act-Execute-Observe** phase.\n", - "- The `infer` function infers the policy (which is a set of actions for the next $T$ time steps) and the agent's state using the agent internal model. This function implements the **Infer** phase.\n", + "- The `compute` function infers the policy (which is a set of actions for the next $T$ time steps) and the agent's state using the agent internal model. This function implements the **Infer** phase. We call it `compute` to avoid the clash with the `infer` function of `RxInfer.jl`.\n", "- The `slide` function implements the **Slide** phase, which moves the agent internal model to the next time step." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "42b9d130", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "create_agent (generic function with 1 method)" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# We are going to use some private functionality from ReactiveMP, \n", "# in the future we should expose a proper API for this\n", @@ -454,7 +630,7 @@ "\n", " # The `infer` function is the heart of the agent\n", " # It calls the `RxInfer.inference` function to perform Bayesian inference by message passing\n", - " infer = (upsilon_t::Float64, y_hat_t::Vector{Float64}) -> begin\n", + " compute = (upsilon_t::Float64, y_hat_t::Vector{Float64}) -> begin\n", " m_u[1] = [ upsilon_t ] # Register action with the generative model\n", " V_u[1] = fill(tiny, 1, 1) # Clamp control prior to performed action\n", "\n", @@ -469,7 +645,7 @@ " :V_s_t_min => V_s_t_min)\n", " \n", " model = mountain_car(; T = T, Fg = Fg, Fa = Fa, Ff = Ff, engine_force_limit = engine_force_limit) \n", - " result = inference(model = model, data = data)\n", + " result = infer(model = model, data = data)\n", " end\n", " \n", " # The `act` function returns the inferred best possible action\n", @@ -509,7 +685,7 @@ " V_x[end] = Sigma\n", " end\n", "\n", - " return (infer, act, slide, future) \n", + " return (compute, act, slide, future) \n", "end" ] }, @@ -524,7 +700,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "df06c331", "metadata": {}, "outputs": [], @@ -537,7 +713,7 @@ "\n", "T_ai = 50\n", "\n", - "(infer_ai, act_ai, slide_ai, future_ai) = create_agent(; # Let there be an agent\n", + "(compute_ai, act_ai, slide_ai, future_ai) = create_agent(; # Let there be an agent\n", " T = T_ai, \n", " Fa = Fa,\n", " Fg = Fg, \n", @@ -556,12 +732,12 @@ "agent_x = Vector{Vector{Float64}}(undef, N_ai) # Observations\n", "\n", "for t=1:N_ai\n", - " agent_a[t] = act_ai() # Invoke an action from the agent\n", - " agent_f[t] = future_ai() # Fetch the predicted future states\n", - " execute_ai(agent_a[t]) # The action influences hidden external states\n", - " agent_x[t] = observe_ai() # Observe the current environmental outcome (update p)\n", - " infer_ai(agent_a[t], agent_x[t]) # Infer beliefs from current model state (update q)\n", - " slide_ai() # Prepare for next iteration\n", + " agent_a[t] = act_ai() # Invoke an action from the agent\n", + " agent_f[t] = future_ai() # Fetch the predicted future states\n", + " execute_ai(agent_a[t]) # The action influences hidden external states\n", + " agent_x[t] = observe_ai() # Observe the current environmental outcome (update p)\n", + " compute_ai(agent_a[t], agent_x[t]) # Infer beliefs from current model state (update q)\n", + " slide_ai() # Prepare for next iteration\n", "end\n", "\n", "animation_ai = @animate for i in 1:N_ai\n", @@ -618,7 +794,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.9.1", + "display_name": "Julia 1.9.3", "language": "julia", "name": "julia-1.9" }, @@ -626,7 +802,7 @@ "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.9.1" + "version": "1.9.3" } }, "nbformat": 4, diff --git a/examples/advanced_examples/Advanced Tutorial.ipynb b/examples/advanced_examples/Advanced Tutorial.ipynb index f5d7b417d..ed184d215 100644 --- a/examples/advanced_examples/Advanced Tutorial.ipynb +++ b/examples/advanced_examples/Advanced Tutorial.ipynb @@ -645,7 +645,7 @@ "\n", "dataset = float.(rand(Bernoulli(p), 500));\n", "\n", - "result = inference(\n", + "result = infer(\n", " model = coin_toss_model(length(dataset)),\n", " data = (y = dataset, )\n", ")\n", @@ -978,7 +978,7 @@ "metadata": {}, "outputs": [], "source": [ - "rxresult = rxinference(\n", + "rxresult = infer(\n", " model = online_coin_toss_model(),\n", " data = (y = dataset, ),\n", " autoupdates = autoupdates,\n", @@ -1297,7 +1297,7 @@ } ], "source": [ - "result = inference(\n", + "result = infer(\n", " model = test_model6(length(dataset)),\n", " data = (y = dataset, ),\n", " constraints = constraints6, \n", diff --git a/examples/advanced_examples/Assessing People Skills.ipynb b/examples/advanced_examples/Assessing People Skills.ipynb index 0c3ba7617..de6718f4c 100644 --- a/examples/advanced_examples/Assessing People Skills.ipynb +++ b/examples/advanced_examples/Assessing People Skills.ipynb @@ -179,7 +179,7 @@ ], "source": [ "test_results = [0.1, 0.1, 0.1]\n", - "inference_result = inference(\n", + "inference_result = infer(\n", " model = skill_model(),\n", " data = (r = test_results, )\n", ")" diff --git a/examples/advanced_examples/Chance Constraints.ipynb b/examples/advanced_examples/Chance Constraints.ipynb index 6bc09156d..dbe441e46 100644 --- a/examples/advanced_examples/Chance Constraints.ipynb +++ b/examples/advanced_examples/Chance Constraints.ipynb @@ -254,11 +254,11 @@ " m_u = zeros(T)\n", " v_u = lambda^(-1)*ones(T)\n", " \n", - " function infer(x_t::Float64)\n", + " function compute(x_t::Float64)\n", " model_t = regulator_model(; T=T, lo=lo, hi=hi, epsilon=epsilon, atol=atol)\n", " data_t = (m_u = m_u, v_u = v_u, x_t = x_t)\n", " \n", - " result = inference(\n", + " result = infer(\n", " model = model_t, \n", " data = data_t,\n", " iterations = n_its)\n", @@ -272,7 +272,7 @@ " pol = zeros(T) # Predefine policy variable\n", " act() = pol[1]\n", "\n", - " return (infer, act)\n", + " return (compute, act)\n", "end;" ] }, @@ -309,7 +309,7 @@ "outputs": [], "source": [ "(execute, observe) = initializeWorld() # Let there be a world\n", - "(infer, act) = initializeAgent() # Let there be an agent\n", + "(compute, act) = initializeAgent() # Let there be an agent\n", "\n", "a = Vector{Float64}(undef, N) # Actions\n", "x = Vector{Float64}(undef, N) # States\n", @@ -317,7 +317,7 @@ " a[t] = act()\n", " execute(t, a[t])\n", " x[t] = observe()\n", - " infer(x[t])\n", + " compute(x[t])\n", "end" ] }, diff --git a/examples/advanced_examples/Conjugate-Computational Variational Message Passing.ipynb b/examples/advanced_examples/Conjugate-Computational Variational Message Passing.ipynb index 05fe54cf0..c241d9a91 100644 --- a/examples/advanced_examples/Conjugate-Computational Variational Message Passing.ipynb +++ b/examples/advanced_examples/Conjugate-Computational Variational Message Passing.ipynb @@ -544,7 +544,7 @@ } ], "source": [ - "results = inference(\n", + "results = infer(\n", " model = measurement_model(nr_observations),\n", " data = (y = measurements,),\n", " iterations = 5,\n", @@ -1164,7 +1164,7 @@ } ], "source": [ - "res = inference(\n", + "res = infer(\n", " model = normal_square_model(1000),\n", " data = (y = y,),\n", " iterations = 10,\n", diff --git a/examples/advanced_examples/GP Regression by SSM.ipynb b/examples/advanced_examples/GP Regression by SSM.ipynb index 7894748ef..c623a1f12 100644 --- a/examples/advanced_examples/GP Regression by SSM.ipynb +++ b/examples/advanced_examples/GP Regression by SSM.ipynb @@ -418,7 +418,7 @@ } ], "source": [ - "result_32 = inference(\n", + "result_32 = infer(\n", " model = gp_regression(n, P∞, A, Q, H, σ²_noise),\n", " data = (y = y_data,)\n", ")" @@ -506,7 +506,7 @@ } ], "source": [ - "result_52 = inference(\n", + "result_52 = infer(\n", " model = gp_regression(n, P∞, A, Q, H, σ²_noise),\n", " data = (y = y_data,)\n", ")" diff --git a/examples/advanced_examples/Global Parameter Optimisation.ipynb b/examples/advanced_examples/Global Parameter Optimisation.ipynb index b1dae3b5d..12b29878d 100644 --- a/examples/advanced_examples/Global Parameter Optimisation.ipynb +++ b/examples/advanced_examples/Global Parameter Optimisation.ipynb @@ -120,7 +120,7 @@ "# c[2] is μ0\n", "function f(c)\n", " x0_prior = NormalMeanVariance(c[2], 100.0)\n", - " result = inference(\n", + " result = infer(\n", " model = smoothing(n, x0_prior, c[1], P), \n", " data = (y = data,), \n", " free_energy = true\n", @@ -494,7 +494,7 @@ "source": [ "function f(θ)\n", " x0 = MvNormalMeanCovariance([ θ[2], θ[3] ], Matrix(Diagonal(0.01 * ones(2))))\n", - " result = inference(\n", + " result = infer(\n", " model = rotate_ssm(n, θ[1], x0, Q, P), \n", " data = (y = y,), \n", " free_energy = true\n", @@ -716,7 +716,7 @@ "source": [ "x0 = MvNormalMeanCovariance([ res.minimizer[2], res.minimizer[3] ], Matrix(Diagonal(100.0 * ones(2))))\n", "\n", - "result = inference(\n", + "result = infer(\n", " model = rotate_ssm(n, res.minimizer[1], x0, Q, P), \n", " data = (y = y,), \n", " free_energy = true\n", @@ -2152,7 +2152,7 @@ "index = 1\n", "data=testset[index]\n", "n=length(data)\n", - "result = inference(\n", + "result = infer(\n", " model = ssm(n, get_matrix_AS(data,W1,b1,W2_1,W2_2,b2,s2_1,W3,b3),Q,B,R), \n", " data = (y = data, ), \n", " returnvars = (x = KeepLast(), ),\n", @@ -2220,7 +2220,7 @@ "function fe_tot_est(W1,b1,W2_1,W2_2,b2,s2_1,W3,b3)\n", " fe_ = 0\n", " for train_instance in trainset\n", - " result = inference(\n", + " result = infer(\n", " model = ssm(n, get_matrix_AS(train_instance,W1,b1,W2_1,W2_2,b2,s2_1,W3,b3),Q,B,R), \n", " data = (y = train_instance, ), \n", " returnvars = (x = KeepLast(), ),\n", @@ -3147,7 +3147,7 @@ "index = 1\n", "data = testset[index]\n", "n = length(data)\n", - "result = inference(\n", + "result = infer(\n", " model = ssm(n, get_matrix_AS(data,W1a,b1a,W2_1a,W2_2a,b2a,s2_1a,W3,b3a),Q,B,R), \n", " data = (y = data, ), \n", " returnvars = (x = KeepLast(), ),\n", diff --git a/examples/advanced_examples/Infinite Data Stream.ipynb b/examples/advanced_examples/Infinite Data Stream.ipynb index cc216160f..23ee5336c 100644 --- a/examples/advanced_examples/Infinite Data Stream.ipynb +++ b/examples/advanced_examples/Infinite Data Stream.ipynb @@ -229,7 +229,7 @@ " τ_rate = rate(q(τ))\n", " end\n", " \n", - " engine = rxinference(\n", + " engine = infer(\n", " model = kalman_filter(),\n", " constraints = filter_constraints(),\n", " datastream = datastream,\n", @@ -332,7 +332,7 @@ " display(p)\n", " end\n", " \n", - " engine = rxinference(\n", + " engine = infer(\n", " model = kalman_filter(),\n", " constraints = filter_constraints(),\n", " datastream = datastream,\n", diff --git a/examples/advanced_examples/Nonlinear Sensor Fusion.ipynb b/examples/advanced_examples/Nonlinear Sensor Fusion.ipynb index 7aa314fb5..655daccac 100644 --- a/examples/advanced_examples/Nonlinear Sensor Fusion.ipynb +++ b/examples/advanced_examples/Nonlinear Sensor Fusion.ipynb @@ -222,7 +222,7 @@ }, "outputs": [], "source": [ - "results_fast = inference(\n", + "results_fast = infer(\n", " model = random_walk_model(nr_observations),\n", " meta = random_walk_model_meta(1, 3, StableRNG(42)), # or random_walk_unscented_meta()\n", " data = (y = [distances[t,:] for t in 1:nr_observations],),\n", @@ -240,7 +240,7 @@ "metadata": {}, "outputs": [], "source": [ - "results_accuracy = inference(\n", + "results_accuracy = infer(\n", " model = random_walk_model(nr_observations),\n", " meta = random_walk_model_meta(1000, 100, StableRNG(42)),\n", " data = (y = [distances[t,:] for t in 1:nr_observations],),\n", @@ -819,7 +819,7 @@ "metadata": {}, "outputs": [], "source": [ - "results_wishart = inference(\n", + "results_wishart = infer(\n", " model = random_walk_model_wishart(nr_observations),\n", " data = (y = [distances[t,:] for t in 1:nr_observations],),\n", " iterations = 100,\n", diff --git a/examples/basic_examples/Bayesian Linear Regression Tutorial.ipynb b/examples/basic_examples/Bayesian Linear Regression Tutorial.ipynb index b4f02a0fa..e743b5bff 100644 --- a/examples/basic_examples/Bayesian Linear Regression Tutorial.ipynb +++ b/examples/basic_examples/Bayesian Linear Regression Tutorial.ipynb @@ -792,7 +792,7 @@ } ], "source": [ - "results = inference(\n", + "results = infer(\n", " model = linear_regression(length(x_data)), \n", " data = (y = y_data, x = x_data), \n", " initmessages = (b = NormalMeanVariance(0.0, 100.0), ), \n", @@ -2018,7 +2018,7 @@ } ], "source": [ - "results_unknown_noise = inference(\n", + "results_unknown_noise = infer(\n", " model = linear_regression_unknown_noise(length(x_data_un)), \n", " data = (y = y_data_un, x = x_data_un), \n", " initmessages = (b = NormalMeanVariance(0.0, 100.0), ), \n", @@ -4423,7 +4423,7 @@ } ], "source": [ - "results_mv = inference(\n", + "results_mv = infer(\n", " model = linear_regression_multivariate(dim_mv, nr_samples_mv),\n", " data = (y = y_data_mv_processed, x = x_data_mv_processed),\n", " initmarginals = (W = InverseWishart(dim_mv + 2, 10 * diageye(dim_mv)), ),\n", @@ -7711,7 +7711,7 @@ " weeks = values(dataset[!, \"Weeks\"])\n", " FVC_obs = values(dataset[!, \"FVC\"]);\n", "\n", - " results = inference(\n", + " results = infer(\n", " model = partially_pooled(patient_codes, weeks),\n", " data = (data = FVC_obs, ),\n", " options = (limit_stack_depth = 500, ),\n", @@ -9485,7 +9485,7 @@ " weeks = values(dataset[!, \"Weeks\"])\n", " FVC_obs = values(dataset[!, \"FVC\"]);\n", " \n", - " return inference(\n", + " return infer(\n", " model = partially_pooled_with_smoking(patient_codes, smoking_status_patient_mapping, weeks),\n", " data = (data = FVC_obs, ),\n", " options = (limit_stack_depth = 500, ),\n", diff --git a/examples/basic_examples/Coin Toss Model.ipynb b/examples/basic_examples/Coin Toss Model.ipynb index 32fe46f1a..d976a9f20 100644 --- a/examples/basic_examples/Coin Toss Model.ipynb +++ b/examples/basic_examples/Coin Toss Model.ipynb @@ -123,7 +123,7 @@ } ], "source": [ - "result = inference(\n", + "result = infer(\n", " model = coin_model(length(dataset)), \n", " data = (y = dataset, )\n", ")" diff --git a/examples/basic_examples/Hidden Markov Model.ipynb b/examples/basic_examples/Hidden Markov Model.ipynb index 5d2e9a170..7483cb9bc 100644 --- a/examples/basic_examples/Hidden Markov Model.ipynb +++ b/examples/basic_examples/Hidden Markov Model.ipynb @@ -409,7 +409,7 @@ " s = KeepLast()\n", ")\n", "\n", - "result = inference(\n", + "result = infer(\n", " model = imodel, \n", " data = idata,\n", " constraints = hidden_markov_model_constraints(),\n", diff --git a/examples/basic_examples/Kalman filtering and smoothing.ipynb b/examples/basic_examples/Kalman filtering and smoothing.ipynb index 1743ce395..c4b81144b 100644 --- a/examples/basic_examples/Kalman filtering and smoothing.ipynb +++ b/examples/basic_examples/Kalman filtering and smoothing.ipynb @@ -1570,8 +1570,8 @@ "outputs": [], "source": [ "# For large number of observations you need to use `limit_stack_depth = 100` option during model creation, e.g. \n", - "# inference(..., options = (limit_stack_depth = 500, ))`\n", - "result = inference(\n", + "# infer(..., options = (limit_stack_depth = 500, ))`\n", + "result = infer(\n", " model = rotate_ssm(length(y), x0, A, B, Q, P), \n", " data = (y = y,),\n", " free_energy = true\n", @@ -1785,7 +1785,7 @@ } ], "source": [ - "@benchmark inference(\n", + "@benchmark infer(\n", " model = rotate_ssm(length($y), $x0, $A, $B, $Q, $P), \n", " data = (y = $y,)\n", ")" @@ -2701,7 +2701,7 @@ "imessages = (x = xinit, w = winit)\n", "imarginals = (τ_x = GammaShapeRate(a_x, b_x), τ_w = GammaShapeRate(a_w, b_w), τ_y = GammaShapeRate(a_y, b_y))\n", "\n", - "result = inference(\n", + "result = infer(\n", " model = identification_problem(+, n, m_x_0, τ_x_0, a_x, b_x, m_w_0, τ_w_0, a_w, b_w, a_y, b_y),\n", " data = (y = real_y,), \n", " options = (limit_stack_depth = 500, ), \n", @@ -4156,7 +4156,7 @@ "min_imessages = (x = NormalMeanPrecision(min_m_x_0, min_τ_x_0), w = NormalMeanPrecision(min_m_w_0, min_τ_w_0))\n", "min_imarginals = (τ_x = GammaShapeRate(min_a_x, min_b_x), τ_w = GammaShapeRate(min_a_w, min_b_w), τ_y = GammaShapeRate(min_a_y, min_b_y))\n", "\n", - "min_result = inference(\n", + "min_result = infer(\n", " model = identification_problem(smooth_min, n, min_m_x_0, min_τ_x_0, min_a_x, min_b_x, min_m_w_0, min_τ_w_0, min_a_w, min_b_w, min_a_y, min_b_y),\n", " data = (y = min_real_y,), \n", " meta = min_meta,\n", @@ -4956,7 +4956,7 @@ "id": "f9c1ade7-fb6b-410a-a384-4cf3abdeb228", "metadata": {}, "source": [ - "Next step is to generate our dataset and to run the actual inference procedure! For that we use the `rxinference` function, which has a similar API as the `inference` function:" + "Next step is to generate our dataset and to run the actual inference procedure! For that we use the `infer` function with `autoupdates` keyword:" ] }, { @@ -5757,7 +5757,7 @@ } ], "source": [ - "engine = rxinference(\n", + "engine = infer(\n", " model = rx_identification(smooth_min),\n", " constraints = rx_constraints,\n", " data = (y = rx_real_y,),\n", @@ -6733,7 +6733,7 @@ "source": [ "x0_prior = NormalMeanVariance(0.0, 1000.0)\n", "\n", - "result = inference(\n", + "result = infer(\n", " model = smoothing(n, x0_prior), \n", " data = (y = missing_data,), \n", " constraints = constraints,\n", diff --git a/examples/basic_examples/Predicting Bike Rental Demand.ipynb b/examples/basic_examples/Predicting Bike Rental Demand.ipynb index 13338e763..e84fb04bf 100644 --- a/examples/basic_examples/Predicting Bike Rental Demand.ipynb +++ b/examples/basic_examples/Predicting Bike Rental Demand.ipynb @@ -96,7 +96,7 @@ ], "source": [ "# Implicit Prediction\n", - "result = inference(model = example_model(), data = (y = missing,))" + "result = infer(model = example_model(), data = (y = missing,))" ] }, { @@ -120,7 +120,7 @@ ], "source": [ "# Explicit Prediction\n", - "result = inference(model = example_model(), predictvars = (y = KeepLast(),))" + "result = infer(model = example_model(), predictvars = (y = KeepLast(),))" ] }, { @@ -455,7 +455,7 @@ "\n", "bicycle_model = bicycle_ssm(length(y), prior_h, prior_θ, prior_a, diageye(state_dim), diageye(state_dim))\n", "\n", - "result = inference(\n", + "result = infer(\n", " model = bicycle_model,\n", " data = (y = y, x=X), \n", " options = (limit_stack_depth = 500, ), \n", diff --git a/examples/hidden_examples/Tiny Benchmark.ipynb b/examples/hidden_examples/Tiny Benchmark.ipynb index 908d8a794..c4c8d6ae4 100644 --- a/examples/hidden_examples/Tiny Benchmark.ipynb +++ b/examples/hidden_examples/Tiny Benchmark.ipynb @@ -117,7 +117,7 @@ " x_prior_mean, x_prior_var = mean_var(q(x_next))\n", " end\n", "\n", - " return rxinference(\n", + " return infer(\n", " model = filtering(c = 1.0, v = v),\n", " datastream = datastream,\n", " autoupdates = autoupdates,\n", @@ -455,7 +455,7 @@ ], "source": [ "function run_smoothing(data, n, v)\n", - " return inference(\n", + " return infer(\n", " model = smoothing(n, c = 1.0, v = v), \n", " data = (y = data, ), \n", " returnvars = KeepLast(),\n", diff --git a/examples/pics/ai-mountain-car-ai.gif b/examples/pics/ai-mountain-car-ai.gif index 612af34f5..d0f4a32ac 100644 Binary files a/examples/pics/ai-mountain-car-ai.gif and b/examples/pics/ai-mountain-car-ai.gif differ diff --git a/examples/problem_specific/Autoregressive Models.ipynb b/examples/problem_specific/Autoregressive Models.ipynb index bd12b27ba..887286cde 100644 --- a/examples/problem_specific/Autoregressive Models.ipynb +++ b/examples/problem_specific/Autoregressive Models.ipynb @@ -1381,7 +1381,7 @@ "\n", "# First execution is slow due to Julia's initial compilation \n", "# Subsequent runs will be faster (benchmarks are below)\n", - "mresult = inference(\n", + "mresult = infer(\n", " model = mmodel, \n", " data = mdata,\n", " constraints = mconstraints,\n", @@ -3274,7 +3274,7 @@ "uinitmarginals = (γ = GammaShapeRate(1.0, 1.0), θ = NormalMeanPrecision(0.0, 1.0))\n", "ureturnvars = (x = KeepLast(), γ = KeepEach(), θ = KeepEach())\n", "\n", - "uresult = inference(\n", + "uresult = infer(\n", " model = umodel, \n", " data = udata,\n", " meta = umeta,\n", @@ -3784,7 +3784,7 @@ "metadata": {}, "outputs": [], "source": [ - "result = inference(\n", + "result = infer(\n", " model = ARMA(length(x_train), x_prev_train, h_prior, γ_prior, τ_prior, η_prior, θ_prior, p_order, q_order), \n", " data = (x = x_train, ),\n", " initmarginals = arma_imarginals,\n", diff --git a/examples/problem_specific/Gamma Mixture.ipynb b/examples/problem_specific/Gamma Mixture.ipynb index a863aad2c..c9766b1a9 100644 --- a/examples/problem_specific/Gamma Mixture.ipynb +++ b/examples/problem_specific/Gamma Mixture.ipynb @@ -218,7 +218,7 @@ " default_factorisation = MeanField() # Mixture models require Mean-Field assumption currently\n", ")\n", "\n", - "gresult = inference(\n", + "gresult = infer(\n", " model = gmodel, \n", " data = gdata,\n", " constraints = constraints,\n", diff --git a/examples/problem_specific/Gaussian Mixture.ipynb b/examples/problem_specific/Gaussian Mixture.ipynb index 82a61c368..85ab78501 100644 --- a/examples/problem_specific/Gaussian Mixture.ipynb +++ b/examples/problem_specific/Gaussian Mixture.ipynb @@ -600,7 +600,7 @@ } ], "source": [ - "results_univariate = inference(\n", + "results_univariate = infer(\n", " model = univariate_gaussian_mixture_model(length(data_univariate)), \n", " constraints = MeanField(),\n", " data = (y = data_univariate,), \n", @@ -2244,7 +2244,7 @@ "source": [ "rng = MersenneTwister(121)\n", "m = [[cos(k*2π/6), sin(k*2π/6)] for k in 1:6]\n", - "results_multivariate = inference(\n", + "results_multivariate = infer(\n", " model = multivariate_gaussian_mixture_model(\n", " 6, \n", " length(data_multivariate), \n", @@ -3631,7 +3631,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.9.2", + "display_name": "Julia 1.9.3", "language": "julia", "name": "julia-1.9" }, @@ -3639,7 +3639,7 @@ "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.9.2" + "version": "1.9.3" }, "orig_nbformat": 4 }, diff --git a/examples/problem_specific/Hierarchical Gaussian Filter.ipynb b/examples/problem_specific/Hierarchical Gaussian Filter.ipynb index 5293876fd..19e471662 100644 --- a/examples/problem_specific/Hierarchical Gaussian Filter.ipynb +++ b/examples/problem_specific/Hierarchical Gaussian Filter.ipynb @@ -10,17 +10,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Activating\u001b[22m\u001b[39m project at `~/.julia/dev/RxInfer/examples`\n" - ] - } - ], + "outputs": [], "source": [ "# Activate local environment, see `Project.toml`\n", "import Pkg; Pkg.activate(\"..\"); Pkg.instantiate(); " @@ -63,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -80,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -89,9 +81,8 @@ "generate_data (generic function with 1 method)" ] }, - "execution_count": 3, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ @@ -120,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -151,548 +142,765 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { + "image/png": "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agzDsFisrKysloV+fn5tOo84OzsDKC4u7iBgAA4ODl9++eXWrVtv3rwZFxf3119/HTt27O+//46IiEhMTHR1de1497Kysk8++URxt7PlyDx18pbiAx4+fPjkyZMty+/cuQNA8QEFAsH8+fP379/v7e09Y8aMSZMmTZs2zdvbu9PGFSorK2fPnl1dXb1+/XrFM0JCegAlQmK86urqWCxWy/6QCk5OTi03FVO3tCl8sKSyshJAXFxcy+yoYGNjw+VyW5bweLw2dRR9WORyuTqRs9ns4cOHDx8+fPXq1ampqRMmTCguLt6+ffuGDRs62KusrCwsLCwrK2v48OFLly61tbVVRLVu3br2xmK2pPhVsWfPngffsrW1bXq9Z8+eIUOGfP/997/99ptivEp4ePi2bdtGjBjRcftyufyJJ55IT0+fO3fuv/71r07jIURbKBES48Xn8ysqKkpLS11cXFqWt7ksU4xgKy4ubtm/tL1q69evb3OvVdcGDBiwevXq999/v2m0Q3u2bduWlZX12muvffrpp02FRUVFbS5h22NlZVVfX3/37l3FxWt7zMzM3n333XfffffevXtnzpz59ddfz507N3Xq1OTk5I53XLduXUxMTGBg4O7du1vefSVE1+hsI8ZLkdjaXMDV19e3ed6mshqAhISElpuKR4Z///23LkLtmGLWlabkobjOe/AiLzExEUCbMXltPkUHu2v6AQMCAp577rmzZ8/Onz+/oqLi7NmzHVQ+cODApk2bbG1tjx492ul4SkK0ixIhMV7z5s3D/f6cTYXR0dE1NTUPVtu2bVtDQ0NT4YkTJ27dutWy2pw5cxwcHH7//XeVqaKurq77Af/8888PtiMUCvfu3QsgNDRUUeLu7g4gNze3TU3FTeCWk4nLZLKWk5R2vLtiTtcNGzYIhcI2b4lEIolEAqChoeHBPkqKJ5eNjY3tfa7ExMRly5axWKw9e/b4+fm1V40QHaFbo8R4LV26dOvWrX/99deSJUteeeUVPp9/9OjR9evXe3p6tkwDo0aNmj9//oEDB6ZPn/7ee++5u7tfvHjxzTff9PLyaplU+Hz+N998s3DhwqioqNdee238+PGurq55eXnJyck//vjjY489pnKou0Y+/PDD1atXP/zwwxMmTPD29haJRKmpqdHR0YrblYruqQAsLS0HDhx4586d5cuXh4SEmJub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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", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", - " \n", + " \n", " \n", " \n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n" + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\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", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\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": 5, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ @@ -718,7 +926,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -727,9 +935,8 @@ "hgfmeta (generic function with 1 method)" ] }, - "execution_count": 6, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ @@ -773,7 +980,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -782,9 +989,8 @@ "run_inference (generic function with 1 method)" ] }, - "execution_count": 7, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ @@ -795,7 +1001,7 @@ " xt_min_mean, xt_min_var = mean_var(q(xt))\n", " end\n", "\n", - " return rxinference(\n", + " return infer(\n", " model = hgf(real_k, real_w, z_variance, y_variance),\n", " constraints = hgfconstraints(),\n", " meta = hgfmeta(),\n", @@ -825,7 +1031,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -837,451 +1043,179 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { + "image/png": "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dP1V+3q4cOHC/PnzhULh1KlTZ8+enZGRweVyZ8yYUVJSEpZpbGwsKSk5efLkwIYoLS0tKSmpqKiIk8q98/LLLyMIsmDBgq5V4bZt24YgSH5+fq9/DghkwEBDCBnFBIPBQCCA43jXQyRJBgIBv98fbsEwrKioaPr06UOoYJw5ffr07NmzDxw4kJeX9/zzz7/++utr16695ZZbLly48N1334XFSktLH3vssU8//XRgo+zZs+exxx47fPhwnLTunWeeeWbatGn79u175513Itvb2tr++Mc/0un09957j0qlDpk+kLEGrOYMGSvQ6fSDBw8OtxbXxZ/+9Ce32/30009v2rQpst1gMFy8eHG4tLp+KBTKe++9l5+fv2bNmgULFiQlJQEASJJcuXKlxWL529/+lpubO9w6Qm5koCGEjBVIkjx//jyTyRw/fnxku9vt/uGHH5qamuRy+a233iqRSGKeHgwG9+7dW1lZyePxiouLx40b191AZrN5//79LS0tDAZj+vTpU6dOjTzqcDiqq6slEsm4cePa29v37NljsVjS0tIWLVpEo9F61v/48eMAgKeeeirqkFQqLS4uDn2uq6urq6sDAOh0unPnzoUak5KSpFJp6HN9ff2FCxdaW1sRBMnKyioqKooct7y8vK2tDQDQ3NwcPj0zM5PD4YRlKioqTpw4YTKZVCrV/PnzlUpllD5Op/Po0aNNTU1er1cikeTm5k6cOBFBkB6uLjs7+4UXXnjuueeWL1++d+9eBEFKSkr27NmTn5//9NNP93AiBBIHSAhk1LJmzRoAwPr167seMhqNAAAajRZucblcAIAJEyZEip06dSohISH878Bms3fu3Dl58mQAgN1uD4s1NTVNnDgxLIZh2N/+9relS5cCAE6ePBnZ4SuvvMJmsyP/xebPn28wGMICBw4cAAAsX7588+bNkct9WVlZLS0tPVwsjuOhnuvq6noQW7JkSdd/87feeoskSb/fn52dHXUoKSkp8hKi3hJCHD58OHRUr9ffdtttkYfodPpLL70UqcD3338vEomienjwwQd70DlEIBAILVyXlJQ0NjZyuVw6nV5WVtbriRDIdQINIWQUc52GUKfTSSQSBEGee+65qqqq6urqP//5z0wmUywWRxpCn88XsoLLli0rLS1tbGzcvHkzi8VSqVRRhnD9+vUAgPT09A8//LC8vPzYsWMhYzl79mwcx0MyIUOYnJzM4XBeffXVU6dO7d27d+7cuQCAu+66q+frLSwsBADMmzevsrKyO5mLFy+G1FiyZMne/9La2kqSpNfrzcnJee211w4dOlRdXX3y5Mmnn36aQqFIpVKz2Rw6/cSJEytWrAAArF69Ony6xWIhSdLtdod+h/vvv3///v2VlZW7du3KyMgAAGzZsiV0utVq5fF4LBZry5YtFRUVzc3Nx44d27hx47p163q+tBDl5eV0Op3H482cORMA8Morr/TlLAjkOoGGEDKKCRnChISEgi6EFiR7NoRr164FADz++OORfT755JOhSUzYEIY8OObOnUsQRFjsrbfeComFDWF9fT2FQlGr1SaTKbLDu+++GwDw9ddfh76GDCEAYO/evWEZu90uEAgwDPN4PD1c76FDh1gsVuj01NTUZcuWlZSUtLW1RYl9+eWXAICnnnqqt9+PJEnyf//3fwEAb775Zrjlb3/7GwBg69atUZIh79xVq1ZFNra3t/N4PKlU6vV6SZLcv39/15+0X4RGBwDMmDEjGAwOuB8IpO9Ar1HIqMdgMJR3obKystcTv/rqKwBA1BZU1x2pkNiaNWsid7l+85vfRO0mfvzxx8Fg8PHHH49aGHz88ccBAD/88ENkY15eXnhXDwDA5XJnzpyJ43hzc3MPCs+ZM+fy5ctLly4VCAR1dXUffPDBo48+mpCQcOedd2q12l6vNyZ33nknAOD06dO9Su7YsQMA8Pzzz0c2KpXKu+++22AwnD17FgAgFAoBABcvXnS73QPTJ7zj+Itf/ALDsIF1AoH0C+gsAxn1PPfccy+88EJUo8lk6s7tJYTP56urq+NyuRqNJrI9KSlJLBabTKZwy5UrVwAAkyZNihSj0+nZ2dlHjx4Nt1y4cAEAcP78+T/96U+RkhaLBQDQ2NgY2ZiZmRmlj1wuBwDodLrQYmN3pKSk7NixIxAInD59+syZMz/++ONPP/307bffzps37/z58wwGo4dzQ2q88sorx44da2trs1qt4fbQSnIPuN3uyspKOp2+ZcuWqEO1tbWhngsLCydOnDh16tTjx4+PGzdu8eLFRUVFCxcuVCgUPXcepq2t7Q9/+AONRkMQ5OWXX37ggQeSk5P7eC4EMmCgIYSMUVwuF0mSYV/KSGQyWaQhdDqdAICukjKZLPJryODt3bs3vPgZRigUUijX/K+FVzjDoCgKACAIoi/KU6nUwsLCwsLCp5566tixYwsWLKioqPj0008ffvjhHs6qrKycNWuWzWabPXv2bbfdJhQKURQ1Go2bNm2KGYsZic1mI0kyGAxGRu5HXmCoBwzD9u7du379+k8++WT79u3bt29HUXThwoVvvvlm1AtHTB599FGLxbJhwwYURZ977rkVK1bs27evZ3dTCOT6gYYQMkZhs9kIguj1+q6HopLFhCIH9Hp9KL6tO7FQFpv333//rrvuir+63TN79ux77rlnx44dZ8+e7dkQvvTSSxaL5V//+ldotTbEsWPHoqISYxK6Og6HYzQaQza7OwQCweuvv/7aa6+VlZUdOHDg/fff371796JFiy5dukSn03s48d133/3hhx/y8vKeeeYZBEG+/PLLAwcObNu2beXKlb2qB4FcD3CPEDJGodPp6enpTqezuro6sr2hocFsNke2TJgwAfx35TOM1+sNLZmGycvLAwCcOHFisDTunpCBCe+ohaIygsFglFgo6P7BBx+MbDx//nyUWCisMGqOyOFw0tPTbTZbeXl5X1RCUXTSpEl/+MMfzp49m5+fX11dXVZW1oN8e3v7008/TaPRQklkQiH2DAbj6aefbmlp6cuIEMiAgYYQMnYJhdy99tprkY1dp0dhMTIiE+a2bdui7OWvfvUrKpX6n//8p76+PqoHgiBCPqvXybvvvhuZNC6EVqv9/vvvAQBTpkwJtajVagBAV/sR2jSN9MdxOp3/93//FyUWCgtpbW2Nan/kkUcAAM8//3zXddTQ6nHoA3ltvlAMw0JryD6fr4dLCyWReeGFF8JJZLKzs5977jm73b58+XKySw5SCCSeDKvPKgRyXVxnHKHRaAy5qDz11FMXLlwoLS1ds2YNi8UKbQeGwycCgUDIxtx7770nT54sLy/fuHEjg8EIrZRGxhFu3LgRACCVSl999dUDBw5cunTpm2++Wb9+vUaj+eKLL0Iy4YD6KIWXL18OADh06FAP10un02Uy2eOPP75jx46DBw9+8803GzZsCCUEyMnJCQUwhK6Ux+NRqdQnn3zyzTff/Pe//33lyhWSJF988cWQ5HfffVdVVfX111/n5eWFtu4WLlwYHqW6uhpFUYFAsG7duq1bt/773/9ub28nSdLj8YQC3gsLCz/44IOzZ8+ePHnyo48++s1vfiOVSkPn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fVVko6BDIJogAgBg8l62shA2grqgC3QviDwiVUpnLCaqRpmGfi/S0Hw0BpcR2YKxYiR6/bnmZ8VPCvfN7lmrZlGonRMCKp9K8URPDrQ6bRAEhWKhgW6wGCz91QfSA6+99prD0fmuM2/evE8++eR6emtvby8pKYmHXr1Dp9Orq6sZDEbvonEiDs8OkUgU/kyn00MT4ba2toqKisWLFwMAqFTqwoUL9+7de/1jQW5IzjWdO7LpyKzqWfU/Xt3zN5lM0oA0b2peX3qgsqmIF6bY6AmP1yPBJWmatNBXWbpM4VT0txNGkMERXLM2SmVRMf81rymNpsbgzmAgO5Bzc05kO0fEoXvpUR22N7XraDoAgI/hc5qc/dVnbLJ3794777yzoKBg7dq1LpcLABAIBNatWzdjxozp06f/+te/Ds1D/H7/b3/72/vuu+/cuXMVFRWhHNxer/e+++7bu3fvvHnzZs2atWfPnurq6l/84hcFBQVhO3f58uWlS5dOmzatuLj4gw8+CDX++c9/7ujouO++++67777QXO2jjz5auHBhYWHhyy+/HAx2rsd88803c+fOLSoq2rNnT1fNL126tHz5co/HAwAwGAxLly5tbW3tKhYMBp955plAYOjSRcVzRb6qquq9997bt28fAKC9vZ3L5bLZnckhFQpFWVm3AbxGo3Hz5s3hFLFyufz3v/99TEmfz0ejjfp0hZAomo41pbJTnQucmi81bq875Mp47vg5OosuJ+Q+39WNpdBnDIueIFJYFOADkZKQKCorKxEKIsSFPtwHAJAnyGkETW/W89m9pIaJhItzERYS+TtTWBTEf7UFJ/Dqd6qVQqXmdk3Un4PNY/sD/lAjHsTL3y7PfTTX3GommITP5wsyg36Lvy9/waF8CIzADZ0DBw48+uij27dv12g0L7300qpVqz766KOSkpLz589/+umnVCr15MmTJEk++uijr7zyynPPPSeXyxUKxf79+w8fPgwACAaDn332GYZhW7duPXfu3AMPPFBUVPTCCy94PJ7bb7/95ptvzsrK8nq9jzzySE5OTlNT069+9avExMSioqLf/e53dXV1IR8cGo329ttvb926taSkRCgUrl69+sUXX3zxxRfPnTu3fPnyTz75JDU1dc2aNV3zJ0ycODEQCDz11FNvvfXWihUrsrOzExISul4jjuNfffUVjkcvueM47vP5fD4fhmF93z6kUChdnxjRMn3sq1fa2toWL168YcOGqVOnAgBQFI38FQiC6EEVDMN4PF44CEwgEKBo7KkqiqLdHYKMXpgmpi3FNj5jfBVWVVpaOm3KtANnDmReyjQWGaP+3Oh/ieqBI+DgQRzeGz1gaDHQmLTwT4TS0HZKO1lHTp7cj8xnfIJPkVAif2c2jx0IBsItJz88ySf5mcszESz6OSWVSREcCUk2tzWn2dMaKhuACfiFfhRFUQGK6vv03z2UD4GuT1vPQY/32NDtXTEXMBkF16wQvv76688///ycOXNCn4VCoc/nc7lcJEniOD5u3Lhf/vKXAAClUokgSFJSUqT3YpiXX345JSUlMzPzj3/848MPP5yfnw8AuOmmm06fPp2VlTV16lSLxVJeXu71emfNmvXjjz8WFRWpVCoqlarRdIa/vPbaa1u3bp0yZQoAYOPGjbfddtuLL764ffv25cuXFxcXAwBeeumlr776quvQW7ZsmTJlyh133GE2mzds6F/WVgRBwk+AvhvCvkjGxxDqdLri4uJVq1Y98cQToRalUul0Oh0OB5fLBQBotVqFott1GKFQ+Otf/3rGjBm9DkSlUqlUaq9ikNGF2CXmJnOpVKperfdf9H9h+6LgTIFvjm/q7KlRkqEboOtLlUgkcuNueG/0gF/vp4gpkT+RhWfBmjDqtL7+aKEFMYlAEvlkEQlFdtwe7lbSIQG/BDRmjBmbQCLwAZ8n6OExecY2owRIDJcMDAeDkkyhUqkcMcfZ7OzLX3AoHwJdn6HMuUzm3OF0gK+vr9+4cWO41uCECRNMJtNvf/vb2tra6dOny+XyVatWPfXUUz13EraOHA5HpVKFPzudTgDArl271qxZM2fOHLlc3tLSQqdHL2gDABoaGp588snw1FwmkwEAWlpaFi1aFGpJTU2NOTSXy129evUTTzyxf//+/v4dURSl/pf4OpTGwRAaDIbi4uKlS5dGZoBVq9W5ubnffPPN0qVLfT7fnj173nrrresfC3LjEQgGEoIJwnQhACBlZgrlEwowAGwRljwlue+dyBQyPaH/+cjPBTcXDJaioxy6lc7Jv2Z7z6/wc7T9SFZuNpttiE2JKCMb+UJ+OMurz+eTEBJhajfhgAiwI3a7wc5L4jm0jgqsQtAhwAiMTCQBAHwpH/HBXd7eUalUDzzwwIoVK6LaS0pKtm7deujQoYceeigvL2/OnDlRy3J959VXX92yZcttt90GAHjiiSdC69VRvSmVys2bN4cmpmHkcnk4315bW+wKlK2trX/9619XrVq1du3akydPxrSyQ08cVhieeOKJ5ubmS5cuhfZRn3/++VD7+vXrV69evXbt2ltuuSU5OXnBggXXPxbkxqOhrsGMmZksJgAgJT2lJbmFvYKtmqLqVydsJtt+m115RHn8zPHBUXPUI/VIE1Ku2Y+RaCQiu6g7+a7YLXYHFh1xwefx2YAdKoPVUN+gxbR0arePNhvFZjaYAQCoBbWmWblBrgSXJCcnAwCkMqkQhwH1vfPoo4++/PLLly5dAgBYrdZdu3YBAA4dOtTY2Ihh2KRJk1gsVmjpOCEh4fDhwyaTqb9eJ0wm8/LlywCAU6dOffzxx6FGtVqt1WrLysosFktoD/LZZ59tamoCAGi12h9++AEAcP/992/btq2urs7v9//1r3/t2nMwGHzwwQdXr15dUlISWpi9rt8ifsRhRrhu3bpVq1aFv/L5nXvvd999d0ZGxv79+wsKCu688064fwOJia5RF2Bd/UedtWzWwPqZNGXS8abj3mNeMC1Omt1AmBwmBalQJF2zPZGZken5zoMHcIzap0RrDqvDTY0OnkdQxIW4SAspk8g6mjoQZk+zOg/D4zf7AQAsJ4ufx69oqUjwJkxkTAQAiCVinMTdPjeLzurftV03hxoPTVJMEjJGhxm+9957Q84sWq2WzWbffffdS5YsCS1Ums1mFov1P//zPzfddBMA4M033/z73//++uuvv/766wKBIBRNj6LolClTwuuKOTk5YZfGlJSU0Arn3//+95UrV/7jH//Iy8v705/+FJoRqlSql19++fe//73T6Txy5MgzzzxDo9EWL15sNBolEkkoSHHevHnPPvtscXExhmHr1q27fPlyVDT9zp07k5OTn332WQDA1q1blyxZcv78+dAOZSQoiubn5w+lyUBGQmGUgoKCf/7zn33ZIwxvOkJuGA68c8BL8d728G19EXa73XQ6vTvHq/OnzrsPu2c/MzuuCt4IXCi/QPualvNcTlT7mZfPCO4SpOf0qUzBkR+OeGu8t6y+Jaq97KUy+v30jLSM3e/uxlDsll9HC4Q58NYBt8S9+J7F1Ruq2Y+wT5w5wa3l3rr21tDRmg016MNoalLsvaUwcX8IfLnxS8p0yh1Fd3Q9tGTJkmXLlt19991xHA4yMDZv3lxTU/PGG2+4XC4WizXi9gghkOuBaWGCOFVs5Qg4SBDuM8XA2GFkM9hd260cq7PO2UdD6Hf5g4wY6Xs8FI/f7gcA0Kw0ek5PWz4UHsVn9tkcNi7JVSgVRbcU1UypCR+1UWy4Hu/VEMaXIBGc5Jt0oeECKBrKYSGduFyuCxcuRLagKDpr1gCXhQYMNISQYUbhUfhS4xP/JxQLUQKuwMfAbXDTODE8OUk5GWjv6wYS6SRBrGVLL8WL2lEAgMgt4o3j9dBD+uR0xi5GdW01hUJRokopSyplXU0h62K4Aqahi6EOUddSJwMytinGWwJkCLBYLDt27IhsoVKp0BBCxhYekwcn4zYJEAlFJEniBI6h/asudMODmlFEEWOuLE2Reho9XdtjgngRVB7jPSNAC5BO0u1zKwmlRCPpoQfleKXza+fpY6cTmLHCqFm4zzLUKRHaa9tRDFV5VSRJDlmKZ0iYhISEkRBQAF+fIcPJ5aOXr3CuUNH4hIVhGOZG3BYLTFkZDdPF5MljzNUysjIS/AkBott5mMPhOPTdodBnipcSlWg0BEEngu5gTV2NETOGM4t2hzXVOt8yP8iPlSGdHzsr96DibfO2yFvEpLheW9+7NOQGBRpCyLBSA+gT4hlIZEfsZrM5jh3eGIgCIrla3rWdzWN7UW9VbVXXQyFqq2sTSxM7hf1spiBWLDkTEG5C26S1sqy9apKzIIeCUGiyGOu0TAGT4h7qNSqGiUFRU7QMbWN14xAPDRk5QEMIGTYMRoPcK599UzydPJ0Up9MKczdfg8vvUhGqmIYQAGDkGJtrm7s7121zi0iR2+UGAMgCMqVa2VUGZaGIB7FV2qjK3mf2LCGrNa01a3KMwng8CY/pHeqkLRK3RJGicAlc9uaBFAyC3BjAPULIsHH68Gkej5fESIpjn16qF7fFKI83lmlsbaSjdAUtdo5DXIL72rvdmfPavQCAlqaWpIQkQAK1MkbiShqbFrQGC/ACxa19Kmcx+cHYXsIyhYwIDmmSa4/bIybE0jSptdHKLI9tg10uF1xsHwmEalYMEtAQQoYNRi2DM70fKb76QpARJJwjrmLA8KJv07Pp3XpFstVsz9luHzFBZxAAYGwzAhxYMMs4ZFxXGQaHMSE4oV5Vn8S/rncaqUJKkITD6+AyhihWuKGmwUFxqDBVYkYi/UyMJXqVSvXkk08++eSTA+icIAhAAJRyddWNDJCAAkiSRHAEUPqUDBoSydq1awepZ2gIIcODyWXK8GfIp8derxswBIMgncOfI2JE4dA5UHa3myDKZCV2vFsnW8SNeIDHZ/CZg2YbyxZThifg4QDPujPGamf/wIAFtZhbzdlp2dfbVd8wNZqcHCcAQDlOCUhgsBmkfGmkwJtvvvnmm2/2t9tKfeWn336ab8pni9lzV8wNtx/5xxFfui/YGizQF+jv12dmZF7/JUDiAtwjhAwP58+ft9AsNHacC8shbAS44tvlqIe0kKige0OYpJQRMrPDDADw4/6oo5gXq6ZXIxbEp/f5+dFHQ2RkZmCLMbY0DqF4FrrF0G4AAOhP6YP2WJ6lcYVsIwOKAAAAoEBL1TbWNcal2+oT1cv0yzLEGbkLciPbcSUeaAlITVI3cNstcEtyBAENIWR4sFRbXPL4mywqh0rxwXWOq5g9ZsSMsOTdJ/BEgY6qa6xrNNgNO1/dGXWQ7qPbRDa2i02xUaiS2L4wCBUR5sUnUaeX7XUZXAAA837z+Z3n49JnD/DsPIWmc1/TzrabW+Pjb4y0Iy1pLRkrMiRJ10RVSlOlCpNCTshrObUuK3xfG0HARwZkeBDrxZL5PQVfDwwGj0H44R5hJzVlNZ5vPPlYvnxST0vQVrY10BywmCyL8cVWh1XAFYQPMYNMdgpbopU4CAdFPeiPC4JPEBYi4A3wcB5TyzTqjRVNFbYO2+I7F8d9rIA/IAvIuOM79yNxCU7o4nPnCG1C4YwYbwbp49Odu51V3Co/w0844F06goAzQsjQ8dGpjxr1jQCAJlNTJp6ZOjH+WSU5fA4jECPoe2zS+HOjVqFNeDaBKu4psCEoDuI63F/pBwAYDIbIQzycp0nX0Em6IqBIGBcjHUx8oUvodAe9vrq+idJUJa268u4VzR6NtFza+5n9p7aqtgVr4TI7DSFbxWbZ+l34wmA17NyxM7J0QQAPjAuO02RqugrTWXQdRYckIySLxJ3Qt3kEAQ0hZOB0ODvOtp/to3C9vn7OT3MY/2Y0vNJw8JODFpoFZcT/9uOL+FwC1ifphO6gM1IYoDfnxJANGGcZZ0EsVuM1QfF8kq+UK9uwNguwqEUxYifii1Ap5Hq4unqdlWOdcs8UJaG03myV43H2qAqhq9FZeVcvVpWiknll/e3k7J6ztzTcsu+rfeGWmtoaG2pjcmIHY4gXi6cWT8U4GOqGz94RBPxjQAbO7m921+2o66PwmWNndFwdbS2tJr9mgWsBL6On7MwDRigSCghB73JjA6FXKFX3Pp1SaVTpnnQMwZq5zU7L1XQEdqvdAzxMOtNCt2ip2iFw91clqOS4nNAShJwQS8Tp69Jz5uSgANUZdHEfC+/AQUT554SEBB7JczijKw/3AEmSifWJFydezLicUX6k/PKhyz6vT1urNbAN3Z0iz5VTOVQGl0H1xSetICQuwD1CyADBSTy1ITWLyDpdc3p6+vRe5dk1bNoUmogpuuWWW8h5g5XgmMfiOYDD7XKz2ENd33WkgRO4DJdxx/U+P05MTGwH7U2CJoSC4HYcAGAsNzLFTJPH5EAdAAAP1xPwDEVdCKFQ6AROiVlCz78a1aej6JAmRC4dyLyw3lJfXlHO1DNn3zabQbtmzVxkF2E3XY0bQVCkjdJmqjNNnDSxj52fO3mOAihFdxV9h38nPSalkbSzlWdxFCdkvez/sQVsENsDFzI8QEMIGSAnyk6MA+Na5C3NB5t7NYRV+qpJgUmqmZ1v4AhlEOcWFsQCzAAawtaWVjfiljN6tx8ogrZQW7AsDNfiISeOyr2VhJjgj+e7KC4AgG+iz+weogyueoo+OZisyLiapMbBdhDtA3QtqdhWMck/yYE6yq+U43fj07OnAwD8uL+mvUYelEuyrnHXsnFsrmYXmNR7t40XG521TlotrSOjAwCweMliAIDWrHVscWAIpsvtZf7KF/IB3CIcSUBDCBkgupM6ipKSUpTC/ZDbamr1Gr1pmWldxS5culB3pK4GrbmdfXsiO3EIFHNhLsSMqBMHfUNrhNPR2hGk9zUUT/iIcIpkyvEfjoMmAADgerkeg8dtc3uoHgDA/QX3D56eUdjotjaibaLg6rQMF+BB/QBjCjVeDf0RepI66exnZ9VfqL+mfe2gOsa5xqWRaTXiGhVNFSkcFAdRXedu0aEfDs0snkmnRaebqW2qtX5kZRPsRlajn+ufe+vVeHmFSHEq/9Tsc7NZmb28hIklYmgIRxTQEEL6is/v2//mfq/Uu2TZEk/Qk23IFj8oVmgUWrpWtEVEBdTyJeU5OTmt51prTtVsc2/77X2/nZ00277Xno1kF3mKfLOGqNScm+pGbDB5FbB32BF2X3+HLHkWAIApYCJVCABAFpB5g95Ge2OAPtSVcv1cvxEYI1sYckagfCBq2Jw2ISmUKWUAgKn3TsVdeNbuLDSIKnOU7Cy2khqdQJydzFYdUvkd/rJTZZPOTapJqJkwcUKUTM3ZGh6Tl/9kfjYaI/3NHYvu+ILzxb2ie3tWjMfneYHX7XOz6GN93WKEAA0hpE8EPIHqN6rFqFjaJLW77Qf3HtTQNIpUBQBg0upJAAEHPj7gP+zPycmx/2Sn8CivEK98+fWXyUuSk93J4qfFbIyN0IbIOHkYHqoReiIA0kQCUf9OEYgEzoDTYrS4gAsncUyHEYyhDnfjTuR6nNfkPpUlyFxnXQAAi9ciZPQjcr+lqQXHcAXaucqKsbHMe3rKajZ75uyPz3+Mv4VLfJI6rM7V5gJdtgsRHeJP8KNobDdDFEHvvbkXKwgAAAiwI3a30Z2sTu7DdUAGHeg1CukTZ74504F15K3J62B1nPzmZFpZGnV+p7FB6AhCQ3KLczPNmQf2H/CT/lmPz5Ivl99lu6t8Z3mVtIrD4iB0pFcn/nhBjiPRJnhjA7qDzpX3L5JEJBUJcEFbc5ueom9htKiNaoQz1HPrwhmFxfOLI1sSkxOVuLLN0NaxqaO+uR/lc02tJjOjH1ubKILevvL288T5n2Q/GRVGnzHGGgbPzhMl9/P9IhYOisNq7r18I2RoiMPzwmazffLJJ88888zvf//7yPZgMLhx48aFCxcuW7asoqLi+gcas3xf9X2zrduKcUMAgROyWplgvoCG0ZhzmHk1eXaGPWvKNUmWZWqZjWFLOpHkyfVgCEaVUJsym6a6po4rjlGvYFCZOG1ioiuRwMd65g6hv0+xE5FIJBIuyTW1mRxsh0vsEhEiKmf459YsFsuBOCrod7lbAAAgAElEQVTeq1CQiva69r6f6NP7fPz+LcgLGILi3xc/+JsHKRIKZo3ORY6TeEIgITU9Dokg3BS3w9KPUA3IoBIHQ3j58uXt27frdLp33nknsn3Dhg07d+5ct25dVlbW3LlznU5YLrXfkCS564Nd+Z/ld2zu2PrO1p8v/0wQw/B8P7H/hIFimJ43HQCQPyX/AvcCd1GMqQYtj8ZEmTMWzgh9LVhScKbgTGbaUKfYT1Qk6jF9eVn5EI87ogjgAQWuSBzXP+8kFEXtiB1vxXEezhrHAgAw+UNdKTcmBroh25NdKip1tfUjRSfVQsWk3RbW6A4pS8qhcfhKPscdXSOsvrHei3o5/DjUDvPT/R7bIBbYg/SLOOwRFhYW7tmz59y5c59//nm4MRAIbNmyZdeuXbNnzy4qKvrhhx8++eSTlStXXv9wNwzHPz2uqFb4gb9KXTX/wfkxa7Ad+vehVEsq7WFahj5DcEJA/Zqq+0rn5rqpeVTZTBmDGs9cYoGmAMJAKPLoW8Jmt7HOsdzT3OGWhU8tjNlDTlFOMDuI0jrfrqgY9dYFt8ZRw75jkprIi2Tu5NzeRYecsh/LyCA58fa+BqsNjKbmpiAalNP7HXtnpVglVokuUafJ0oATgCsYEWl6/DJ/I7cR0ACtrh/lSngeHq4coHemKlHlD0TH+rXWtVIZ1AyQMbA+IyEYhN8ZO5YQN+EoHx3UECNIFIPlLNPc3GwymQoKCkJfZ86cee7cOWgIwxBBQlmt1Bfr1UJ16reprZtaPdmevEV5COvq3f/1/q8nmiYKfycUCAQgCQinCgEAZ+rPHD58eO7RuYYjBv4KfpoyRsRCf/F5fDXba7hmLgpQ2xLbhOwJAIB9e/dRLlOoTGqCMcEtdM+aN6v3jjBAUY0I9yvReJH/yAiNWDbXmAPYoLtiNlY2MlgDeU9yU92p7lSv3KtRab5Cv5omnxZ33QbA3F/PBQBcvHSRLOtHsUl5QA4GujCvlCvbyDaXw8XmXi0v5W5zM0Rxevtkg+7qhV3YfoE+k547ayS+xt2oDNZjS6/X83g8CqWzf7FYXFfXbS6u5ubmhx9+mM3uvOFSU1PffffdmJIul2s0lnUOEkEv7uVQOUEiuKN8x0PjH6o4UUFSyMkTJgMAhL8VVpyr0J/UyyvkLeoW1QKVkC/84OIHBT8XBGcHKRRK5Kpytiw7+95sAMDlHZevfHpFsULR7ah95uT7J0kX6b7dTammZH+R/Z7gPQVTkdmR2ZzabHFYiLlE3qQ8t9vde0eDj9vtDgQCGNbLepcmU+PZ72nTtfHZ/KFRrO9wHBw7wz7YOwWB2gAhJwYwipfmRdyIUCx0uVy5K3MFTMHI2dSQq+QgCJx2Z+ghcPSno5n5mTJJ7AShbrvbR/qkTOmA9e+gdJiqTGlZV981aUYaJYsSnx+EAVAjGrMrho+h0+tGzs8+0nC73QRB9N0QMBiMsCXqjsEyhBwOJ/LR6Xa7ebxuc0sqFIrVq1dPmNAZssPj8Tic2KvwJEl2d2gk8+1/vtXoNc3zmw9ePpiny3u77u15HfMMEwzha5k2Z1rgpsC+0n2MIwzsXawMLbubvJtMIVVzVN31mftQruENQ0NjQ+6Efr85BtuDuBmnT6ADAI6fP55uTuf9jicSisBk4Ch3TDw+0WV2Yb/Bbk64ecCXPEigKEqn03s1hIADLlAuAC1QTxpZYfUkQaqDal/QN9i3sdqups+nD2AUkkO6rK60lDQEQdI4cVhviCMcDqcULWVZWUq18tvd384qn3WRdVFza4w6DwCAtto2PUWfyh24Y4udYWeamZG/ocwrE2QJ4vK3E0gFlnpLzK6EuFAb0I7GB93QgCAIi8WK74xosAxhQkJCMBhsa2tTq9UAgPr6eo0m9v0KAKDRaFlZWVOmTBkkZYYYv9tPY13dybhYdjFXl9s+sV29T30X5S75THnayTRAgszia7xIqCh1Uf4ikA88To/9rF2SJ6Hye3LYY/PYP2f9zNnNAdEhv90SaAlQ5BQc4C0ftOAInjYhLUgEg7uD9nx7sjA5JMPN4ebl5PXrekcmdrbd1+LrS7qsoaS9rZ0O6KzA4IZRa3VaPslPykoawLkoD9Vj+gRk0CsuDQwDw8BqYXWQHRPOTahj1/l13S6AW9otduZ1VYH38XyIvvNpi5P4hx98WEQWJSbHJzuSQCLw+2Mo73a7WYBFuMe6z/MQM1iGUCgU3nLLLSUlJevXr29tbf3hhx+OHj06SGONHC42XXTtdCX6EpsXNgeQgPwnuQtzMXFm66TW2XfMthXbEpgJGIJ587znK85rGLHfDJgcZnZRjKQVXSm8o7BjY0drc2tCUudjq93R3mxtFrPE6eL0KGGH0eHa7nJiziZak5/i13g0dq39fMt5NaJOXxQtfAMQFAb9+hG3TdhS34JSUDEuHtRRqkqrAAuMQweyP8aUMTvaO+KuUrxwC9yUVgrvHM81weWmuLG6btcG/Aa/X3BdNwAmxrA2DABAkuTOt3bOts7m/4aPYPGZiEjlUhyP4cij0+kEQACgP+nQEofwiY6ODpFING/ePI/HIxKJ8vI65xObNm16//338/Pz8/LynnjiifDK542KJ+BB30cZUoax0Jj4U6LmR01wapDIJ0xJptl3zAYA8Fl8DMEAAEqh8vZZt1//iAw6o1paXXWgKvS1sraS+AeRsT0D34r/cfsfo0IPL3x44bj0uL3AnkJNKX68uJJbefnoZftJuyHZMGSh7kMJU8FkWEdchV57u90oMHLJwXXFDNYHfaoBJrS76aabFjy+IL76xBGKgpLbkWtn2if8YoJILeJ5ut1wQe0oTdQPF9Ou8BQ8iUNC+smfPv9pqmWq+ndqfkLctpx5Qh4f8O2e6DmrxWgBAGD+fkd9QK6HOMwI5XJ5pCNMOPlQTk5OTU1NZWWlQqGQSCTdnH3jUHq5VEAR5D6SCwCwqqwIBUlKG8jaVL9Q3aSif0knCRJBkba9baSaLF5eTCulrdm9ZusHW//f7/4fiqAAgO+PfJ/lzMpflc9hccA8AADgTuYyTjJyg7nCB/qRs2oUoUhSmM8MUcGEvoMZMCwZ8xg9TruTwxuUTSASJ1VmVfCmAWapBgDQsOuyH4OKWCM+ev5oztIcAEBScpI1YCXJ2CW9WG4WuL6CvposzfEDxwX/J8ggMrBlGJ0XnYD7ukCAHbVbdVZe8jW23GF02IGd6h/+PAZjijjMCFEUFUbA5199aaJQKBMmTBgLVhAA0HGlwyzqfPIKsgT8tKHwV8zNybWj9nPHznnsnnRTeuaiTAAAZzJH8hvJKtuqbQe2AQDqTfWKowryJpLDuvrkLZxVKAlI9Ey9QHZjlrFNTE5U42pvwDvcilwD18WVJkltqM1sHiwjffyT4yaKKScnZ5D6H17yM/Kxu7EMeQYAQCAUoAiqNWpjSgoDQmVCdFrtfqEQKO78051lxWXGu4xJyfF/qbVT7GZj9G3gsXnaae30YFyNLqQ3YErGuMHsYLJShyGXvHOGU3ZYVr+t/iL7YqKycyefqqRis7C8k3nrPl3303s/sYSstJuv8QCkU+ktCS3MWSMib8hgQKVTbaitoalhuBW5Ck7i6qBak6pxoS6b1TYYQ9RU1CQ0JKgeUoVWAm48aBht7rirlY/0VH1LY0ukwPmL5wmCCHgDNJKWqLhexxYqSl00Y9G0iYMSTOmmu53GLjESdmDn2lkErEoxpIyI8OdRjdapDRABCUuS4k1JmDQMvnZF84t283e79rh4i65ZY1HNVdF8tKcuPEWQhGxVjFirwkcKh0rH4cHMMPuafdlpffI8Gmy+rf62/kL9ImSRmqv2UD2DVCiq9adWX7rv1sThSegz9DhZTl/H1d3QQDCg+EZRjpTzmDwjalRjIyt4JgqchXttnSsWFpfli91frLxnJebBEDXCNY+IhD5jh7FuCMtPl6s0KqFkIPtkLo/rQMkBpoNZSivV3KyZjEzmSIcn9GfR1EUdWR0KdnRwveRWCVgAcCeOccfi3ruP73N2jIio5NKOUvQz9F7KvbZZNgBAgBbw2gdlzZbv5lOzx9D2EiEgAoaraXquXLySBJK01VqfzGejD8qcO55wAfivr0xjTeNtFbc5vA6Gl8FKYLEr2ARBdFfsCRJ3xvoPje5DS3eVRraQJPnO1++crj3d67lnT5xN8iTNuG3GA8gDyF7EKDD2esrgoeQoY0eYYgDjj0UrCADA5BjFPCJe9Q7tOpTJzVStVWXPywYAEEzC74p/aAdBEMqgMiUtJe49j1gYcgbNftW1x1BhMCEmtB116B1e9sjaHu4KXUDH3J3/m3aTnQmYFy9d5Af5YrnYjbitdlikaegYEY+J4aKquopG0DQ6jd/np9E7/52+2vnVgroFSBlyiHvISDNaaVZRmiglNSVFkiJgXONXEigPmNJNk/InsZJYhf8udGTDoioji8SURFop7dTLpxA+kpSTpLhJAYbjleBw5eG7LXfLV8rDo5MsEgxCxrrm5mYX6lKyrstDZHQhVUuxs1i9uV7CkPBYPE4HpyqlKqkxSW/RI4KRHhXEEXN83s51XY/VAwDQV+mTiWSxXFyP1OMWXCSIQ+FDSF8Y04aw/ud6mpSG2bHWfa2FtxcCAE4dOjW5djLlYQqVTkX2Ihl4Bt1Np5+gs4+w3cDdQGmwaqxz758LAAjggRR7CuseFgAAk2CiVSKpoH+13yCDTcqElIAo4G53l5WXsY+xHVxH+pShTh3QZGvSfqWVpkgZiqtBjRQ2BbXGfzGmrbENZwyw2MIoJSklSYALyH+RTVhT2uq0RG+iZpHG/y+/y+zCkkf6QohIKgoEO9d1CRvRTm3nt/IRgDBZTDfmDjoGHgAD6S9j2hCK2kSsBSy9TS84KwC3A7fXLTouMi4wTkuaBgCY86s5kcJBT9B4yZi4L/Hg4YNz58w9f+48nUJPVXVmMqTIxvQvOWKhqqjpqvT0qenfbfmO18gbYkOodWo3vb3pWexZ9b3XeG0wuAzCF/8cWo4OB8obW5sddBZd9LgI5aIVmyuubLkSwAIFooLj9ONZvqx2VT9K+A4LMrksSARxEscQDHNh1hTrxOqJOkynBmovxRuwD3qJEkiYMfr4DhCBU5WnEvHEpLykABko+7ns2AfHXMDFZrFnz5gd8xQKkzJxxsQKUKHYq9gj3+M76+OoYFbcUQMpIQnDUOdvfGPvG+v86+S/liO0a5bpWDxWMBD/933MiGHjRvo0KO5gYgwAkPJQCv42fll+GQDgEDvQdjQhcYSmSw1DZVFpgKa36ZUCJdPDZCQxrHVWJ80JAAhQA37HiEsQeAMzFg1hU0eTdps2GSQbFIZx2DgaoMlXyJ3bnBpCgy/rZWUpe0b2lfIrMz6bEQRB9y0jojIRpC+IEkXUxiF1p9Q6tfPL59MKaJgq2jhxBVw/Hv/HHM/FYybesIGhPZOkTPpmzjdqpRoAwE5mWzusKbxR4DRkwkyEllAKlPwgnyfj6QQ6H+EDAOB0HHePrVXu4WUsGsLLhy6L+CLVI6oEduc7Y4IiQf+IvqWsZUpy7xUwxi8fP8gKQuJPUkoSsX9IZ4RHvjoyiTFJMi9GWiWhSOgm4vwWRZKkMqAUaG7MPEF94c6b7wx9yJmSc0J3IgWMAkPoorm8Ri8AQIyLRXIRq4DVuSJKB7AAxVByQ+0ofFj2od3Xe+EVSYOEOZWJctDIZNMylWzKwhukDhSkKwnyhCAZtJgtQzOc1+ed0TCDuYQZ8z9MJBCxSTaBx37Skb5+FGEP09ze7Ef8PH63SajHDiKBaPFDi4dbiz7hY/jsJrvZZiYByeKw5PnyhKIEAADKRmEBiqHkxjGEO/funPrV1He+eCeqXWfQle0vqz5eHfpaUVshI2STpo+wOnWQQQZBEC1N21jbODTDGfVGN+pO0sROUEnBKHZgt1hjWOVjO49V/r1yACO2NrTq6LoBnAgZRqgSqrfdq9PqzNg1SUcpLAriG+nhHzcSN4ghPHPsTMGpAvok+p31dx6rOhZqPNF84oPNHwT+HbCfszMOMEx6EwCg8Vhjo7QxXkXFIKMIF8dlbh2iehQ2q82B9RRX6kAdVnN0xPShnw4pa5ScIMdq6Xcwta3V5uWN9BBySBSK8QqFRWE1WB20a+4WBpsBC1AMJTeIIQTHQcOMhuQ7k70aL/45/t6P723+bDPzA2YhKBQ/Li58prBMVnb588s1DTUZrRmq2arhVhcyDJBSktAN0b6Lw+bwYj2ZJSfVaTNfkwOMIImk00mBOwIN9Iaqi1X9HREzYqj8Rvl3HjOMyx6XiqfqWnRexjV3C4vHogf6VIDi6NdHT248OTjajSFuBGeZ9tZ2cUA8sWgiAGD8/ePrv6xPOZ8CAGAvYIund5YCn37fdNebrsCHAW22tjDnBk82DYmJQC0INA5RbJbX7g3QehrLzXIHtNcI1NfXB5BA9qTshtKGQH0AFPVvRJ6Tx02CmZpHGSgVbWe0CxoFfuU1XsQcHsdP9O5X7LF4ksqSAAB19XWpmtTB0nIMcCMYworDFYSQ0FA1AACAAc09mq4yUqG0PLccI7Cbltw01PpBRgZJKUnOg0OUgzvgCvSc5CUoDKLGayZwrVWtgA2yQTY/jY8d6z0cUHtZS/gI1RQVACBIBNUBtSRtTBT+vMFwyp0TGyee55+PbOTz+X0xhHUf110SXpJT5YGDAWgIr4cbwRBKmiT+4t5vmqJfFA2+LpCRi0Kh0JE6r8/LoDN6l74+CBcBeozoY0qZaPk1hjDYHAzKgwCA8bnjXQdcwUCQQu3p37PyRCUIgpAhrG+uR1GUxYNF7EYfomwR0oSwBNf87fgCvp/0uwIuNpXd3Yn603rcjOetyqNYKMTnBE7gGDrm0inEi1G/qVBZWckgGVOmwcgHSC8gKGJBLR3ajqEYy4Og7J7+ucRqscB7TcyfwCoQpYoAAAKeoJ3SXnmlF99RmoPGdnY+JVvqWwwMw/WpDBkeMiZm+IFfIL3mZsBomAf1XK653N1ZQVvQt9d3fPLxbHl2ela6m+L++cTPg6ekw+24sOHC0bNHB2+I4WXUG8KavTVtCW03aj1uSHyxUWwh5+HBhuKl0Di0HgTGJY+TB+Uk0RkySAQJVUCVOT4z9NUkMOmqeomFEHqFokBndQJnu9Mn8PUsDxmZMOiMmvwaTXr0ho6Op2uv7jZdatlHZT9yfnzs9sdCX01qk6NyEKvflJ4tFQKhYo9if9n+wRtlGBnd9qOsrSzXljv9junDrQhkdOBheOym3lMuXD+0AI3F72mhks/mWxGrTttp7eqr69uwNj6HH/qKqTFM29MyFxEkRISIRbD8Xj8AgGak0RQ92V3ISGb27bO7LtcTKgJt7eb5TACJSXLTL2/CkM6bhJvMHdSi9s4rzvrkel+mD99zYyZ+G8WG0OA2/PjNj06xkyOCya8hfSLICnqtQxFsxwqyOLxebks9Vd/e3PnK31HdYeReLewsS5EJXcIezm1tadWhuja0rb2pHQAgdAsVKYrr1hoyglBkKuR2ecxDdVfqtKg2MyEz3JKSlaL2q0myc4HB4Xd89uNn5a+W15TV9HE4v99fW14b7iFaGZMiIS9BdZMq0ZvYn4sYNQyiIdTr9bfeeiuHw1Gr1R9//HF8O3/j4zfe+8d7v7D9ImX+KMgoCBkhIDwEsQ1FLgUuwRUIe0n76Wa7bR2doYTMRqZPfXVtMy09TRaUBfzdBmBoW7RmutlKt+radXavPRFP7C6LDWSUkpyZnIQnmRwxVvJbLrXoRfrIFplU5gf+5qbm0Nddu3YVnC3wkb6W6pY+Dndi9wneLl7NSzVHj0dvBFY3VQtIQcb4DJFCxEf47aaRXt9qAAyiIXz66adlMpnFYvn8888fffTR1tbWePXs9DkX1i5ckblCXaBmp3frVQWBRMEUMCnuofCU5pE8kaiX8uJBUZAwEgCAhsoGnpNXML8gfIjNYLdhbU11Td2d69A5vGyvj+tz6V0XLl6wUWwUxo3gAQ4Jg1JRLU1bebky4Azg/msWJJmtTHZm9HOvndXeVN15wyTVJ3nme7TjtIS5rxkksDqsbEpZe2q770L0ZnPN2Zo2flsoM3MHpaO5oXkAlzPCGSxD6HQ6P/vssz//+c9UKnXmzJnz5s3bsWNHvDo/+fNJP80v/KWQWcQEMFcapM9wpVym/5qwBsJHaEu18R3FbrcHQKDXIA22jE230wEALd+1NGQ0KPjXrG2aWKaO+m4dXEkTCUQAiABiRmzlNpNsKDyAIEOMVWR1n3Z3/KPj5LtXc8d4PJ4EX0LetLwoYZ/E523xAgDKGsvS8fT0KekcCYfq6FOeNq/Pm+xKnlQwSZGnUNij19gZ9QxqRmc/Tq7T0jpEmeuHksEyhM3NzQRBZGRkhL7m5OTU1HS7Wk2SpMPhsPwXv7+XoEC8FLem9jsZIwQilUn5QX5kS9nFMv1ufXfyA8NitthQW69i0gSpwqPY/a/dap96/t3zo476pL5ge7fFexkOBlfB5Sl4DBdDqpfyJsCiEzcgTA0zx55TOaEywZBg1nWmyb104lILrSXsVxWGPY7NMXMAAJUnK9uF7QgVkagkfG+0WEwunL7QRmuTiCQZGRlsnG00Xt2uLq8q1/g0eXM67S4hIoYsT+FQMljLKVarlc1mI0jnfI3H4125cqU74fr6+iVLlmBYpwdURkbGvn37Yko6nU63z51tz0Z/gTocg+guDBmZeDwev98fvlX6C4PFkBJSi81CQTvvfGO7MRlPvv57yaQ3NR1oyn8gHwCg0+pIlOy1T6lUepRyVEQR0e+ie7wecK0TD11KZ5WyuutE6BeSYjIIgnwPnwqorLRuJW88nM4hSg807EyYNsGb453JnrmvfZ9klyR7VrbxoFHpUNbm1Xb9c8sT5dSjVIfDIW4UU6ZTHA6HUCIEOLDb7eHncHfYLtlIZecd28hoRM4gU2Z3Rmbr9+h9ap8kIPEFfAAAmpRGtvZ+bw8qbrcbx/FeLyoMg8GgUnuZGQ+WIRSLxQ6HgyTJkLpWq1Umk3UnnJqa+s9//nPGjBl96fnS2UsIA5k1blbcdIWMHjAMo9PpAzaEAIBGpDHgCSQqOp3fSBf5/9u79+AmrnMB4GdXq/f7bcmSLb8N2MQ8jIGYRzEkFzukSer0ZsibS6dJmpn0JtPOvZ3OtJ2kLb1N77RhkjalCbm36SQUAmSgXF6BGNtjCMYEA7HBBr9kS7Yk6716rKS9f8gVtjGWH5KFre/3l3R0dveAj/bTnj17PjEtFgqEsxxjv/rVVd2gTigUIoRCwRDFpKKvJyFEwtr/qL3XpwVLCphfMYVCodfp5YvH3BAKBoOKiEJWLAvTYSdy3uTeXCdPr4UD4/7fLhhCkRAhVPZ4GfsvbMsRy1nF2epnqzfJN01QUyhsQ22d73QWRYo06zQ4CxcKhbewW8iLNBrNJIegaTrbkc3Ywoj+r3o1Xr6RLxAImoxNcrfc4DIInhfE/sNzCnPs5+2p/f/HcZzH4009EE5pnwnc12h6vZ7D4Vy7NrIywpUrV4qKiibfZIpKVpRkPQ0T5MAM2Qm7dejOyA/mwhiI4XTFH8mcHDlESmhJiAohhAKuQJAdf82/yRm0BpImb/7XTfIdsqdrzKyZ7t7uIXyISTA5TM4QPuTOSpdrwbSVo8lp+3Yb71XeKy+9YpAb7lWNu5Mr3yaXbZfhrJETu4WwDBjjTPJsvtwcwe7cxpIWSqU26d7P9/L/l889yG3UNyolylhljU4jo2VOz2y/L7MRdAdRokdnk3VFyOPxtm/f/rOf/eyDDz5obGxsbGz86KOPErJnsUgsFk1p4BuAu3lZXsp657EEpo+JEBoeHhaLZ9Wp8GEcR7ip36Q36IOeIJpSCp1Jd4jhJ0QnEA/lE/mCw4Lsf8+OfTTYO0hzRp73upxzee1aGB1Z+KqWjr+LfDdDhgGNneni4Xswc5wrp6GmIX7WnSGHktISzwnPpmub+NV85TLlM9gzoytjOGYmzPgt/IEHUpbbvOujLrQFLV+xPIH7TOKU69/+9revvvrqokWLMjIy9u3bp1ZP/HAoAHOJ4lLkMBl7KwgKvMjrsrvQ7J5H5Xv5fuS3mC16gx6RiOZN/GDytHz/1e+zGWyf39f/dv/FSxfLV5RHyz1mD0M0Mjj83PbnZn8gsFBFxJGwdbK1YNx+96LhRcLH7gx1irnivfq9G9ZtMOQZJtzEyXdSfRRKURy09lvFIbG2NME5ZZMYCMVi8V//+tfk7R+AGaCFdNh559QgC8l6mD2zf8peGVS2s9sxK4YQwv04JkvADQw2g40Q4nK45gfM6AuE/rmwPDFM4Lp5vCYUmDNsBTvYOdkofd2XdXq2PjdzzEqnP3zhh5NsgumwyO2UTRy9WX/TIrSMJN1LHPg6gfTCkrAY3pHLKZ/Px6bZHoHH75zVumtet5dJM0klSQ1TCCFGgMHiJ3LlzzVb12QGM6+0XYm+FXgF0szJFmADIEqaIRV6J5vYgrfjgeLpLddeUllS6CokA2T8qkkg7ZYSpYm/foNACNKLRCXh+UaWwzaZTBbcQnPoEHnPJ/amoqerZ4AxwJKycDeOEOIFeHxJIhc8YhAMY5ax54uRKTNqSq03LMwlH0Fi6bJ0ypBykgoKUiEriLME0jhyldzJdDadb4pfNdHsvfYIFSlfXp7wPUMgBOlFrVXHshcNDw47mU5aQCMvQgh1fNLhMs8kN8Vw/7CL5xIoBVySG6JCekqfW5jgoZulW5cudSwdsA9Yh60MmqFUTnZ2AyBKppDhGN5+a+LclhE6og6rM3WZ090taSA9V1LwNGf7xfZ2SfskyYpnDAIhSC9KjTKDznD4HAght83t5/pZfBbuxxFCjNuMb67cc9mHSfiH/AFxQKFRiIPitm/azIRZKk7w0KVYKR4SDjWdaOq93WtmJnhNOLCA9cBW9YwAABRRSURBVMh6ui92T/iR2WrGMIwr5E746SSKHywuchZ5Ke9sGzdNocEQUzOlReOmCwIhSDMM5MJdff19CKGgIxgRRDhCDivICvqC0oiUNM3kzgfTwWQr2VqtVhFRWL6xWMRJSRYvWC3Q39Lb+m1uPjw4CKaKvYQt7p340SCT0WQhZtJXZToZzaQbLzTOrmnTJnAJFNmKZOwZAiFIOw62wzJgQQhhLgwX4wKpgENx+rr7EEJMx0x+bwp9QmmmlM/hOzGnrEdG5CZlMvbiVYulSErcIMKyhZkcFSTD0lVLdQGdyzHBmL/D7PBwZjjCac+2B76e3iybmH5n/6GmQ9Pdio7QGVRGQWHBzA46OQiEIO34eX63xY0QYvvYfBlfLBYLwoIh49Bt/LaUvOeQZn1v/anbpyb8SEkpdVk6hJCNsGVT2XmleUlpN4aMWcayQBlPw0vK/sFCxOfyO3gd15uuI4T8If+vTv3K4R/JWOC3+UPCGU4Ty1uXt8i+KBiayQpKDZ81lJ0uM1qml5jP2Gu0YlalOCl3xyEQgvQjQeHhMEJIEBRIlVKZXCaOiL2DXrPCrAgr7pX8xHjaaP/U7gqM/2UdDAYJRKhkKoSQh+Mx4saczGQliy6uKg6jsFoPa1OAafDl+kRXRA0XGva8u2fn+Z2xlAaEg8BlMwwBap3axXQ1n2+e7oY2r+2B/gfsfHvb/rZpbdh7q9fKtcavNyMQCEHa4Sq4LA/LF/SpQ2qdXicSihiIwbQxmWrmIGPw1q1bE24lsUs2RDac/PTkuHLroNWKW3EMRwhRfKpf2J+8lmu0ms5vdRbkJ2V0CCxUa/9lbae2M/t0dnWoenD5YE7ryA81DskRqAQz3q3VYA1cmfbo6Bf/+MLH8xleNOTb8ntvTiPHr9foDUhnOBgbFwRCkHZkGpnIJ2o632RhWaKr+zsxZ4YnQ5IpcfAcpp6J0+Eq/Ur3ZvfKvpXdXd2jy4etw27GyOwVZaVSXJXchXBXV65O7Lr7YMGTcqXffu7b+v/U572et6R6CaJRe1M7QkhGyZTamY80Fq8vzrHnDA8NT30TmqZzOnKEG4Uyqezr/K8dhx1oymsRMoeZvMxk3RSAQAjSjiZTowqrHFcc/uyRBWXcDLcqotJl6Sgp5TePFLbWtfbfHrm8s3ltuogub2Veh6Tj1pUxl4yuYRfJHplrWr6ofM2SNXP17wBgOnCEMIRjeNuiNrwBp0KUKqKawUOEMVnarNaM1puf3pz6JhaHRRvR5q/IRwhtrd1KhsiW4y1T3Fbmk2XmzLy1k4NACNIOV8qVImmxo7h4bXG0xEf4PMijUWl4Gh7TPjJxdLhl+OaXI1/y27dvDxPDGIEhLUJj7/EHnIEgZ7ZJlwCYM+uq1lkClo5/dDhwR9yMtZOr/NdKiUtys2WqsdDcb449sMFhckIPhWSXZD6PL+6GLtKlDqsNuYYZN3VyEAhB+sGQjbBxGBxp1sgc0SAraCbMGIZps7VS30ghESIkQ5Loa0uvxcFzIIQyizLlbvnonYVdYZqfgFwTAMyNbHF2d3m3olVhI2yz3JVMKLtddjtwMjDFEc7hwWE3+85TsJUrK29zb188ezHuhp0dnYPEIIOYeUbuyUEgBOkoxA8Fsu7ceA+xQ26eGyGkydJow1qaphFC7BBbT+n9Xj9CKDgYpGQUQqiwqFAZUjrddxKTYiQWS4oEwLyw/aHt17nXffz4l2JxPVzzcCASqP+/+qlUJi1kQDBmwgtRQtDt8aOopdvi4Dtm2MQpgEAI0lHR+qLCzYWxt1w1l5HJQAixuWwGYrh8LoQQL8IbwAbaL7cjhLgOLlfDRQgRBGFkGduu3Zn5zfKzeGJ4sA/MJxiGlf1b2eLHFs9+VwyMgW/BVZdVXn/8FddwJ44kY0pWrVuVF8jrtcSZPkqb6ZByVivjx2lY8nYNwH2LXcZmZNy5jFv/+PoNtRuir9242263I4QEtKBL2eVqdyGE5D55RvZI8m+31G27ZfN0e4YuDCGEeEGeSC6a638AALMjlUo1Ok1CdrW8fLmD7Wg42YAQamhsaPpVky848bUm08vkyscsbcrhccwCc9OXcXJZCJwCUVYSv2UQCAEYw4t7XXZXOBLm0TzJAxKpVerxe3QRXaZhZMYa18BVGBX2j+0DXw4ghCQhiUwxvUQ2ACwwwcIgfgtHCHkve7PD2af/5/SE1UQBkSxj/JdFVCbidfC+Nn89yf41QU1WflaiWns3CIQAjEESpMfjcbgcJEYue2CZgBIY/9voIBwM5sgVZP6S/EKq8GvD16qgKhwIC2iBWgVLvYC0VrK2JN+b7/a7sx3Z5CPk0sGlDRcb7q6mDCm1Ou24woLVBcu5ywN/CRw9d3TCnQ+YB3CEq9VJ/JZBIARgjCAz6Hf7XQ6XF/OKuKJvHvuGfJjMfi47VkGdqcaewbY9s60H72m72ObAHGyCncIGA5ByUoXUTbiPHDhC43T+snx7uZ15kklSY3K5DDuHCUSIxeNXnMA4WOYPMzPWZiw+t7iure7unffe6h1gDSSx9RAIARgnzAoHPAG3y00ySIRQTWnN8hXLuZljbmxIciQIIZvI5rjqcDCSOJkNgPnCqXWu6VpjU9sQQmUPl/FZ/MP7D4+uYDKaLIx7ZH3CUPambGoxFTkY6bJ3jfvQ1evyiJObBxgCIQBj0Gw6RIa8Hq+f4Z+8ZlgbzrJleZlznZ4UgPuQfoVegiQZy0fmlCkfV666tard1B6rMGwednEmyAYVU/R4kYajaToxfuIMYSVGT21LhoQFQofD0dU1PpK73e66urobN24k6igAJBvGwzAf5nf7KSY1eU1tkVZIC2FZGQAQQoZFBqvemr80P/pWna92qV2tB1pjFUgbGeBNumo2hujVtK5LN65Y7pErDUnJvhSTgEB46dKl/Px8uVxeUlIyuvzixYv5+flvvfXWli1bXnnlldkfCIA5QPAJzIcFyWCEFZm8ZklxiRu5Q7wkPt4EwLyBo4IXCtCoK7clTy2pcFZ8dfWrkfd2RMviPDu/aPWirHDW9Y7rsZJhy7A4JC5eUpz4Bo+SgECo0+k+/fTThobxc4R+/OMfv/HGG6dOnWppadm/f/+lS5dmfywAko3NZzMpZsgXollxvrRcgtvN7MaFcH8BgAmwReyBogHyGBmhIwghkUMkUMbL+sRA3cruvoa+WMG189c6hZ3Jno+WgO+wWq1euXIli8UaXWi1Wuvq6l544QWEkEKhqK6uPnDgwOyPBUCy8UQ8FsWifTTixq88UD6gLEvuoA0A81fF4xXqiPro0aNnzp6RhqWrKlfF3USxVmEYMNCRkZ+h+C08nBtOcjMRkaT9Go1GNputUqmibw0Gw73ynSKESJI8ffp0T09P9G1GRkZlZeWENSORSCQSZ8AKLGDRDpDUhHw8Ic8X9pEBkiFjxO1s3/3Wd6OtSl57wDhwEphPcMSuZhcfKfZi3uC6IIMR/zu1eMniC8cunD1wdmPtxkgoku3JplfSo7ea7kkAx+Nf700pEF67du2nP/3p3eW7d+/W6/UTbuL3+9nsOxezbDabJMkJayKEHA7H6dOnY2OnGRkZy5cvn7Cmz+djMGCB4/RFkmQ4HE5qH+CwOYKIwBawYQQ2SacFqQIngflFlafqUHWw3Kzs5dlT/EIJa4SaQ5r22+2+QV8IDy0RLRm9oc/nQwhNPRByOByCiBPpphQINRrN9773vbvLpVLpvTZRq9Uul4uiqGi+K6vVqtHcc107rVa7a9euioqKuC2haVogiDfKDBYuHMfZbHZSz4NcJhfRiBViCWVC6Gz3ITgJzDtlO8pQCGGcqYaukpKSxkuNqk9VQiS8nHm5QjAmNGAYxuPxEjssNKVAKJfLa2pqprVfvV6v0Wjq6+s3bdqEEDp37txrr702kwYCMLcYbAYTMbkUlyeAnBIAJABGYNO9C/fgMw8a24yD+OC6nHXJadQYCbhH6Ha733vvvf7+foqifvOb34jF4pdeeokgiNdee+0HP/jBW2+91djYaLVaa2trZ38sAOaAG3dnhjMhyyAAKcNAuhKdDo1/pjBJEhAIaZq22+08Hu/111+32+2xK9Yf/ehHCoXis88+y8jIqK+v53KnMAkPgPuAl+HVR/SENFlTyQAA95UEfNVFItGuXbvuLscwbMeOHTt27Jj9IQCYS36GH1FIKBSmuiEAgLkAzwIDMF6QGQygAIKRUQDSAwRCAMYLcUJu3J3qVgAA5ggEQgDuwkIkDk8QApAuIBACMB7Ox4ME5JQAIF3Mp0Do8/l2796d6laAVDp8+HB7e3v8erMjl8lZPFb8emDOuVyu999/P9WtAKm0b9++u1P+zdJ8CoQWi+WPf/xjqlsBUunIkSNzkMakaFFRYVlhso8CZqCvr+/DDz9MdStAKh06dKi1tTV+vemAJ6UAGI/QEYQOvhoApIv5dEUIAAAAJBwEQgAAAGkNo+k4abjngFarZTAY41L73i0cDg8MDNwr8RNIBxaLhcfj8fn8VDcEpAZFUYODgzrdHC1BCe5Dg4ODQqGQx5vqmvjbt29/8803J69zXwTCwcFBr9c7lZqBQGB0mkOQbiiKYjAYU8m0CRYqOAmkuWAwyGQyp56GSaPRxF3p+r4IhAAAAECqwC9rAAAAaQ0CIQAAgLQGgRAAAEBag0AIAAAgrc2b5TN8Pt+f//znnp6e1atXP/nkk1OfMgTmF4qirl692traKhAIamtrY+U0TX/yySfNzc25ubk7d+7kcDjR8r6+vr1797rd7u985zurV69OUatBIjU3N586dcpmsy1evPjpp5+OzRF1OBx79uwxmUybN2+urq6O1a+vr//888+lUumOHTs0Gk2KWg0SZmBg4PPPP+/s7OTxeFVVVRs3box9dOLEiRMnTmRkZOzcuVMmk0UL79Uxpm7eXBE+8sgjx48fLygo+PnPf/6LX/wi1c0ByfLBBx/U1tbu3r173F/5Jz/5ya9//euCgoIjR4488cQT0UKLxbJq1Sqr1arRaLZu3Xr69OlUNBkkktlsfuKJJ2w2m16v//DDDzdu3EhRFEIoFApt2LAh+kvo5Zdf/tOf/hStf/To0ccee0yn0xmNxoqKCqfTmdLmgwRobm6+evVqVlYWQRBPPvnku+++Gy3fu3fvjh07cnJyWltbKysrg8EgQigUCq1fv/7SpUvjOsb00PNBU1OTXC73+/00Tbe0tIjFYo/Hk+pGgaQIh8M0Tf/9738vKSmJFTqdToFAcO3aNZqmSZIUi8UtLS00Te/atau6ujpa5/e//31VVVUqmgwSKRQKBYPB6GuPx8Plci9cuEDT9KFDhwoLC6Pd49ixY9nZ2aFQiKbptWvXvv/++9H6mzZteuedd1LUcJAU77333tq1a2majkQiBQUFBw8ejL4uLS395JNPaJo+ePDg6I5hMBiir6dlflwR1tXVrV+/PjpCsmzZMhaLdeXKlVQ3CiTFhA/Lt7S0iESiJUuWIIS4XG5lZWVdXR1C6Ny5c1u2bInWeeihh+rr62l4LnaeYzAYTCYz+jocDodCIYFAgBCqq6urqqqKdo+qqqq+vr7u7u5gMNjU1LR58+Zo/S1btkQ7BlgYKIq6cOFCaWkpQshkMnV0dET/1hiGbd68Ofq3Htcxent7u7u7p3ug+REIzWazUqmMvVWpVAMDAylsD5hj4zqAWq2OdgCTyRQrV6lUwWDQarWmpokgCV5//fWtW7cuXrwYje0DLBZLKpWaTCaz2UzTtEqlipar1WqTyZSy5oLE6ezszMvLk0gkN27c+N3vfocQMplMXC5XKBRGK8ROAhN2jOkebn4EQoIgwuFw7C1FUXEXJgULyd0dIDo8QBBEKBSKFkZfQMdYMN58882GhoY9e/ZE3054EoheO8b6AJwZFoycnJzm5ubz589LpdKXX34ZIcRkMqOD4dEKo08Cs48O8yMQZmZm9vf3R1+Hw2Gz2azValPbJDCXtFqtyWSKRCLRt/39/dHJgZmZmbGxAaPRyOfzxWJxyloJEuftt9/++OOPz549G7vaG30ScLvdbrdbq9WqVCqCIGLlsY4B5jsGgyGVSktLS3/5y1/u27ePpmmtVktRlMViiVYYfRK4u2NM93DzIxDW1NTU19cPDg4ihE6ePCkWi5ctW5bqRoG5U15ezmQyz5w5gxAaGBg4f/58TU0NQmjbtm0HDx6M/h7cv3//tm3bUtxQkAh/+MMf3n333ZMnT46Oatu2bTt+/Ljb7UYIHThwoKysTKfTMRiMmpqaAwcOIIQoijp8+PCjjz6asnaDBCFJMva6ublZp9NhGKZQKNasWRP9W5MkeezYsejfelzHWLZsWWZm5rQPmcj5Pcn06quv5ufnv/jiiyqV6m9/+1uqmwOSpaWlZcWKFbm5uVwud8WKFS+99FK0fO/evSqV6sUXX8zLy3vjjTeihSRJrlq1qrKy8qmnnlKpVNFppWBe6+rqwjDMYDCs+KeTJ09GP6qtrS0pKXn++ecVCsXx48ejhS0tLQqFYvv27WvWrFm3bl0gEEhd20FiPP300+vWrXv22WerqqpkMtmxY8ei5WfOnJHL5c8991xZWdmjjz4aiUSi5bW1taWlpdGOceLEiRkccT5ln2hqauru7i4vL8/Pz091W0CyeDyeGzduxN4KhcLCwsLo6xs3brS0tOTm5lZUVMQqBIPBM2fOuFyuzZs3xx6wBfOX3++/fv366JLc3FypVIoQomm6rq7ObDY/+OCDo/OSWiyWs2fPSiSSTZs2EcS8WSQE3Ivf7//qq6/6+/vlcnlFRcXo+x39/f319fVqtXrDhg2xGeb36hhTN58CIQAAAJBw8+MeIQAAAJAkEAgBAACkNQiEAAAA0hoEQgAAAGkNAiEAAIC0BoEQAABAWoNACAAAIK1BIAQAAJDWIBACAABIaxAIAQAApDUIhAAAANLa/wPe78zGZhezVwAAAABJRU5ErkJggg==", "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" + ], + "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", + " \n", + "\n", + "\n", + "\n", + "\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" + "output_type": "display_data" } ], "source": [ @@ -1470,15 +1404,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.8.1", + "display_name": "Julia 1.9.3", "language": "julia", - "name": "julia-1.8" + "name": "julia-1.9" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.8.1" + "version": "1.9.3" } }, "nbformat": 4, diff --git a/examples/problem_specific/Invertible Neural Network Tutorial.ipynb b/examples/problem_specific/Invertible Neural Network Tutorial.ipynb index a72d14775..b784d0065 100644 --- a/examples/problem_specific/Invertible Neural Network Tutorial.ipynb +++ b/examples/problem_specific/Invertible Neural Network Tutorial.ipynb @@ -427,7 +427,7 @@ "end\n", "\n", "# First execution is slow due to Julia's initial compilation \n", - "result = inference(\n", + "result = infer(\n", " model = fmodel, \n", " data = data,\n", " constraints = constraints,\n", @@ -5209,7 +5209,7 @@ "source": [ "function f(params)\n", " Random.seed!(123) # Flow uses random permutation matrices, which is not good for the optimisation procedure\n", - " result = inference(\n", + " result = infer(\n", " model = fcmodel, \n", " data = data,\n", " meta = fmeta(model, params),\n", diff --git a/examples/problem_specific/Probit Model (EP).ipynb b/examples/problem_specific/Probit Model (EP).ipynb index b30b888f9..18370c88b 100644 --- a/examples/problem_specific/Probit Model (EP).ipynb +++ b/examples/problem_specific/Probit Model (EP).ipynb @@ -375,7 +375,7 @@ } ], "source": [ - "result = inference(\n", + "result = infer(\n", " model = probit_model(length(data_y)), \n", " data = (y = data_y, ), \n", " iterations = 5, \n", diff --git a/examples/problem_specific/RTS vs BIFM Smoothing.ipynb b/examples/problem_specific/RTS vs BIFM Smoothing.ipynb index 9b36e1cb7..3eb90fac5 100644 --- a/examples/problem_specific/RTS vs BIFM Smoothing.ipynb +++ b/examples/problem_specific/RTS vs BIFM Smoothing.ipynb @@ -327,7 +327,7 @@ " *() -> ReactiveMP.MatrixCorrectionTools.ClampSingularValues(tiny, Inf)\n", " end\n", " \n", - " result = inference(\n", + " result = infer(\n", " model = RTS_smoother(length(data_y), A, B, C, μu, Wu, Wy),\n", " data = (y = data_y, ),\n", " returnvars = (z = KeepLast(), u = KeepLast()),\n", @@ -356,7 +356,7 @@ ], "source": [ "function inference_BIFM(data_y, A, B, C, μu, Wu, Wy)\n", - " result = inference(\n", + " result = infer(\n", " model = BIFM_smoother(length(data_y), A, B, C, μu, Wu, Wy),\n", " data = (y = data_y, ),\n", " returnvars = (z = KeepLast(), u = KeepLast())\n", diff --git a/examples/problem_specific/Simple Nonlinear Node.ipynb b/examples/problem_specific/Simple Nonlinear Node.ipynb index 12a107d18..ad07c6f4b 100644 --- a/examples/problem_specific/Simple Nonlinear Node.ipynb +++ b/examples/problem_specific/Simple Nonlinear Node.ipynb @@ -267,7 +267,7 @@ } ], "source": [ - "result = inference(\n", + "result = infer(\n", " model = nonlinear_estimation(n),\n", " meta = nmeta(nonlinear_fn, nsamples),\n", " constraints = nconstsraints(nsamples),\n", diff --git a/examples/problem_specific/Universal Mixtures.ipynb b/examples/problem_specific/Universal Mixtures.ipynb index 54e6dfbde..02b0e5369 100644 --- a/examples/problem_specific/Universal Mixtures.ipynb +++ b/examples/problem_specific/Universal Mixtures.ipynb @@ -757,7 +757,7 @@ } ], "source": [ - "result_john = inference(\n", + "result_john = infer(\n", " model = beta_model_john(nr_throws), \n", " data = (y = dataset, ),\n", " free_energy = true,\n", @@ -782,7 +782,7 @@ } ], "source": [ - "result_jane = inference(\n", + "result_jane = infer(\n", " model = beta_model_jane(nr_throws), \n", " data = (y = dataset, ),\n", " free_energy = true\n", @@ -1132,7 +1132,7 @@ } ], "source": [ - "result_mary = inference(\n", + "result_mary = infer(\n", " model = beta_model_mary(nr_throws), \n", " data = (y = dataset, ),\n", " returnvars = (θ = KeepLast(), θ_john = KeepLast(), θ_jane = KeepLast(), john_is_right = KeepLast()),\n", diff --git a/paper/example.jl b/paper/example.jl index b68a1fa00..0f68391fa 100644 --- a/paper/example.jl +++ b/paper/example.jl @@ -77,7 +77,7 @@ function experiment(observations) noise_scale = scale(q(noise)) end - results = rxinference( + results = infer( model = pendulum(), constraints = pendulum_constraint(), meta = pendulum_meta(), diff --git a/paper/paper.md b/paper/paper.md index 373659ed4..c585528f6 100644 --- a/paper/paper.md +++ b/paper/paper.md @@ -210,7 +210,7 @@ function pendulum_experiment(observations) noise_scale = scale(q(noise)) end - results = rxinference( + results = infer( model = pendulum(), constraints = pendulum_constraint(), meta = pendulum_meta(), diff --git a/src/inference.jl b/src/inference.jl index a74069c97..0a83952eb 100644 --- a/src/inference.jl +++ b/src/inference.jl @@ -1,7 +1,8 @@ export KeepEach, KeepLast export DefaultPostprocess, UnpackMarginalPostprocess, NoopPostprocess -export inference, InferenceResult -export rxinference, @autoupdates, RxInferenceEngine, RxInferenceEvent +export infer, inference, rxinference +export InferenceResult +export @autoupdates, RxInferenceEngine, RxInferenceEvent import DataStructures: CircularBuffer @@ -128,13 +129,13 @@ function __inference_check_itertype(keyword::Symbol, ::T) where {T} """) end -function __inference_check_dicttype(::Symbol, ::Union{Nothing, NamedTuple, Dict}) +function __infer_check_dicttype(::Symbol, ::Union{Nothing, NamedTuple, Dict}) # This function check is the second argument is of type `Nothing`, `NamedTuple` or `Dict`. # Does nothing is true, throws an error otherwise (see the second method below) nothing end -function __inference_check_dicttype(keyword::Symbol, ::T) where {T} +function __infer_check_dicttype(keyword::Symbol, ::T) where {T} error(""" Keyword argument `$(keyword)` expects either `Dict` or `NamedTuple` as an input, but a value of type `$(T)` has been used. If you specify a `NamedTuple` with a single entry - make sure you put a trailing comma at then end, e.g. `(x = something, )`. @@ -182,17 +183,17 @@ __inference_postprocess(::Nothing, result) = result """ InferenceResult -This structure is used as a return value from the [`inference`](@ref) function. +This structure is used as a return value from the [`infer`](@ref) function. # Public Fields -- `posteriors`: `Dict` or `NamedTuple` of 'random variable' - 'posterior' pairs. See the `returnvars` argument for [`inference`](@ref). -- `free_energy`: (optional) An array of Bethe Free Energy values per VMP iteration. See the `free_energy` argument for [`inference`](@ref). +- `posteriors`: `Dict` or `NamedTuple` of 'random variable' - 'posterior' pairs. See the `returnvars` argument for [`infer`](@ref). +- `free_energy`: (optional) An array of Bethe Free Energy values per VMP iteration. See the `free_energy` argument for [`infer`](@ref). - `model`: `FactorGraphModel` object reference. - `returnval`: Return value from executed `@model`. -- `error`: (optional) A reference to an exception, that might have occurred during the inference. See the `catch_exception` argument for [`inference`](@ref). +- `error`: (optional) A reference to an exception, that might have occurred during the inference. See the `catch_exception` argument for [`infer`](@ref). -See also: [`inference`](@ref) +See also: [`infer`](@ref) """ struct InferenceResult{P, A, F, M, R, E} posteriors :: P @@ -278,244 +279,7 @@ inference_get_callback(::Nothing, name) = nothing unwrap_free_energy_option(option::Bool) = (option, Real, CountingReal) unwrap_free_energy_option(option::Type{T}) where {T <: Real} = (true, T, CountingReal{T}) -""" - inference( - model; - data, - initmarginals = nothing, - initmessages = nothing, - constraints = nothing, - meta = nothing, - options = nothing, - returnvars = nothing, - predictvars = nothing, - iterations = nothing, - free_energy = false, - free_energy_diagnostics = BetheFreeEnergyDefaultChecks, - showprogress = false, - callbacks = nothing, - addons = nothing, - postprocess = DefaultPostprocess() - ) - -This function provides a generic way to perform probabilistic inference in RxInfer.jl. Returns `InferenceResult`. - -## Arguments - -For more information about some of the arguments, please check below. - -- `model`: specifies a model generator, required -- `data`: `NamedTuple` or `Dict` with data, required -- `initmarginals = nothing`: `NamedTuple` or `Dict` with initial marginals, optional -- `initmessages = nothing`: `NamedTuple` or `Dict` with initial messages, optional -- `constraints = nothing`: constraints specification object, optional, see `@constraints` -- `meta = nothing`: meta specification object, optional, may be required for some models, see `@meta` -- `options = nothing`: model creation options, optional, see `ModelInferenceOptions` -- `returnvars = nothing`: return structure info, optional, defaults to return everything at each iteration, see below for more information -- `predictvars = nothing`: return structure info, optional, see below for more information -- `iterations = nothing`: number of iterations, optional, defaults to `nothing`, the inference engine does not distinguish between variational message passing or Loopy belief propagation or expectation propagation iterations, see below for more information -- `free_energy = false`: compute the Bethe free energy, optional, defaults to false. Can be passed a floating point type, e.g. `Float64`, for better efficiency, but disables automatic differentiation packages, such as ForwardDiff.jl -- `free_energy_diagnostics = BetheFreeEnergyDefaultChecks`: free energy diagnostic checks, optional, by default checks for possible `NaN`s and `Inf`s. `nothing` disables all checks. -- `showprogress = false`: show progress module, optional, defaults to false -- `callbacks = nothing`: inference cycle callbacks, optional, see below for more info -- `addons = nothing`: inject and send extra computation information along messages, see below for more info -- `postprocess = DefaultPostprocess()`: inference results postprocessing step, optional, see below for more info -- `warn = true`: enables/disables warnings - -## Note on NamedTuples - -When passing `NamedTuple` as a value for some argument, make sure you use a trailing comma for `NamedTuple`s with a single entry. The reason is that Julia treats `returnvars = (x = KeepLast())` and `returnvars = (x = KeepLast(), )` expressions differently. This first expression creates (or **overwrites!**) new local/global variable named `x` with contents `KeepLast()`. The second expression (note trailing comma) creates `NamedTuple` with `x` as a key and `KeepLast()` as a value assigned for this key. - -## Extended information about some of the arguments - -- ### `model` - -The `model` argument accepts a `ModelGenerator` as its input. The easiest way to create the `ModelGenerator` is to use the `@model` macro. -For example: - -```julia -@model function coin_toss(some_argument, some_keyword_argument = 3) - ... -end - -result = inference( - model = coin_toss(some_argument; some_keyword_argument = 3) -) -``` - -**Note**: The `model` keyword argument does not accept a `FactorGraphModel` instance as a value, as it needs to inject `constraints` and `meta` during the inference procedure. - -- ### `data` - -The `data` keyword argument must be a `NamedTuple` (or `Dict`) where keys (of `Symbol` type) correspond to all `datavar`s defined in the model specification. For example, if a model defines `x = datavar(Float64)` the -`data` field must have an `:x` key (of `Symbol` type) which holds a value of type `Float64`. The values in the `data` must have the exact same shape as the `datavar` container. In other words, if a model defines `x = datavar(Float64, n)` then -`data[:x]` must provide a container with length `n` and with elements of type `Float64`. - -**Note**: The behavior of the `data` keyword argument is different from that which is used in the `rxinference` function. - -- ### `initmarginals` - -For specific types of inference algorithms, such as variational message passing, it might be required to initialize (some of) the marginals before running the inference procedure in order to break the dependency loop. If this is not done, the inference algorithm will not be executed due to the lack of information and message and/or marginals will not be updated. In order to specify these initial marginals, you can use the `initmarginals` argument, such as -```julia -inference(... - initmarginals = ( - # initialize the marginal distribution of x as a vague Normal distribution - # if x is a vector, then it simply uses the same value for all elements - # However, it is also possible to provide a vector of distributions to set each element individually - x = vague(NormalMeanPrecision), - ), -) -``` -This argument needs to be a named tuple, i.e. `initmarginals = (a = ..., )`, or dictionary. - -- ### `initmessages` - -For specific types of inference algorithms, such as loopy belief propagation or expectation propagation, it might be required to initialize (some of) the messages before running the inference procedure in order to break the dependency loop. If this is not done, the inference algorithm will not be executed due to the lack of information and message and/or marginals will not be updated. In order to specify these initial messages, you can use the `initmessages` argument, such as -```julia -inference(... - initmessages = ( - # initialize the messages distribution of x as a vague Normal distribution - # if x is a vector, then it simply uses the same value for all elements - # However, it is also possible to provide a vector of distributions to set each element individually - x = vague(NormalMeanPrecision), - ), -) -``` -This argument needs to be a named tuple, i.e. `initmessages = (a = ..., )`, or dictionary. - -- ### `options` - -- `limit_stack_depth`: limits the stack depth for computing messages, helps with `StackOverflowError` for large models, but reduces the performance of the inference backend. Accepts integer as an argument that specifies the maximum number of recursive depth. Lower is better for stack overflow error, but worse for performance. -- `pipeline`: changes the default pipeline for each factor node in the graph -- `global_reactive_scheduler`: changes the scheduler of reactive streams, see Rocket.jl for more info, defaults to no scheduler - -- ### `returnvars` - -`returnvars` specifies the variables of interests and the amount of information to return about their posterior updates. - -`returnvars` accepts a `NamedTuple` or `Dict` or return var specification. There are two specifications: -- `KeepLast`: saves the last update for a variable, ignoring any intermediate results during iterations -- `KeepEach`: saves all updates for a variable for all iterations - -Note: if `iterations` are specified as a number, the `inference` function tracks and returns every update for each iteration for every random variable in the model (equivalent to `KeepEach()`). -If number of iterations is set to `nothing`, the `inference` function saves the 'last' (and the only one) update for every random variable in the model (equivalent to `KeepLast()`). -Use `iterations = 1` to force `KeepEach()` setting when number of iterations is equal to `1` or set `returnvars = KeepEach()` manually. - -Example: - -```julia -result = inference( - ..., - returnvars = ( - x = KeepLast(), - τ = KeepEach() - ) -) -``` - -It is also possible to set either `returnvars = KeepLast()` or `returnvars = KeepEach()` that acts as an alias and sets the given option for __all__ random variables in the model. - -# Example: - -```julia -result = inference( - ..., - returnvars = KeepLast() -) -``` - -- ### `predictvars` - -`predictvars` specifies the variables which should be predicted. In the model definition these variables are specified -as datavars, although they should not be passed inside data argument. - -Similar to `returnvars`, `predictvars` accepts a `NamedTuple` or `Dict`. There are two specifications: -- `KeepLast`: saves the last update for a variable, ignoring any intermediate results during iterations -- `KeepEach`: saves all updates for a variable for all iterations - -Example: - -```julia -result = inference( - ..., - predictvars = ( - o = KeepLast(), - τ = KeepEach() - ) -) -``` - -- ### `iterations` - -Specifies the number of variational (or loopy belief propagation) iterations. By default set to `nothing`, which is equivalent of doing 1 iteration. - -- ### `free_energy` - -This setting specifies whenever the `inference` function should return Bethe Free Energy (BFE) values. -Note, however, that it may be not possible to compute BFE values for every model. - -Additionally, the argument may accept a floating point type, instead of a `Bool` value. Using his option, e.g.`Float64`, improves performance of Bethe Free Energy computation, but restricts using automatic differentiation packages. - -- ### `free_energy_diagnostics` - -This settings specifies either a single or a tuple of diagnostic checks for Bethe Free Energy values stream. By default checks for `NaN`s and `Inf`s. See also [`BetheFreeEnergyCheckNaNs`](@ref) and [`BetheFreeEnergyCheckInfs`](@ref). -Pass `nothing` to disable any checks. - -- ### `callbacks` - -The inference function has its own lifecycle. The user is free to provide some (or none) of the callbacks to inject some extra logging or other procedures in the inference function, e.g. - -```julia -result = inference( - ..., - callbacks = ( - on_marginal_update = (model, name, update) -> println("\$(name) has been updated: \$(update)"), - after_inference = (args...) -> println("Inference has been completed") - ) -) -``` - - -The `callbacks` keyword argument accepts a named-tuple of 'name = callback' pairs. -The list of all possible callbacks and their arguments is present below: - -- `on_marginal_update`: args: (model::FactorGraphModel, name::Symbol, update) -- `before_model_creation`: args: () -- `after_model_creation`: args: (model::FactorGraphModel, returnval) -- `before_inference`: args: (model::FactorGraphModel) -- `before_iteration`: args: (model::FactorGraphModel, iteration::Int)::Bool -- `before_data_update`: args: (model::FactorGraphModel, data) -- `after_data_update`: args: (model::FactorGraphModel, data) -- `after_iteration`: args: (model::FactorGraphModel, iteration::Int)::Bool -- `after_inference`: args: (model::FactorGraphModel) - -`before_iteration` and `after_iteration` callbacks are allowed to return `true/false` value. -`true` indicates that iterations must be halted and no further inference should be made. - -- ### `addons` - -The `addons` field extends the default message computation rules with some extra information, e.g. computing log-scaling factors of messages or saving debug-information. -Accepts a single addon or a tuple of addons. If set, replaces the corresponding setting in the `options`. Automatically changes the default value of the `postprocess` argument to `NoopPostprocess`. - -- ### `postprocess` - -The `postprocess` keyword argument controls whether the inference results must be modified in some way before exiting the `inference` function. -By default, the inference function uses the `DefaultPostprocess` strategy, which by default removes the `Marginal` wrapper type from the results. -Change this setting to `NoopPostprocess` if you would like to keep the `Marginal` wrapper type, which might be useful in the combination with the `addons` argument. -If the `addons` argument has been used, automatically changes the default strategy value to `NoopPostprocess`. - -- ### `catch_exception` - -The `catch_exception` keyword argument specifies whether exceptions during the inference procedure should be caught in the `error` field of the -result. By default, if exception occurs during the inference procedure the result will be lost. Set `catch_exception = true` to obtain partial result -for the inference in case if an exception occurs. Use `RxInfer.issuccess` and `RxInfer.iserror` function to check if the inference completed successfully or failed. -If an error occurs, the `error` field will store a tuple, where first element is the exception itself and the second element is the caught `backtrace`. Use the `stacktrace` function -with the `backtrace` as an argument to recover the stacktrace of the error. Use `Base.showerror` function to display -the error. - -See also: [`InferenceResult`](@ref), [`rxinference`](@ref) -""" -function inference(; +function __inference(; # `model`: specifies a model generator, with the help of the `Model` function model::ModelGenerator, # NamedTuple or Dict with data, optional if predictvars are specified @@ -554,32 +318,6 @@ function inference(; # catch exceptions during the inference procedure, optional, defaults to false catch_exception = false ) - if isnothing(data) && isnothing(predictvars) - error("""One of the keyword arguments `data` or `predictvars` must be specified""") - end - __inference_check_dicttype(:initmarginals, initmarginals) - __inference_check_dicttype(:initmessages, initmessages) - __inference_check_dicttype(:callbacks, callbacks) - - # Check for available callbacks - if warn && !isnothing(callbacks) - for key in keys(callbacks) - if key ∉ ( - :on_marginal_update, - :before_model_creation, - :after_model_creation, - :before_inference, - :before_iteration, - :before_data_update, - :after_data_update, - :after_iteration, - :after_inference - ) - @warn "Unknown callback specification: $(key). Available callbacks: on_marginal_update, before_model_creation, after_model_creation, before_inference, before_iteration, before_data_update, after_data_update, after_iteration, after_inference. Set `warn = false` to supress this warning." - end - end - end - _options = convert(ModelInferenceOptions, options) # If the `options` does not have `warn` key inside, override it with the keyword `warn` if isnothing(options) || !haskey(options, :warn) @@ -644,8 +382,8 @@ function inference(; ) end - __inference_check_dicttype(:returnvars, returnvars) - __inference_check_dicttype(:predictvars, predictvars) + __infer_check_dicttype(:returnvars, returnvars) + __infer_check_dicttype(:predictvars, predictvars) # Use `__check_has_randomvar` to filter out unknown or non-random variables in the `returnvar` specification __check_has_randomvar(vardict, variable) = begin @@ -796,6 +534,11 @@ function inference(; return InferenceResult(posterior_values, predicted_values, fe_values, fmodel, freturval, potential_error) end +function inference(; kwargs...) + @warn "inference is deprecated and will be removed in the future. Use `infer` instead." + return infer(; kwargs...) +end + ## ------------------------------------------------------------------------ ## struct FromMarginalAutoUpdate end @@ -915,7 +658,7 @@ end This structure specifies to update our prior as soon as we have a new posterior `q(x_next)`. It then applies the `mean_cov` function on the updated posteriors and updates `datavar`s `x_current_mean` and `x_current_var` automatically. -See also: [`rxinference`](@ref) +See also: [`infer`](@ref) """ macro autoupdates(code) ((code isa Expr) && (code.head === :block)) || error("Autoupdate requires a block of code `begin ... end` as an input") @@ -977,20 +720,20 @@ end The return value of the `rxinference` function. # Public fields -- `posteriors`: `Dict` or `NamedTuple` of 'random variable' - 'posterior stream' pairs. See the `returnvars` argument for the [`rxinference`](@ref). -- `free_energy`: (optional) A stream of Bethe Free Energy values per VMP iteration. See the `free_energy` argument for the [`rxinference`](@ref). -- `history`: (optional) Saves history of previous marginal updates. See the `historyvars` and `keephistory` arguments for the [`rxinference`](@ref). +- `posteriors`: `Dict` or `NamedTuple` of 'random variable' - 'posterior stream' pairs. See the `returnvars` argument for the [`infer`](@ref). +- `free_energy`: (optional) A stream of Bethe Free Energy values per VMP iteration. See the `free_energy` argument for the [`infer`](@ref). +- `history`: (optional) Saves history of previous marginal updates. See the `historyvars` and `keephistory` arguments for the [`infer`](@ref). - `free_energy_history`: (optional) Free energy history, average over variational iterations - `free_energy_raw_history`: (optional) Free energy history, returns returns computed values of all variational iterations for each data event (if available) - `free_energy_final_only_history`: (optional) Free energy history, returns computed values of final variational iteration for each data event (if available) -- `events`: (optional) A stream of events send by the inference engine. See the `events` argument for the [`rxinference`](@ref). +- `events`: (optional) A stream of events send by the inference engine. See the `events` argument for the [`infer`](@ref). - `model`: `FactorGraphModel` object reference. - `returnval`: Return value from executed `@model`. Use the `RxInfer.start(engine)` function to subscribe on the `data` source and start the inference procedure. Use `RxInfer.stop(engine)` to unsubscribe from the `data` source and stop the inference procedure. Note, that it is not always possible to start/stop the inference procedure. -See also: [`rxinference`](@ref), [`RxInferenceEvent`](@ref), [`RxInfer.start`](@ref), [`RxInfer.stop`](@ref) +See also: [`infer`](@ref), [`RxInferenceEvent`](@ref), [`RxInfer.start`](@ref), [`RxInfer.stop`](@ref) """ mutable struct RxInferenceEngine{T, D, L, V, P, H, S, U, A, FA, FH, FO, FS, R, I, M, N, X, E, J} datastream :: D @@ -1395,12 +1138,12 @@ end and later on: ```julia -engine = rxinference(events = Val((:after_iteration, )), ...) +engine = infer(events = Val((:after_iteration, )), ...) subscription = subscribe!(engine.events, MyEventListener(...)) ``` -See also: [`rxinference`](@ref), [`RxInferenceEngine`](@ref) +See also: [`infer`](@ref), [`RxInferenceEngine`](@ref) """ struct RxInferenceEvent{T, D} data::D @@ -1423,366 +1166,48 @@ function inference_invoke_event(::Val{Event}, ::Val{EnabledEvents}, events, args return nothing end -## +function __rxinference(; + model::ModelGenerator, + data = nothing, + datastream = nothing, + initmarginals = nothing, + initmessages = nothing, + autoupdates = nothing, + constraints = nothing, + meta = nothing, + options = nothing, + returnvars = nothing, + historyvars = nothing, + keephistory = nothing, + iterations = nothing, + free_energy = false, + free_energy_diagnostics = BetheFreeEnergyDefaultChecks, + autostart = true, + events = nothing, + addons = nothing, + callbacks = nothing, + postprocess = DefaultPostprocess(), + uselock = false, + warn = true +) -""" - rxinference( - model, - data = nothing, - datastream = nothing, - initmarginals = nothing, - initmessages = nothing, - autoupdates = nothing, - constraints = nothing, - meta = nothing, - options = nothing, - returnvars = nothing, - historyvars = nothing, - keephistory = nothing, - iterations = nothing, - free_energy = false, - free_energy_diagnostics = BetheFreeEnergyDefaultChecks, - autostart = true, - events = nothing, - callbacks = nothing, - addons = nothing, - postprocess = DefaultPostprocess(), - uselock = false, - warn = true - ) + # In case if `data` is used we cast to a synchronous `datastream` with zip operator + _datastream, _T = if isnothing(datastream) && !isnothing(data) + __infer_check_dicttype(:data, data) -This function provides a generic way to perform probabilistic inference in RxInfer.jl. Returns `RxInferenceEngine`. + names = tuple(keys(data)...) + items = tuple(values(data)...) + stream = labeled(Val(names), iterable(zip(items...))) + etype = NamedTuple{names, Tuple{eltype.(items)...}} -## Arguments + stream, etype + else + eltype(datastream) <: NamedTuple || error("`eltype` of the `datastream` must be a `NamedTuple`") + datastream, eltype(datastream) + end -For more information about some of the arguments, please check below. - -- `model`: specifies a model generator, required -- `data`: `NamedTuple` or `Dict` with data, required (or `datastream`) -- `datastream`: A stream of `NamedTuple` with data, required (or `data`) -- `initmarginals = nothing`: `NamedTuple` or `Dict` with initial marginals, optional -- `initmessages = nothing`: `NamedTuple` or `Dict` with initial messages, optional -- `autoupdates = nothing`: auto-updates specification, required for many models, see `@autoupdates` -- `constraints = nothing`: constraints specification object, optional, see `@constraints` -- `meta = nothing`: meta specification object, optional, may be required for some models, see `@meta` -- `options = nothing`: model creation options, optional, see `ModelInferenceOptions` -- `returnvars = nothing`: return structure info, optional, by default creates observables for all random variables that return posteriors at last vmp iteration, see below for more information -- `historyvars = nothing`: history structure info, optional, defaults to no history, see below for more information -- `keephistory = nothing`: history buffer size, defaults to empty buffer, see below for more information -- `iterations = nothing`: number of iterations, optional, defaults to `nothing`, the inference engine does not distinguish between variational message passing or Loopy belief propagation or expectation propagation iterations, see below for more information -- `free_energy = false`: compute the Bethe free energy, optional, defaults to false. Can be passed a floating point type, e.g. `Float64`, for better efficiency, but disables automatic differentiation packages, such as ForwardDiff.jl -- `free_energy_diagnostics = BetheFreeEnergyDefaultChecks`: free energy diagnostic checks, optional, by default checks for possible `NaN`s and `Inf`s. `nothing` disables all checks. -- `autostart = true`: specifies whether to call `RxInfer.start` on the created engine automatically or not -- `showprogress = false`: show progress module, optional, defaults to false -- `events = nothing`: inference cycle events, optional, see below for more info -- `callbacks = nothing`: inference cycle callbacks, optional, see below for more info -- `addons = nothing`: inject and send extra computation information along messages, see below for more info -- `postprocess = DefaultPostprocess()`: inference results postprocessing step, optional, see below for more info -- `uselock = false`: specifies either to use the lock structure for the inference or not, if set to true uses `Base.Threads.SpinLock`. Accepts custom `AbstractLock`. -- `warn = true`: enables/disables warnings - -## Note on NamedTuples - -When passing `NamedTuple` as a value for some argument, make sure you use a trailing comma for `NamedTuple`s with a single entry. The reason is that Julia treats `returnvars = (x = KeepLast())` and `returnvars = (x = KeepLast(), )` expressions differently. This first expression creates (or **overwrites!**) new local/global variable named `x` with contents `KeepLast()`. The second expression (note trailing comma) creates `NamedTuple` with `x` as a key and `KeepLast()` as a value assigned for this key. - -## Extended information about some of the arguments - -- ### `data` or `datastream` - -Either `data` or `datastream` keyword argument is required, but specifying both is not supported and will result in an error. - -- ### `data` - -The `data` keyword argument must be a `NamedTuple` (or `Dict`) where keys (of `Symbol` type) correspond to all `datavar`s defined in the model specification. For example, if a model defines `x = datavar(Float64)` the `data` field must have an `:x` key (of `Symbol` type) which holds an iterable container with values of type `Float64`. The elements of such containers in the `data` must have the exact same shape as the `datavar` container. In other words, if a model defines `x = datavar(Float64, n)` then `data[:x]` must provide an iterable container with elements of type `Vector{Float64}`. - -All entries in the `data` argument are zipped together with the `Base.zip` function to form one slice of the data chunck. This means all containers in the `data` argument must be of the same size (`zip` iterator finished as soon as one container has no remaining values). -In order to use a fixed value for some specific `datavar` it is not necessary to create a container with that fixed value, but rather more efficient to use `Iterators.repeated` to create an infinite iterator. - -**Note**: The behavior of the `data` keyword argument is different from that which is used in the `inference` function. - -- ### `datastream` - -The `datastream` keyword argument must be an observable that supports `subscribe!` and `unsubscribe!` functions (streams from the `Rocket.jl` package are also supported). -The elements of the observable must be of type `NamedTuple` where keys (of `Symbol` type) correspond to all `datavar`s defined in the model specification, except for those which are listed in the `autoupdates` specification. -For example, if a model defines `x = datavar(Float64)` (which is not part of the `autoupdates` specification) the named tuple from the observable must have an `:x` key (of `Symbol` type) which holds a value of type `Float64`. The values in the named tuple must have the exact same shape as the `datavar` container. In other words, if a model defines `x = datavar(Float64, n)` then -`namedtuple[:x]` must provide a container with length `n` and with elements of type `Float64`. - -**Note**: The behavior of the individual named tuples from the `datastream` observable is similar to that which is used in the `inference` function and its `data` argument. -In fact, you can see the `rxinference` function as an efficient streamed version of the `inference` function, which automatically updates some `datavar`s with the `autoupdates` specification and listens to the `datastream` to update the rest of the `datavar`s. - -- ### `model` - -The `model` argument accepts a `ModelGenerator` as its input. The easiest way to create the `ModelGenerator` is to use the `@model` macro. -For example: - -```julia -@model function coin_toss(some_argument, some_keyword_argument = 3) - ... -end - -result = rxinference( - model = coin_toss(some_argument; some_keyword_argument = 3) -) -``` - -**Note**: The `model` keyword argument does not accept a `FactorGraphModel` instance as a value, as it needs to inject `constraints` and `meta` during the inference procedure. - -- ### `initmarginals` - -For specific types of inference algorithms, such as variational message passing, it might be required to initialize (some of) the marginals before running the inference procedure in order to break the dependency loop. If this is not done, the inference algorithm will not be executed due to the lack of information and message and/or marginals will not be updated. In order to specify these initial marginals, you can use the `initmarginals` argument, such as -```julia -rxinference(... - initmarginals = ( - # initialize the marginal distribution of x as a vague Normal distribution - # if x is a vector, then it simply uses the same value for all elements - # However, it is also possible to provide a vector of distributions to set each element individually - x = vague(NormalMeanPrecision), - ), -) -``` -This argument needs to be a named tuple, i.e. `initmarginals = (a = ..., )`, or dictionary. - -- ### `initmessages` - -For specific types of inference algorithms, such as loopy belief propagation or expectation propagation, it might be required to initialize (some of) the messages before running the inference procedure in order to break the dependency loop. If this is not done, the inference algorithm will not be executed due to the lack of information and message and/or marginals will not be updated. In order to specify these initial messages, you can use the `initmessages` argument, such as -```julia -rxinference(... - initmessages = ( - # initialize the messages distribution of x as a vague Normal distribution - # if x is a vector, then it simply uses the same value for all elements - # However, it is also possible to provide a vector of distributions to set each element individually - x = vague(NormalMeanPrecision), - ), -) -``` -This argument needs to be a named tuple, i.e. `initmessages = (a = ..., )`, or dictionary. - -- ### `autoupdates` - -See `@autoupdates` for more information. - -- ### `options` - -- `limit_stack_depth`: limits the stack depth for computing messages, helps with `StackOverflowError` for some huge models, but reduces the performance of inference backend. Accepts integer as an argument that specifies the maximum number of recursive depth. Lower is better for stack overflow error, but worse for performance. -- `pipeline`: changes the default pipeline for each factor node in the graph -- `global_reactive_scheduler`: changes the scheduler of reactive streams, see Rocket.jl for more info, defaults to no scheduler - -- ### `returnvars` - -`returnvars` accepts a tuple of symbols and specifies the latent variables of interests. For each symbol in the `returnvars` specification the `rxinference` function will prepare an observable stream (see `Rocket.jl`) of posterior updates. An agent may subscribe on the new posteriors events and perform some actions. -For example: - -```julia -engine = rxinference( - ..., - returnvars = (:x, :τ), - autostart = false -) - -x_subscription = subscribe!(engine.posteriors[:x], (update) -> println("x variable has been updated: ", update)) -τ_subscription = subscribe!(engine.posteriors[:τ], (update) -> println("τ variable has been updated: ", update)) - -RxInfer.start(engine) - -... - -unsubscribe!(x_subscription) -unsubscribe!(τ_subscription) - -RxInfer.stop(engine) -``` - -- ### `historyvars` - -`historyvars` specifies the variables of interests and the amount of information to keep in history about the posterior updates. The specification is similar to the `returnvars` in the `inference` procedure. -The `historyvars` requires `keephistory` to be greater than zero. - -`historyvars` accepts a `NamedTuple` or `Dict` or return var specification. There are two specifications: -- `KeepLast`: saves the last update for a variable, ignoring any intermediate results during iterations -- `KeepEach`: saves all updates for a variable for all iterations - -Example: - -```julia -result = rxinference( - ..., - historyvars = ( - x = KeepLast(), - τ = KeepEach() - ), - keephistory = 10 -) -``` - -It is also possible to set either `historyvars = KeepLast()` or `historyvars = KeepEach()` that acts as an alias and sets the given option for __all__ random variables in the model. - -# Example: - -```julia -result = rxinference( - ..., - historyvars = KeepLast(), - keephistory = 10 -) -``` - -- ### `keep_history` - -Specifies the buffer size for the updates history both for the `historyvars` and the `free_energy` buffers. - -- ### `iterations` - -Specifies the number of variational (or loopy belief propagation) iterations. By default set to `nothing`, which is equivalent of doing 1 iteration. - -- ### `free_energy` - -This setting specifies whenever the `inference` function should create an observable of Bethe Free Energy (BFE) values. The BFE observable returns a new computed value for each VMP iteration. -Note, however, that it may be not possible to compute BFE values for every model. If `free_energy = true` and `keephistory > 0` the engine exposes extra fields to access the history of the Bethe free energy updates: - -- `engine.free_energy_history`: Returns a free energy history averaged over the VMP iterations -- `engine.free_energy_final_only_history`: Returns a free energy history of values computed on last VMP iterations for every observation -- `engine.free_energy_raw_history`: Returns a raw free energy history - -Additionally, the argument may accept a floating point type, instead of a `Bool` value. Using this option, e.g.`Float64`, improves performance of Bethe Free Energy computation, but restricts using automatic differentiation packages. - -- ### `free_energy_diagnostics` - -This settings specifies either a single or a tuple of diagnostic checks for Bethe Free Energy values stream. By default checks for `NaN`s and `Inf`s. See also [`BetheFreeEnergyCheckNaNs`](@ref) and [`BetheFreeEnergyCheckInfs`](@ref). -Pass `nothing` to disable any checks. - -- ### `events` - -The engine from the `rxinference` function has its own lifecycle. The events can be listened by subscribing to the `engine.events` field. E.g. - -```julia -engine = rxinference( - ..., - autostart = false -) - -subscription = subscribe!(engine.events, (event) -> println(event)) - -RxInfer.start(engine) -``` - -By default all events are disabled, in order to enable an event its identifier must be listed in the `Val` tuple of symbols passed to the `events` keyword arguments. - -```julia -engine = rxinference( - events = Val((:on_new_data, :before_history_save, :after_history_save)) -) -``` - -The list of all possible events and their event data is present below (see `RxInferenceEvent` for more information about the type of event data): - -- `on_new_data`: args: (model::FactorGraphModel, data) -- `before_iteration` args: (model::FactorGraphModel, iteration) -- `before_auto_update` args: (model::FactorGraphModel, iteration, auto_updates) -- `after_auto_update` args: (model::FactorGraphModel, iteration, auto_updates) -- `before_data_update` args: (model::FactorGraphModel, iteration, data) -- `after_data_update` args: (model::FactorGraphModel, iteration, data) -- `after_iteration` args: (model::FactorGraphModel, iteration) -- `before_history_save` args: (model::FactorGraphModel, ) -- `after_history_save` args: (model::FactorGraphModel, ) -- `on_tick` args: (model::FactorGraphModel, ) -- `on_error` args: (model::FactorGraphModel, err) -- `on_complete` args: (model::FactorGraphModel, ) - -- ### `callbacks` - -The `rxinference` function has its own lifecycle. The user is free to provide some (or none) of the callbacks to inject some extra logging or other procedures in the preparation of the inference engine. -To inject extra procedures during the inference use the `events`. Here is the example of the `callbacks` - -```julia -result = rxinference( - ..., - callbacks = ( - after_model_creation = (model, returnval) -> println("The model has been created. Number of nodes: \$(length(getnodes(model)))"), - ) -) -``` - -The `callbacks` keyword argument accepts a named-tuple of 'name = callback' pairs. -The list of all possible callbacks and their input arguments is present below: - -- `before_model_creation`: args: () -- `after_model_creation`: args: (model::FactorGraphModel, returnval) -- `before_autostart`: args: (engine::RxInferenceEngine) -- `after_autostart`: args: (engine::RxInferenceEngine) - -- ### `addons` - -The `addons` field extends the default message computation rules with some extra information, e.g. computing log-scaling factors of messages or saving debug-information. -Accepts a single addon or a tuple of addons. If set, replaces the corresponding setting in the `options`. Automatically changes the default value of the `postprocess` argument to `NoopPostprocess`. - -- ### `postprocess` - -The `postprocess` keyword argument controls whether the inference results must be modified in some way before exiting the `inference` function. -By default, the inference function uses the `DefaultPostprocess` strategy, which by default removes the `Marginal` wrapper type from the results. -Change this setting to `NoopPostprocess` if you would like to keep the `Marginal` wrapper type, which might be useful in the combination with the `addons` argument. -If the `addons` argument has been used, automatically changes the default strategy value to `NoopPostprocess`. - -See also [`inference`](@ref) -""" -function rxinference(; - model::ModelGenerator, - data = nothing, - datastream = nothing, - initmarginals = nothing, - initmessages = nothing, - autoupdates = nothing, - constraints = nothing, - meta = nothing, - options = nothing, - returnvars = nothing, - historyvars = nothing, - keephistory = nothing, - iterations = nothing, - free_energy = false, - free_energy_diagnostics = BetheFreeEnergyDefaultChecks, - autostart = true, - events = nothing, - addons = nothing, - callbacks = nothing, - postprocess = DefaultPostprocess(), - uselock = false, - warn = true -) - __inference_check_dicttype(:callbacks, callbacks) - - # Check for available callbacks - if warn && !isnothing(callbacks) - for key in keys(callbacks) - if warn && key ∉ (:before_model_creation, :after_model_creation, :before_autostart, :after_autostart) - @warn "Unknown callback specification: $(key). Available callbacks: before_model_creation, after_model_creation, before_autostart, after_autostart. Set `warn = false` to supress this warning." - end - end - end - - # The `rxinference` support both static `data` and dynamic `datastream` - if !isnothing(data) && !isnothing(datastream) # Ensure that only one of them set - error("`data` and `datastream` keyword arguments cannot be used together.") - elseif isnothing(data) && isnothing(datastream) # Ensure that at least one of them set - error("The `rxinference` function requires either `data` or `datastream` keyword argument to be non-empty.") - end - - # In case if `data` is used we cast to a synchronous `datastream` with zip operator - _datastream, _T = if isnothing(datastream) && !isnothing(data) - __inference_check_dicttype(:data, data) - - names = tuple(keys(data)...) - items = tuple(values(data)...) - stream = labeled(Val(names), iterable(zip(items...))) - etype = NamedTuple{names, Tuple{eltype.(items)...}} - - stream, etype - else - eltype(datastream) <: NamedTuple || error("`eltype` of the `datastream` must be a `NamedTuple`") - datastream, eltype(datastream) - end - - datavarnames = fields(_T)::NTuple - N = length(datavarnames) # should be static + datavarnames = fields(_T)::NTuple + N = length(datavarnames) # should be static _options = convert(ModelInferenceOptions, options) # If the `options` does not have `warn` key inside, override it with the keyword `warn` @@ -1814,9 +1239,6 @@ function rxinference(; # Second we check autoupdates and pregenerate all necessary structures here _autoupdates = map((autoupdate) -> autoupdate(_model), something(autoupdates, ())) - __inference_check_dicttype(:initmarginals, initmarginals) - __inference_check_dicttype(:initmessages, initmessages) - # If everything is ok with `datavars` and `redirectvars` next step is to initialise marginals and messages in the model # This happens only once at the creation, we do not reinitialise anything if the inference has been stopped and resumed with the `stop` and `start` functions if !isnothing(initmarginals) @@ -1909,7 +1331,7 @@ function rxinference(; historyvars = Dict((varkey => value) for (varkey, value) in pairs(historyvars) if __check_has_randomvar(:historyvars, vardict, varkey)) - __inference_check_dicttype(:historyvars, historyvars) + __infer_check_dicttype(:historyvars, historyvars) else if !isnothing(historyvars) && warn @warn "`historyvars` keyword argument requires `keephistory > 0`. Ignoring `historyvars`. Use `warn = false` to suppress this warning." @@ -1986,3 +1408,445 @@ function rxinference(; return engine end + +function rxinference(; kwargs) + @warn "The `rxinference` function is deprecated and will be removed in the future. Use `infer` with the `autoupdates` keyword argument instead." + + infer(; kwargs...) +end + +available_callbacks(::typeof(__inference)) = ( + :on_marginal_update, + :before_model_creation, + :after_model_creation, + :before_inference, + :before_iteration, + :before_data_update, + :after_data_update, + :after_iteration, + :after_inference +) + +available_callbacks(::typeof(__rxinference)) = (:before_model_creation, :after_model_creation, :before_autostart, :after_autostart) + +function __check_available_callbacks(warn, callbacks, available_callbacks) + if warn && !isnothing(callbacks) + for key in keys(callbacks) + if warn && key ∉ available_callbacks + @warn "Unknown callback specification: $(key). Available callbacks: $(available_callbacks). Set `warn = false` to supress this warning." + end + end + end +end + +""" + infer( + model; + data = nothing, + datastream = nothing, + autoupdates = nothing, + initmarginals = nothing, + initmessages = nothing, + constraints = nothing, + meta = nothing, + options = nothing, + returnvars = nothing, + predictvars = nothing, + historyvars = nothing, + keephistory = nothing, + iterations = nothing, + free_energy = false, + free_energy_diagnostics = BetheFreeEnergyDefaultChecks, + showprogress = false, + callbacks = nothing, + addons = nothing, + postprocess = DefaultPostprocess(), + warn = true, + events = nothing, + uselock = false, + autostart = true, + catch_exception = false + ) +This function provides a generic way to perform probabilistic inference for batch/static and streamline/online scenarios. +Returns an `InferenceResult` (batch setting) or `RxInferenceEngine` (streamline setting) based on the parameters used. + +## Arguments + +For more information about some of the arguments, please check below. +- `model`: specifies a model generator, required +- `data`: `NamedTuple` or `Dict` with data, required (or `datastream` or `predictvars`) +- `datastream`: A stream of `NamedTuple` with data, required (or `data`) +- `autoupdates = nothing`: auto-updates specification, required for streamline inference, see `@autoupdates` +- `initmarginals = nothing`: `NamedTuple` or `Dict` with initial marginals, optional +- `initmessages = nothing`: `NamedTuple` or `Dict` with initial messages, optional +- `constraints = nothing`: constraints specification object, optional, see `@constraints` +- `meta = nothing`: meta specification object, optional, may be required for some models, see `@meta` +- `options = nothing`: model creation options, optional, see `ModelInferenceOptions` +- `returnvars = nothing`: return structure info, optional, defaults to return everything at each iteration, see below for more information +- `predictvars = nothing`: return structure info, optional, see below for more information (exclusive for batch inference) +- `historyvars = nothing`: history structure info, optional, defaults to no history, see below for more information (exclusive for streamline inference) +- `keephistory = nothing`: history buffer size, defaults to empty buffer, see below for more information (exclusive for streamline inference) +- `iterations = nothing`: number of iterations, optional, defaults to `nothing`, the inference engine does not distinguish between variational message passing or Loopy belief propagation or expectation propagation iterations, see below for more information +- `free_energy = false`: compute the Bethe free energy, optional, defaults to false. Can be passed a floating point type, e.g. `Float64`, for better efficiency, but disables automatic differentiation packages, such as ForwardDiff.jl +- `free_energy_diagnostics = BetheFreeEnergyDefaultChecks`: free energy diagnostic checks, optional, by default checks for possible `NaN`s and `Inf`s. `nothing` disables all checks. +- `showprogress = false`: show progress module, optional, defaults to false (exclusive for batch inference) +- `catch_exception` specifies whether exceptions during the inference procedure should be caught, optional, defaults to false (exclusive for batch inference) +- `callbacks = nothing`: inference cycle callbacks, optional, see below for more info +- `addons = nothing`: inject and send extra computation information along messages, see below for more info +- `postprocess = DefaultPostprocess()`: inference results postprocessing step, optional, see below for more info +- `events = nothing`: inference cycle events, optional, see below for more info (exclusive for streamline inference) +- `uselock = false`: specifies either to use the lock structure for the inference or not, if set to true uses `Base.Threads.SpinLock`. Accepts custom `AbstractLock`. (exclusive for streamline inference) +- `autostart = true`: specifies whether to call `RxInfer.start` on the created engine automatically or not (exclusive for streamline inference) +- `warn = true`: enables/disables warnings + +## Note on NamedTuples + +When passing `NamedTuple` as a value for some argument, make sure you use a trailing comma for `NamedTuple`s with a single entry. The reason is that Julia treats `returnvars = (x = KeepLast())` and `returnvars = (x = KeepLast(), )` expressions differently. This first expression creates (or **overwrites!**) new local/global variable named `x` with contents `KeepLast()`. The second expression (note trailing comma) creates `NamedTuple` with `x` as a key and `KeepLast()` as a value assigned for this key. + +The `model` argument accepts a `ModelGenerator` as its input. The easiest way to create the `ModelGenerator` is to use the `@model` macro. +For example: + +```julia +@model function coin_toss(some_argument, some_keyword_argument = 3) + ... +end + +result = infer( + model = coin_toss(some_argument; some_keyword_argument = 3) +) +``` + +**Note**: The `model` keyword argument does not accept a `FactorGraphModel` instance as a value, as it needs to inject `constraints` and `meta` during the inference procedure. + +- ### `data` +Either `data` or `datastream` or `predictvars` keyword argument is required. Specifying both `data` and `datastream` is not supported and will result in an error. Specifying both `datastream` and `predictvars` is not supported and will result in an error. + +**Note**: The behavior of the `data` keyword argument depends on the inference setting (batch or streamline). + +The `data` keyword argument must be a `NamedTuple` (or `Dict`) where keys (of `Symbol` type) correspond to all `datavar`s defined in the model specification. For example, if a model defines `x = datavar(Float64)` the +`data` field must have an `:x` key (of `Symbol` type) which holds a value of type `Float64`. The values in the `data` must have the exact same shape as the `datavar` container. In other words, if a model defines `x = datavar(Float64, n)` then +`data[:x]` must provide a container with length `n` and with elements of type `Float64`. + +- #### `streamline` setting +All entries in the `data` argument are zipped together with the `Base.zip` function to form one slice of the data chunck. This means all containers in the `data` argument must be of the same size (`zip` iterator finished as soon as one container has no remaining values). +In order to use a fixed value for some specific `datavar` it is not necessary to create a container with that fixed value, but rather more efficient to use `Iterators.repeated` to create an infinite iterator. + +- ### `datastream` + +The `datastream` keyword argument must be an observable that supports `subscribe!` and `unsubscribe!` functions (streams from the `Rocket.jl` package are also supported). +The elements of the observable must be of type `NamedTuple` where keys (of `Symbol` type) correspond to all `datavar`s defined in the model specification, except for those which are listed in the `autoupdates` specification. +For example, if a model defines `x = datavar(Float64)` (which is not part of the `autoupdates` specification) the named tuple from the observable must have an `:x` key (of `Symbol` type) which holds a value of type `Float64`. The values in the named tuple must have the exact same shape as the `datavar` container. In other words, if a model defines `x = datavar(Float64, n)` then +`namedtuple[:x]` must provide a container with length `n` and with elements of type `Float64`. + +**Note**: The behavior of the individual named tuples from the `datastream` observable is similar to that which is used in the batch setting. +In fact, you can see the streamline inference as an efficient version of the batch inference, which automatically updates some `datavar`s with the `autoupdates` specification and listens to the `datastream` to update the rest of the `datavar`s. + +For specific types of inference algorithms, such as variational message passing, it might be required to initialize (some of) the marginals before running the inference procedure in order to break the dependency loop. If this is not done, the inference algorithm will not be executed due to the lack of information and message and/or marginals will not be updated. In order to specify these initial marginals, you can use the `initmarginals` argument, such as +```julia +infer(... + initmarginals = ( + # initialize the marginal distribution of x as a vague Normal distribution + # if x is a vector, then it simply uses the same value for all elements + # However, it is also possible to provide a vector of distributions to set each element individually + x = vague(NormalMeanPrecision), + ), +) + +This argument needs to be a named tuple, i.e. `initmarginals = (a = ..., )`, or dictionary. + +- ### `initmessages` + +For specific types of inference algorithms, such as loopy belief propagation or expectation propagation, it might be required to initialize (some of) the messages before running the inference procedure in order to break the dependency loop. If this is not done, the inference algorithm will not be executed due to the lack of information and message and/or marginals will not be updated. In order to specify these initial messages, you can use the `initmessages` argument, such as +```julia +infer(... + initmessages = ( + # initialize the messages distribution of x as a vague Normal distribution + # if x is a vector, then it simply uses the same value for all elements + # However, it is also possible to provide a vector of distributions to set each element individually + x = vague(NormalMeanPrecision), + ), +) + +- ### `options` + +- `limit_stack_depth`: limits the stack depth for computing messages, helps with `StackOverflowError` for some huge models, but reduces the performance of inference backend. Accepts integer as an argument that specifies the maximum number of recursive depth. Lower is better for stack overflow error, but worse for performance. +- `pipeline`: changes the default pipeline for each factor node in the graph +- `global_reactive_scheduler`: changes the scheduler of reactive streams, see Rocket.jl for more info, defaults to no scheduler + +- ### `returnvars` + +`returnvars` specifies latent variables of interest and their posterior updates. Its behavior depends on the inference type: streamline or batch. + +**Batch inference:** +- Accepts a `NamedTuple` or `Dict` of return variable specifications. +- Two specifications available: `KeepLast` (saves the last update) and `KeepEach` (saves all updates). +- When `iterations` is set, returns every update for each iteration (equivalent to `KeepEach()`); if `nothing`, saves the last update (equivalent to `KeepLast()`). +- Use `iterations = 1` to force `KeepEach()` for a single iteration or set `returnvars = KeepEach()` manually. + +Example: + +```julia +result = infer( + ..., + returnvars = ( + x = KeepLast(), + τ = KeepEach() + ) +) +``` + +Shortcut for setting the same option for all variables: + +```julia +result = infer( + ..., + returnvars = KeepLast() # or KeepEach() +) +``` + +**Streamline inference:** +- For each symbol in `returnvars`, `infer` creates an observable stream of posterior updates. +- Agents can subscribe to these updates using the `Rocket.jl` package. + +Example: + +```julia +engine = infer( + ..., + autoupdates = my_autoupdates, + returnvars = (:x, :τ), + autostart = false +) +``` + +- ### `predictvars` + +`predictvars` specifies the variables which should be predicted. In the model definition these variables are specified +as datavars, although they should not be passed inside data argument. + +Similar to `returnvars`, `predictvars` accepts a `NamedTuple` or `Dict`. There are two specifications: +- `KeepLast`: saves the last update for a variable, ignoring any intermediate results during iterations +- `KeepEach`: saves all updates for a variable for all iterations + +Example: + +```julia +result = infer( + ..., + predictvars = ( + o = KeepLast(), + τ = KeepEach() + ) +) +``` + +**Note**: The `predictvars` argument is exclusive for batch setting. + +- ### `historyvars` + +`historyvars` specifies the variables of interests and the amount of information to keep in history about the posterior updates when performing streamline inference. The specification is similar to the `returnvars` when applied in batch setting. +The `historyvars` requires `keephistory` to be greater than zero. + +`historyvars` accepts a `NamedTuple` or `Dict` or return var specification. There are two specifications: +- `KeepLast`: saves the last update for a variable, ignoring any intermediate results during iterations +- `KeepEach`: saves all updates for a variable for all iterations + +Example: + +```julia +result = infer( + ..., + autoupdates = my_autoupdates, + historyvars = ( + x = KeepLast(), + τ = KeepEach() + ), + keephistory = 10 +) +``` + +It is also possible to set either `historyvars = KeepLast()` or `historyvars = KeepEach()` that acts as an alias and sets the given option for __all__ random variables in the model. + +# Example: + +```julia +result = infer( + ..., + autoupdates = my_autoupdates, + historyvars = KeepLast(), + keephistory = 10 +) +``` + +- ### `keep_history` + +Specifies the buffer size for the updates history both for the `historyvars` and the `free_energy` buffers in streamline inference. + +- ### `iterations` + +Specifies the number of variational (or loopy belief propagation) iterations. By default set to `nothing`, which is equivalent of doing 1 iteration. + +- ### `free_energy` + +**Streamline inference:** + +Specifies if the `infer` function should create an observable stream of Bethe Free Energy (BFE) values, computed at each VMP iteration. + +- When `free_energy = true` and `keephistory > 0`, additional fields are exposed in the engine for accessing the history of BFE updates. + - `engine.free_energy_history`: Averaged BFE history over VMP iterations. + - `engine.free_energy_final_only_history`: BFE history of values computed in the last VMP iterations for each observation. + - `engine.free_energy_raw_history`: Raw BFE history. + +**Batch inference:** + +Specifies if the `infer` function should return Bethe Free Energy (BFE) values. + +- Optionally accepts a floating-point type (e.g., `Float64`) for improved BFE computation performance, but restricts the use of automatic differentiation packages. + +- ### `free_energy_diagnostics` + +This settings specifies either a single or a tuple of diagnostic checks for Bethe Free Energy values stream. By default checks for `NaN`s and `Inf`s. See also [`BetheFreeEnergyCheckNaNs`](@ref) and [`BetheFreeEnergyCheckInfs`](@ref). +Pass `nothing` to disable any checks. + +- ### `catch_exception` + +The `catch_exception` keyword argument specifies whether exceptions during the batch inference procedure should be caught in the `error` field of the +result. By default, if exception occurs during the inference procedure the result will be lost. Set `catch_exception = true` to obtain partial result +for the inference in case if an exception occurs. Use `RxInfer.issuccess` and `RxInfer.iserror` function to check if the inference completed successfully or failed. +If an error occurs, the `error` field will store a tuple, where first element is the exception itself and the second element is the caught `backtrace`. Use the `stacktrace` function +with the `backtrace` as an argument to recover the stacktrace of the error. Use `Base.showerror` function to display +the error. + +- ### `callbacks` + +The inference function has its own lifecycle. The user is free to provide some (or none) of the callbacks to inject some extra logging or other procedures in the inference function, e.g. + +```julia +result = infer( + ..., + callbacks = ( + on_marginal_update = (model, name, update) -> println("\$(name) has been updated: \$(update)"), + after_inference = (args...) -> println("Inference has been completed") + ) +) +``` + + +The `callbacks` keyword argument accepts a named-tuple of 'name = callback' pairs. +The list of all possible callbacks for different inference setting (batch or streamline) and their arguments is present below: + +- `on_marginal_update`: args: (model::FactorGraphModel, name::Symbol, update) (exlusive for batch inference) +- `before_model_creation`: args: () +- `after_model_creation`: args: (model::FactorGraphModel, returnval) +- `before_inference`: args: (model::FactorGraphModel) (exlusive for batch inference) +- `before_iteration`: args: (model::FactorGraphModel, iteration::Int)::Bool (exlusive for batch inference) +- `before_data_update`: args: (model::FactorGraphModel, data) (exlusive for batch inference) +- `after_data_update`: args: (model::FactorGraphModel, data) (exlusive for batch inference) +- `after_iteration`: args: (model::FactorGraphModel, iteration::Int)::Bool (exlusive for batch inference) +- `after_inference`: args: (model::FactorGraphModel) (exlusive for batch inference) +- `before_autostart`: args: (engine::RxInferenceEngine) (exlusive for streamline inference) +- `after_autostart`: args: (engine::RxInferenceEngine) (exlusive for streamline inference) + +`before_iteration` and `after_iteration` callbacks are allowed to return `true/false` value. +`true` indicates that iterations must be halted and no further inference should be made. + +- ### `addons` + +The `addons` field extends the default message computation rules with some extra information, e.g. computing log-scaling factors of messages or saving debug-information. +Accepts a single addon or a tuple of addons. If set, replaces the corresponding setting in the `options`. Automatically changes the default value of the `postprocess` argument to `NoopPostprocess`. + +- ### `postprocess` + +The `postprocess` keyword argument controls whether the inference results must be modified in some way before exiting the `inference` function. +By default, the inference function uses the `DefaultPostprocess` strategy, which by default removes the `Marginal` wrapper type from the results. +Change this setting to `NoopPostprocess` if you would like to keep the `Marginal` wrapper type, which might be useful in the combination with the `addons` argument. +If the `addons` argument has been used, automatically changes the default strategy value to `NoopPostprocess`. + +""" +function infer(; + model::ModelGenerator, + data = nothing, + datastream = nothing, # streamline specific + autoupdates = nothing, # streamline specific + initmarginals = nothing, + initmessages = nothing, + constraints = nothing, + meta = nothing, + options = nothing, + returnvars = nothing, + predictvars = nothing, # batch specific + historyvars = nothing, # streamline specific + keephistory = nothing, # streamline specific + iterations = nothing, + free_energy = false, + free_energy_diagnostics = BetheFreeEnergyDefaultChecks, + showprogress = false, # batch specific + catch_exception = false, # batch specific + callbacks = nothing, + addons = nothing, + postprocess = DefaultPostprocess(), # streamline specific + events = nothing, # streamline specific + uselock = false, # streamline specific + autostart = true, # streamline specific + warn = true +) + if !isnothing(data) && !isnothing(datastream) + error("""`data` and `datastream` keyword arguments cannot be used together. """) + elseif isnothing(data) && isnothing(predictvars) && isnothing(datastream) + error("""One of the keyword arguments `data` or `predictvars` or `datastream` must be specified""") + end + + __infer_check_dicttype(:initmarginals, initmarginals) + __infer_check_dicttype(:initmessages, initmessages) + __infer_check_dicttype(:callbacks, callbacks) + + if isnothing(autoupdates) + __check_available_callbacks(warn, callbacks, available_callbacks(__inference)) + __inference( + model = model, + data = data, + initmarginals = initmarginals, + initmessages = initmessages, + constraints = constraints, + meta = meta, + options = options, + returnvars = returnvars, + predictvars = predictvars, + iterations = iterations, + free_energy = free_energy, + free_energy_diagnostics = free_energy_diagnostics, + showprogress = showprogress, + callbacks = callbacks, + addons = addons, + postprocess = postprocess, + warn = warn, + catch_exception = catch_exception + ) + else + __check_available_callbacks(warn, callbacks, available_callbacks(__rxinference)) + __rxinference( + model = model, + data = data, + datastream = datastream, + autoupdates = autoupdates, + initmarginals = initmarginals, + initmessages = initmessages, + constraints = constraints, + meta = meta, + options = options, + returnvars = returnvars, + historyvars = historyvars, + keephistory = keephistory, + iterations = iterations, + free_energy = free_energy, + free_energy_diagnostics = free_energy_diagnostics, + autostart = autostart, + callbacks = callbacks, + addons = addons, + postprocess = postprocess, + warn = warn, + events = events, + uselock = uselock + ) + end +end diff --git a/src/model.jl b/src/model.jl index 1ccb955f5..10627ace0 100644 --- a/src/model.jl +++ b/src/model.jl @@ -29,7 +29,7 @@ Creates model inference options object. The list of available options is present - `pipeline`: changes the default pipeline for each factor node in the graph - `global_reactive_scheduler`: changes the scheduler of reactive streams, see Rocket.jl for more info, defaults to no scheduler -See also: [`inference`](@ref), [`rxinference`](@ref) +See also: [`infer`](@ref) """ struct ModelInferenceOptions{P, S, A} pipeline :: P @@ -238,9 +238,9 @@ end """ ModelGenerator -`ModelGenerator` is a special object that is used in the `inference` function to lazily create model later on given `constraints`, `meta` and `options`. +`ModelGenerator` is a special object that is used in the `infer` function to lazily create model later on given `constraints`, `meta` and `options`. -See also: [`inference`](@ref) +See also: [`infer`](@ref) """ struct ModelGenerator{G, A, K} generator :: G diff --git a/test/inference_test.jl b/test/inference_test.jl index c2150274d..153eb4dd9 100644 --- a/test/inference_test.jl +++ b/test/inference_test.jl @@ -12,19 +12,19 @@ @test_throws ErrorException __inference_check_itertype(:something, missing) end -@testitem "__inference_check_dicttype" begin - import RxInfer: __inference_check_dicttype - - @test __inference_check_dicttype(:something, nothing) === nothing - @test __inference_check_dicttype(:something, (x = 1,)) === nothing - @test __inference_check_dicttype(:something, (x = 1, y = 2)) === nothing - @test __inference_check_dicttype(:something, Dict(:x => 1)) === nothing - @test __inference_check_dicttype(:something, Dict(:x => 1, :y => 2)) === nothing - - @test_throws ErrorException __inference_check_dicttype(:something, 1) - @test_throws ErrorException __inference_check_dicttype(:something, (1)) - @test_throws ErrorException __inference_check_dicttype(:something, missing) - @test_throws ErrorException __inference_check_dicttype(:something, (missing)) +@testitem "__infer_check_dicttype" begin + import RxInfer: __infer_check_dicttype + + @test __infer_check_dicttype(:something, nothing) === nothing + @test __infer_check_dicttype(:something, (x = 1,)) === nothing + @test __infer_check_dicttype(:something, (x = 1, y = 2)) === nothing + @test __infer_check_dicttype(:something, Dict(:x => 1)) === nothing + @test __infer_check_dicttype(:something, Dict(:x => 1, :y => 2)) === nothing + + @test_throws ErrorException __infer_check_dicttype(:something, 1) + @test_throws ErrorException __infer_check_dicttype(:something, (1)) + @test_throws ErrorException __infer_check_dicttype(:something, missing) + @test_throws ErrorException __infer_check_dicttype(:something, (missing)) end @testitem "`@autoupdates` macro" begin @@ -166,7 +166,7 @@ end observations = rand(10) # Case #0: no errors at all - result = inference( + result = infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -188,7 +188,7 @@ end @test contains(error_str, "The inference has completed successfully.") # Case #1: no error handling - @test_throws ErrorException inference( + @test_throws ErrorException infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -205,7 +205,7 @@ end end,) ) - result_with_error = inference( + result_with_error = infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -244,7 +244,7 @@ end observations = rand(10) # Case #1: no halting - results1 = inference( + results1 = infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -259,7 +259,7 @@ end @test length(results1.posteriors[:τ]) === 10 # Case #2: halt before iteration starts - results2 = inference( + results2 = infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -279,7 +279,7 @@ end @test length(results2.posteriors[:τ]) === 4 # Case #3: halt after iteration ends - results3 = inference( + results3 = infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -305,7 +305,7 @@ end end end -@testitem "Test warn argument in `inference()`" begin +@testitem "Test warn argument in `infer()`" begin @testset "Test warning for addons" begin #Add a new case for testing warning of addons @@ -328,7 +328,7 @@ end dataset2 = float.(rand(Bernoulli(θ_real), n)) #with warn - @test_logs (:warn, r"Both .* specify a value for the `addons`.*") result_2 = inference( + @test_logs (:warn, r"Both .* specify a value for the `addons`.*") result_2 = infer( model = beta_model2(length(dataset2)), data = (y = dataset2,), returnvars = (θ = KeepLast(),), @@ -338,7 +338,7 @@ end warn = true ) #without warn - @test_logs result_2 = inference( + @test_logs result_2 = infer( model = beta_model2(length(dataset2)), data = (y = dataset2,), returnvars = (θ = KeepLast(),), @@ -377,7 +377,7 @@ end end observations = rand(10) - @test_logs (:warn, r"Unused data variable .*") result = inference( + @test_logs (:warn, r"Unused data variable .*") result = infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -387,7 +387,7 @@ end free_energy = true, warn = true ) - @test_logs result = inference( + @test_logs result = infer( model = test_model1(10), constraints = test_model1_constraints(), data = (y = observations,), @@ -400,7 +400,7 @@ end end end -@testitem "Reactive inference with `rxinference` for test model #1" begin +@testitem "Streamline inference with `autoupdates` for test model #1" begin # A simple model for testing that resembles a simple kalman filter with # random walk state transition and unknown observational noise @@ -450,7 +450,7 @@ end for keephistory in (0, 1, 2), iterations in (3, 4), free_energy in (true, Float64, false), returnvars in ((:x_t,), (:x_t, :τ)), historyvars in ((:x_t,), (:x_t, :τ)) historyvars = keephistory > 0 ? NamedTuple{historyvars}(map(_ -> KeepEach(), historyvars)) : nothing - engine = rxinference( + engine = infer( model = test_model1(), constraints = MeanField(), data = (y = observedy,), @@ -516,7 +516,7 @@ end @testset "Check callbacks usage: autostart enabled" begin callbacksdata = [] - engine = rxinference( + engine = infer( model = test_model1(), constraints = MeanField(), data = (y = observedy,), @@ -543,7 +543,7 @@ end @testset "Check callbacks usage: autostart disabled" begin callbacksdata = [] - engine = rxinference( + engine = infer( model = test_model1(), constraints = MeanField(), data = (y = observedy,), @@ -573,7 +573,7 @@ end @testset "Check callbacks usage: unknown callback warning" begin callbacksdata = [] - @test_logs (:warn, r"Unknown callback specification.*hello_world.*Available callbacks.*") result = rxinference( + @test_logs (:warn, r"Unknown callback specification.*hello_world.*Available callbacks.*") result = infer( model = test_model1(), constraints = MeanField(), data = (y = observedy,), @@ -600,7 +600,7 @@ end end for iterations in (2, 3), keephistory in (0, 1) - engine = rxinference( + engine = infer( model = test_model1(), constraints = MeanField(), data = (y = observedy,), @@ -756,7 +756,7 @@ end end @testset "Check postprocess usage: UnpackMarginalPostprocess" begin - engine = rxinference( + engine = infer( model = test_model1(), constraints = MeanField(), data = (y = observedy,), @@ -775,7 +775,7 @@ end @testset "Check postprocess usage: NoopPostprocess & nothing" begin for postprocess in (RxInfer.NoopPostprocess(), nothing) - engine = rxinference( + engine = infer( model = test_model1(), constraints = MeanField(), data = (y = observedy,), @@ -801,11 +801,11 @@ end end @testset "Either `data` or `datastream` is required" begin - @test_throws ErrorException rxinference(model = test_model1()) + @test_throws ErrorException infer(model = test_model1()) end @testset "`data` and `datastream` cannot be used together" begin - @test_throws ErrorException rxinference(model = test_model1(), data = (y = observedy,), datastream = labeled(Val((:y,)), combineLatest(from(observedy)))) + @test_throws ErrorException infer(model = test_model1(), data = (y = observedy,), datastream = labeled(Val((:y,)), combineLatest(from(observedy)))) end end @@ -836,7 +836,7 @@ end o[2] ~ NormalMeanPrecision(x[n + 2], 1.0) end - result = inference(model = model_1(length(data[:y])), iterations = 10, data = data, predictvars = (o = KeepLast(),)) + result = infer(model = model_1(length(data[:y])), iterations = 10, data = data, predictvars = (o = KeepLast(),)) @test all(typeof.(result.predictions[:o]) .<: NormalDistributionsFamily) @test length(result.predictions[:o]) === 2 @@ -860,7 +860,7 @@ end o ~ NormalMeanPrecision(x[n + 1], 1.0) end - result = inference(model = model_2(length(data[:y])), iterations = 10, data = data, predictvars = (o = KeepEach(),)) + result = infer(model = model_2(length(data[:y])), iterations = 10, data = data, predictvars = (o = KeepEach(),)) # note we used KeepEach for variable o with BP algorithm (10 iterations), we expect all predicted variables to be equal (because of the beleif propagation) @test all(y -> y == result.predictions[:o][1], result.predictions[:o]) @@ -884,7 +884,7 @@ end o ~ NormalMeanPrecision(x[n + 1], 1.0) end - result = inference(model = model_3(length(data[:y])), iterations = 10, data = data, predictvars = (o = KeepLast(),)) + result = infer(model = model_3(length(data[:y])), iterations = 10, data = data, predictvars = (o = KeepLast(),)) @test !haskey(result.predictions, :y) @test haskey(result.predictions, :o) @@ -904,7 +904,7 @@ end end end - result = inference(model = model_4(length(data[:y])), iterations = 10, data = data) + result = infer(model = model_4(length(data[:y])), iterations = 10, data = data) @test all(typeof.(result.predictions[:y]) .<: NormalDistributionsFamily) @@ -917,7 +917,7 @@ end o ~ NormalMeanPrecision(x, 10.0) end - result = inference(model = model_5(), iterations = 1, predictvars = (o = KeepLast(),)) + result = infer(model = model_5(), iterations = 1, predictvars = (o = KeepLast(),)) @test haskey(result.predictions, :o) @test typeof(result.predictions[:o]) <: NormalDistributionsFamily @@ -936,7 +936,7 @@ end y ~ Normal(mean = d, var = 1.0) end - result = inference(model = model_6(), data = (y = missing, x_0 = 1.0), initmessages = (a = vague(NormalMeanPrecision),), iterations = 10, free_energy = false) + result = infer(model = model_6(), data = (y = missing, x_0 = 1.0), initmessages = (a = vague(NormalMeanPrecision),), iterations = 10, free_energy = false) @test haskey(result.predictions, :y) @test typeof(result.predictions[:y]) <: NormalDistributionsFamily @@ -965,7 +965,7 @@ end q(x_0, x, γ) = q(x_0, x)q(γ) end - result = inference( + result = infer( model = vmp_model(length(data[:y])), data = data, constraints = constraints, @@ -990,7 +990,7 @@ end end end - result = inference(model = coin_model1(length(dataset)), data = (y = dataset,)) + result = infer(model = coin_model1(length(dataset)), data = (y = dataset,)) @test typeof(last(result.predictions[:y])) <: Bernoulli @@ -1008,9 +1008,9 @@ end end end - @test_throws ErrorException inference(model = coin_model2(length(dataset)), data = (y = dataset,)) + @test_throws ErrorException infer(model = coin_model2(length(dataset)), data = (y = dataset,)) - @test_throws ErrorException inference(model = coin_model2(length(dataset)), data = (y = dataset,), free_energy = true) + @test_throws ErrorException infer(model = coin_model2(length(dataset)), data = (y = dataset,), free_energy = true) # test #10 predictvars, no dataset @model function coin_model3(n) @@ -1022,7 +1022,7 @@ end end end - result = inference(model = coin_model3(length(dataset)), predictvars = (y = KeepLast(),)) + result = infer(model = coin_model3(length(dataset)), predictvars = (y = KeepLast(),)) @test all(result.predictions[:y] .== Bernoulli(mean(Beta(1.0, 1.0)))) end diff --git a/test/model_tests.jl b/test/model_tests.jl index 73f227de8..4206b532e 100644 --- a/test/model_tests.jl +++ b/test/model_tests.jl @@ -125,9 +125,9 @@ testsets = [(prior = Beta(4.0, 8.0), answer = Beta(43.0, 19.0)), (prior = Beta(54.0, 1.0), answer = Beta(93.0, 12.0)), (prior = Beta(1.0, 12.0), answer = Beta(40.0, 23.0))] for ts in testsets - @test inference(model = coin_model_priors1(n, ts[:prior]), data = (y = data,)).posteriors[:θ] == ts[:answer] - @test inference(model = coin_model_priors2(n, ts[:prior]), data = (y = data,)).posteriors[:θ] == ts[:answer] - @test inference(model = coin_model_priors3(n, [ts[:prior]]), data = (y = data,)).posteriors[:θ] == [ts[:answer]] + @test infer(model = coin_model_priors1(n, ts[:prior]), data = (y = data,)).posteriors[:θ] == ts[:answer] + @test infer(model = coin_model_priors2(n, ts[:prior]), data = (y = data,)).posteriors[:θ] == ts[:answer] + @test infer(model = coin_model_priors3(n, [ts[:prior]]), data = (y = data,)).posteriors[:θ] == [ts[:answer]] end end diff --git a/test/models/aliases/test_aliases_binary.jl b/test/models/aliases/test_aliases_binary.jl new file mode 100644 index 000000000..78b8f3af6 --- /dev/null +++ b/test/models/aliases/test_aliases_binary.jl @@ -0,0 +1,29 @@ +module RxInferModelsAliasesTest + +using Test, InteractiveUtils +using RxInfer, BenchmarkTools, Random, Plots, LinearAlgebra, StableRNGs + +@model function binary_aliases() + x1 ~ Bernoulli(0.5) + x2 ~ Bernoulli(0.5) + x3 ~ Bernoulli(0.5) + x4 ~ Bernoulli(0.5) + + x ~ x1 -> x2 && x3 || ¬x4 + + y = datavar(Float64) + x ~ Bernoulli(y) +end + +function binary_aliases_inference() + return infer(model = binary_aliases(), data = (y = 0.5,), free_energy = true) +end + +@testset "aliases for binary operations" begin + results = binary_aliases_inference() + # Here we simply test that it ran and gave some output + @test mean(results.posteriors[:x1]) ≈ 0.5 + @test first(results.free_energy) ≈ 0.6931471805599454 +end + +end diff --git a/test/models/aliases/test_aliases_normal.jl b/test/models/aliases/test_aliases_normal.jl new file mode 100644 index 000000000..630e5fe99 --- /dev/null +++ b/test/models/aliases/test_aliases_normal.jl @@ -0,0 +1,51 @@ +module RxInferModelsAliasesTest + +using Test, InteractiveUtils +using RxInfer, BenchmarkTools, Random, Plots, LinearAlgebra, StableRNGs + +@model function normal_aliases() + x1 ~ MvNormal(μ = zeros(2), Σ⁻¹ = diageye(2)) + x2 ~ MvNormal(μ = zeros(2), Λ = diageye(2)) + x3 ~ MvNormal(mean = zeros(2), W = diageye(2)) + x4 ~ MvNormal(μ = zeros(2), prec = diageye(2)) + x5 ~ MvNormal(m = zeros(2), precision = diageye(2)) + + y1 ~ MvNormal(mean = zeros(2), Σ = diageye(2)) + y2 ~ MvNormal(m = zeros(2), Λ⁻¹ = diageye(2)) + y3 ~ MvNormal(μ = zeros(2), V = diageye(2)) + y4 ~ MvNormal(mean = zeros(2), cov = diageye(2)) + y5 ~ MvNormal(mean = zeros(2), covariance = diageye(2)) + + x ~ x1 + x2 + x3 + x4 + x5 + y ~ y1 + y2 + y3 + y4 + y5 + + r1 ~ Normal(μ = dot(x + y, ones(2)), τ = 1.0) + r2 ~ Normal(m = r1, γ = 1.0) + r3 ~ Normal(mean = r2, σ⁻² = 1.0) + r4 ~ Normal(mean = r3, w = 1.0) + r5 ~ Normal(mean = r4, p = 1.0) + r6 ~ Normal(mean = r5, prec = 1.0) + r7 ~ Normal(mean = r6, precision = 1.0) + + s1 ~ Normal(μ = r7, σ² = 1.0) + s2 ~ Normal(m = s1, τ⁻¹ = 1.0) + s3 ~ Normal(mean = s2, v = 1.0) + s4 ~ Normal(mean = s3, var = 1.0) + s5 ~ Normal(mean = s4, variance = 1.0) + + d = datavar(Float64) + d ~ Normal(μ = s5, variance = 1.0) +end + +function normal_aliases_inference() + return infer(model = normal_aliases(), data = (d = 1.0,), returnvars = (x1 = KeepLast(),), free_energy = true) +end + +@testset "aliases for `Normal` family of distributions" begin + result = normal_aliases_inference() + # Here we simply test that it ran and gave some output + @test first(mean(result.posteriors[:x1])) ≈ 0.04182509505703423 + @test first(result.free_energy) ≈ 2.319611135721246 +end + +end diff --git a/test/models/autoregressive/test_ar.jl b/test/models/autoregressive/test_ar.jl new file mode 100644 index 000000000..b32190e74 --- /dev/null +++ b/test/models/autoregressive/test_ar.jl @@ -0,0 +1,70 @@ +module RxInferModelsAutoregressiveTest + +using Test, InteractiveUtils +using RxInfer, BenchmarkTools, Random, Plots, LinearAlgebra, StableRNGs + +# `include(test/utiltests.jl)` +include(joinpath(@__DIR__, "..", "..", "utiltests.jl")) + +@model function ar_model(n, order) + x = datavar(Vector{Float64}, n) + y = datavar(Float64, n) + + γ ~ Gamma(shape = 1.0, rate = 1.0) + θ ~ MvNormal(mean = zeros(order), precision = diageye(order)) + + for i in 1:n + y[i] ~ Normal(mean = dot(x[i], θ), precision = γ) + end +end + +function ar_inference(inputs, outputs, order, niter) + return infer( + model = ar_model(length(outputs), order), + data = (x = inputs, y = outputs), + constraints = MeanField(), + options = (limit_stack_depth = 500,), + initmarginals = (γ = GammaShapeRate(1.0, 1.0),), + returnvars = (γ = KeepEach(), θ = KeepEach()), + iterations = niter, + free_energy = Float64 + ) +end + +function ar_ssm(series, order) + inputs = [reverse!(series[1:order])] + outputs = [series[order + 1]] + for x in series[(order + 2):end] + push!(inputs, vcat(outputs[end], inputs[end])[1:(end - 1)]) + push!(outputs, x) + end + return inputs, outputs +end + +@testset "Autoregressive model" begin + rng = StableRNG(1234) + + ## Inference execution and test inference results + for order in 1:5 + series = randn(rng, 1_000) + inputs, outputs = ar_ssm(series, order) + result = ar_inference(inputs, outputs, order, 15) + qs = result.posteriors + + (γ, θ) = (qs[:γ], qs[:θ]) + fe = result.free_energy + + @test length(γ) === 15 + @test length(θ) === 15 + @test length(fe) === 15 + @test last(fe) < first(fe) + @test all(filter(e -> abs(e) > 1e-3, diff(fe)) .< 0) + end + + benchrng = randn(StableRNG(32), 1_000) + inputs5, outputs5 = ar_ssm(benchrng, 5) + + @test_benchmark "models" "ar" ar_inference($inputs5, $outputs5, 5, 15) +end + +end diff --git a/test/models/autoregressive/test_lar.jl b/test/models/autoregressive/test_lar.jl new file mode 100644 index 000000000..964372b93 --- /dev/null +++ b/test/models/autoregressive/test_lar.jl @@ -0,0 +1,187 @@ +module RxInferModelsAutoregressiveTest + +using Test, InteractiveUtils +using RxInfer, BenchmarkTools, Random, Plots, LinearAlgebra, StableRNGs + +# `include(test/utiltests.jl)` +include(joinpath(@__DIR__, "..", "..", "utiltests.jl")) + +@model function lar_model(::Type{Multivariate}, n, order, c, stype, τ) + + # Parameter priors + γ ~ Gamma(shape = 1.0, rate = 1.0) + θ ~ MvNormal(mean = zeros(order), precision = diageye(order)) + + # We create a sequence of random variables for hidden states + x = randomvar(n) + # As well a sequence of observartions + y = datavar(Float64, n) + + ct = constvar(c) + # We assume observation noise to be known + cτ = constvar(τ) + + # Prior for first state + x0 ~ MvNormal(mean = zeros(order), precision = diageye(order)) + + x_prev = x0 + + # AR process requires extra meta information + meta = ARMeta(Multivariate, order, stype) + + for i in 1:n + # Autoregressive node uses structured factorisation assumption between states + x[i] ~ AR(x_prev, θ, γ) where {q = q(y, x)q(γ)q(θ), meta = meta} + y[i] ~ Normal(mean = dot(ct, x[i]), precision = cτ) + x_prev = x[i] + end +end + +@model function lar_model(::Type{Univariate}, n, order, c, stype, τ) + + # Parameter priors + γ ~ Gamma(shape = 1.0, rate = 1.0) + θ ~ Normal(mean = 0.0, precision = 1.0) + + # We create a sequence of random variables for hidden states + x = randomvar(n) + # As well a sequence of observartions + y = datavar(Float64, n) + + ct = constvar(c) + # We assume observation noise to be known + cτ = constvar(τ) + + # Prior for first state + x0 ~ Normal(mean = 0.0, precision = 1.0) + + x_prev = x0 + + # AR process requires extra meta information + meta = ARMeta(Univariate, order, stype) + + for i in 1:n + x[i] ~ AR(x_prev, θ, γ) where {q = q(y, x)q(γ)q(θ), meta = meta} + y[i] ~ Normal(mean = ct * x[i], precision = cτ) + x_prev = x[i] + end +end + +function lar_init_marginals(::Type{Multivariate}, order) + return (γ = GammaShapeRate(1.0, 1.0), θ = MvNormalMeanPrecision(zeros(order), diageye(order))) +end + +function lar_init_marginals(::Type{Univariate}, order) + return (γ = GammaShapeRate(1.0, 1.0), θ = NormalMeanPrecision(0.0, 1.0)) +end + +function lar_inference(data, order, artype, stype, niter, τ) + n = length(data) + c = ReactiveMP.ar_unit(artype, order) + return infer( + model = lar_model(artype, n, order, c, stype, τ), + data = (y = data,), + initmarginals = lar_init_marginals(artype, order), + returnvars = (γ = KeepEach(), θ = KeepEach(), x = KeepLast()), + iterations = niter, + free_energy = Float64 + ) +end + +# The following coefficients correspond to stable poles +coefs_ar_5 = [0.10699399235785655, -0.5237303489793305, 0.3068897071844715, -0.17232255282458891, 0.13323964347539288] + +function generate_lar_data(rng, n, θ, γ, τ) + order = length(θ) + states = Vector{Vector{Float64}}(undef, n + 3order) + observations = Vector{Float64}(undef, n + 3order) + + γ_std = sqrt(inv(γ)) + τ_std = sqrt(inv(γ)) + + states[1] = randn(rng, order) + + for i in 2:(n + 3order) + states[i] = vcat(rand(rng, Normal(dot(θ, states[i - 1]), γ_std)), states[i - 1][1:(end - 1)]) + observations[i] = rand(rng, Normal(states[i][1], τ_std)) + end + + return states[(1 + 3order):end], observations[(1 + 3order):end] +end + +@testset "Latent autoregressive model" begin + + # Seed for reproducibility + rng = StableRNG(123) + + # Number of observations in synthetic dataset + n = 500 + + # AR process parameters + real_γ = 5.0 + real_τ = 5.0 + real_θ = coefs_ar_5 + states, observations = generate_lar_data(rng, n, real_θ, real_γ, real_τ) + + # Test AR(1) + Univariate + result = lar_inference(observations, 1, Univariate, ARsafe(), 15, real_τ) + qs = result.posteriors + fe = result.free_energy + + (γ, θ, xs) = (qs[:γ], qs[:θ], qs[:x]) + + @test length(xs) === n + @test length(γ) === 15 + @test length(θ) === 15 + @test length(fe) === 15 + @test abs(last(fe) - 518.9182342) < 0.01 + @test last(fe) < first(fe) + @test all(filter(e -> abs(e) > 1e-3, diff(fe)) .< 0) + + # Test AR(k) + Multivariate + for k in 1:4 + result = lar_inference(observations, k, Multivariate, ARsafe(), 15, real_τ) + qs = result.posteriors + fe = result.free_energy + + (γ, θ, xs) = (qs[:γ], qs[:θ], qs[:x]) + + @test length(xs) === n + @test length(γ) === 15 + @test length(θ) === 15 + @test length(fe) === 15 + @test last(fe) < first(fe) + end + + # AR(5) + Multivariate + result = lar_inference(observations, length(real_θ), Multivariate, ARsafe(), 15, real_τ) + qs = result.posteriors + fe = result.free_energy + + (γ, θ, xs) = (qs[:γ], qs[:θ], qs[:x]) + + @test length(xs) === n + @test length(γ) === 15 + @test length(θ) === 15 + @test length(fe) === 15 + @test abs(last(fe) - 514.66086) < 0.01 + @test all(filter(e -> abs(e) > 1e-1, diff(fe)) .< 0) + @test (mean(last(γ)) - 3.0std(last(γ)) < real_γ < mean(last(γ)) + 3.0std(last(γ))) + + @test_plot "models" "lar" begin + p1 = plot(first.(states), label = "Hidden state") + p1 = scatter!(p1, observations, label = "Observations") + p1 = plot!(p1, first.(mean.(xs)), ribbon = sqrt.(first.(var.(xs))), label = "Inferred states", legend = :bottomright) + + p2 = plot(mean.(γ), ribbon = std.(γ), label = "Inferred transition precision", legend = :bottomright) + p2 = plot!([real_γ], seriestype = :hline, label = "Real transition precision") + + p3 = plot(fe, label = "Bethe Free Energy") + + p = plot(p1, p2, p3, layout = @layout([a; b c])) + end + + @test_benchmark "models" "lar" lar_inference($observations, length($real_θ), Multivariate, ARsafe(), 15, $real_τ) +end + +end diff --git a/test/models/datavars/fn_datavars_tests.jl b/test/models/datavars/fn_datavars_tests.jl index 46162ed38..d66d4b904 100644 --- a/test/models/datavars/fn_datavars_tests.jl +++ b/test/models/datavars/fn_datavars_tests.jl @@ -44,7 +44,7 @@ # Inference function function fn_datavars_inference(modelfn, adata, bdata, ydata) - return inference(model = modelfn(), data = (a = adata, b = bdata, y = ydata), free_energy = true) + return infer(model = modelfn(), data = (a = adata, b = bdata, y = ydata), free_energy = true) end adata = 2.0 diff --git a/test/models/iid/mv_iid_covariance_known_mean_tests.jl b/test/models/iid/mv_iid_covariance_known_mean_tests.jl index ca4608b04..aed6985c3 100644 --- a/test/models/iid/mv_iid_covariance_known_mean_tests.jl +++ b/test/models/iid/mv_iid_covariance_known_mean_tests.jl @@ -17,7 +17,7 @@ end function inference_mv_inverse_wishart_known_mean(mean, data, n, d) - return inference(model = mv_iid_inverse_wishart_known_mean(mean, n, d), data = (y = data,), iterations = 10, returnvars = KeepLast(), free_energy = Float64) + return infer(model = mv_iid_inverse_wishart_known_mean(mean, n, d), data = (y = data,), iterations = 10, returnvars = KeepLast(), free_energy = Float64) end ## Data creation diff --git a/test/models/iid/mv_iid_covariance_tests.jl b/test/models/iid/mv_iid_covariance_tests.jl index 9cfe7fc60..ed9f98da4 100644 --- a/test/models/iid/mv_iid_covariance_tests.jl +++ b/test/models/iid/mv_iid_covariance_tests.jl @@ -20,7 +20,7 @@ end function inference_mv_inverse_wishart(data, n, d) - return inference( + return infer( model = mv_iid_inverse_wishart(n, d), data = (y = data,), constraints = constraints_mv_iid_inverse_wishart(), diff --git a/test/models/iid/mv_iid_precision_known_mean_tests.jl b/test/models/iid/mv_iid_precision_known_mean_tests.jl index 2145ec6c9..06ec04e29 100644 --- a/test/models/iid/mv_iid_precision_known_mean_tests.jl +++ b/test/models/iid/mv_iid_precision_known_mean_tests.jl @@ -19,7 +19,7 @@ end function inference_mv_wishart_known_mean(mean, data, n, d) - return inference(model = mv_iid_wishart_known_mean(mean, n, d), data = (y = data,), iterations = 10, returnvars = KeepLast(), free_energy = Float64) + return infer(model = mv_iid_wishart_known_mean(mean, n, d), data = (y = data,), iterations = 10, returnvars = KeepLast(), free_energy = Float64) end ## Data creation diff --git a/test/models/iid/mv_iid_precision_tests.jl b/test/models/iid/mv_iid_precision_tests.jl index 2f0f83191..e1af5cffe 100644 --- a/test/models/iid/mv_iid_precision_tests.jl +++ b/test/models/iid/mv_iid_precision_tests.jl @@ -25,7 +25,7 @@ ## Inference definition function inference_mv_wishart(data, n, d) - return inference( + return infer( model = mv_iid_wishart(n, d), data = (y = data,), constraints = constraints_mv_iid_wishart(), diff --git a/test/models/mixtures/gmm_multivariate_tests.jl b/test/models/mixtures/gmm_multivariate_tests.jl index 46a99450b..d3b292233 100644 --- a/test/models/mixtures/gmm_multivariate_tests.jl +++ b/test/models/mixtures/gmm_multivariate_tests.jl @@ -60,7 +60,7 @@ push!(winitmarginals, Wishart(3, [1e2 0.0; 0.0 1e2])) end - return inference( + return infer( model = multivariate_gaussian_mixture_model(rng, L, nmixtures, length(data)), data = (y = data,), constraints = constraints, diff --git a/test/models/mixtures/gmm_univariate_tests.jl b/test/models/mixtures/gmm_univariate_tests.jl index bd8b7a87e..aa62524d3 100644 --- a/test/models/mixtures/gmm_univariate_tests.jl +++ b/test/models/mixtures/gmm_univariate_tests.jl @@ -23,7 +23,7 @@ end function inference_univariate(data, n_its, constraints) - return inference( + return infer( model = univariate_gaussian_mixture_model(length(data)), data = (y = data,), constraints = constraints, diff --git a/test/models/mixtures/mixture_tests.jl b/test/models/mixtures/mixture_tests.jl index 223cdceba..b000ccef3 100644 --- a/test/models/mixtures/mixture_tests.jl +++ b/test/models/mixtures/mixture_tests.jl @@ -62,11 +62,11 @@ ## -------------------------------------------- ## ## Inference execution - result1 = inference(model = beta_model1(length(dataset)), data = (y = dataset,), returnvars = (θ = KeepLast(),), free_energy = true, addons = AddonLogScale()) + result1 = infer(model = beta_model1(length(dataset)), data = (y = dataset,), returnvars = (θ = KeepLast(),), free_energy = true, addons = AddonLogScale()) - result2 = inference(model = beta_model2(length(dataset)), data = (y = dataset,), returnvars = (θ = KeepLast(),), free_energy = true, addons = AddonLogScale()) + result2 = infer(model = beta_model2(length(dataset)), data = (y = dataset,), returnvars = (θ = KeepLast(),), free_energy = true, addons = AddonLogScale()) - resultswitch = inference( + resultswitch = infer( model = beta_mixture_model(length(dataset)), data = (y = dataset,), returnvars = (θ = KeepLast(), in1 = KeepLast(), in2 = KeepLast(), selector = KeepLast()), diff --git a/test/models/nonlinear/cvi_tests.jl b/test/models/nonlinear/cvi_tests.jl index 26db4b50d..112ed058c 100644 --- a/test/models/nonlinear/cvi_tests.jl +++ b/test/models/nonlinear/cvi_tests.jl @@ -51,7 +51,7 @@ function inference_cvi(transformed, rng, iterations) T = length(transformed) - return inference( + return infer( model = non_linear_dynamics(T), data = (y = transformed,), iterations = iterations, diff --git a/test/models/nonlinear/test_generic_applicability.jl b/test/models/nonlinear/test_generic_applicability.jl new file mode 100644 index 000000000..3f100186a --- /dev/null +++ b/test/models/nonlinear/test_generic_applicability.jl @@ -0,0 +1,162 @@ +module RxInferNonlinearityModelsDeltaTest + +using Test, InteractiveUtils +using RxInfer, BenchmarkTools, Random, Plots, LinearAlgebra, StableRNGs + +# `include(test/utiltests.jl)` +include(joinpath(@__DIR__, "..", "..", "utiltests.jl")) + +# Please use StableRNGs for random number generators + +## Model definition +## -------------------------------------------- ## + +# We test that the function can depend on a global variable +# A particular value does not matter here, only the fact that it runs +globalvar = 0 + +function f₁(x) + return sqrt.(x .+ globalvar) +end + +function f₁_inv(x) + return x .^ 2 +end + +@model function delta_1input(meta) + y2 = datavar(Float64) + c = zeros(2) + c[1] = 1.0 + + x ~ MvNormal(μ = ones(2), Λ = diageye(2)) + z ~ f₁(x) where {meta = meta} + y1 ~ Normal(μ = dot(z, c), σ² = 1.0) + y2 ~ Normal(μ = y1, σ² = 0.5) +end + +function f₂(x, θ) + return x .+ θ +end + +function f₂_x(θ, z) + return z .- θ +end + +function f₂_θ(x, z) + return z .- x +end + +@model function delta_2inputs(meta) + y2 = datavar(Float64) + c = zeros(2) + c[1] = 1.0 + + θ ~ MvNormal(μ = ones(2), Λ = diageye(2)) + x ~ MvNormal(μ = zeros(2), Λ = diageye(2)) + z ~ f₂(x, θ) where {meta = meta} + y1 ~ Normal(μ = dot(z, c), σ² = 1.0) + y2 ~ Normal(μ = y1, σ² = 0.5) +end + +function f₃(x, θ, ζ) + return x .+ θ .+ ζ +end + +@model function delta_3inputs(meta) + y2 = datavar(Float64) + c = zeros(2) + c[1] = 1.0 + + θ ~ MvNormal(μ = ones(2), Λ = diageye(2)) + ζ ~ MvNormal(μ = 0.5ones(2), Λ = diageye(2)) + x ~ MvNormal(μ = zeros(2), Λ = diageye(2)) + z ~ f₃(x, θ, ζ) where {meta = meta} + y1 ~ Normal(μ = dot(z, c), σ² = 1.0) + y2 ~ Normal(μ = y1, σ² = 0.5) +end + +function f₄(x, θ) + return θ .* x +end + +@model function delta_2input_1d2d(meta) + y2 = datavar(Float64) + c = zeros(2) + c[1] = 1.0 + + θ ~ Normal(μ = 0.5, γ = 1.0) + x ~ MvNormal(μ = zeros(2), Λ = diageye(2)) + z ~ f₄(x, θ) where {meta = meta} + y1 ~ Normal(μ = dot(z, c), σ² = 1.0) + y2 ~ Normal(μ = y1, σ² = 0.5) +end + +## -------------------------------------------- ## +## Inference definition +## -------------------------------------------- ## +function inference_1input(data) + + # We test here different approximation methods + metas = ( + DeltaMeta(method = Linearization(), inverse = f₁_inv), + DeltaMeta(method = Unscented(), inverse = f₁_inv), + DeltaMeta(method = Linearization()), + DeltaMeta(method = Unscented()), + Linearization(), + Unscented() + ) + + return map(metas) do meta + return infer(model = delta_1input(meta), data = (y2 = data,), free_energy = true, free_energy_diagnostics = (BetheFreeEnergyCheckNaNs(), BetheFreeEnergyCheckInfs())) + end +end + +function inference_2inputs(data) + metas = ( + DeltaMeta(method = Linearization(), inverse = (f₂_x, f₂_θ)), + DeltaMeta(method = Unscented(), inverse = (f₂_x, f₂_θ)), + DeltaMeta(method = Linearization()), + DeltaMeta(method = Unscented()), + Linearization(), + Unscented() + ) + + return map(metas) do meta + return infer(model = delta_2inputs(meta), data = (y2 = data,), free_energy = true, free_energy_diagnostics = (BetheFreeEnergyCheckNaNs(), BetheFreeEnergyCheckInfs())) + end +end + +function inference_3inputs(data) + metas = (DeltaMeta(method = Linearization()), DeltaMeta(method = Unscented()), Linearization(), Unscented()) + + return map(metas) do meta + return infer(model = delta_3inputs(meta), data = (y2 = data,), free_energy = true, free_energy_diagnostics = (BetheFreeEnergyCheckNaNs(), BetheFreeEnergyCheckInfs())) + end +end + +function inference_2input_1d2d(data) + metas = (DeltaMeta(method = Linearization()), DeltaMeta(method = Unscented()), Linearization(), Unscented()) + + return map(metas) do meta + return infer(model = delta_2input_1d2d(meta), data = (y2 = data,), free_energy = true, free_energy_diagnostics = (BetheFreeEnergyCheckNaNs(), BetheFreeEnergyCheckInfs())) + end +end + +@testset "Nonlinear models: generic applicability" begin + @testset "Linearization, Unscented transforms" begin + ## -------------------------------------------- ## + ## Data creation + data = 4.0 + ## -------------------------------------------- ## + ## Inference execution + result₁ = inference_1input(data) + result₂ = inference_2inputs(data) + result₃ = inference_3inputs(data) + result₄ = inference_2input_1d2d(data) + + ## All models have been created. The inference finished without errors ## + @test true + end +end + +end diff --git a/test/models/regression/test_linreg.jl b/test/models/regression/test_linreg.jl new file mode 100644 index 000000000..079d771e8 --- /dev/null +++ b/test/models/regression/test_linreg.jl @@ -0,0 +1,84 @@ +module RxInferModelsLinearRegressionTest + +using Test, InteractiveUtils +using RxInfer, BenchmarkTools, Random, Plots, Dates, LinearAlgebra, StableRNGs + +# Please use StableRNGs for random number generators + +# `include(test/utiltests.jl)` +include(joinpath(@__DIR__, "..", "..", "utiltests.jl")) + +## Model definition +@model function linear_regression(n) + a ~ Normal(mean = 0.0, var = 1.0) + b ~ Normal(mean = 0.0, var = 1.0) + + x = datavar(Float64, n) + y = datavar(Float64, n) + + for i in 1:n + y[i] ~ Normal(mean = x[i] * b + a, var = 1.0) + end +end + +@model function linear_regression_broadcasted(n) + a ~ Normal(mean = 0.0, var = 1.0) + b ~ Normal(mean = 0.0, var = 1.0) + + x = datavar(Float64, n) + y = datavar(Float64, n) + + # Variance over-complicated for a purpose of checking that this expressions are allowed, it should be equal to `1.0` + y .~ Normal(mean = x .* b .+ a, var = det((diageye(2) .+ diageye(2)) ./ 2)) +end + +## Inference definition +function linreg_inference(modelfn, niters, xdata, ydata) + return infer( + model = modelfn(length(xdata)), + data = (x = xdata, y = ydata), + returnvars = (a = KeepLast(), b = KeepLast()), + initmessages = (b = NormalMeanVariance(0.0, 100.0),), + free_energy = true, + iterations = niters + ) +end + +@testset "Linear regression" begin + + ## Data creation + reala = 10.0 + realb = -10.0 + + N = 100 + + rng = StableRNG(1234) + + xdata = collect(1:N) .+ 1 * randn(rng, N) + ydata = reala .+ realb .* xdata + + ## Inference execution + result = linreg_inference(linear_regression, 25, xdata, ydata) + resultb = linreg_inference(linear_regression_broadcasted, 25, xdata, ydata) + + ares = result.posteriors[:a] + bres = result.posteriors[:b] + fres = result.free_energy + + aresb = resultb.posteriors[:a] + bresb = resultb.posteriors[:b] + fresb = resultb.free_energy + + ## Test inference results + @test mean(ares) ≈ mean(aresb) && var(ares) ≈ var(aresb) # Broadcasting may change the order of computations, so slight + @test mean(bres) ≈ mean(bresb) && var(bres) ≈ var(bresb) # differences are allowed + @test all(fres .≈ fresb) + @test isapprox(mean(ares), reala, atol = 5) + @test isapprox(mean(bres), realb, atol = 0.1) + @test fres[end] < fres[2] # Loopy belief propagation has no guaranties though + + @test_benchmark "models" "linreg" linreg_inference(linear_regression, 25, $xdata, $ydata) + @test_benchmark "models" "linreg_broadcasted" linreg_inference(linear_regression_broadcasted, 25, $xdata, $ydata) +end + +end diff --git a/test/models/statespace/hgf_tests.jl b/test/models/statespace/hgf_tests.jl index 03feda172..e9fb7d6d1 100644 --- a/test/models/statespace/hgf_tests.jl +++ b/test/models/statespace/hgf_tests.jl @@ -48,7 +48,7 @@ xt_min_mean, xt_min_var = mean_var(q(xt)) end - return rxinference( + return infer( model = hgf(real_k, real_w, z_variance, y_variance), constraints = hgfconstraints(), meta = hgfmeta(), diff --git a/test/models/statespace/hmm_tests.jl b/test/models/statespace/hmm_tests.jl index 3437a0a79..c6394108a 100644 --- a/test/models/statespace/hmm_tests.jl +++ b/test/models/statespace/hmm_tests.jl @@ -29,7 +29,7 @@ ## Inference definition function hidden_markov_model_inference(data, vmp_iters) - return inference( + return infer( model = hidden_markov_model(length(data)), constraints = hidden_markov_constraints(), data = (x = data,), diff --git a/test/models/statespace/mlgssm_test.jl b/test/models/statespace/mlgssm_test.jl index 14f763dbd..152838a90 100644 --- a/test/models/statespace/mlgssm_test.jl +++ b/test/models/statespace/mlgssm_test.jl @@ -30,7 +30,7 @@ ## Inference definition function multivariate_lgssm_inference(data, x0, A, B, Q, P) - return inference(model = multivariate_lgssm_model(length(data), x0, A, B, Q, P), data = (y = data,), free_energy = true, options = (limit_stack_depth = 500,)) + return infer(model = multivariate_lgssm_model(length(data), x0, A, B, Q, P), data = (y = data,), free_energy = true, options = (limit_stack_depth = 500,)) end ## Data creation diff --git a/test/models/statespace/probit_tests.jl b/test/models/statespace/probit_tests.jl index fa5c2042f..54ee38bbf 100644 --- a/test/models/statespace/probit_tests.jl +++ b/test/models/statespace/probit_tests.jl @@ -23,7 +23,7 @@ ## Inference definition function probit_inference(data_y) - return inference(model = probit_model(length(data_y)), data = (y = data_y,), iterations = 10, returnvars = (x = KeepLast(),), free_energy = true) + return infer(model = probit_model(length(data_y)), data = (y = data_y,), iterations = 10, returnvars = (x = KeepLast(),), free_energy = true) end ## Data creation diff --git a/test/models/statespace/ulgssm_tests.jl b/test/models/statespace/ulgssm_tests.jl index 19df19486..c0096a365 100644 --- a/test/models/statespace/ulgssm_tests.jl +++ b/test/models/statespace/ulgssm_tests.jl @@ -22,7 +22,7 @@ end function univariate_lgssm_inference(data, x0, c, P) - return inference(model = univariate_lgssm_model(length(data), x0, c, P), data = (y = data,), free_energy = true) + return infer(model = univariate_lgssm_model(length(data), x0, c, P), data = (y = data,), free_energy = true) end ## Data creation