diff --git a/__marimo__/session/marimo_test.py.json b/__marimo__/session/marimo_test.py.json new file mode 100644 index 000000000..cd4bb431a --- /dev/null +++ b/__marimo__/session/marimo_test.py.json @@ -0,0 +1,28 @@ +{ + "version": "1", + "metadata": { + "marimo_version": "0.18.3" + }, + "cells": [ + { + "id": "Hbol", + "code_hash": "072b56a0ec87f792811305870b9d8722", + "outputs": [ + { + "type": "data", + "data": { + "application/vnd.marimo+mimebundle": {} + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + } + ] +} \ No newline at end of file diff --git a/__marimo__/session/marimo_tutorial.py.json b/__marimo__/session/marimo_tutorial.py.json new file mode 100644 index 000000000..5f027a175 --- /dev/null +++ b/__marimo__/session/marimo_tutorial.py.json @@ -0,0 +1,7 @@ +{ + "version": "1", + "metadata": { + "marimo_version": "0.18.3" + }, + "cells": [] +} \ No newline at end of file diff --git a/docs/tutorials/__marimo__/session/marimo_tutorial.py.json b/docs/tutorials/__marimo__/session/marimo_tutorial.py.json new file mode 100644 index 000000000..fb810ad7c --- /dev/null +++ b/docs/tutorials/__marimo__/session/marimo_tutorial.py.json @@ -0,0 +1,3703 @@ +{ + "version": "1", + "metadata": { + "marimo_version": "0.18.3" + }, + "cells": [ + { + "id": "MJUe", + "code_hash": "b744b10707e1ed1f83d64011cbfce178", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "
" + } + } + ], + "console": [] + }, + { + "id": "vblA", + "code_hash": "3cd798fdba347ae205aec504e4b1fd9d", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "This tutorial provides a comprehensive introduction to the HSSM package for Hierarchical Bayesian Estimation of Sequential Sampling Models.\nTo make the most of the tutorial, let us cover the functionality of the key supporting packages that we use along the way." + } + } + ], + "console": [] + }, + { + "id": "bkHC", + "code_hash": "b3a5ab143bbb83c945bef42d4be18a82", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Colab Instructions

\nIf you would like to run this tutorial on Google colab, please click this link.\nOnce you are in the colab, follow the installation instructions below and then restart your runtime.\nJust uncomment the code in the next code cell and run it!\nNOTE:\nYou may want to switch your runtime to have a GPU or TPU. To do so, go to Runtime > Change runtime type and select the desired hardware accelerator.\nNote that if you switch your runtime you have to follow the installation instructions again.
" + } + } + ], + "console": [] + }, + { + "id": "PKri", + "code_hash": "e06d4a677f503002c7f346d04e8f4c6b", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Basic Imports

" + } + } + ], + "console": [] + }, + { + "id": "SFPL", + "code_hash": "a60459dd15e9e437992b6a6f05d3bd2d", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Data Simulation

\nWe will rely on the ssms package for data simulation repeatedly. Let's look at a basic isolated use case below.\nAs an example, let's use ssms to simulate from the basic Drift Diffusion Model (a running example in this tutorial).\n
\n\nIf you are not familiar with the DDM. For now just consider that it has four parameters.\n
" + } + } + ], + "console": [] + }, + { + "id": "BYtC", + "code_hash": "2b5981acde95188f05d550d649a6a688", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Using simulate_data()

" + } + } + ], + "console": [] + }, + { + "id": "RGSE", + "code_hash": "526250fe8eef7597644f5dc4bf95cf88", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "HSSM comes with a basic simulator function supplied the simulate_data() function. We can use this function to create synthetic datasets.\nBelow we show the most basic usecase:\nWe wish to generate 500 datapoints (trials) from the standard Drift Diffusion Model with a fixed parameters, v = 0.5, a = 1.5, z = 0.5, t = 0.5.\nNote:\nIn the course of the tutorial, we will see multiple strategies for synthetic dataset generation, this being the most straightforward one." + } + } + ], + "console": [] + }, + { + "id": "emfo", + "code_hash": "03b076b1557a532e2554298fd029c461", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "If instead you wish to supply a parameter that varies by trial (a lot more on this later), you can simply supply a vector of parameters to the theta dictionary, when calling the simulator.\nNote:\nThe size argument conceptually functions as number of synthetic datasets. So if you supply a parameter as a (1000,) vector, then the simulator assumes that one dataset consists of 1000 trials, hence if we set the size = 1 as below, we expect in return a dataset with 1000 trials." + } + } + ], + "console": [] + }, + { + "id": "nWHF", + "code_hash": "cbe65eea932071f0de552826df9ccb81", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "If we wish to simulate from another model, we can do so by changing the model string.\nThe number of models we can simulate differs from the number of models for which we have likelihoods available (both will increase over time). To get the models for which likelihood functions are supplied out of the box, we should inspect hssm.HSSM.supported_models." + } + } + ], + "console": [] + }, + { + "id": "ZHCJ", + "code_hash": "c5315e08cf739fa8498b5d19d651e7af", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "If we wish to check more detailed information about a given supported model, we can use the accessor get_default_model_config under hssm.modelconfig. For example, we inspect ddm model configuration below." + } + } + ], + "console": [] + }, + { + "id": "qnkX", + "code_hash": "0450c543509ca2b1c7ceeca19767df9c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "This dictionary contains quite a bit of information. For purposes of simulating data from a given model, we will highlight two aspects:\n
    \n
  1. The key list_of_params provides us with the necessary information to define out theta dictionary
  2. \n
  3. The bounds key inside the likelihoods sub-dictionaries, provides us with an indication of reasonable parameter values.
  4. \n
\nThe likelihoods dictionary inhabits three sub-directories for the ddm model, since we have all three, an analytical, an approx_differentiable (LAN) and a blackbox likelihood available. For many models, we will be able to access only one or two types of likelihoods.
" + } + } + ], + "console": [] + }, + { + "id": "TqIu", + "code_hash": "2207d2a3fdc9f5bf21716b6c5d28bbe4", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Using ssm-simulators

\nInternally, HSSM natively makes use of the ssm-simulators package for forward simulation of models.\nhssm.simulate_data() functions essentially as a convenience-wrapper.\nBelow we illustrate how to simulate data using the ssm-simulators package directly, to generate an equivalent dataset as created above. We will use the third way of passing parameters to the simulator, which is as a parameter-matrix.\nNotes:\n
    \n
  1. If you pass parameters as a parameter matrix, make sure the column ordering is correct. You can follow the parameter ordering under hssm.defaults.default_model_config['ddm']['list_params'].
  2. \n
  3. This is a minimal example, for more information about the package, check the associated github-page.
  4. \n
" + } + } + ], + "console": [] + }, + { + "id": "DnEU", + "code_hash": "13bb70689fdcef156be3630c96d4efe8", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We will stick to hssm.simulate_data() in this tutorial, to keep things simple." + } + } + ], + "console": [] + }, + { + "id": "ulZA", + "code_hash": "560a650e2bb9f77dd770f10b58b77ff6", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

ArviZ for Plotting

\n
\n\nWe use the ArviZ package for most of our plotting needs.\nArviZ is a useful aid for plotting when doing anything Bayesian.\nIt works with HSSM out of the box, by virtue of HSSMs reliance on PyMC for model construction and sampling.\nChecking out the ArviZ Documentation is a good idea to give you communication superpowers for not only your HSSM results, but also other libraries in the Bayesian Toolkit such as NumPyro or STAN.\nWe will see ArviZ plots throughout the notebook.
" + } + } + ], + "console": [] + }, + { + "id": "ecfG", + "code_hash": "676d2f2cecc3125737e9150b214d3e61", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Main Tutorial

" + } + } + ], + "console": [] + }, + { + "id": "Pvdt", + "code_hash": "326e6372f09a3b87d8e9d80a400397e4", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Initial Dataset

" + } + } + ], + "console": [] + }, + { + "id": "ZBYS", + "code_hash": "83705df43e705f57f1ccd2dad5b0e0cb", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Let's proceed to simulate a simple dataset for our first example." + } + } + ], + "console": [] + }, + { + "id": "nHfw", + "code_hash": "7716a09eeeeb7f64bea5317e4f85d081", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

First HSSM Model

\nIn this example we will use the analytical likelihood function computed as suggested in this paper.
" + } + } + ], + "console": [] + }, + { + "id": "xXTn", + "code_hash": "a74617ba3519fe82610150dc4a4d1d7c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Instantiate the model

\nTo instantiate our HSSM class, in the simplest version, we only need to provide an appropriate dataset.\nThe dataset is expected to be a pandas.DataFrame with at least two columns, respectively called rt (for reaction time) and response.\nOur data simulated above is already in the correct format, so let us try to construct the class.\nNOTE:\nIf you are a user of the HDDM python package, this workflow should seem very familiar.
" + } + } + ], + "console": [] + }, + { + "id": "NCOB", + "code_hash": "6de2f8fd488d9a327179cfc46e122a44", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "The print() function gives us some basic information about our model including the number of observations the parameters in the model and their respective prior setting. We can also create a nice little graphical representation of our model..." + } + } + ], + "console": [] + }, + { + "id": "aqbW", + "code_hash": "1d8ac96f6273e8d6c9371ff5e88bdca8", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Model Graph

\nSince HSSM creates a PyMC Model, we can can use the .graph() function, to get a graphical representation of the the model we created.
" + } + } + ], + "console": [] + }, + { + "id": "TXez", + "code_hash": "038a76152d71d7a289ba475a1a383ed8", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "This is the simplest model we can build. The graph above follows plate notation, commonly used for probabilistic graphical models.\n\nThis notation is helpful to get a quick overview of the structure of a given model we construct.\nThe graph() function of course becomes a lot more interesting and useful for more complicated models!" + } + } + ], + "console": [] + }, + { + "id": "dNNg", + "code_hash": "35949bc382a80073dbac384bb0f2f1ed", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Sample from the Model

\nWe can now call the .sample() function, to get posterior samples. The main arguments you may want to change are listed in the function call below.\nImportantly, multiple backends are possible. We choose the nuts_numpyro backend below,\nwhich in turn compiles the model to a JAX function.
" + } + } + ], + "console": [] + }, + { + "id": "wlCL", + "code_hash": "60d9155303f8a4a929a0bdc9d386fcd5", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We sampled from the model, let's look at the output..." + } + } + ], + "console": [] + }, + { + "id": "wAgl", + "code_hash": "f21bd128060406d30020b18987768785", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Errr... a closer look might be needed here!" + } + } + ], + "console": [] + }, + { + "id": "rEll", + "code_hash": "36097423dad9390a1c83a90d4eecb55b", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Inference Data / What gets returned from the sampler?

\nThe sampler returns an ArviZ InferenceData object.\nTo understand all the logic behind these objects and how they mesh with the Bayesian Workflow, we refer you to the ArviZ Documentation.\nInferenceData is build on top of xarrays. The xarray documentation will help you understand in more detail how to manipulate these objects.\nBut let's take a quick high-level look to understand roughly what we are dealing with here!
" + } + } + ], + "console": [] + }, + { + "id": "SdmI", + "code_hash": "4f864b3f48fe545119c7e57b758f2a31", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We see that in our case, infer_data_simple_ddm_model contains four basic types of data (note: this is extensible!)\n\nThe posterior object contains our traces for each of the parameters in the model. The log_likelihood field contains the trial wise log-likelihoods for each sample from the posterior. The sample_stats field contains information about the sampler run. This can be important for chain diagnostics, but we will not dwell on this here. Finally we retreive our observed_data." + } + } + ], + "console": [] + }, + { + "id": "lgWD", + "code_hash": "76cc86595fd74b5620c8150754f22ff0", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Basic Manipulation

" + } + } + ], + "console": [] + }, + { + "id": "yOPj", + "code_hash": "dc11ff09e8ffab08c1699e523e9352a7", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Accessing groups and variables

" + } + } + ], + "console": [] + }, + { + "id": "urSm", + "code_hash": "8dd1ee80a93ba57f7d943db89526e510", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "To simply access the underlying data as a numpy.ndarray, we can use .values (as e.g. when using pandas.DataFrame objects)." + } + } + ], + "console": [] + }, + { + "id": "CcZR", + "code_hash": "08adb26fc6de99adb0e98e9c2d9b9b5a", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Combine chain and draw dimension

\nWhen operating directly on the xarray, you will often find it useful to collapse the chain and draw coordinates into a single coordinate.\nArviz makes this easy via the extract method.
" + } + } + ], + "console": [] + }, + { + "id": "zlud", + "code_hash": "a51b86ffa2e1fa2e5f72dc23d029fc6b", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Since Arviz really just calls the .stack() method from xarray, here the corresponding example using the lower level xarray interface." + } + } + ], + "console": [] + }, + { + "id": "xvXZ", + "code_hash": "e2c1b8fa553d58be239622b927c1f1ba", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Making use of ArviZ

\nWorking with the InferenceData directly, is very helpful if you want to include custom computations into your workflow.\nFor a basic Bayesian Workflow however, you will often find that standard functionality available through ArviZ\nsuffices.\nBelow we provide a few examples of useful Arviz outputs, which come handy for analyzing your traces (MCMC samples).\n

Summary table

\nLet's take a look at a summary table for our posterior.
" + } + } + ], + "console": [] + }, + { + "id": "YECM", + "code_hash": "14e3dc1d9c4ae7dcf4dbadd761eb2d36", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "This table returns the parameter-wise mean of our posterior and a few extra statistics.\nOf these extra statistics, the one-stop shop for flagging convergence issues is the r_hat value, which\nis reported in the right-most column.\nTo navigate this statistic, here is a rule of thumb widely used in applied Bayesian statistics.\nIf you find an r_hat value > 1.01, it warrants investigation." + } + } + ], + "console": [] + }, + { + "id": "cEAS", + "code_hash": "5c1969d0dc408f1a49f5df69614126b9", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Trace plot

" + } + } + ], + "console": [] + }, + { + "id": "EJmg", + "code_hash": "168a45c60e578d2fa5d2bb335ad1ef68", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "The .sample() function also sets a trace attribute, on our hssm class, so instead, we could call the plot like so:" + } + } + ], + "console": [] + }, + { + "id": "vEBW", + "code_hash": "a55bb3b77fd95bab7afeec895046a7c4", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "In this tutorial we are most often going to use the latter way of accessing the traces, but there is no preferred option.\nLet's look at a few more plots." + } + } + ], + "console": [] + }, + { + "id": "kLmu", + "code_hash": "44953874e98f6450a494ec7a35106635", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Forest Plot

\nThe forest plot is commonly used for a quick visual check of the marginal posteriors. It is very effective for intuitive communication of results.
" + } + } + ], + "console": [] + }, + { + "id": "dxZZ", + "code_hash": "272311154b8cd53b4b850d65538469e9", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "
Combining Chains
\nBy default, chains are separated out into separate caterpillars, however\nsometimes, especially if you are looking at a forest plot which includes many posterior parameters at once, you want to declutter and collapse the chains into single caterpillars.\nIn this case you can combine chains instead.
" + } + } + ], + "console": [] + }, + { + "id": "TTti", + "code_hash": "d12c299b9c1865806f6f2709ec9f863d", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Basic Marginal Posterior Plot

\nAnother way to view the marginal posteriors is provided by the plot_posterior() function. It shows the mean and by default the ||(94\\%||) HDIs.
" + } + } + ], + "console": [] + }, + { + "id": "IaQp", + "code_hash": "98cb626c91c7374507d0c819132efd3c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Especially for parameter recovery studies, you may want to include reference values for the parameters of interest.\nYou can do so using the ref_val argument. See the example below:" + } + } + ], + "console": [] + }, + { + "id": "fCoF", + "code_hash": "92822dde383e897b13b183185f0a72f3", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Since it is sometimes useful, especially for more complex cases, below an alternative approach in which we pass ref_val as a dictionary." + } + } + ], + "console": [] + }, + { + "id": "zVRe", + "code_hash": "8e7d34d04503fbe7583163607bcba304", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Posterior Pair Plot

" + } + } + ], + "console": [] + }, + { + "id": "woaO", + "code_hash": "0b01b4510c5ccbef6c2874cfcd51f6ad", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "The posterior pair plot show us bi-variate traceplots and is useful to check for simple parameter tradeoffs that may emerge. The simplest (linear) tradeoff may be a high correlation between two parameters.\nThis can be very helpful in diagnosing sampler issues for example. If such tradeoffs exist, one often see extremely wide marginal distributions.\nIn our ddm example, we see a little bit of a tradeoff between a and t, as well as between v and z, however nothing concerning." + } + } + ], + "console": [] + }, + { + "id": "wadT", + "code_hash": "26c25e87ada51e6de06fa9d5a616a938", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "The few plot we showed here are just the beginning: ArviZ has a much broader spectrum of graphs and other convenience function available. Just check the documentation." + } + } + ], + "console": [] + }, + { + "id": "VCRE", + "code_hash": "d8fdf9a76132d9cfce86594a906398cc", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Compute Quantities from idata

\n

Example: Mean and Covariance of Posterior Parameters

\nAs a simple example, let us calculate the covariance matrix for our posterior samples.
" + } + } + ], + "console": [] + }, + { + "id": "PSUk", + "code_hash": "61f5fc6954cb49a1daed4e2b1b796a49", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

HSSM Model based on LAN likelihood

\nWith HSSM you can switch between pre-supplied models with a simple change of argument. The type of likelihood that will be accessed might change in the background for you.\nHere we see an example in which the underlying likelihood is now a LAN.\nWe will talk more about different types of likelihood functions and backends later in the tutorial. For now just keep the following in mind:\nThere are three types of likelihoods\n
    \n
  1. analytic
  2. \n
  3. approx_differentiable
  4. \n
  5. blackbox
  6. \n
\nTo check which type is used in your HSSM model simple type:
" + } + } + ], + "console": [] + }, + { + "id": "vGiW", + "code_hash": "fc73ae9d3c803329403a4cb1ea7dfaa6", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Ah... we were using an analytical likelihood with the DDM model in the last section.\nNow let's see something different!" + } + } + ], + "console": [] + }, + { + "id": "SYQT", + "code_hash": "795d16757f2571050e0c89644638ee4e", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Simulating Angle Data

\nAgain, let us simulate a simple dataset. This time we will use the angle model (passed via the model argument to the simulator() function).\nThis model is distinguished from the basic ddm model by an additional theta parameter which specifies the angle with which the decision boundaries collapse over time.\n
\n\nDDMs with collapsing bounds have been of significant interest in the theoretical literature, but applications were rare due to a lack of analytical likelihoods. HSSM facilitates inference with such models via the our approx_differentiable likelihoods. HSSM ships with a few predefined models based on LANs, but really we don't want to overemphasize those. They reflect the research interest of our and adjacent labs to a great extend.\nInstead, we encourage the community to contribute to this model reservoir (more on this later).
" + } + } + ], + "console": [] + }, + { + "id": "PSQn", + "code_hash": "bc4a1494200eaef3948f9fde51c13dba", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We pass a single additional argument to our HSSM class and set model='angle'." + } + } + ], + "console": [] + }, + { + "id": "lQxp", + "code_hash": "95323027096e88c7dfe15a771b8dff0e", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "The model graph now show us an additional parameter theta!" + } + } + ], + "console": [] + }, + { + "id": "rSYo", + "code_hash": "adfc9fd1e9391dd1f569c057e39aaa98", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Let's check the type of likelihood that is used under the hood ..." + } + } + ], + "console": [] + }, + { + "id": "WfYj", + "code_hash": "8399a1fb4ac136510cafcc70aac454cd", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Ok so here we rely on a likelihood of the approx_differentiable kind.\nAs discussed, with the initial set of pre-supplied likelihoods, this implies that we are using a LAN in the background." + } + } + ], + "console": [] + }, + { + "id": "uDnK", + "code_hash": "7ef0ec928ed944775357bf40445fce01", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Choosing Priors

" + } + } + ], + "console": [] + }, + { + "id": "aWBL", + "code_hash": "7caa8fe32e17ae28217a32261b28fbc3", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "HSSM allows you to specify priors quite freely. If you used HDDM previously, you may feel relieved to read that your hands are now untied!\n
\n\nWith HSSM we have multiple routes to priors. But let's first consider a special case:
" + } + } + ], + "console": [] + }, + { + "id": "MIsd", + "code_hash": "d493325b681724d6e68122d9f6985c48", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Fixing a parameter to a given value

" + } + } + ], + "console": [] + }, + { + "id": "IrqS", + "code_hash": "07765b97b2ba5c3f558b55de21d8b987", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Assume that instead of fitting all parameters of the DDM,\n
\n\nwe instead want to fit only the v (drift) parameter, setting all other parameters to fixed scalar values.\n
\n\nHSSM makes this extremely easy!
" + } + } + ], + "console": [] + }, + { + "id": "WJUG", + "code_hash": "6ecd157a2e6a96da177fd99856071aee", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Since we fix all but one parameter, we therefore estimate only one parameter. This should be reflected in our model graph, where we expect only one free random variable v:" + } + } + ], + "console": [] + }, + { + "id": "PieA", + "code_hash": "3fbe72f2577573be05523d2a2dd16c88", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Instead of the trace on the right, a useful alternative / complement is the rank plot.\nAs a rule of thumb, if the rank plots within chains look uniformly distributed, then our chains generally exhibit good mixing." + } + } + ], + "console": [] + }, + { + "id": "Ilkb", + "code_hash": "88628ad8ad3b98d8d4409a51b4da3e9b", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Named priors

\nWe can choose any PyMC Distribution to specify a prior for a given parameter.\nEven better, if natural parameter bounds are provided, HSSM automatically truncates the prior distribution so that it respect these bounds.\nBelow is an example in which we specify a Normal prior on the v parameter of the DDM.\nWe choose a ridiculously low ||(\\sigma||) value, to illustrate it's regularizing effect on the parameter (just so we see a difference and you are convinced that something changed).
" + } + } + ], + "console": [] + }, + { + "id": "jXAc", + "code_hash": "b49b5e11aeb3876af57b3d0f5bdf934a", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Observe how we reused our previous dataset with underlying parameters\n\nIn contrast to our previous sampler round, in which we used Uniform priors, here the v estimate is shrunk severley towared ||(0||) and the t and z parameter estimates are very biased to make up for this distortion. Also, overall we see a lot of divergences now, which is a sign of poor sampler performance." + } + } + ], + "console": [] + }, + { + "id": "mSxP", + "code_hash": "b4ca8899d02714f7d8d29fa14a61ccf2", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

HSSM Model with Regression

\n
\n\nCrucial to the scope of HSSM is the ability to link parameters with trial-by-trial covariates via (hierarchical, but more on this later) general linear models.\nIn this section we explore how HSSM deals with these models. No big surprise here... it's simple!
" + } + } + ], + "console": [] + }, + { + "id": "IZEX", + "code_hash": "0b7778e21bf1d3698fb46199f6e19e96", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Case 1: One parameter is a Regression Target

" + } + } + ], + "console": [] + }, + { + "id": "UFLA", + "code_hash": "47266aed40fdf3aa85302e735c38170a", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Simulating Data

" + } + } + ], + "console": [] + }, + { + "id": "RCUM", + "code_hash": "9ad4f61ce15a28f597826549d6962d02", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Let's first simulate some data, where the trial-by-trial parameters of the v parameter in our model are driven by a simple linear regression model.\nThe regression model is driven by two (random) covariates x and y, respectively with coefficients of ||(0.8||) and ||(0.3||) which are also simulated below.\nWe set the intercept to ||(0.3||).\nThe rest of the parameters are fixed to single values as before." + } + } + ], + "console": [] + }, + { + "id": "NBGo", + "code_hash": "3659d5ca90065c7d7ec42d92341ee4cb", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Basic Model

" + } + } + ], + "console": [] + }, + { + "id": "eooq", + "code_hash": "6e69d3d7e277b29bb98a43b8bc1e58c9", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We now create the HSSM model.\nNotice how we set the include argument. The include argument expects a list of dictionaries, one dictionary for each parameter to be specified via a regression model.\nFour keys are expected to be set:\n\nThe regression formula follows the syntax in the formulae python package (as used by the Bambi package for building Bayesian Hierarchical Regression Models.\nBambi forms the main model-construction backend of HSSM." + } + } + ], + "console": [] + }, + { + "id": "vkvV", + "code_hash": "83b7fa3587f31fbdf290d2974493ff3c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "
Param class
\nAs illustrated below, there is an alternative way of specifying the parameter specific data via the Param class.
" + } + } + ], + "console": [] + }, + { + "id": "wbrJ", + "code_hash": "9190e9707002f2ae7189ea07060236cc", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Custom Model

" + } + } + ], + "console": [] + }, + { + "id": "viyg", + "code_hash": "8167c96f4a686909ad8033b15b94b2aa", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "These were the defaults, with a little extra labor, we can e.g. customize the choice of priors for each parameter in the model." + } + } + ], + "console": [] + }, + { + "id": "ctlq", + "code_hash": "c63488a7a41dfa92ae050160f1d6119d", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Notice how v is now set as a regression." + } + } + ], + "console": [] + }, + { + "id": "iFMf", + "code_hash": "350299302ca853e886b443ecacb717fd", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Case 2: One parameter is a Regression (LAN)

\nWe can do the same thing with the angle model.\nNote:\nOur dataset was generated from the basic DDM here, so since the DDM assumes stable bounds, we expect the theta (angle of linear collapse) parameter to be recovered as close to ||(0||).
" + } + } + ], + "console": [] + }, + { + "id": "gZOs", + "code_hash": "88079d1614e304a6323a7b782c66d0df", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Great! theta is recovered correctly, on top of that, we have reasonable recovery for all other parameters!" + } + } + ], + "console": [] + }, + { + "id": "wtAr", + "code_hash": "f431576506f6893ad658452a71f97b00", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Case 3: Multiple Parameters are Regression Targets (LAN)

" + } + } + ], + "console": [] + }, + { + "id": "SQfX", + "code_hash": "fdf9405d349459b6aa3c64990abaeefb", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Let's get a bit more ambitious. We may, for example, want to try a regression on a few of our basic model parameters at once. Below we show an example where we model both the a and the v parameters with a regression.\nNOTE:\nIn our dataset of this section, only v is actually driven by a trial-by-trial regression, so we expect the regression coefficients for a to hover around ||(0||) in our posterior." + } + } + ], + "console": [] + }, + { + "id": "lPrT", + "code_hash": "354766c20debfd2fa548b2ed96147973", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We successfully recover our regression betas for a! Moreover, no warning signs concerning our chains." + } + } + ], + "console": [] + }, + { + "id": "KoaX", + "code_hash": "eac42d855b6b30e5f9ffa5424448c8c7", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Case 4: Categorical covariates

" + } + } + ], + "console": [] + }, + { + "id": "ngkg", + "code_hash": "7fc6884f8e28f7ffd9dac2c41dcf99cb", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Hierarchical Inference

" + } + } + ], + "console": [] + }, + { + "id": "BNjl", + "code_hash": "bdc72ff2e24293c1fbf1151fce853f46", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Let's try to fit a hierarchical model now. We will simulate a dataset with ||(15||) participants, with ||(200||) observations / trials for each participant.\nWe define a group mean mean_v and a group standard deviation sd_v for the intercept parameter of the regression on v, which we sample from a corresponding normal distribution for each participant." + } + } + ], + "console": [] + }, + { + "id": "zLYB", + "code_hash": "10a055021fc2aaa1152269d2aeb7dccd", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Simulate Data

" + } + } + ], + "console": [] + }, + { + "id": "jaBo", + "code_hash": "43c57a0f927ec4006494bb39ec43f834", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We can now define our HSSM model.\nWe specify the regression as v ~ 1 + (1|participant_id) + x + y.\n(1|participant_id) tells the model to create a participant-wise offset for the intercept parameter. The rest of the regression ||(\\beta||)'s is fit globally.\nAs an R user you may recognize this syntax from the lmer package.\nOur Bambi backend is essentially a Bayesian version of lmer, quite like the BRMS package in R, which operates on top of STAN.\nAs a previous HDDM user, you may recognize that now proper mixed-effect models are viable!\nYou should be able to handle between and within participant effects naturally now!" + } + } + ], + "console": [] + }, + { + "id": "YCKg", + "code_hash": "ad1e4e0cdadd8e0dcbd92d17e57bfece", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Basic Hierarchical Model

" + } + } + ], + "console": [] + }, + { + "id": "dGch", + "code_hash": "67ef188dfadcf2beb37252d72f121034", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Let's look at the posteriors!" + } + } + ], + "console": [] + }, + { + "id": "NFPl", + "code_hash": "698ec6b1b7f1bf6e993bb75486ab822b", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Model Comparison

" + } + } + ], + "console": [] + }, + { + "id": "BxxS", + "code_hash": "0bca84feb1555b2daee235138c99a32a", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Fitting single models is all well and good. We are however, often interested in comparing how well a few different models account for the same data.\nThrough ArviZ, we have out of the box access to modern Bayesian Model Comparison. We will keep it simple here, just to illustrate the basic idea.\n

Scenario

\nThe following scenario is explored.\nFirst we generate data from a ddm model with fixed parameters, specifically we set the a parameter to ||(1.5||).\nWe then define two HSSM models:\n
    \n
  1. A model which allows fitting all but the a parameter, which is fixed to ||(1.0||) (wrong)
  2. \n
  3. A model which allows fitting all but the a parameter, which is fixed to ||(1.5||) (correct)
  4. \n
\nWe then use the ArviZ's compare() function, to perform model comparison via elpd_loo.
" + } + } + ], + "console": [] + }, + { + "id": "ZpGF", + "code_hash": "9f823ea68143a857c1b38ca32d0db056", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Data Simulation

" + } + } + ], + "console": [] + }, + { + "id": "Iijd", + "code_hash": "982bfc7c2d3dd2894476cb1aa2ce3bfc", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Defining the Models

" + } + } + ], + "console": [] + }, + { + "id": "pgJK", + "code_hash": "144873be2fa66b12a90ab340638b974e", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Compare

" + } + } + ], + "console": [] + }, + { + "id": "cwqn", + "code_hash": "3a35cbe10d202b444b4c602b7b282569", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Notice how the posterior weight on the correct model is close to (or equal to ) ||(1||) here.\nIn other words model comparison points us to the correct model with\na very high degree of certainty here!\nWe can also use the .plot_compare() function to illustrate the model comparison visually." + } + } + ], + "console": [] + }, + { + "id": "XZIo", + "code_hash": "5b9c7c4373cc4eaa0ca54c805f3f8146", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Using the forest plot we can take a look at what goes wrong for the \"wrong\" model.\nTo make up for the mistplaced setting of the a parameter, the posterior seems to compensate by\nmis-estimating the other parameters." + } + } + ], + "console": [] + }, + { + "id": "VjEH", + "code_hash": "6bf71eebc8936a7bf3d43bc8630d1390", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Closer look!

\n
" + } + } + ], + "console": [] + }, + { + "id": "zesr", + "code_hash": "ecdf2b5638ae4650818508cadbda2ec3", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We have seen a few examples of HSSM models at this point. Add a model via a string, maybe toy a bit with with the priors and set regression functions for a given parameter. Turn it hierarchical... Here we begin to peak a bit under the hood.\nAfter all, we want to encourage you to contribute models to the package yourself.\nLet's remind ourself of the model_config dictionaries that define model properties for us. Again let's start with the DDM." + } + } + ], + "console": [] + }, + { + "id": "oXQC", + "code_hash": "cef5700c705c5ae14400baf0b5581df4", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "The dictionary has a few high level keys.\n
    \n
  1. response
  2. \n
  3. list_params
  4. \n
  5. description
  6. \n
  7. likelihoods
  8. \n
\nLet us take a look at the available likelihoods:
" + } + } + ], + "console": [] + }, + { + "id": "vAZI", + "code_hash": "7843d55563c488acb5c2681674b9b2e8", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "For the DDM we have available all three types of likelihoods that HSSM deals with:\n
    \n
  1. analytical
  2. \n
  3. approx_differentiable
  4. \n
  5. blackbox
  6. \n
\nLet's expand the dictionary contents more:
" + } + } + ], + "console": [] + }, + { + "id": "NGNk", + "code_hash": "bee7091e58e3d091383e6d14cb41cdd2", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We see three properties (key) in this dictionary, of which two are essential:\n\nIf you provide bounds for a parameter, but no default_priors, a Uniform prior that respects the specified bounds will be applied." + } + } + ], + "console": [] + }, + { + "id": "CWwK", + "code_hash": "fb66f3bd1cb223a85aa981039b9bb8bf", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Next, let's look at the approx_differentiable part.\nThe likelihood in this part is based on a LAN which was available in HDDM through the LAN extension." + } + } + ], + "console": [] + }, + { + "id": "iCCe", + "code_hash": "5c878216096505af663b943305e34fac", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We see that the loglik field is now a string that points to a .onnx file.\nOnnx is a meta framework for Neural Network specification, that allows translation between deep learning Frameworks. This is the preferred format for the neural networks we store in our model reservoir on HuggingFace.\nMoreover notice that we now have a backend field. We allow for two primary backends in the approx_differentiable field.\n
    \n
  1. pytensor
  2. \n
  3. jax
  4. \n
\nThe jax backend assumes that your likelihood is described as a jax function, the pytensor backend assumes that your likelihood is described as a pytensor function. Ok not that surprising...\nWe won't dwell on this here, however the key idea is to provide users with a large degree of flexibility in describing their likelihood functions and moreover to allow targeted optimization towards MCMC sampler types that PyMC allows us to access.\nYou can find a dedicated tutorial in the documentation, which describes the different likelihoods in much more detail.\nInstead, let's take a quick look at how these newfound insights can be used for custom model definition.
" + } + } + ], + "console": [] + }, + { + "id": "oRYm", + "code_hash": "7a6c70059380f1ff0928c36435a8844e", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "In this case we actually built the model class with an approx_differentiable LAN likelihood, instead of the default analytical likelihood we used in the beginning of the tutorial. The assumed generative model remains the ddm however!" + } + } + ], + "console": [] + }, + { + "id": "vWAQ", + "code_hash": "362689ebacbec087b6ff836d76636408", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We can take this further and specify a completely custom likelihood. See the dedicated tutorial for more examples!\nWe will see one specific example below to illustrate another type of likelihood function we have available for model building in HSSM, the Blackbox likelihood." + } + } + ], + "console": [] + }, + { + "id": "opEZ", + "code_hash": "5610cb45075a5ea4f06b8d9370f8d87d", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

'Blackbox' Likelihoods

\n
" + } + } + ], + "console": [] + }, + { + "id": "zhCr", + "code_hash": "aae32d442f99236c41ea0cfcbdf3ba3f", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

What is a Blackbox Likelihood Function?

\nA Blackbox Likelihood Function is essentially any Python callable (function) that provides trial by trial likelihoods for your model of interest. What kind of computations are performed in this Python function is completely arbitrary.\nE.g. you could built a function that performs forward simulation from you model, constructs are kernel-density estimate for the resulting likelihood functions and evaluates your datapoints on this ad-hoc generated approximate likelihood.\nWhat I just described is a once state-of-the-art method of performing simulation based inference on Sequential Sampling models, a precursor to LANs if you will.
" + } + } + ], + "console": [] + }, + { + "id": "CCxq", + "code_hash": "e15cceecd9306e0a90b1964de2292638", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We will do something simpler to keep it short and sweet, but really... the possibilities are endless!\n

\n
\n

" + } + } + ], + "console": [] + }, + { + "id": "jKDm", + "code_hash": "1b79f6d90d77310125422cae43d6354e", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Simulating simple dataset from the DDM

" + } + } + ], + "console": [] + }, + { + "id": "OcMK", + "code_hash": "0720db7ae37f5fbfeb0fad274a740ce3", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "As always, let's begin by generating some simple dataset." + } + } + ], + "console": [] + }, + { + "id": "ZzbA", + "code_hash": "2ea7c99d5fe5ff542087e6c075c5e47c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Define the likelihood

" + } + } + ], + "console": [] + }, + { + "id": "ETTw", + "code_hash": "23177d963cd1474416f1e7108a301d9c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Now the fun part... we simply define a Python function my_blackbox_loglik which takes in our data as well as a bunch of model parameters (in our case the familiar v,a, z, t from the DDM).\nThe function then does some arbitrary computation inside (in our case e.g. we pass the data and parameters to the DDM log-likelihood from our predecessor package HDDM).\nThe important part is that inside my_blackbox_loglik anything can happen. We happen to call a little custom function that defines the likelihood of a DDM.\nFun fact:\nIt is de-facto the likelihood which is called by HDDM." + } + } + ], + "console": [] + }, + { + "id": "IiyY", + "code_hash": "66ae2a9c51775b772d6b3e3e0c1bd432", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Define HSSM class with our Blackbox Likelihood

" + } + } + ], + "console": [] + }, + { + "id": "rKHS", + "code_hash": "4ccde8cc786cf75ec2c14daa706c8c5b", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We can now define our HSSM model class as usual, however passing our my_blackbox_loglik() function to the loglik argument, and passing as loglik_kind = blackbox.\nThe rest of the model config is as usual. Here we can reuse our ddm model config, and simply specify bounds on the parameters (e.g. your Blackbox Likelihood might be trustworthy only on a restricted parameters space)." + } + } + ], + "console": [] + }, + { + "id": "MwfG", + "code_hash": "58151af82b7b9378ab3bc9bfbfc178c9", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "NOTE:\nSince Blackbox likelihood functions are assumed to not be differentiable, our default sampler for such likelihood functions is a Slice sampler. HSSM allows you to choose any other suitable sampler from the PyMC package instead. A bunch of options are available for gradient-free samplers." + } + } + ], + "console": [] + }, + { + "id": "TxKU", + "code_hash": "4a7640cb2435f7a5e042691b8a5ab97c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Results

" + } + } + ], + "console": [] + }, + { + "id": "ieTG", + "code_hash": "bc86abcb5090ec15c6877e9f282fcfd0", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

HSSM Random Variables in PyMC

\nWe covered a lot of ground in this tutorial so far. You are now a sophisticated HSSM user.\nIt is therefore time to reveal a secret. We can actuallly peel back one more layer...\n

\n
\n

\nInstead of letting HSSM help you build the entire model, we can instead use HSSM to construct valid PyMC distributions and then proceed to build a custom PyMC model by ourselves...\n

\n
\n

\nWe will illustrate the simplest example below. It sets a pattern that can be exploited for much more complicated modeling exercises, which importantly go far beyond what our basic HSSM class may facilitate for you!\nSee the dedicated tutorial in the documentation if you are interested.\nLet's start by importing a few convenience functions:
" + } + } + ], + "console": [] + }, + { + "id": "nnaP", + "code_hash": "736f77a65cca13c354132f3b4d486756", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Simulate some data

" + } + } + ], + "console": [] + }, + { + "id": "rEHw", + "code_hash": "38864260ac1c5ec88d8bd657aeeea58b", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Build a custom PyMC Model

" + } + } + ], + "console": [] + }, + { + "id": "nRku", + "code_hash": "912f3e00dd142f1a8421d8eb45e27145", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "We can now use our custom random variable DDM directly in a PyMC model." + } + } + ], + "console": [] + }, + { + "id": "ZpYI", + "code_hash": "5683733bc64dd45f9024e21b35b80da3", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Let's check the model graph:" + } + } + ], + "console": [] + }, + { + "id": "cFzV", + "code_hash": "e1bfeaa3bc3f6bc1938372d84ceb4d9c", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Looks remarkably close to our HSSM version!\nWe can use PyMC directly to sample and finally return to ArviZ for some plotting!" + } + } + ], + "console": [] + }, + { + "id": "HqwE", + "code_hash": "7c687f17fd04eb170f1c2aed8235ef99", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Alternative Models with PyMC

\nWith very little extra work, we can in fact load any of the models accessible via HSSM. Here is an example, where we load the angle model instead.\nWe first construction the likelihood function, using make_likelihood_callable().\nThen we produce a valid pymc.distribution using the\nmake_distribution() utility function.\nJust like the DDM class above, we can then use this distribution inside a PyMC model.
" + } + } + ], + "console": [] + }, + { + "id": "jgCY", + "code_hash": "5ff2c060baa7b9d5b94c48f520f9fa56", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "Note that we need to supply the params_is_reg argument (\"reg\" for \"regression\").\nThis is a boolean vector, which specifies for each input to the likelihood function, whether or not it is defined to be \"trial-wise\", as is expected if the parameter\nis the output e.g. of a regression function." + } + } + ], + "console": [] + }, + { + "id": "YSLY", + "code_hash": "0e3c51915d1d57dc2379a386fe184151", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

Regression via PyMC

\nFinally to illustrate the usage of PyMC a little more elaborately, let us build a PyMC model with regression components.
" + } + } + ], + "console": [] + }, + { + "id": "QVpv", + "code_hash": "eb10fcd51d58229a66495ad7867a359a", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "All layers peeled back, the only limit in your modeling endeavors becomes the limit of the PyMC universe!\n

\n
\n\n
Enjoy the exploration!
" + } + } + ], + "console": [] + }, + { + "id": "hXpz", + "code_hash": "ca218914ead314da414928fce753fe2e", + "outputs": [ + { + "type": "data", + "data": { + "text/markdown": "

End

" + } + } + ], + "console": [] + }, + { + "id": "Hbol", + "code_hash": "8aa048bef04d5e215cc8514cee844ca7", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
PosixPath('/home/jovan/Documents/projects/hssm_wksp/HSSM/docs/tutorials')
" + } + } + ], + "console": [] + }, + { + "id": "lEQa", + "code_hash": "c29e154ba88da175215ab5d4c799118c", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "Xref", + "code_hash": "a50dcb87a223aac4a2c6e754f7c3b585", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "Kclp", + "code_hash": "379681790c04615eca36146b12d9db64", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "Hstk", + "code_hash": "585b745a3330a8917829b9ea68afe6d7", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "iLit", + "code_hash": "af11df090be7dd1b12cafa3629beb85f", + "outputs": [ + { + "type": "data", + "data": { + "application/json": "[\"ddm\", \"ddm_sdv\", \"full_ddm\", \"angle\", \"levy\", \"ornstein\", \"weibull\", \"race_no_bias_angle_4\", \"ddm_seq2_no_bias\", \"lba3\", \"lba2\"]" + } + } + ], + "console": [] + }, + { + "id": "ROlb", + "code_hash": "5ba22750d6834e4f055f784e19ec0ac1", + "outputs": [ + { + "type": "data", + "data": { + "application/json": "{\"response\": [\"rt\", \"response\"], \"list_params\": [\"v\", \"a\", \"z\", \"t\"], \"choices\": [-1, 1], \"description\": \"The Drift Diffusion Model (DDM)\", \"likelihoods\": {\"analytical\": {\"loglik\": \"text/html:
functionlogp_ddm
Compute analytical likelihood for the DDM model with `sv`.
def logp_ddm(data: numpy.ndarray, v: float, a: float, z: float, t: float, err: float = 1e-15, k_terms: int = 20, epsilon: float = 1e-15) -> numpy.ndarray:
\", \"backend\": null, \"bounds\": {\"v\": [\"text/plain+float:-inf\", \"text/plain+float:inf\"], \"a\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"]}, \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"extra_fields\": null}, \"approx_differentiable\": {\"loglik\": \"ddm.onnx\", \"backend\": \"jax\", \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"bounds\": {\"v\": [\"text/plain+float:-3.0\", \"text/plain+float:3.0\"], \"a\": [\"text/plain+float:0.3\", \"text/plain+float:2.5\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:2.0\"]}, \"extra_fields\": null}, \"blackbox\": {\"loglik\": \"text/html:
functionouter
def outer(data: numpy.ndarray, *args, **kwargs):
\", \"backend\": null, \"bounds\": {\"v\": [\"text/plain+float:-inf\", \"text/plain+float:inf\"], \"a\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"]}, \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"extra_fields\": null}}}" + } + } + ], + "console": [] + }, + { + "id": "Vxnm", + "code_hash": "b849e1f67d64898458f6645d5cb141bc", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "aLJB", + "code_hash": "19e7daf3f594fd27aca34d1ea3e90200", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "AjVT", + "code_hash": "7481d7f032267a83544366f4834d9125", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "pHFh", + "code_hash": "96bf3f613b57aaad95a638c21d0c9fef", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
Hierarchical Sequential Sampling Model\nModel: ddm\n\nResponse variable: rt,response\nLikelihood: analytical\nObservations: 500\n\nParameters:\n\nv:\n    Prior: Normal(mu: 0.0, sigma: 2.0)\n    Explicit bounds: (-inf, inf)\n\na:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\nz:\n    Prior: Uniform(lower: 0.0, upper: 1.0)\n    Explicit bounds: (0.0, 1.0)\n\nt:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)
" + } + } + ], + "console": [] + }, + { + "id": "TRpd", + "code_hash": "90c8b356c5ba0b881f7de499a330be3f", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "yCnT", + "code_hash": "361fb77c0069452430ce387c638a2015", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nSequential sampling (2 chains in 1 job)\nNUTS: [a, t, z, v]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1500 0 0.463 3 94.96 draws/s 0:00:15 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1500 0 0.782 7 48.60 draws/s 0:00:30 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 1_000 tune and 500 draw iterations (2_000 + 1_000 draws total) took 31 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n\r 0%| | 0/1000 [00:00<class 'arviz.data.inference_data.InferenceData'>" + } + } + ], + "console": [] + }, + { + "id": "dGlV", + "code_hash": "d02de374d9d74b8b812da23fc49f7d8d", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "\n
\n
\n
arviz.InferenceData
\n
\n \n
\n " + } + } + ], + "console": [] + }, + { + "id": "fwwy", + "code_hash": "6dfef4c4e137cd8647a7c8d5d5429347", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
<xarray.Dataset> Size: 36kB\nDimensions:  (chain: 2, draw: 500)\nCoordinates:\n  * chain    (chain) int64 16B 0 1\n  * draw     (draw) int64 4kB 0 1 2 3 4 5 6 7 ... 493 494 495 496 497 498 499\nData variables:\n    t        (chain, draw) float64 8kB 0.4858 0.4874 0.5649 ... 0.5131 0.5023\n    a        (chain, draw) float64 8kB 1.42 1.396 1.432 ... 1.459 1.465 1.531\n    v        (chain, draw) float64 8kB 0.46 0.4994 0.4201 ... 0.4756 0.4639\n    z        (chain, draw) float64 8kB 0.4921 0.4953 0.5207 ... 0.5448 0.5019\nAttributes:\n    created_at:                  2026-01-08T04:55:33.399374+00:00\n    arviz_version:               0.22.0\n    inference_library:           pymc\n    inference_library_version:   5.26.1\n    sampling_time:               30.849383115768433\n    tuning_steps:                1000\n    modeling_interface:          bambi\n    modeling_interface_version:  0.15.0
" + } + } + ], + "console": [] + }, + { + "id": "LJZf", + "code_hash": "951eddecca5029c3c95bb7fa16dc64f9", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
<xarray.DataArray 'a' (chain: 2, draw: 5)> Size: 80B\narray([[1.41962593, 1.39567367, 1.4317506 , 1.43815873, 1.43815873],\n       [1.49850733, 1.46560166, 1.45534524, 1.3908701 , 1.49430976]])\nCoordinates:\n  * chain    (chain) int64 16B 0 1\n  * draw     (draw) int64 40B 0 1 2 3 4
" + } + } + ], + "console": [] + }, + { + "id": "jxvo", + "code_hash": "2a2f7ab87f0f5fdbe6e00a9916195dcb", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
<class 'numpy.ndarray'>
" + } + } + ], + "console": [] + }, + { + "id": "mWxS", + "code_hash": "efe5b9b6b5e607baadafd94a3add68e9", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "YWSi", + "code_hash": "1bb0635197876b993e437259b446d9d7", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
<xarray.Dataset> Size: 56kB\nDimensions:  (sample: 1000)\nCoordinates:\n  * sample   (sample) object 8kB MultiIndex\n  * chain    (sample) int64 8kB 0 0 0 0 0 0 0 0 0 0 0 ... 1 1 1 1 1 1 1 1 1 1 1\n  * draw     (sample) int64 8kB 0 1 2 3 4 5 6 7 ... 493 494 495 496 497 498 499\nData variables:\n    t        (sample) float64 8kB 0.4858 0.4874 0.5649 ... 0.4735 0.5131 0.5023\n    a        (sample) float64 8kB 1.42 1.396 1.432 1.438 ... 1.459 1.465 1.531\n    v        (sample) float64 8kB 0.46 0.4994 0.4201 ... 0.5438 0.4756 0.4639\n    z        (sample) float64 8kB 0.4921 0.4953 0.5207 ... 0.4846 0.5448 0.5019\nAttributes:\n    created_at:                  2026-01-08T04:55:33.399374+00:00\n    arviz_version:               0.22.0\n    inference_library:           pymc\n    inference_library_version:   5.26.1\n    sampling_time:               30.849383115768433\n    tuning_steps:                1000\n    modeling_interface:          bambi\n    modeling_interface_version:  0.15.0
" + } + } + ], + "console": [] + }, + { + "id": "tZnO", + "code_hash": "81738950ca38d6577095620f3f0c23fc", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
<xarray.Dataset> Size: 56kB\nDimensions:  (sample: 1000)\nCoordinates:\n  * sample   (sample) object 8kB MultiIndex\n  * chain    (sample) int64 8kB 0 0 0 0 0 0 0 0 0 0 0 ... 1 1 1 1 1 1 1 1 1 1 1\n  * draw     (sample) int64 8kB 0 1 2 3 4 5 6 7 ... 493 494 495 496 497 498 499\nData variables:\n    t        (sample) float64 8kB 0.4858 0.4874 0.5649 ... 0.4735 0.5131 0.5023\n    a        (sample) float64 8kB 1.42 1.396 1.432 1.438 ... 1.459 1.465 1.531\n    v        (sample) float64 8kB 0.46 0.4994 0.4201 ... 0.5438 0.4756 0.4639\n    z        (sample) float64 8kB 0.4921 0.4953 0.5207 ... 0.4846 0.5448 0.5019\nAttributes:\n    created_at:                  2026-01-08T04:55:33.399374+00:00\n    arviz_version:               0.22.0\n    inference_library:           pymc\n    inference_library_version:   5.26.1\n    sampling_time:               30.849383115768433\n    tuning_steps:                1000\n    modeling_interface:          bambi\n    modeling_interface_version:  0.15.0
" + } + } + ], + "console": [] + }, + { + "id": "CLip", + "code_hash": "d4bef0a0e0ab47d186f5daddf5090311", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "iXej", + "code_hash": "cea6cff9fcb97bb61a9fe87dafac4136", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "UmEG", + "code_hash": "4ce037f032ffd2fbc6d83f012c29d93e", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "IpqN", + "code_hash": "ece8ee4092a1e62ff45fa6d4ddea76fa", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "dlnW", + "code_hash": "86d097df4bb8fc71e738c0a6a3ad02bd", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "RKFZ", + "code_hash": "de964d1e39e02f7d66ea3cfd8b724cf0", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "IWgg", + "code_hash": "45f1fd310a291c447df837b24d5c4d41", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "LkGn", + "code_hash": "47a838cfd5962ac8ef30dd5da4a78c4c", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "HnMC", + "code_hash": "d09102f45050087f0419495714baca8c", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "hgqU", + "code_hash": "7c2aec14da23e91ab964c6ad4346857b", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "streamMedia", + "name": "media", + "mimetype": "application/vnd.marimo+mimebundle", + "data": "{\"image/png\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+4AAANlCAYAAADik6OlAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAewgAAHsIBbtB1PgAA7lVJREFUeJzs3Xd0VNXax/HfmfRK6L2HEFCa9N4UFURAsaOgYLk29KJ4RV+Ea8GGBcv1Iki5iqKooAYFxdBrIFKkhF5CDRAS0st5/xgyJKRMEpLMCXw/a81aJ3P22efJzGQyz+zn7G2YpmkKAAAAAABYks3VAQAAAAAAgPyRuAMAAAAAYGEk7gAAAAAAWBiJOwAAAAAAFkbiDgAAAACAhZG4AwAAAABgYSTuAAAAAABYGIk7AAAAAAAWRuIOAAAAAICFkbgDAAAAAGBhJO4AAAAAAFgYiTsAAAAAABZG4g4AAAAAgIWRuAMAAAAAYGEk7gAAAAAAWBiJOwAAAAAAFkbiDgAAAACAhZG4AwAAAABgYSTuAAAAAABYGIk7gHKrQYMGMgxDhmHowIEDrg4H5czMmTMdr58RI0a4OpwC9erVyxHr0qVLXR0OLKg8vZ4BAEVH4g4UIPuH5bxuAQEBatCggQYNGqSPPvpI586dc3XIuEIlJydrwYIFevLJJ9WuXTvVrVtXPj4+8vPzU+3atdWjRw/985//1O+//67MzExXhwtctgMHDuR6z61WrZrS09ML3UdGRoZq1qyZqx++6AMAlDck7sBlOH/+vA4ePKiffvpJTz/9tOrVq6fZs2e7OqxCy/7BuEGDBq4OB3lIT0/Xf/7zHzVu3FiDBw/WJ598oo0bN+rIkSNKTk5WYmKijh49qhUrVuj9999Xv379VK9ePX3yySdFSnBQdhg9L75Tp07p119/LXT7RYsW6fjx46UYUcF4jwUAlBR3VwcAlBft27dXhw4dHD+bpqnY2Fht2LBBu3fvliTFxcVp+PDhSk5O1iOPPOKqUHGFOHv2rG6//XaFh4fnuL969epq27atqlatKpvNpuPHj2v79u06ePCgJCk6OlpPPvmk/v77b3366aeuCB0oNbNnz9bAgQML3RYAgCsBiTtQSP3799eECRPy3Pfjjz/qwQcfdJTKP/300+rfv7/q1KlThhFefa7kctfY2Fh16dJFO3fudNx3880365VXXlGHDh1kGEauY7Zu3arp06frs88+U0pKihITE8syZJQiRual5s2ba/v27fr5558VGxuroKCgAtufO3dOCxYsyHHslWzEiBFc2w4AVzBK5YESMGTIEH311VeOn1NSUhjpRLGZpqnhw4c7knabzaZPPvlECxcuVMeOHfNM2iWpRYsW+uCDDxQVFaUePXqUZchAqbv//vsl2d9f586d67T9t99+q+TkZEnSAw88UKqxAQBQ2kjcgRIyYMAAtWrVyvHzH3/84cJoUJ599dVX+umnnxw/T5o0SY8//nihj69Xr56WLFmi4cOHl0Z4gEvce++9cne3FwoWpgQ+q42Hh4fuvffeUo0NAIDSRuIOlKAuXbo4tvft25dvu0WLFumhhx5SSEiIAgMD5ePjo/r162vIkCGaOXOm0tLSCnW+tLQ0ffnll7rtttvUqFEj+fv7y93dXQEBAQoODtaNN96o8ePHa/369TmOy1o2qGHDho77Dh48mO/s+QXZsWOHxo0bpw4dOqh69ery9PRU1apV1bFjR40fP15Hjx51+nvkNVnXsWPH9MYbb6hDhw6qUaOG3NzccpXGFnU5uIMHD2r8+PHq1KmTI9bq1aurU6dOeuWVV3T48GGnfSxdutRxzl69ejnuX7hwoe655x41adJE/v7+MgxDH3zwgdP+LmWapt566y3Hz+3atdNzzz1X5H7c3d3Vu3fvAtvExMTozTffVM+ePVWzZk15eXmpSpUqatOmjZ5//vlClRbnN/nWypUrNWrUKIWGhqpChQoyDEPPPPOMY39er6/Nmzdr9OjRuvbaa1WpUiUZhqHBgwfned7Tp09r8uTJuuGGG1S3bl15e3srKChIzZs31xNPPKGIiAinsRfFxo0bNWnSJN1yyy2Ov7Ws10+XLl300ksv6dChQwX2kfX7Llu2zHFf79698/ybmzlzZo5jizqhXWk+txERERo1apRCQkLk6+urihUrqkOHDnrjjTeUkJDgtN/iqlatmm666SZJ0urVq7V379582+7fv1+rVq2SJN10002qWrVqoc+TlJSk+fPn6+mnn1a3bt0c7xX+/v5q0KCBhgwZounTpys1NTXfPi7nPba47zHOloObN2+eY7+7u7tWr15d4OOQmpqqtm3bOo655ZZbCn7gAAClywSQr549e5qSTEnmK6+84rT9uHHjHO09PDxy7T9x4oTZ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1AfLF154wbH90Ucf6Y8//ihULFLZl9f369dPDRs2lGQvO3/mmWfybWuapp566inHY9C4cWNdf/31ZRFmLsOGDdOAAQMcP7/wwgs5qiecOXTokK6//vpcS6aFhoaqR48ejp+ffPLJAp/zl19+2fFlR2BgYKHXTy8Njz76qGPyx02bNmnixImFPjYmJqZYI4cNGzZ0/O1t27ZN+/bty7ft3Llz9csvvxSq3+x/h9nXAr8c5fm5vRxubm5asWKFY2WN5cuXy83NrVh9NWrUyLH9008/5dsuIyNDjzzyiFJTU532WZz32NK2f/9+PfHEE46f33jjDbVq1UqSfYm47O81r776qtauXVvmMQIAciNxB8pA7969dfPNNzt+Hjp0qL777rtc7TZu3Kjrr7/esQxY3bp19fTTT+dq17lzZ91777369ddf8/3wGBUVlWNm5b59+8rT0zNHGy8vLzVp0kSSfTRo/vz5Tn+Xnj175pjNecCAAZo0aVK+a44nJydr/vz5GjRoUI4KgLJgs9lyTLz09ddf6+GHH84Va3x8vB588EH98MMPjvvefvvtHCNwZckwDM2ePdvx3GRkZOjRRx/VwIEDtWHDhnxHm7dt26ZnnnlGISEhWrZsWZ5tJk2a5EhsVqxYodtvvz1XJUJqaqpefPHFHCP9r7zySo4J0MpahQoVcsQzceJEDR8+PN/ruU3T1KpVq/T444+rXr16jrXFi6JKlSrq1KmTJPus4UOHDtWuXbtytMnMzNQnn3yi+++/X25ubjlGWPOT/VKIefPmlVj1QHl9bi9XcHCw2rVrp3bt2ik4OLjY/QwYMMDxRc3SpUv13HPP5XrdHD9+XLfffrvCwsIKNXt/cd5jS1NGRobuu+8+x8R6119/fa75T4YOHaoHH3xQkv09ftiwYVfERHwAUN4xqzxQRmbMmKGuXbtq7969On/+vO688041adJEHTt2lKenp7Zv365169Y5PsT7+fnp66+/znOJubS0NH399df6+uuv5ePjo5YtW6pRo0YKDAzU2bNntW/fPkVERDja+/j45JgdO7vbb79db7zxhiTpvvvu08yZMxUcHJzjet5Lj/3vf/+rY8eOafHixUpNTdW4ceP02muvqWPHjqpXr568vLwUGxurvXv3atu2bY5r69u2bXtZj2Fx3HnnnVq+fLljzflp06Zp7ty56t27t6pXr66TJ09qyZIlOZL5Z555RrfddluZx5pdpUqVtGbNGt1+++2OJPyXX37RL7/8oho1aqht27aqWrWqbDabjh8/rr///jvXZFJ5TdDVpUsXvfnmm3r++eclST///LPq1aun3r17q27dujp79qzCw8N1+vRpxzFDhgzRs88+W4q/beGMGDFC+/bt06uvvipJmj17tr766iu1bt1aoaGh8vf31/nz53XkyBH99ddfJbKM3Kuvvqp+/fopMzNTkZGRatGihbp27apGjRrp/PnzWrFihY4dOyZJev311zV16lSnk3rddtttGjdunEzTVFhYmFq2bKkuXbrkeL7uvvtutWvXrkixlufn1gpCQ0N1//33a/bs2ZKkyZMna86cOWrfvr2qVaumAwcOaPny5UpNTVVAQIDeeecdPfbYY077Lc57bGl59dVXtWbNGkn2yo9Zs2bleR3+lClTtGLFCu3Zs0d79+7VU089VajLvAAApcgEkK+ePXuakkxJ5iuvvHLZ/R0/ftzs06ePo8/8bsHBweb69evz7efaa6912kfWrWHDhuaqVavy7Ss2NtYMDQ0tsI+8pKenm//3f/9n+vr6FioODw8P84knnsizr+yPc3h4eKEfz/r16zuO279/f4FtX331VdPLy6vAGL29vc033nijwH7Cw8Md7Xv27FnoWIsrNTXV/Oijj8yaNWsW+jlv3LixOX36dDMjIyPffqdNm2YGBgYW2I+bm5s5evRoMz09Pd9+9u/f72hfv379Qv9ezl5fBZk7d65Zq1atQj8eHTp0MJOTk3P1M2PGDEeb4cOH53u+//znP6a7u3u+/dtsNnP8+PFmZmZmoV+TL774YoExz5gxI0f7ovyNuPK5LcrfpDPZzy/JTEpKKnZfSUlJOfrKL7aEhASzX79+BT52derUMVeuXFno94KivscW9z3G2et51apVppubm6PNDz/8UGB/69aty/G6//bbbwsdCwCg5DHiDpSh6tWra8mSJfrtt980d+5crVy5UsePH1daWpqqVaumNm3aaPDgwRo2bFiBM1j/9ddfWrt2rcLDw7V+/Xrt2rVLR48eVWJionx9fVWjRg21bt1at956q+68884C1wGvUKGCNmzYoE8//VRhYWHasWOHYmNjnV6L6ebmpn//+9966qmnNHv2bP3xxx/avn27YmJilJaWpsDAQNWvX18tWrRQ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\", \"__metadata__\": {\"image/png\": {\"width\": 503, \"height\": 434}}}" + } + ] + }, + { + "id": "mfOT", + "code_hash": "17be40e791fcb936ab77687ed79579e0", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
'analytical'
" + } + } + ], + "console": [] + }, + { + "id": "bMrW", + "code_hash": "71e47d37fdf094a6b34a88a806548115", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "OfTS", + "code_hash": "081dc83996ffbb5854c272909689e338", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
Hierarchical Sequential Sampling Model\nModel: angle\n\nResponse variable: rt,response\nLikelihood: approx_differentiable\nObservations: 1000\n\nParameters:\n\nv:\n    Prior: Uniform(lower: -3.0, upper: 3.0)\n    Explicit bounds: (-3.0, 3.0)\n\na:\n    Prior: Uniform(lower: 0.3, upper: 3.0)\n    Explicit bounds: (0.3, 3.0)\n\nz:\n    Prior: Uniform(lower: 0.1, upper: 0.9)\n    Explicit bounds: (0.1, 0.9)\n\nt:\n    Prior: Uniform(lower: 0.001, upper: 2.0)\n    Explicit bounds: (0.001, 2.0)\n\ntheta:\n    Prior: Uniform(lower: -0.1, upper: 1.3)\n    Explicit bounds: (-0.1, 1.3)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)
" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "Plbk", + "code_hash": "b70f66e871dcca6defb50ab00885a226", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "HuZB", + "code_hash": "2c17433d975e01efa6a1278e720c97e3", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
'approx_differentiable'
" + } + } + ], + "console": [] + }, + { + "id": "Ynfw", + "code_hash": "795040c7e96b67a9d6f4548a6e0408ff", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "\r 0%| | 0/1000 [00:00" + } + } + ], + "console": [] + }, + { + "id": "Lpqv", + "code_hash": "7a8fb0d52f13319a85e58367f4c31e6c", + "outputs": [ + { + "type": "data", + "data": { + "application/json": "{\"v\": \"text/plain+float:0.5\", \"a\": \"text/plain+float:1.5\", \"z\": \"text/plain+float:0.5\", \"t\": \"text/plain+float:0.5\"}" + } + } + ], + "console": [] + }, + { + "id": "upgv", + "code_hash": "9ef55deb01af081403927141be6f467b", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "pCao", + "code_hash": "844342adc4b510dcc33411101d8edfbf", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "wEIy", + "code_hash": "df1edfd63a9ca2f98091914db349dbf1", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "\n
\n
\n
arviz.InferenceData
\n
\n \n
\n " + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nMultiprocess sampling (2 chains in 2 jobs)\nNUTS: [v]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 1.181 3 2287.01 draws/s 0:00:00 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 1.252 1 374.87 draws/s 0:00:02 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 500 tune and 500 draw iterations (1_000 + 1_000 draws total) took 11 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "wlyU", + "code_hash": "a757f284768cce9719b56f4ad9887a04", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "GrQN", + "code_hash": "361dd8284e340f581d8090a4ec260898", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "mySd", + "code_hash": "5883f7bd0584604e42f234d13268f244", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "vGkK", + "code_hash": "1de6a377ea06ad43551d6b2e83c6594a", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
Hierarchical Sequential Sampling Model\nModel: ddm\n\nResponse variable: rt,response\nLikelihood: analytical\nObservations: 500\n\nParameters:\n\nv:\n    Prior: Normal(mu: 0.0, sigma: 0.01)\n    Explicit bounds: (-inf, inf)\n\na:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\nz:\n    Prior: Uniform(lower: 0.0, upper: 1.0)\n    Explicit bounds: (0.0, 1.0)\n\nt:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)
" + } + } + ], + "console": [] + }, + { + "id": "zmIa", + "code_hash": "d1004fec36de15b95ac649b1ae66e5b7", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nMultiprocess sampling (2 chains in 2 jobs)\nNUTS: [a, t, z, v]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 0.561 3 66.02 draws/s 0:00:15 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 0.514 3 58.35 draws/s 0:00:17 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 500 tune and 500 draw iterations (1_000 + 1_000 draws total) took 26 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "NOfw", + "code_hash": "4dceafa3a25dcc4cdf6db0c4c401d598", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "ynmH", + "code_hash": "b2d6cef98f71b3bc1d14cc4046ce06e8", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "ChmK", + "code_hash": "b1830d5f93bb0500d7a963d221529223", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "KdvC", + "code_hash": "382be22448d8de9a9239ddb14d59a0bf", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
Hierarchical Sequential Sampling Model\nModel: ddm\n\nResponse variable: rt,response\nLikelihood: analytical\nObservations: 1000\n\nParameters:\n\nv:\n    Formula: v ~ 1 + x + y\n    Priors:\n        v_Intercept ~ Normal(mu: 2.0, sigma: 3.0)\n        v_x ~ Normal(mu: 0.0, sigma: 0.25)\n        v_y ~ Normal(mu: 0.0, sigma: 0.25)\n    Link: identity\n    Explicit bounds: (-inf, inf)\n\na:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\nz:\n    Prior: Uniform(lower: 0.0, upper: 1.0)\n    Explicit bounds: (0.0, 1.0)\n\nt:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)
" + } + } + ], + "console": [] + }, + { + "id": "EKSN", + "code_hash": "249969ad166dd51acd14410516f31067", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "tasN", + "code_hash": "591440de6b7f4814526437caec7de25a", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
Hierarchical Sequential Sampling Model\nModel: ddm\n\nResponse variable: rt,response\nLikelihood: analytical\nObservations: 1000\n\nParameters:\n\nv:\n    Formula: v ~ 1 + x + y\n    Priors:\n        v_Intercept ~ Normal(mu: 2.0, sigma: 3.0)\n        v_x ~ Normal(mu: 0.0, sigma: 0.25)\n        v_y ~ Normal(mu: 0.0, sigma: 0.25)\n    Link: identity\n    Explicit bounds: (-inf, inf)\n\na:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\nz:\n    Prior: Uniform(lower: 0.0, upper: 1.0)\n    Explicit bounds: (0.0, 1.0)\n\nt:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)
" + } + } + ], + "console": [] + }, + { + "id": "SXvM", + "code_hash": "b30808ef95e931bdfc0bb7d19e499064", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "CFll", + "code_hash": "80d5498b9cf7c86809a7e711650b5e77", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Hierarchical Sequential Sampling Model\nModel: ddm\n\nResponse variable: rt,response\nLikelihood: analytical\nObservations: 1000\n\nParameters:\n\nv:\n Formula: v ~ 1 + x + y\n Priors:\n v_Intercept ~ Normal(mu: 2.0, sigma: 3.0)\n v_x ~ Normal(mu: 0.0, sigma: 0.25)\n v_y ~ Normal(mu: 0.0, sigma: 0.25)\n Link: identity\n Explicit bounds: (-inf, inf)\n\na:\n Prior: HalfNormal(sigma: 2.0)\n Explicit bounds: (0.0, inf)\n\nz:\n Prior: Uniform(lower: 0.0, upper: 1.0)\n Explicit bounds: (0.0, 1.0)\n\nt:\n Prior: HalfNormal(sigma: 2.0)\n Explicit bounds: (0.0, inf)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "GbuD", + "code_hash": "f5edd1927e52a5cb97933b8fb88707fe", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "bHhy", + "code_hash": "e5c0889cec505a983b62d1ff9c682254", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
Hierarchical Sequential Sampling Model\nModel: ddm\n\nResponse variable: rt,response\nLikelihood: analytical\nObservations: 1000\n\nParameters:\n\nv:\n    Formula: v ~ 1 + x + y\n    Priors:\n        v_Intercept ~ Uniform(lower: -3.0, upper: 3.0)\n        v_x ~ Uniform(lower: -1.0, upper: 1.0)\n        v_y ~ Uniform(lower: -1.0, upper: 1.0)\n    Link: identity\n    Explicit bounds: (-inf, inf)\n\na:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\nz:\n    Prior: Uniform(lower: 0.0, upper: 1.0)\n    Explicit bounds: (0.0, 1.0)\n\nt:\n    Prior: HalfNormal(sigma: 2.0)\n    Explicit bounds: (0.0, inf)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)
" + } + } + ], + "console": [] + }, + { + "id": "NtNR", + "code_hash": "d6d4b1c4f5a9b3b94f3adc9aab7d6a93", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nMultiprocess sampling (2 chains in 2 jobs)\nNUTS: [a, t, z, v_Intercept, v_x, v_y]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 0.530 7 25.63 draws/s 0:00:38 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 0.474 7 24.22 draws/s 0:00:41 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 500 tune and 500 draw iterations (1_000 + 1_000 draws total) took 50 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n\r 0%| | 0/1000 [00:00\n
\n
arviz.InferenceData
\n
\n \n \n " + } + } + ], + "console": [] + }, + { + "id": "ZsHO", + "code_hash": "70ebb3d3d7aa6a00da6bc9bf5e77683c", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "HNXk", + "code_hash": "ae51fbf7ab64e830ec4568ab822e3d44", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "bhgI", + "code_hash": "44f947eb61bdc12553048113bd4384ef", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "DlKN", + "code_hash": "b0db33c2eaa15cf2009a0c7603a93680", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "QYfb", + "code_hash": "44021c99c9c8dab765e6585956b86186", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "qJXu", + "code_hash": "95170aee36a03a4e7f90b1be271bbf52", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "LdJG", + "code_hash": "9f8147656aca8428164678c11972c9e3", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nSequential sampling (1 chains in 1 job)\nNUTS: [z, theta, a, t, v_Intercept, v_x, v_y]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1500 0 0.264 15 18.20 draws/s 0:01:22 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 1 chain for 500 tune and 1_000 draw iterations (500 + 1_000 draws total) took 82 seconds.\nOnly one chain was sampled, this makes it impossible to run some convergence checks\n\r 0%| | 0/1000 [00:00" + } + } + ], + "console": [] + }, + { + "id": "HRKw", + "code_hash": "7c9e03defee881af8aaf0f55a384ea93", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "MYoQ", + "code_hash": "81131f40505dd8143f8cdd1f3f592748", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
Hierarchical Sequential Sampling Model\nModel: angle\n\nResponse variable: rt,response\nLikelihood: approx_differentiable\nObservations: 1000\n\nParameters:\n\nv:\n    Formula: v ~ 1 + x + y\n    Priors:\n        v_Intercept ~ Uniform(lower: -3.0, upper: 3.0)\n        v_x ~ Uniform(lower: -1.0, upper: 1.0)\n        v_y ~ Uniform(lower: -1.0, upper: 1.0)\n    Link: identity\n    Explicit bounds: (-3.0, 3.0)\n\na:\n    Formula: a ~ 1 + x + y\n    Priors:\n        a_Intercept ~ Uniform(lower: 0.5, upper: 3.0)\n        a_x ~ Uniform(lower: -1.0, upper: 1.0)\n        a_y ~ Uniform(lower: -1.0, upper: 1.0)\n    Link: identity\n    Explicit bounds: (0.3, 3.0)\n\nz:\n    Prior: Uniform(lower: 0.1, upper: 0.9)\n    Explicit bounds: (0.1, 0.9)\n\nt:\n    Prior: Uniform(lower: 0.001, upper: 2.0)\n    Explicit bounds: (0.001, 2.0)\n\ntheta:\n    Prior: Uniform(lower: -0.1, upper: 1.3)\n    Explicit bounds: (-0.1, 1.3)\n\n\nLapse probability: 0.05\nLapse distribution: Uniform(lower: 0.0, upper: 20.0)
" + } + } + ], + "console": [] + }, + { + "id": "BzwM", + "code_hash": "05b233760d741781b9ffd2a549f7e6c4", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "nSRe", + "code_hash": "d0533d558dd38a9400a769ddf852a4f2", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nSequential sampling (2 chains in 1 job)\nNUTS: [z, theta, t, v_Intercept, v_x, v_y, a_Intercept, a_x, a_y]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.449 7 21.24 draws/s 0:01:34 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.277 15 10.14 draws/s 0:03:17 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 1_000 tune and 1_000 draw iterations (2_000 + 2_000 draws total) took 197 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n\r 0%| | 0/2000 [00:00" + } + } + ], + "console": [] + }, + { + "id": "tbSj", + "code_hash": "ba9b62d415b8fb5b23b67d658f585145", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "eLzN", + "code_hash": "ce80c8b9ed14ed14c9015acfafaf7de7", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "JHzP", + "code_hash": "167ead55e24ad2713ece00502d6e7b79", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "elJp", + "code_hash": "001120caffcd10214ed7bb5761a74991", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "EyBw", + "code_hash": "f7be7fdd87f2ea7287963dfa606b0b1a", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nSequential sampling (2 chains in 1 job)\nNUTS: [z, theta, a, t, v_C(x), v_y]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1500 0 0.362 7 24.34 draws/s 0:01:01 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1500 0 0.343 7 11.57 draws/s 0:02:09 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 500 tune and 1_000 draw iterations (1_000 + 2_000 draws total) took 130 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n\r 0%| | 0/2000 [00:00" + } + } + ], + "console": [] + }, + { + "id": "ofkl", + "code_hash": "59facf26867c6e91b470717661a4c070", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "TzTD", + "code_hash": "39f453e72dcc8b60538e5750c636184d", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "ywjc", + "code_hash": "175b601e84163b0c002cc17c0ceec3f0", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "WyQu", + "code_hash": "96a6485ec3fe08d449aeeb1b2e29f903", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "\n
\n
\n
arviz.InferenceData
\n
\n \n
\n " + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\nParallel sampling might not work with `jax` backend and the PyMC NUTS sampler on some platforms. Please consider using `nuts_numpyro` or `nuts_blackjax` sampler if that is a problem.\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nMultiprocess sampling (2 chains in 2 jobs)\nNUTS: [z, theta, a, t, v_Intercept, v_x, v_y, v_1|participant_id_sigma, v_1|participant_id_offset]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 0.136 31 1.00 draws/s 0:16:36 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 1000 0 0.208 15 1.03 draws/s 0:16:09 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 500 tune and 500 draw iterations (1_000 + 1_000 draws total) took 1006 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\nThe rhat statistic is larger than 1.01 for some parameters. This indicates problems during sampling. See https://arxiv.org/abs/1903.08008 for details\nThe effective sample size per chain is smaller than 100 for some parameters. A higher number is needed for reliable rhat and ess computation. See https://arxiv.org/abs/1903.08008 for details\n\r 0%| | 0/1000 [00:00" + } + } + ], + "console": [] + }, + { + "id": "MXkk", + "code_hash": "9cb64fcf06758ae281400044ec722d2b", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": " rt response\n0 0.742448 -1.0\n1 1.626247 1.0\n2 1.289860 1.0\n3 1.338989 1.0\n4 1.291685 1.0\n.. ... ...\n495 0.952013 1.0\n496 0.906471 1.0\n497 1.467497 1.0\n498 0.814649 -1.0\n499 0.523454 1.0\n\n[500 rows x 2 columns]\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "axEp", + "code_hash": "f76c639aeffbc264d28f5d13a6201903", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "mKKx", + "code_hash": "61ed45701803f4a369ee43735d5fafee", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "JWOG", + "code_hash": "6a7d078bda9c385a4c83dbc3d5852531", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "IWwC", + "code_hash": "a0621c22d5b26ed8e5d9a183391983a5", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nSequential sampling (2 chains in 1 job)\nNUTS: [z, theta, t, v]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.831 7 69.85 draws/s 0:00:28 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.741 7 33.15 draws/s 0:01:00 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 1_000 tune and 1_000 draw iterations (2_000 + 2_000 draws total) took 60 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n\r 0%| | 0/2000 [00:00" + } + } + ], + "console": [] + }, + { + "id": "eYRD", + "code_hash": "eaee07c5773d39b5dd230239df179969", + "outputs": [ + { + "type": "data", + "data": { + "application/vnd.marimo+mimebundle": "{\"image/png\": \"data:image/png;base64,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OnjwoJYuXap79+5p//79qlevnnbs2CEfHx+rsd2+fVtt2rTRiRMnVLFiRbVo0UJeXl46deqUfvnlF4WHh+vYsWPq3r27Vq9erY4dO2rlypUqXLiw2rVrJx8fH127dk0LFixQSEiI7t27p27duunYsWPKly9fqnO3a9dOp0+flre3t9q1a6ciRYrowoULWrx4sc6fP6979+6pT58+cnNzU/fu3ZMd5+rVq5LivkN169aVr6+vPD09FRMTo+DgYK1atUrnzp1TWFiYunbtqlWrViX7s/GgLVu2aNq0aYqOjlbNmjXl5+enPHnyKCQkJNW+CcXGxsrf31/79u2TJHl4eKhly5YqV66c3NzcFB4errNnz2r37t3mxnPJuXnzpurXr6+TJ09KkhwdHdWiRQtVr15dkvTXX39pxYoVio6O1tq1a/XMM89ox44dypMnj9X4zp8/r5YtW+rSpUuqVKmSmjVrpgIFCuiff/7RokWLdPHiRUVGRurll19WtWrVVLp06XS9fgBAKrI6wwsAAAD8mz24gtUwDKNDhw6GJCNnzpzG7du3k/T5+OOPzT779u0zDMNI0wrWiRMnmm2cnJyMmTNnJmlz6dKlRKs0y5QpY9y9ezdJu7CwMMPb29ts16pVK+PmzZuJ2kRHRxuffPKJIcmwWCypxvf555+bbWrWrGkcO3Ys2XZz5swxnJ2dDUlG3rx5jevXrydpk5ErWCMiIoxy5cqZ41WsWNHYv39/sm2joqKMRYsWGX/++WeSax988IE5hoeHh7Fq1aokbU6ePGmUL1/ebNegQYNk50m44jL+/R07dqwRGxubqN3Ro0eNfPnyme3ivycBAQFGeHh4orahoaFGzZo1zbajR49Ode74z7VPnz7GvXv3ErW7e/euERgYaLbNmzevceHChWTH/Oqrr4w1a9YYMTExyV6PiYkxxo4da668fvLJJ1Nsm3AFq/63gja1lZuprWBds2aNeb1GjRrGtWvXUhzr1KlTKa7Y7datmzlO0aJFjT179iRp89dffxmFCxc227300kvJjpVwBaskw9HR0fjxxx+TtLtz545Rr149s12fPn1SjB0AYBsSrAAAAEAWSi7BumTJEvO5SZMmJWofExNjFC9e3JBkPP300+bzqSVYo6KizH6SjG+++SbFmG7fvm0UK1bMbJtc0ub77783rz/55JPJJmGTiy2l+K5fv264ubkZUlx5guQSywmNHz/eHG/EiBFJrmdkgnXcuHHmWCVKlEg2oZuaGzduGLly5TLHWbx4cYptz507Z74XkoyVK1cmafNggvWdd95JcbzPPvssUdu6deummJzcvHlzokRich6cu3HjxkkSu/FiYmISJew//PDDFONMizfeeMMcK6UyBg8mWFMrT/Dga0ouwfrVV1+Z1229zf7IkSNmQjpHjhzGX3/9lWLbnTt3mslki8WS7B8bHkywfvnllymOd/jwYbNd/vz5bYofAJAyNrkCAAAAspnnnntOhQsXliRNmTIl0bWVK1fq/PnzktK3udXatWvNfiVKlNBrr72WYtvcuXNryJAh5nlQUFCSNjNnzjSPP/nkE7m6uqY43ujRo2WxWKzGFxQUpPDwcHO83LlzW23ft29fubu7S5KWLFlite3DmjBhgnn8xRdfpHrbfHLmz5+viIgISVL9+vXVrl27FNt6e3sn+nySe/8TcnZ21gcffJDi9VatWiU6//jjj+XgkPyvgvXr15enp6ck6e+//0621MGDRo0aleLn6+DgoJEjR5rnqb2W1CQsMRBfJsOaEiVKKDAw8KHmlJTofYj/HNNr+vTp5uZn3bp109NPP51i25o1a6pz586S4kpnTJ8+3erYBQoU0BtvvJHi9fLly5sb6F27ds38bwEAIGOQYAUAAACyGUdHRwUEBEiSduzYocOHD5vX4hOuLi4uevHFF9M85pYtW8zj559/PsUEW7wuXbqYx7t379b9+/fN8/v37+uvv/6SpCS7sSfHx8cnxTqu8dauXWset2jRwmpbKS6pWL58eUnS3r1705QItMU///xj7r7u7u6ujh072jROwve/U6dOqbZP+P5v3rzZatvq1avLy8srxeulSpUyjx0dHVOtXfrEE09Iivucb926ZbVtoUKFVK9ePattGjZsaMZ34cIFnTt3zmr7a9euafXq1Zo6darGjx+vr776ynwkTKbHfy7WPPfcc6l+19OiatWq5vEnn3xifv/TIzO/A02aNEm1FnPZsmXN4/hawgCAjMEmVwAAAEA2FBgYqC+++EKSNHXqVH355Ze6ceOGmWDy9/c3VxqmxYkTJ8zjp556KtX2+fLlk4+Pj86dO6f79+8rODhYZcqUkSSdPXtWkZGRkuKScamtNpXiElS7du1K8fr+/fvN42LFiqU6XkIxMTG6efOm8ufPn65+aZFww6KnnnpKTk5ONo2T3ve/cuXKcnR0VHR0tM6dO6eoqKgU5/b29rY6VvxKX0ny8vJSzpw509w+PDzcavI2YeIxJRaLRZUrV9b69eslxSVGk9u4a/Xq1Ro5cqQ2bdpkrvS0JrXkrySVK1cu1TZp0axZMz311FPau3evzp07pxo1aqhKlSpq1qyZ6tWrpzp16qho0aJWx0jvdyDhCteEfZOT2kZoUtzGXPHCwsJSbQ8ASDtWsAIAAADZkK+vr7kycMaMGYqOjtasWbPMlaTpKQ8gxe1eHi+ticiE7W7cuJHsWNaSbymNlZzr16+naZyUxJcXyGgJ4ypYsKDN46T3/Xdyckq0c3zC9/9B1sozSEp0+35qbR9sHxsba7WtLZ9/wvci3vDhw9WsWTNt3LgxTclVSbp3716qbRK+hw/DwcFBy5YtU9OmTc3nDhw4oK+//lodO3ZUsWLFVL58eQ0bNkxXr15Ndoz0fgdS+vlLTkZ/rgCA9GEFKwAAAJBNBQYGauvWrbp8+bKWLVtmlgcoXry4mjVrlsXRZazo6Gjz+PPPP5ejY/p+VUnPal5kL6tXr9awYcPM865du6pz586qXLmyChcurJw5c5qrd8+cOZOo5EFqMqI8QLzChQtr1apV2rZtm+bNm6cNGzbowIEDZnmKo0ePavjw4RozZoyCgoLUoUOHDJsbAJC9kWAFAAAAsqkuXbpo0KBBCg8P14cffmjWYu3Ro0e6E0cJE5BpXS167do18zjhxk4PO1ZyvLy8dPHiRUlxieWHWS2akRKu0HyYupXpfc+ioqJ0+/Zt89yWjbXswZbP/8Fk+Pjx483jMWPG6K233kpxnITvSVapW7eu6tatK0m6c+eOtm7dquXLl2v27Nm6evWqQkND1bVrV+3du9fcWEqKe93x3/Hr16/Lzc3N6jwp/fwBALIfSgQAAAAA2ZSHh4e5GU7Cja7SWx5Aklk/VYrbFCo1N27cMDcjcnFxSVTjsWTJkuaGOmfOnNGdO3dSHS9hjdXkJKyVmVpbe0qYINu7d6+ioqJsGie97//BgwfNVb0lS5a0ufZrZkvLZ2UYhv7++2/z3NfXN9H17du3S4q7zX3gwIFWxzp48KANUWae3Llzq2XLlho3bpxOnz6t2rVrS4pLkP/000+J2qb3O5CwTcINqgAA2Q8JVgAAACAbCwwMTHTesGFDlS5dOt3j1K9f3zz+9ddfU63BuGDBAvO4Ro0aiXYod3FxMTfgMQxDixcvtjpWcHCwdu/ebbVNwpIHc+fOtdrWnooUKWImf8PCwrRw4UKbxkn4/id8b1Myf/78ZPtmN5cvX9a2bdusttm0aZO50rVo0aJJNmSKr03q7u6e6HuWnLS8d1nF3d090erbY8eOJbr+uH4HAAAkWAEAAIBsrWHDhnr33Xc1cOBADRw4UJ9++qlN4zz77LMqUaKEJOncuXOaMGFCim1DQ0M1atQo87xnz55J2rz88svm8ahRo8zNt5LzySefpLpxUWBgoLm7/fTp07Vp0yar7RNK66ZIturfv795/N5776W64VByOnfurFy5ckmSNm/erD/++CPFtufPn9d3331nnif3/mcn1j5fwzASfWcDAgKStIkvw3Dt2jUFBwenOM/atWu1ZMmSh4zWfuK/z/ECAgLMjabmzp1rdfXvnj17NG/ePElxm1P16NEj8wIFADw0EqwAAABANvfFF1/ou+++03fffacmTZrYNIajo6OGDBling8ePDjZlaJXrlxR27ZtFRISIinutuaXXnopSbuAgAAzYXv8+HF17tw5SamA2NhYDR8+XNOnT0+0g3lyChUqpI8//lhS3IZXrVu31owZM1JcaRsbG6stW7bo5ZdfTlTDMzO8+uqr5irWkJAQNWzYUAcOHEi2bVRUlBYtWqTly5cnet7T01ODBg0yz1988UWtXbs2Sf/Tp0+rZcuWCg0NlSQ1aNAg0c712Y3FYtGaNWs0cOBARUZGJrp2//599e3bVxs2bJAk5cmTR6+//nqSMRo2bGge9+7d23ztCf355596/vnnMzj6tHvzzTf1zjvv6NChQym2+eeffxL9YSLh65LiymB069ZNUtx3vG3btskmWffu3au2bduam2e9+OKLicoLAACyHza5AgAAAP4l+vTpo1WrVmnBggWKjIxU9+7dNXbsWD377LNyd3fXiRMn9Ntvv5kbCbm7u2v27NlydXVNMpa7u7smT56sVq1aKTo6WkuXLtWTTz6pDh06yMfHRzdu3NAff/yho0ePytPTU/7+/po6darV+D766CMdOXJEs2bNUmhoqAICAvTJJ5+oSZMm8vHxkZOTk27evKmjR49q586dunz5siSpatWqGf9mJZAzZ04tXLhQjRo10rVr13To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YAUAAACQYVq3bq2qVatKkq5cuaJ27drpypUrSdrNmjVLQ4YMMVeT2tNnn30md3d3SdKkSZMUGBiYqFbog0JCQvSf//xHLVq0sFeIafbss89q7NixunTpUoptNm/erJkzZ5rnDRs2fOh5LRaLrl69qrZt2+ry5ctJrv/8888aPXq0eT5kyJAkbVxdXfXFF1+Y5z169NCYMWMUGRmZ4rx79+7Va6+9pvfffz/Z6/FlCMLDw7Vz585UX0fCsgXr1q1LtX27du3MlbchISF65plntG3bthTb3717V4sWLVKjRo20Z8+eVMcHADya2OQKAAAAQIbJkSOHpk6dqmeeeUYRERHavHmzypYtK39/f5UpU0ZhYWFau3atdu7cKRcXFw0YMEDjx4+XJLslW8uVK6fZs2erc+fOun//vqZOnaq5c+eqSZMmqlKlinLnzq2wsDCFhIRoz549Zp3YihUr2iW+9Dh9+rQGDx6sd955R0899ZSeeuopFStWTM7Ozrpy5Yp27Nih7du3m+27du2qatWqPfS83t7eql69uhYtWqSyZcuqQ4cO5ue7cuXKRMnEV155Ra1bt052nBdffFGHDh3S559/rsjISL399tv64osv1LRpU5UuXVo5c+bU7du3dfLkSe3cuVPBwcGSEq8kTah169baunWrJKlt27Z68cUX5ePjY262VqxYMXMjMEl65plnlCdPHt2+fVt//vmnWrZsqUaNGsnDw8Ns06FDBxUrVsw8nzt3rho2bKhDhw7p+PHjqlevnp5++mnVr19fhQsXVkxMjK5du6a///5bO3fuVHh4uCRWsALA44wEKwAAAIAM9dRTT+mPP/5Q586dde3aNd2+fVtBQUGJ2ri7uysoKCjRrdwZdet6WrRt21abNm1Sjx49dOTIEd29e1e///67fv/99xT7VKpUyW7xpZWzs7MkKTY2Vn/99Zf++uuvFNsGBAToxx9/zLC5p0yZojt37mj16tVJPt94gYGBmjhxotVxPvvsM5UrV06DBw/W9evXdfnyZc2aNSvF9s7OzknKDcR7/fXXNWPGDB09elRXrlzR2LFjE11v1KhRogRrzpw59cUXX6hfv34yDEMrVqxIUhe4UqVKiRKs+fLl0/bt2zVw4EDNnDlTsbGx2rNnj9UVqsWKFZOnp6fV9wEA8OgiwQoAAAAgw/n5+eno0aMaN26clixZ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9vj69eubx7ZsGGaxWFSjRg1JcYnLo0ePWm2/atUq89iemykVKFDArDG7efPmNK2QTskzzzxjHi9dutSmMRKuerX2PU9Owvc4/nMGAAAA8HgqVKiQxowZY56fO3dONWvW1KBBg5L8/nX06FENGjRINWvWTLRXypgxY1SwYEG7xQxkByRYHwEJ64NaW0UZHBysadOm2SGih3f27Fm99tprkuJugZ45c6Zy5Mih0aNHq1q1apKkqVOnauHChUn6tmrVyrxt/dtvv9XVq1dtisHV1VUtW7aUFPfe/frrrym2nTZtWrp3UH8c3LhxQ99884153qpVq2TbxZdzMAxDu3btSnG8QoUKqWnTppKkw4cPa9asWemO6fnnnzePv/zyyxTbhYeH64cffpAUl2Bs165duud6GPGlL+7cuWN107bUdO3aVY6OcdVcxo4dm2hFcVqlt7RCQjt27JAkeXp6Jto0DAAAAMDjacCAARoyZIh5HhoaqvHjx6t8+fIqV66cateurXLlyql8+fIaP358ov0uhgwZogEDBmRF2ECWIsH6CChfvrxZL/Tnn3/WqVOnkrS5cOGC2rVrZ1NdS3uLiYnRSy+9ZG7e8+2336pUqVKS4m43nz17trmZTp8+fRLtPC/FJYs+/fRTSXGre1u2bGm1NIJhGFqzZo1Gjx6d5Fr8xmFSXLmC5G5b37Vrl9599930vcgsZrFYzEdy7822bdv0888/6/79+ymOcf78eT333HO6ePGipLiVwwlXoCbUrFkz83jnzp1WYxs6dKi5orJv375WV2WeOnUqSV3hXr16qUCBApLikvA//fRTkn73799XQECAeXt+586d9cQTT1iNK6O99tprKlGihCRp+PDh+uabb6yuHr169apGjRqlAwcOJHrex8dHvXr1khS3Qrh169bmZ/IgwzC0ZMmSJM8nfO179uxJ82sIDQ01/0rdtGlTWSyWNPcFAAAA8OgaOXKkvv/++0SbGktx5QB27tyZpGyAi4uLvv/+e40cOdKeYQLZBptcPQKcnZ3Vt29fjRkzRrdv31a1atXUp08fVa1aVRaLRbt27VJQUJDu3LmjgIAATZ8+PatDtmr06NHm7fZdunRRjx49El0vX768vvrqKw0cOFA3btxQjx49tGrVqkTJnTfeeEM7d+7UrFmztGfPHvn6+srf318NGjRQoUKFFBUVpcuX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3njjDe3cuVOzZs3Snj175OvrK39/fzVo0ECFChVSVFSULl++rP3792vVqlW6cOGCmjRpYhbcj9e4cWP17t1bkydP1pUrV1S9enUFBgaqTp06MgxDmzZtUlBQkAzDUKtWrbRs2bJMe1/27t2bZMXu3r17zePJkydr9erVia6/8847yps3b5Kx/P39tWbNGkVERGjnzp2qV6+e1bnj67Bu2LDBTGimlDT18/PT4cOHzXYZVX813k8//aSnn35a169fV1BQkHbv3q2AgACVLFlSV69e1fz5881b8Z2cnDR9+vQk/3DPaF9//bVWrVqlq1evas6cOdq/f7969OiRJKa6desqODhY//zzjxwcrP+NbdOmTYqNjZUUt+MuAADA42bAgAHq2LGjpkyZookTJyo4ODhJG29vb/Xr10+9e/emLAAAIFkkWJFhRo8erb1792rdunUKCwtLVNcoXt++ffXee+9l6wTr9u3bzb9KFy9eXBMnTky23YABA7Rs2TL98ccfWrNmjcaMGWPWZ403ffp0Pfnkk/r8888VGRmpefPmad68eSnOnXBzrIQmTJigO3fuaP78+bp7966+//57ff/99+Z1FxcXTZ48WSdPnszUBOv+/fuTXWUbb+bMmUmee+WVV5JNsHbt2lVvvfWWoqOjNXv27FQTrFJc4jRhDdEH668mbPfDDz8kOs9I3t7e2rhxo9q1a6dTp07p0KFDev/995O0y5cvn2bNmpVhq2etKVy4sFauXKlWrVrp4sWLOnz4cJKYKlasqLlz55rvtYeHh9UxZ82aJUlyc3OTv79/psQNAACQ1QoVKqQPP/xQ7733njZt2qTg4GCFhobKw8ND3t7eatCggXLkyJHVYQIAsrEMTbAm99e+jOTt7Z2p4+PhuLq6auXKlfrpp580Y8YMHTx4UJGRkSpcuLBq166t3r17q3nz5lZvlc9qYWFheumllxQdHS0HBwfNmDFDnp6eKbafMmWKqlSposuXL+ujjz5S06ZNVbVqVfO6g4ODhg0bpldeeUU//fST1qxZoxMnTujmzZtycnJSgQIFVL58eT3zzDNq27atqlSpkuw8Tk5OmjdvnhYuXKgff/xRf/31l8LCwlS0aFE1btxYb775pipXrqxhw4Zl9FuSaQoUKKCOHTvql19+0S+//KJx48aZdURT4ufnp+HDhyc6T6mdxWIxNwXL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Vv3x8fEerx+Ac2+//bZ17UVERJidO3dmab0dO3aYiIgIa93Ro0fncqQAAACAZ+XW91CGCFDqC5CuXbumcuXKqU2bNrrjjjtUsmRJ2Ww2xcfHa+XKlVqwYIEuX76sRx55RFFRUWrcuHGOt1uiRAl99dVXkqRx48YpLi5OkjR58mSVKFHCKndjbxJXJk+erFWrVunw4cN644031K5dOzVq1MhaboxR3759dfr0aUnS3//+d9WoUcOhDmOMunfvrgULFkiSypUrp4cffli1atVSaGio9u7dqxkzZmj79u1asmSJHnjgAf34448KDAxMF8+QIUP05ZdfSpLy5cunxx57TI0bN5YxRj///LOmT5+uAQMGqG3btlnex7zKGKOuXbtqxYoVkqQiRYpo4MCBqlOnjq5cuaIlS5Zozpw56tmzp+rUqeOyritXrqhdu3batm2bJKls2bIaMGCAqlevroSEBH311VdasmSJunbtqsKFC2c5xuHDh2vu3LmqW7eu+vTpo3LlyunQoUP66KOPdODAAW3ZskV/+ctf9MYbb+jee+9VcnKyhgwZorvuuksBAQFavHixPv/8cxlj9OKLL6pt27aqWbNmuu38+uuvVk/TO++8M8N4GjdurNDQUF29elVxcXF6+umn05VJO55pli9fnq636bFjx7Rr1y5JctoT1V6fPn20evVq3XnnnXrooYcUFRWlU6dO6fjx41aZhQsX6qGHHlJKSookqW3bturSpYsiIyO1d+9eTZ06VXv27NHWrVt19913a+PGjSpevLjL7fbv318LFy5U/fr11atXL5UvX16nTp3S559/rpUrVyohIUEPP/yw/vjjD6fDiCxdulT9+vVziOnBBx9U0aJFrZjmzZtn9ZbNioYNG1rT33//vdPjDyBvSU5O1qRJk6z5/v37q2rVqllat1q1anrsscc0btw4SalPELz44otO7/8AAADArYQEq6QCBQrohx9+0D333JNhmc2bN6t9+/Y6fvy4XnzxRf3000853m7+/PnVpUsXSanjUaZp166dKlSo4FadRYoU0YwZM3TPPfcoKSlJvXv31u+//24NPv3BBx/o+++/lyR17NhRzzzzTLo6xo4dayVX+/fvr48++khhYWEOZV544QUNGjRIU6dO1YoVKzR58uR0Y7HFxcVpypQpkqRixYpp+fLlDsnc2NhYDRw4UG3bttW3337r1v7mJdOmTdMPP/wgSapcubKWL1+usmXLWsv79++vRx55RN27d9fy5ctd1vXOO+9YydXGjRtr8eLFKlSokLV88ODBmjBhgp566qlsxTh37lw99dRTGjdunMNbIfv166fatWvr6NGjmjVrlrZu3aoCBQpo2bJluv32261yvXv3VrVq1TRixAglJSXpww8/dPgin2bNmjXWtH0S70ZhYWFq3LixVqxYoZ9++knGGIcE4fbt261HVBs3bqzVq1c7PXb2P8sswbpkyRINHz5cb7/9ttNkZEJCggYMGKCUlBTZbDZNmDBBTzzxhEOZ5557Tr169dLXX3+tI0eO6Omnn9bs2bNdbnfWrFl65ZVX9Oabbzps94knnlC3bt00f/587du3T1999ZX16H6a69eva/DgwVZydfz48emSoc8995x69OihuXPnuozDXrFixXTbbbdp3759Dm2WVYcPH3a53NPDrnjDxYsXdfHiRV+HAbht5cqVDi/WHDJkSLbWHzJkiJVgPXTokL7++ms1adLEozEC3hQeHs5LWgAgiy5evKiJEyda80OGDOF3KJDGY31hbwGffPKJ1Y344MGDHq3b/jFtV4/IZ/VR+pdfftkq169fP2OMMb///rv1+HCJEiXM8ePH062XmJhoihcvbiSZJk2amJSUlAy3ce3aNVOpUiUjyVSuXDnd8vvuu8+KYc6cORnWM3HiRIfHmG/WIQJq1aplJBmbzWbWrFmTYbmXXnrJ4Xjc6MqVK6ZYsWJGksmXL5/Lc/Ghhx6y6snKEAG1atUy169fd1pu9OjRDnFl1KaJiYnWI6QVK1Z0WsZ+GILdu3dnGL8xjuf8pk2bHJZNmDDBSDKRkZFm5syZ1rATiYmJDuUGDRpkHfs///wz3TbsH9Vv3Lixy/P+gw8+sMo+9thjGZa7cOGCKVu2rJFkAgICnA4VYL/d1q1bZ1jX7t27XW7zyy+/dBgGICNnz551GNYhsyECjDHm3nvvdRg+ITvsz5fMPnlliAD785EPn7z+qVatmlvXQbVq1XweOx8+nvpk5V4IAEh14cIFM2rUKOtz4cIFX4cEZFtuDRHAS66ywb6Hhju9ubzpjTfeUIMGDSSl9pycMWOGHnnkEetlVp988olKliyZbr3FixdbLwB67rnnXD5OHBwcbL1ZfM+ePQ4vaEp75F2Sypcvr27dumVYT//+/VWkSJHs7WAes2/fPuuFXk2bNnX5WPz//d//uXzc8tdff9WpU6ckSd26dVP58uUzLDts2LBsxTl48GAFBTnv2N60aVNrumTJkuratavTcmFhYda5d+DAASUmJqYrY//CpKJFi7qMyb7H6Y29U9OG1WjevLlatWolKfXFX6tWrXJa7vbbb8/0Uf0hQ4a4PO/ThvWQpBdffDHDcuHh4Vav7pSUFKtXeEaGDh2a4bLKlSsrKipKkvTHH3+kW27/wrm//OUvGdZTuHBhPfrooy7juJH9tXnw4MFsrQvAv2VnCBl79k9MAAAAAGCIAAcHDx7UtGnTtHz5cu3YsUPnzp3L8I3kR44c8XJ02RMcHKyZM2eqbt26unTpkmJjY61lTz75ZIZvbf/555+t6dOnTzsMXeDMmTNnrOnt27dbQxts2rRJ169fl/S/N6VnJCQkRE2bNtWiRYsy2608a+3atdZ069atXZYtVaqUqlevrq1bt+a4rgYNGqhgwYI6f/58luJ09bi+fUK+fv36DkMIZFTWGKNz584pX758DsvTzhubzZbpF/wbx2G1TyCmjb/aqlUrlSpVSjExMdqxY4eWL19uJVyPHj2q3bt3S8p8eABJLh91NcZo3bp1klLHJs5sfOS2bdvqlVdekST99ttvLstmNq5z2bJlFR8fr7Nnz6Zbtn79ekmp19Jdd93lsp4WLVpo7NixLsvYs0+AO9u2K/aPITtz7Ngxl+ccgNx17tw5t9ZLSEjwbCAAAABAHkeC9b/Gjh2rl19+2erhmZmsJqx8qUqVKvrnP/+pgQMHWj+7/fbbNWbMmAzXse+hNnjw4Gxtzz75cvToUWu6cuXKma6blTJ5mTvHI6MEa3bqstlsuu222/T7779nKc7IyMgMl9m/WMlVuRvLOrum0n6WP39+l4laKeNxWP/44w/9+eefkv6XOG3ZsqWVYE2TnfFXJTmMi3ujhIQEXb58WVLq9ZUZ+xfH2L8ky5lixYq5XJ52TJ0dz7Rzoly5cgoODnZZz2233eZy+Y0KFixoTTvrjexKuXLlslU+L3j++efTjbkL5CUrV660nirZuXOnduzYka2XaW7fvl07d+605ufNm8cYrMjTGDsQAAB4AglWSZ9//rmeffZZSVJAQIDuueceNWnSROXLl1d4eLhCQkIkSX/++aeVdExOTvZZvNlxYxLo3nvvTdeb0F5OeqVcu3bNmr506ZI1nT9//kzXLVCggNvbzQs8eTxy89hmluzMbrmMpCULL1++rOTk5EzfQN2yZUutWLFCZ86c0aZNm1SnTh0rcVqsWDHVrFnTKjdp0iT99ttvunLlisLCwqxyNptNLVq0yDQ2V9eH/cuNsnJc7ctcuHDBZdmcHNO0cyI3rjX73wmujs2tgpehIK/r3Lmzypcvbw3VMmnSpGz1ard/cWH58uXVuXPnTH+HAwAAADc7xmCVNGLECElSRESEVq9eraVLl2rUqFHq37+/evbsqS5duqhLly4OY1DmBQkJCQ5DA0ipPXVdPapsnzg4evSojDFZ/vTr189a1z6Jk9bjzxX7pOHNyJPH42Y4tmmPnRtjsvTYubNxWNPGVW3RooU1BEVauatXr2rlypUO5bIy/mpm7K+PrBxX+zIRERE52rYraedEbpwP9sOAZDZeLgD/FxgY6PCEyieffOLQI9WVnTt3aurUqdb8E088QXIVAAAAEAlW7du3T/v375ckDRo0yOXLh+xf4pQXDBkyxHrkv0uXLrLZbEpKSlKfPn0ceuLZs388+vDhw25vu0yZMtb0nj17Mi2flTJ5mSePR3bqMsZo3759WYjQu9LG6pUcE3gZSRuHVfpfwtR+/NU0JUuWVPXq1SWlJmKPHDliHaOsDA+QmUKFClm9RNPGdXXFvkzp0qVzvP2MpJ0Thw8ftsY+zkh2zwf7BHh0dHT2gwPgdwYMGGD9Tr1w4YLat2+faZJ1586dat++vdUbPzQ0VAMGDMj1WAEAAIC84JZPsJ44ccKazmw8y8WLF+d2OB4zY8YMffHFF5Kku+66S3PnzrXeKL9nz54M3zTevHlza3rp0qVub7927drWWJDLly+XMSbDsteuXdOvv/7q9rbyAvvEfVqCMCPHjx/X9u3bPVLX+vXr/XK84LRH+iVlqedU2jisUuqL2LZs2aKTJ09KckywSv9LpC5fvjzb469mxmazqUGDBpJSk5k7duxwWf7777+3pnPzZU7169eXlHotrVq1ymXZtMR0VqXtY+nSpTMdexdA3lCyZEm9//771vzBgwd15513aujQoel+r+3YsUNDhw7VnXfe6TBO+/vvv68SJUp4LWYAAADAn93yCVb7MQtd9QY8dOiQpk2b5oWIcu7AgQN6+umnJaU+lvzZZ58pMDBQb7/9turUqSNJmjp1qubNm5du3XvvvddKoowfP95KYmVXWFiYOnToICn12H311VcZlp02bVq2306e19x2222qVauWJOmXX36x3vruzLhx41yO8dusWTPrhUjz5s1z2dPY/gu0P2nUqJE17WrICntpCdKzZ89a4wWWKFFCt99+u9Nya9as0XfffScp6+OvZkXXrl2t6ffeey/DcpcuXdKECRMkpY6v+sADD3hk+8507tzZmh43blyG5c6dO6cZM2Zkud6TJ09aPfxzM0EMwPuefPJJvfrqq9b8hQsXNG7cOFWvXl0xMTFq1KiRYmJiVL16dY0bN85hHOlXX31VTz75pC/CBgAAAPzSLZ9grV69ujV+4b///W/t3bs3XZmjR4/qgQceyPCxen+SnJysPn36WL0Wx48fb701PCQkRDNnzrReVDNo0CAdOXLEYf3w8HC99tprklJ793bo0MHl0AjGGP344496++230y1Le3GYlDpcgbNemWvXrtULL7yQvZ3Mo9KOhzFGjzzyiI4dO5auzKJFizRmzBiX9YSEhFhfbC9fvqyHHnrIaS/VyZMnW72Y/U2TJk2s627NmjVZWse+B+qnn36a7mc3lrt69apmz54tyTPjr6Z57LHHrLqmTp2qjz/+OF2Zq1evKjY21kp+9+jRQxUrVvTI9p3p3LmzNezCvHnz9OGHH6Yrc+XKFT366KM6ffp0luu1b5t27drlOE4A/uXNN9/URx99ZA0XkGbnzp1as2ZNuicMQkND9dFHH+nNN9/0ZpgAAACA3wvydQC+FhISosGDB+v9999XQkKC6tSpo0GDBql27dqy2Wxau3atpk+frvPnzys2NtZK7Pirt99+23rcvmfPnurbt6/D8urVq2vMmDF66qmndObMGfXt21fff/+99ZIgSfrLX/6iNWvW6PPPP9eGDRtUrVo1denSRXfffbdKliyp69ev68SJE9q0aZO+//57HT16VPfcc49eeeUVh221atVKAwYM0JQpU/Tnn3+qfv366t+/vxo3bixjjH7++WdNnz5dxhjde++9+vbbb3PtuGzcuDFdj92NGzda01OmTNEPP/zgsPz5559X4cKFPRZDv379NHPmTP3www/atWuXatasqYEDB6pOnTq6cuWKli5dqtmzZ6tQoUKqU6eOw+PtNxo+fLjmzZunbdu2aeXKlapRo4YGDhyomJgYJSQk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+WP7+HNd/uj69eumTZs21j4UKFDAPP3002bGjBnm888/N88//7wpUqSItfztt992WR/3f8/ydPsYw/3fk3KjfW50q97/XSHBCgDIc5599lkzatQos2jRInPixAljjDF9+/Z164uTJ+t6+umnrfU6dOiQ7n/FT58+7fAF9z//+Y9X6vIFfzyuy5cvd/iyfeDAAafl/vWvf1nlIiMjzfXr152Ws/+y1r9//3T/y37gwAFTvnx5I8nYbDazfv36LO9zbvPH9jHGmEuXLllJogIFCrgsm5SUZI4ePeqVuLzNX9vnRomJidaX2KeeesqhN0pm8vL1Y4x/tlGNGjXMM888Y3bt2uV0eXJysnnhhResegoVKmROnz6dYVx5uY38sX38uS5/9OGHH1qxlytXzuzevTtdmaNHj5qYmBgjpfbE2759u9O6uP97nifbxxju/57m6fa50a18/3eFBCsA4Kbg7hcnT9V1/PhxExwcbP1hmPaF7kZbtmwxNpvNSDK1a9fO9br8ia+P61//+ldr+x999JHL7davX98qu3nz5nTL169fby0vX758ho+YffPNN1a5zp07u9ymr/m6fYwxDsmfBQsWuLEXuROXP/CH9rnRyy+/bCSZMmXKmISEhCx/wboZrx9jfN9GZ86cydI2GzZsaMU5ZcoUp2Vuxjbydfv4a13+qlq1alZ7LVy4MMNyv/32m1WuV69eTstw//c8T7aPMdz/Pc3T7XMj7v/O8ZIrAAA8YP78+bp+/bok6eGHH1aJEiWclqtZs6Zat24tSdq0aZPTQfo9WVde58ljcfLkSWu6SpUqLrdbtWpVa/rSpUvpls+ZM8eaHjRokMLCwpzW07FjR1WuXFmStHjxYl24cMHldvMaT7bPxYsXNWnSJEnSPffco/vvv98v4srLcvM4bNq0SWPGjJEk/fOf/1TBggWzHBfXz/94so2KFCmSpW127drVmt6yZYvTMrRRKn+9t9/sv+OOHj2qnTt3SpKKFi2qTp06ZVi2YcOGiomJkSQtWLBAly9fTleG+79nebp9uP97lqfb50bc/zNGghUAAA9YunSpNd2hQweXZe2XL168OFfryus8eSzs/8jO7A/ptOWBgYEOX7ayG5fNZlP79u0lSVevXnXrzdX+zJPtM2/ePOsP6N69e/tNXHlZbh2H5ORkDRw4UElJSerUqZO6d++eK3Hd7NeP5JtzNSIiwpq+cuVKjuK62dvIX+/tN/vvuMOHD1vTVapUyfTN5Gn36cuXL2vFihXplnP/9yxPtw/3f8/ydPvY4/7vGglWAAA8YOvWrdZ0/fr1XZZt0KCBNb1t27ZcrSuv8+SxeOCBB6zpd999VwcPHnRaz8cff6x169ZJkh599FEVLVrUYXlKSoq2b98uSQoKClLt2rVzFFde5sn2+fnnn63phg0b6sqVK3r//ffVoEEDFSpUSOHh4YqJidETTzyR6XHkGkqVW8fhgw8+0Lp165Q/f3599NFH2YqJ68eRL85V+22WL18+3XLa6H/89d7O77iM2R+bNNz//Yez9uH+7z+ctY897v+uBfk6AAAA8rqUlBTt3btXUmqPh3LlyrksHx0dbU3f2JPCk3XldZ4+Fg0bNtTTTz+tDz/8UPHx8YqJiVFsbKzq1KmjIkWKKD4+XgsWLNAvv/wiSXrwwQc1fvz4dPXEx8crMTFRklS2bFkFBbn+c+pmbSNPt0/al1pJSkpKUv369fXHH384lNm5c6d27typjz/+WKNGjdKIESNyPa68KreOw759+zRy5EhJ0qhRoxzWywqun//xxbl6/vx5zZ4925p31oOINkrlr/f2W+F3XKlSpazp3bt3yxjjshferl27rOm0R6Ptcf/3LE+3D/d/z/J0+6Th/p85EqwAAOTQhQsXlJycLEkqXLhwpn8wREZGWtPnzp3Ltbryutw4FuPHj1fFihU1evRonT59Wv/617/SlalXr57eeOMN3XvvvU7/ILWvu1ixYpnux83aRp5un+PHj1vTPXv21K5du1SuXDkNHDhQMTExSkhI0IIFC/TNN98oJSVFr732msLCwvTCCy/kalx5VW4dh8GDB+vy5cuqXbu2nn322WzHxfXzP744V//617/qzJkzkqT27durbt266crQRqn89d5+K/yOK1++vMqVK6fDhw/rzJkz+vbbbzMcR3LdunXasWOHNc/9P/d5un24/3tWblw/Evf/rGCIAAAAcsj+JQgZDdZuL1++fNb0xYsXc62uvC63jsXgwYM1evToDAfl37Bhg959912tWrXKq3HlNZ4+DvZ/PO/atUtNmjTRH3/8oZEjR+qhhx7SoEGDtGjRIv373/+2yr3yyivpHvWkfVLlxnGYNm2afvjhBwUEBGjy5MmZfnn1Vlx5lbePxezZs61HOsPDw5320PNFXP7KX+/tt0r7PP7449b0kCFDtG/fvnRlTpw4ob59+zr8zNXLcLj/e44n24f7v+d5+vrh/p819GAFAHjc2LFjPfI/jRUqVFC/fv1yXA/Su1XbaO3aterSpYuOHj2qOnXq6LXXXtPdd9+tQoUK6dixY1q0aJFGjRqlX375Rffcc49mzZqlzp07ez3OW7F9UlJSrOng4GB98cUXDi/jSTNgwAAtWbJEc+bM0fXr1zVp0iS988473gz1lmyfP//8U8OGDZMkPfHEE2rUqJGPI3LtVmwjV9asWaP+/ftb85MnT870beq5ifa5OeRmOz733HP68ssvtW3bNsXHx6tOnTp67LHH1LBhQwUEBOj333/Xv//9b505c0a33XablUAKCHDehyyv3P89Ka+0T166/3tSXmmfvHb/9ykDAICHRUdHG0k5/rRo0SLL2+zbt6+1XlxcXI7iz25d586ds8pHRkZmWj4hIcEqX69evVyry5W80EaePhabNm0y+fLlM5JMkyZNTGJiotN69u3bZyIjI40kExERYY4dO+aw/Pfff7e2U79+/Uzj2rRpk1W+a9eumZY35tZsnyJFiljLO3Xq5LKupUuXWmUbNmyYq3E5cyu2z0MPPWQkmdKlS5tz5845rcP+uGTEG9fPjbHcKm2Uka1bt1q/0ySZ9957z2V5fsel8td7u7fOm6zI7XaMj483DRo0cLluhw4dzKxZs6z5Xr16pasnL93/PSmvtE9euv97Ul5pn7x2//clhggAACCHIiIiFBgYKCn1MaekpCSX5U+fPm1NFy5cONfqyus8fSxefvlla3D9999/P8PHkypWrKjnn39eUuqjUtOmTXNYbl/3qVOnMtuNm7aNPN0+9j+rV6+ey7rsl6e90CK34sqrPHkcFi1aZL0YaezYsSpUqJDbcXH9/I83ztXdu3erTZs21rqvv/669fstI7RRKn+9t99Kv+PKlSun1atX67PPPtN9992nUqVKKSQkRJGRkWrdurU+++wzffvtt7p8+bK1jv0LftJw/88dnmof7v+5wxPtw/0/exgiAADgcQcOHPB1CF4VEBCgSpUqadeuXUpOTtbhw4dVoUKFDMvbjxl14yOanqzLlbzQRp48FlevXtUPP/wgKfUP8IYNG7rcdps2bTR8+HBJqY/W2ouKilK+fPmUmJioI0eOKCkpyeVY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jo52WW7RokWmePHiLo95SEiIeeeddzLd5sWLF0337t0zbcPatWubvXv3emQ/N27caNX74IMPZlr+xrbPyIkTJxzaKaNP69atzcmTJzPd7osvvmhsNluG9TRs2NAcOXIkW+fGokWLrLL/93//l2kMAICbQ1COM7QAAAAAbjonT55Us2bNtGvXLklSeHi4OnTooNtvv11hYWE6dOiQvvnmG8XHx2vXrl1q2rSp1q9frwoVKuR42wsXLtT7778vSWrRooWaNWumkJAQbd68WYsWLdLVq1e1c+dOtWrVSuvWrVOJEiWc1vPWW2/pzTfftOarVq2q++67T0WLFtWBAwc0f/58rVu3Tj169FBAgH883Dd//nx1795dycnJkqQSJUqoc+fOio6O1pkzZ/Tdd99p+/btunbtmoYPH66EhAS98847Tuu6du2a2rZtq1WrVlk/a9mypZo2baqQkBBt3bpVCxcu1JUrV7Rp0yY1adJEv/32m6Kjo3O0D999953D9jzh7Nmzatq0qfbs2SNJCgoKUvv27VW/fn1J0vr167VkyRIlJSVp2bJlatasmX777TcVKlTIaX0jRozQ3//+d2u+evXq6tixo4oWLapDhw7p66+/1po1a9SjRw/ZbLYsx3n33XcrMDBQycnJ+vbbb/XBBx/kYK8BAHmGrzO8AAAAAPxP+/btrZ54sbGx5ty5c+nKXLt2zQwbNswqd/fddzutK7s9WG02m8mXL5/55ptv0pXbvn27qVixolW2Z8+eTuvbuHGjQw/Y1157zSQnJzuUOXv2rLn33nutbSqLvRTdlVZ/Rj1Yjx07ZooUKeKwb+fPn3cok5KSYt555x2HY/X99987re/ll1+2ykVERDgtt2fPHlO9evVM2zA7OnToYNW3cuXKTMtnpQdrr169rDJlypQxGzZsSFdm/fr1plSpUla5Pn36OK1rzZo1Dr2aR48ebVJSUhzKXLhwwer5m91zw/54Hj9+PNPyAIC8zz/+mxYAAACA31iyZImWLFkiSerevbumT5/utCdgcHCwxowZo65du0pKHefz559/zvH2jTGaOHGi7r333nTLYmJitGjRIgUHB0uSvvzyS+3cuTNdudGjRyspKUmS1KdPH73++uvpeqkWLlxYc+fOVeXKlWWMyXHcOfXPf/5TZ8+elSTdeeed+vzzzxUREeFQxmaz6eWXX9YzzzwjKfVYjRw5Ml1dZ8+edXjR0meffaY2bdqkK1epUiUtXrxYBQoUkJTaht9//32O9mP9+vXWdM2aNXNUl5Q6nuns2bMlpY5zunDhQtWtWzdduXr16mnBggVWO3/++edWD2x77777rjXm7MCBAzV8+PB0vVTDw8M1c+ZM1axZM9vnRq1atazptWvXZmtdAEDeRIIVAAAAgIMJEyZISk3m/e1vf8u0/LBhw6zpBQsW5Hj7VatWVd++fTNcfvvtt6t3797W/Keffuqw/OLFi5o/f76k1H2wHybgRvny5dNrr72Ws4A9ZPr06db06NGjFRSU8Yhur7/+usLCwiRJK1eutB6dTzNnzhxdvnxZktS0aVM98MADGdZVvnx5Pf30007jyK6EhASdPHlSklS0aNF0CWJ3fPrpp1aSs1evXqpXr16GZe+880716NFDUmry+cZz48KFC9Y5GhAQoFGjRmVYV3BwsEaMGJHteO2HWNi9e3e21wcA5D0kWAEAAABYUlJStGLFCklS5cqVddttt2W6Tp06dazpdevW5TiGLl26ZFomrdeslJpgtLd27Vpdv35dklS3bt1Mx4Xt0qWLz8dg3b9/v44dOyZJKlKkiFq3bu2yfJEiRdS2bVtr/pdffnFY/uuvv1rT3bt3z3T7PXv2zLCu7Dh8+LA1Xbp0abfrsefJfVm7dq3Vs7l+/foqW7asy7ruu+8+BQYGZidclSpVypqOj4/P1roAgLyJBCsAAAAAy4EDB5SQkCAptfedzWbL9JP2eLkkq/diTtgnbDNyxx13WNM3DhFg/1h4VuqKiIjIUiI5N9n3dKxdu3aWEr72PTlv7ClpP+/scfob1apVy+oxe/DgQStBnV3nz5+3pvPnz+9WHTfK7r5k9bjYP8qfkfz582f73LC/Hi5cuJCtdQEAeRMJVgAAAACW06dP52j9S5cu5TiGyMjITMsUK1bMmk4bt9TZfFbqurE+X7CPOaux2Jc7c+ZMjuoLDg52GGf3xvqyKq13qCSXQxxkR3b3JavHJavnRlbLpbHfb3cT1QCAvMUzdzwAAAAANwX7BFn58uWtlylllbOXYeHWYd9r9cqVKz6MxHcSExOtafverACAmxcJVgAAAAAW+956BQoU0PPPP+/1GLLSi/bUqVPWdJEiRRyW2c9ntUeufX2+kNOYixYtmqP6rl+/bg0N4ay+rCpevLg17W4v2BsVKVLEGp/29OnTmSYtXR2XwoULW9NZPc7Z7dVt30vW/ngAAG5eDBEAAAAAwBIdHa18+fJJkvbs2WO9id6bNm3alGmZzZs3W9PVqlVzWFa1atVs1XXx4kXt27cvGxF6XpUqVazpTZs2yRiT6TobN260pu33+cb67MtlZOvWrVbv5QoVKig4ODjTdZwpW7aste7Ro0eztB+Zye6+ZPW4bNmyJdO6Ll++nO1z48iRI9Z0Zi9YAwDcHEiwAgAAALCEhobq7rvvlpTaq3HevHlej2H+/PmZlvnqq6+s6SZNmjgsu/POO60k34YNG3Tw4MFMt5eSkpL9QD2oYsWKKlOmjKTUnp/Lli1zWT4hIUHff/+9Nd+0aVOH5fbzc+fOzXT7c+bMybCu7AgMDFSNGjUkpZ4/nkhce3Jf7rzzTmuM1PXr1zskQ51ZtGiRkpOTsxOuduzYYU3Xrl07W+sCAPImEqwAAAAAHDz11FPW9CuvvKKTJ09meV1P9FjcuXOnZsyYkeHyHTt26PPPP7fmH330UYfl4eHh6tKlixXPa6+9lmFdV65c0ZtvvpmzgD0kNjbWmn711VddJvZGjRpljfXZtGlTVa5c2WF5jx49rPFQf/nlF33zzTcZ1nX48GF9+OGH1ny/fv3cCd/SqFEjazorPYgzExsbK5vNJkmaNWuWyzo3bNigL7/8UpJks9nUt29fh+UFCxbU/fffL0lKSUnR66+/nmFd169f11tvvZWtWI0xVu/q/Pnzq2bNmtlaHwCQN5FgBQAAAODggQceUNu2bSVJ8fHxatasmVatWpVh+cTERP3nP/9RixYttGHDhhxv32az6YknntDixYvTLdu1a5fuv/9+Xbt2TVJqIjEmJiZduZdfflmBgYGSpE8//VRvvPFGul6qCQkJ6tGjh3bt2mUl8Hxp6NCh1pihq1ev1qOPPqqLFy86lDHG6L333tPYsWMlpR6rUaNGpaurSJEiGjp0qDXfu3dvp71i9+3bpw4dOujChQuSpLvvvltt2rTJ0X60a9fOmv7ll19yVJckxcTEqFevXpJSX8J2//33O02ybty4Uffff7+VmO7du7fDkABpXnrpJQUEpH4V/vjjj/Xuu++m+4+Bixcvqnfv3tqyZUu2zo1t27ZZY7C2atXK7aEWAAB5Cy+5AgAAAJDOrFmz1Lx5c23btk27du1SkyZNVK9ePTVt2lSlSpVScnKyTp06pS1btmjNmjW6dOmSJM/0YP2///s/ffDBB+rYsaNatWqlZs2aKTg4WJs3b9bChQt19epVSanjfY4fP95pHfXq1dOIESOs5OPIkSP1xRdfqFOnTipatKgOHjyor776SidPnlTjxo0VGBioX3/9Ncex50SpUqU0ZcoUde/eXcnJyfriiy+0bNkyde7cWdHR0Tpz5oy+++47/fHHH9Y6L730UoYJ0VGjRmn58uVatWqVEhIS1KZNG7Vs2VJNmzZVSEiItm7dqoULF1o9YUuWLOmy53BWtWvXTvny5VNiYqJ++OGHHNcnSR999JHWrl2rPXv2KD4+Xg0aNFCHDh1Uv359SamP+y9evNgaR7ZatWoOvXLtNWrUSC+++KLeffddSdLw4cM1Y8YMdezYUUWLFtWhQ4c0f/58nThxQk2aNJHNZrPOjcySrfZJ7AceeCDH+w0AyCMMAAAAADhx4cIFExsbawICAoykTD9ly5Y1e/bsSVfP1KlTrTIjR450uq2+fftaZeLi4szYsWNNUFBQhtuqUqWK2bVrV6b78Ne//tVl/PXq1TOHDx82LVq0sH62f//+HB4559Lqj46Odllu4cKFplixYi6PdUhIiBk9enSm27x48aLp1q1bpm1Xu3Zts3fvXg/tqTG9evWy6t69e7fLsje2fUZOnDhhmjdvnum+tGrVypw8eTLTGIcNG2ZsNluG9TRo0MAcOXLENGvWzPrZiRMnXNaZdh6Fhoaas2fPZhoDAODmwBABAAAAAJwKDw/X9OnT9ccff2j48OFq0qSJSpYsqeDgYIWFhals2bJq1aqVXnrpJS1btkyHDh1SpUqVPLLtoUOH6rffftOAAQNUqVIl5cuXT4ULF1ajRo30j3/8Q5s3b3b6+PeN3n77ba1evVqxsbGKiopSSEiISpQooWbNmunDDz/UypUrVbZsWY/E7Cn33Xef9u7dq/fee08tW7a0jnnRokVVt25dvfTSS9qxY4eGDx+eaV0FChTQ3LlztWLFCg0YMEBVqlRReHi4QkNDFRUVpa5du+rzzz/Xhg0bdNttt3lsHwYPHmxNz5w50yN1lihRQitWrNCCBQv0yCOPqGLFisqfP7/y58+vihUrqnfv3lq4cKGWLVumYsWKZVrfmDFj9Msvv6h3797pzo0JEybol19+UZkyZZSQkGCtU6hQoQzrO3z4sH7++WdJqUNXFC5cOMf7DADIG2zGeOAZHgAAAADIgX79+mn69OmSpLi4OLVs2dK3ASHH6tWrp40bNyoqKkoHDhywxj3NS5KSklSwYEElJiaqVKlSOnbsWIZlX3/9dWtIig0bNqhu3bpeihIA4Gt57w4HAAAAAPB7r732mqTUF6XNmzfPx9G4Z9myZdYYtWnjvTpz5coVTZw4UVJqD2SSqwBwayHBCgAAAADwuC5duqhhw4aSZL1QKi9JTk7WyJEjrfkuXbpkWHbq1Kk6ceKEAgIC9NZbb3khOgCAPyHBCgAAAADIFePGjZPNZtOGDRs0d+5cX4djWbx4scaOHavz5887XX7q1Cn16NFDq1evliSVLFlSvXr1clr28uXLevPNNyVJjz/+uGrXrp07QQMA/FaQrwMAAAAAANycGjVqpClTpujgwYO6fPmyr8OxnDp1Ss8++6z++te/qnnz5rrjjjtUtGhRXbp0Sdu2bdPSpUt16dIlSVJAQID+9a9/KTw83Gld+/bt06BBgyRJzzzzjNf2AQDgP0iwAgAAAIAT8fHxmj17do7qeOihhxQVFeWhiPKmxx57zNchZCgxMVFLlizRkiVLnC4vVKiQPvnkEz3wwAMZ1lGzZk3VrFkzt0IEAOQBJFgBAAAAwIm9e/fqhRdeyFEdDRo0uOUTrP6oW7duCgsL09KlS7V582adOHFCJ0+eVFJSkiIjI3X77berXbt2evzxx1W4cGFfhwsA8HM2Y4zxdRAAAAAA4G+WL1+uVq1a5aiOuLg4tWzZ0jMBAQAAv0SCFQAAAAAAAADcFODrAAAAAAAAAAAgryLBCgAAAAAAAABuIsEKAAAAAAAAAG4iwQoAAAAAAAAAbiLBCgAAAAAAAABuIsEKAAAAAAAAAG4iwQoAAAAAAAAAbiLBCgAAAAAAAABuIsEKAAAAAAAAAG4iwQoAAAAAAAAAbiLBCgAAAAAAAABuIsEKAAAAAAAAAG4iwQoAAAAAAAAAbiLBCgAAAAAAAABuIsEKAAAAAAAAAG4iwQoAAAAAAAAAbiLBCgAAAAAAAABuIsEKAAAAAAAAAG4iwQoAAAAAAAAAbvp/dHVnZCXoXiEAAAAASUVORK5CYII=\", \"__metadata__\": {\"image/png\": {\"width\": 684, \"height\": 335}}}" + } + } + ], + "console": [] + }, + { + "id": "cNyH", + "code_hash": "ab0265e37728950a86f064ba471f9f31", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "ISrK", + "code_hash": "ff9b1e2c64a6155b1168dd9f33cfba84", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
dict_keys(['response', 'list_params', 'choices', 'description', 'likelihoods'])
" + } + } + ], + "console": [] + }, + { + "id": "xqqY", + "code_hash": "318e2b05490a9ca912db794e97b922f7", + "outputs": [ + { + "type": "data", + "data": { + "application/json": "{\"analytical\": {\"loglik\": \"text/html:
functionlogp_ddm
Compute analytical likelihood for the DDM model with `sv`.
def logp_ddm(data: numpy.ndarray, v: float, a: float, z: float, t: float, err: float = 1e-15, k_terms: int = 20, epsilon: float = 1e-15) -> numpy.ndarray:
\", \"backend\": null, \"bounds\": {\"v\": [\"text/plain+float:-inf\", \"text/plain+float:inf\"], \"a\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"]}, \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"extra_fields\": null}, \"approx_differentiable\": {\"loglik\": \"ddm.onnx\", \"backend\": \"jax\", \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"bounds\": {\"v\": [\"text/plain+float:-3.0\", \"text/plain+float:3.0\"], \"a\": [\"text/plain+float:0.3\", \"text/plain+float:2.5\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:2.0\"]}, \"extra_fields\": null}, \"blackbox\": {\"loglik\": \"text/html:
functionouter
def outer(data: numpy.ndarray, *args, **kwargs):
\", \"backend\": null, \"bounds\": {\"v\": [\"text/plain+float:-inf\", \"text/plain+float:inf\"], \"a\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"]}, \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"extra_fields\": null}}" + } + } + ], + "console": [] + }, + { + "id": "Cvjs", + "code_hash": "e4cb95b58d3a2ba1322185fbdb3eef97", + "outputs": [ + { + "type": "data", + "data": { + "application/json": "{\"loglik\": \"text/html:
functionlogp_ddm
Compute analytical likelihood for the DDM model with `sv`.
def logp_ddm(data: numpy.ndarray, v: float, a: float, z: float, t: float, err: float = 1e-15, k_terms: int = 20, epsilon: float = 1e-15) -> numpy.ndarray:
\", \"backend\": null, \"bounds\": {\"v\": [\"text/plain+float:-inf\", \"text/plain+float:inf\"], \"a\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:inf\"]}, \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"extra_fields\": null}" + } + } + ], + "console": [] + }, + { + "id": "gYFm", + "code_hash": "6741a30ab07cdde0b83f25183911d143", + "outputs": [ + { + "type": "data", + "data": { + "application/json": "{\"loglik\": \"ddm.onnx\", \"backend\": \"jax\", \"default_priors\": {\"t\": {\"name\": \"HalfNormal\", \"sigma\": \"text/plain+float:2.0\"}}, \"bounds\": {\"v\": [\"text/plain+float:-3.0\", \"text/plain+float:3.0\"], \"a\": [\"text/plain+float:0.3\", \"text/plain+float:2.5\"], \"z\": [\"text/plain+float:0.0\", \"text/plain+float:1.0\"], \"t\": [\"text/plain+float:0.0\", \"text/plain+float:2.0\"]}, \"extra_fields\": null}" + } + } + ], + "console": [] + }, + { + "id": "ZVxg", + "code_hash": "97ad532806fa080719e1f6418c0342b3", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "RzLA", + "code_hash": "48a755a65c405641490d7d8870624547", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "
'approx_differentiable'
" + } + } + ], + "console": [] + }, + { + "id": "CtVA", + "code_hash": "95060699c18374f33bcd1fa541579ae2", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "\n
\n
\n
arviz.InferenceData
\n
\n \n
\n " + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using adapt_diag...\nSequential sampling (2 chains in 1 job)\nNUTS: [a, t, z, v]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.847 7 40.34 draws/s 0:00:49 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.498 7 19.21 draws/s 0:01:44 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 2 chains for 1_000 tune and 1_000 draw iterations (2_000 + 2_000 draws total) took 104 seconds.\nWe recommend running at least 4 chains for robust computation of convergence diagnostics\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "TSoP", + "code_hash": "fa8fc962dec8120abf91979b8d8944f3", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "QuIQ", + "code_hash": "b1430b8a86046b5a3dc419fd95f41e50", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "BxLv", + "code_hash": "23e22dcb7a5385e2f70b0066b489a949", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "SStq", + "code_hash": "712415a747c3eba268c85268ef79619c", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Model initialized successfully.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "LNTb", + "code_hash": "860d5e2005534a06b440656c6fe5f691", + "outputs": [ + { + "type": "data", + "data": { + "application/vnd.marimo+mimebundle": {} + } + } + ], + "console": [] + }, + { + "id": "dGVZ", + "code_hash": "81cc53b9319916aea15084142ac167e4", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stdout", + "text": "Using default initvals. \n\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Multiprocess sampling (4 chains in 4 jobs)\nCompoundStep\n>Slice: [a]\n>Slice: [t]\n>Slice: [z]\n>Slice: [v]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Tuning Steps out Steps in Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 False 0 0 16.90 draws/s 0:01:58 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 False 0 2 16.74 draws/s 0:01:59 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 False 0 0 16.65 draws/s 0:02:00 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 False 0 1 16.98 draws/s 0:01:57 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 120 seconds.\n\r 0%| | 0/4000 [00:00" + } + } + ], + "console": [] + }, + { + "id": "hBDP", + "code_hash": "4bd4c0468e674450d1d780ffb724ced7", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "mVhx", + "code_hash": "c2ec6f089df4bb41f4448281a53cf42b", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "UJiw", + "code_hash": "4b70089f08f1c57165eda8e03fdffc01", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "zmDD", + "code_hash": "815a39cd1465813031c6232f5503c1dd", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "oDJM", + "code_hash": "8e7808a160e39289dcd2a8ae98802c7d", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "oPFs", + "code_hash": "6dad5f821a610dafe93694ee8bbc83a9", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [ + { + "type": "stream", + "name": "stderr", + "text": "Initializing NUTS using jitter+adapt_diag...\nMultiprocess sampling (4 chains in 4 jobs)\nNUTS: [v, a, z, t]\n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stdout", + "text": " \n Progress Draws Divergences Step size Grad evals Sampling Speed Elapsed Remaining \n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.732 7 24.56 draws/s 0:01:21 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.668 7 23.81 draws/s 0:01:23 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.585 7 24.12 draws/s 0:01:22 0:00:00 \n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 2000 0 0.505 7 24.74 draws/s 0:01:20 0:00:00 \n \n", + "mimetype": "text/plain" + }, + { + "type": "stream", + "name": "stderr", + "text": "Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 84 seconds.\n", + "mimetype": "text/plain" + } + ] + }, + { + "id": "HGJL", + "code_hash": "34accc155f0c7e6feea9e08ec79fbc0d", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "IRGU", + "code_hash": "b553ce13f8fc9590c0a21feedcae1eb3", + "outputs": [ + { + "type": "data", + "data": { + "text/html": "" + } + } + ], + "console": [] + }, + { + "id": "MepM", + "code_hash": "3eea098532aedceb7b1e79f0a52d734c", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "BVRn", + "code_hash": "f75583fcae399d3325ea65f6576a2005", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "QzPM", + "code_hash": "c132a41b44bc4882cd9570335bf4d5d3", + "outputs": [ + { + "type": "error", + "ename": "exception", + "evalue": "vmap got inconsistent sizes for array axes to be mapped:\n * one axis had size 1000: axis 0 of argument inputs of type float32[1000,2];\n * one axis had size 1: axis 0 of args[1] of type float32[1]", + "traceback": [] + } + ], + "console": [ + { + "type": "stream", + "name": "stderr", + "text": "
Traceback (most recent call last):\n  File "/tmp/marimo_7529/__marimo__cell_QzPM_.py", line 2, in <module>\n    idata_object = pm.sample(nuts_sampler="numpyro")\n                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/mcmc.py", line 802, in sample\n    return _sample_external_nuts(\n           ^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/mcmc.py", line 391, in _sample_external_nuts\n    idata = pymc_jax.sample_jax_nuts(\n            ^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/jax.py", line 642, in sample_jax_nuts\n    initial_points = _get_batched_jittered_initial_points(\n                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/jax.py", line 236, in _get_batched_jittered_initial_points\n    initial_points = _init_jitter(\n                     ^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/mcmc.py", line 1475, in _init_jitter\n    point_logp = model_logp_fn(point)\n                 ^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/jax.py", line 234, in eval_logp_initial_point\n    return logp_fn([jax.numpy.asarray(v) for v in point.values()])\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/jax.py", line 143, in logp_fn_wrap\n    return logp_fn(*x)[0]\n           ^^^^^^^^^^^\n  File "/tmp/tmp6e9daamz", line 87, in jax_funcified_fgraph\n    tensor_variable_42 = logp(ANGLE, tensor_variable_41, tensor_variable_35, tensor_variable_29, tensor_variable_23, tensor_variable_20)\n                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nValueError: vmap got inconsistent sizes for array axes to be mapped:\n  * one axis had size 1000: axis 0 of argument inputs of type float32[1000,2];\n  * one axis had size 1: axis 0 of args[1] of type float32[1]\n--------------------\nFor simplicity, JAX has removed its internal frames from the traceback of the following exception. Set JAX_TRACEBACK_FILTERING=off to include these.\n
\n
", + "mimetype": "application/vnd.marimo+traceback" + } + ] + }, + { + "id": "rfYh", + "code_hash": "0e731d2b61076ff7c0f6e562d7460532", + "outputs": [ + { + "type": "error", + "ename": "exception", + "evalue": "An ancestor raised an exception (ValueError): ", + "traceback": [] + } + ], + "console": [] + }, + { + "id": "YPtP", + "code_hash": "980e8f65848724704dd7efe185560f10", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "aBxI", + "code_hash": "0ad37bc67c000eb1752c28e1d314554f", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "IEQW", + "code_hash": "900efb663af6cdd5fa92c58b4dd29ae2", + "outputs": [ + { + "type": "data", + "data": { + "text/plain": "" + } + } + ], + "console": [] + }, + { + "id": "fmbT", + "code_hash": "8dc2207b5b3833df0dd375fd6bfbc841", + "outputs": [ + { + "type": "error", + "ename": "interruption", + "evalue": "This cell was interrupted and needs to be re-run", + "traceback": [] + } + ], + "console": [ + { + "type": "stream", + "name": "stderr", + "text": "\r 0%| | 0/2000 [00:00
Traceback (most recent call last):\n  File "/tmp/marimo_7529/__marimo__cell_fmbT_.py", line 2, in <module>\n    idata_pymc_reg = pm.sample(\n                     ^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/mcmc.py", line 802, in sample\n    return _sample_external_nuts(\n           ^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/mcmc.py", line 391, in _sample_external_nuts\n    idata = pymc_jax.sample_jax_nuts(\n            ^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/jax.py", line 652, in sample_jax_nuts\n    raw_mcmc_samples, sample_stats, library = sampler_fn(\n                                              ^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/pymc/sampling/jax.py", line 489, in _sample_numpyro_nuts\n    pmap_numpyro.run(\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/numpyro/infer/mcmc.py", line 706, in run\n    states, last_state = _laxmap(partial_map_fn, map_args)\n                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/numpyro/infer/mcmc.py", line 177, in _laxmap\n    ys.append(f(x))\n              ^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/numpyro/infer/mcmc.py", line 489, in _single_chain_mcmc\n    collect_vals = fori_collect(\n                   ^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/numpyro/util.py", line 399, in fori_collect\n    vals = _body_fn(i, *vals)\n           ^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/traceback_util.py", line 180, in reraise_with_filtered_traceback\n    return fun(*args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/pjit.py", line 263, in cache_miss\n    executable, pgle_profiler, const_args) = _python_pjit_helper(\n                                             ^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/pjit.py", line 146, in _python_pjit_helper\n    out_flat, compiled, profiler, const_args = _pjit_call_impl_python(\n                                               ^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/pjit.py", line 1600, in _pjit_call_impl_python\n    compiled = computation.compile()\n               ^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/interpreters/pxla.py", line 2527, in compile\n    executable = UnloadedMeshExecutable.from_hlo(\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/interpreters/pxla.py", line 3073, in from_hlo\n    xla_executable = _cached_compilation(\n                     ^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/interpreters/pxla.py", line 2854, in _cached_compilation\n    xla_executable = compiler.compile_or_get_cached(\n                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/compiler.py", line 491, in compile_or_get_cached\n    return _compile_and_write_cache(\n           ^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/compiler.py", line 759, in _compile_and_write_cache\n    executable = backend_compile_and_load(\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/profiler.py", line 359, in wrapper\n    return func(*args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/jax/_src/compiler.py", line 375, in backend_compile_and_load\n    return backend.compile_and_load(\n           ^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "/home/jovan/Documents/projects/hssm_wksp/HSSM/.venv/lib/python3.12/site-packages/marimo/_runtime/handlers.py", line 48, in interrupt_handler\n    raise MarimoInterrupt\nKeyboardInterrupt\n
\n", + "mimetype": "application/vnd.marimo+traceback" + } + ] + }, + { + "id": "DVld", + "code_hash": "1380fe1f061d91f97d86b4f7152cf519", + "outputs": [ + { + "type": "error", + "ename": "exception", + "evalue": "An ancestor raised an exception (KeyboardInterrupt): ", + "traceback": [] + } + ], + "console": [] + } + ] +} \ No newline at end of file diff --git a/docs/tutorials/marimo_tutorial.py b/docs/tutorials/marimo_tutorial.py new file mode 100644 index 000000000..11d52c6f2 --- /dev/null +++ b/docs/tutorials/marimo_tutorial.py @@ -0,0 +1,2912 @@ +import marimo + +__generated_with = "0.18.3" +app = marimo.App(width="medium") + + +@app.cell +def _(): + import marimo as mo + mo.notebook_dir() + return (mo,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" +
+ """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + This tutorial provides a comprehensive introduction to the HSSM package for Hierarchical Bayesian Estimation of Sequential Sampling Models. + + To make the most of the tutorial, let us cover the functionality of the key supporting packages that we use along the way. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Colab Instructions + + If you would like to run this tutorial on Google colab, please click this [link](https://github.com/lnccbrown/HSSM/blob/main/docs/tutorials/main_tutorial.ipynb). + + Once you are *in the colab*, follow the *installation instructions below* and then **restart your runtime**. + + Just **uncomment the code in the next code cell** and run it! + + **NOTE**: + + You may want to *switch your runtime* to have a GPU or TPU. To do so, go to *Runtime* > *Change runtime type* and select the desired hardware accelerator. + + Note that if you switch your runtime you have to follow the installation instructions again. + """) + return + + +@app.cell +def _(): + # If running this on Colab, please uncomment the next line + # !pip install git+https://github.com/lnccbrown/HSSM@workshop_tutorial + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Basic Imports + """) + return + + +@app.cell +def _(): + import warnings + warnings.filterwarnings("ignore") + + # Basics + import numpy as np + from matplotlib import pyplot as plt + + random_seed_sim = 134 + np.random.seed(random_seed_sim) + return np, plt + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Data Simulation + + We will rely on the [ssms](https://github.com/AlexanderFengler/ssm-simulators) package for data simulation repeatedly. Let's look at a basic isolated use case below. + + As an example, let's use [ssms](https://github.com/AlexanderFengler/ssm-simulators) to simulate from the basic [Drift Diffusion Model](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2474742/) (a running example in this tutorial). + +
+ + If you are not familiar with the DDM. For now just consider that it has four parameters. + + - `v` the drift rate + - `a` the boundary separation + - `t` the non-decision time + - `z` the a priori decision bias (starting point) + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Using `simulate_data()` + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + HSSM comes with a basic simulator function supplied the `simulate_data()` function. We can use this function to create synthetic datasets. + + Below we show the most basic usecase: + + We wish to generate `500` datapoints (trials) from the standard [Drift Diffusion Model](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2474742/) with a fixed parameters, `v = 0.5, a = 1.5, z = 0.5, t = 0.5`. + + + **Note**: + + In the course of the tutorial, we will see multiple strategies for synthetic dataset generation, this being the most straightforward one. + """) + return + + +@app.cell +def _(): + # Single dataset + import arviz as az # Visualization + import bambi as bmb # Model construction + import hddm_wfpt + import jax + import pytensor # Graph-based tensor library + + import hssm + + # pytensor.config.floatX = "float32" + # jax.config.update("jax_enable_x64", False) + + v_true = 0.5 + a_true = 1.5 + z_true = 0.5 + t_true = 0.5 + + # Call the simulator function + dataset_simulated = hssm.simulate_data( + model="ddm", theta=dict(v=v_true, a=a_true, z=z_true, t=t_true), size=500 + ) + + dataset_simulated + return ( + a_true, + az, + bmb, + dataset_simulated, + hddm_wfpt, + hssm, + jax, + t_true, + v_true, + z_true, + ) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + If instead you wish to supply a parameter that *varies by trial* (a lot more on this later), you can simply supply a vector of parameters to the `theta` dictionary, when calling the simulator. + + **Note**: + + The `size` argument conceptually functions as *number of synthetic datasets*. So if you supply a parameter as a `(1000,)` vector, then the simulator assumes that one dataset consists of `1000` trials, hence if we set the `size = 1` as below, we expect in return a dataset with `1000` trials. + """) + return + + +@app.cell +def _(hssm, np, t_true, v_true, z_true): + # a changes trial wise + a_trialwise = np.random.normal(loc=2, scale=0.3, size=1000) + + dataset_a_trialwise = hssm.simulate_data( + model="ddm", + theta=dict( + v=v_true, + a=a_trialwise, + z=z_true, + t=t_true, + ), + size=1, + ) + + dataset_a_trialwise + return (a_trialwise,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + If we wish to simulate from another model, we can do so by changing the `model` string. + + The number of models we can simulate differs from the number of models for which we have likelihoods available (both will increase over time). To get the models for which likelihood functions are supplied out of the box, we should inspect `hssm.HSSM.supported_models`. + """) + return + + +@app.cell +def _(hssm): + hssm.HSSM.supported_models + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + If we wish to check more detailed information about a given supported model, we can use the accessor `get_default_model_config` under `hssm.modelconfig`. For example, we inspect `ddm` model configuration below. + """) + return + + +@app.cell +def _(hssm): + hssm.modelconfig.get_default_model_config("ddm") + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + This dictionary contains quite a bit of information. For purposes of *simulating data from a given model*, we will highlight two aspects: + + 1. The key `list_of_params` provides us with the necessary information to define out `theta` dictionary + 2. The `bounds` key inside the `likelihoods` sub-dictionaries, provides us with an indication of reasonable parameter values. + + The `likelihoods` dictionary inhabits three sub-directories for the `ddm` model, since we have all three, an `analytical`, an `approx_differentiable` (LAN) and a `blackbox` likelihood available. For many models, we will be able to access only one or two types of likelihoods. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Using `ssm-simulators` + + Internally, HSSM natively makes use of the [ssm-simulators](https://github.com/AlexanderFengler/ssm-simulators) package for forward simulation of models. + `hssm.simulate_data()` functions essentially as a convenience-wrapper. + + Below we illustrate how to simulate data using the `ssm-simulators` package directly, to generate an equivalent dataset as created above. We will use the *third* way of passing parameters to the simulator, which is as a parameter-*matrix*. + + **Notes**: + + 1. If you pass parameters as a parameter matrix, make sure the column ordering is correct. You can follow the parameter ordering under `hssm.defaults.default_model_config['ddm']['list_params']`. + + 2. This is a minimal example, for more information about the package, check the associated [github-page](https://github.com/AlexanderFengler/ssm-simulators). + """) + return + + +@app.cell +def _(a_trialwise, np, t_true, v_true, z_true): + import pandas as pd + from ssms.basic_simulators.simulator import simulator + + # a changes trial wise + theta_mat = np.zeros((1000, 4)) + theta_mat[:, 0] = v_true # v + theta_mat[:, 1] = a_trialwise # a + theta_mat[:, 2] = z_true # z + theta_mat[:, 3] = t_true # t + + # simulate data + sim_out_trialwise = simulator( + theta=theta_mat, # parameter_matrix + model="ddm", # specify model (many are included in ssms) + n_samples=1, # number of samples for each set of parameters + # (plays the role of `size` parameter in `hssm.simulate_data`) + ) + + # Turn into nice dataset + dataset_trialwise = pd.DataFrame( + np.column_stack( + [sim_out_trialwise["rts"][:, 0], sim_out_trialwise["choices"][:, 0]] + ), + columns=["rt", "response"], + ) + + dataset_trialwise + return (pd,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We will stick to `hssm.simulate_data()` in this tutorial, to keep things simple. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## ArviZ for Plotting + +
+ + + We use the [ArviZ](https://python.arviz.org/en/stable/) package for most of our plotting needs. + ArviZ is a useful aid for plotting when doing anything Bayesian. + + It works with HSSM out of the box, by virtue of HSSMs reliance on [PyMC](https://www.pymc.io/welcome.html) for model construction and sampling. + + Checking out the [ArviZ Documentation](https://python.arviz.org/en/stable/getting_started/index.html) is a good idea to give you communication superpowers for not only your HSSM results, but also other libraries in the Bayesian Toolkit such as [NumPyro](https://num.pyro.ai/en/latest/index.html#introductory-tutorials) or [STAN](https://mc-stan.org/users/documentation/). + + We will see [ArviZ](https://python.arviz.org/en/stable/) plots throughout the notebook. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + # Main Tutorial + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Initial Dataset + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Let's proceed to simulate a simple dataset for our first example. + """) + return + + +@app.cell +def _(a_true, hssm, t_true, v_true, z_true): + # Specify + param_dict_init = dict( + v=v_true, + a=a_true, + z=z_true, + t=t_true, + ) + + + dataset_simulated_main = hssm.simulate_data( + model="ddm", + theta=param_dict_init, + size=500, + ) + + dataset_simulated_main + return dataset_simulated_main, param_dict_init + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## First HSSM Model + + In this example we will use the *analytical likelihood function* computed as suggested in [this paper](https://psycnet.apa.org/record/2009-11068-003). + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Instantiate the model + + To instantiate our `HSSM` class, in the simplest version, we only need to provide an appropriate dataset. + The dataset is expected to be a `pandas.DataFrame` with at least two columns, respectively called `rt` (for reaction time) and `response`. + Our data simulated above is already in the correct format, so let us try to construct the class. + + **NOTE:** + + If you are a user of the [HDDM](https://github.com/hddm-devs/hddm) python package, this workflow should seem very familiar. + """) + return + + +@app.cell +def _(dataset_simulated_main, hssm): + simple_ddm_model = hssm.HSSM(data=dataset_simulated_main) + return (simple_ddm_model,) + + +@app.cell +def _(simple_ddm_model): + simple_ddm_model + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + The `print()` function gives us some basic information about our model including the *number of observations* the *parameters in the model* and their respective *prior setting*. We can also create a nice little graphical representation of our model... + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Model Graph + + Since `HSSM` creates a `PyMC Model`, we can can use the `.graph()` function, to get a graphical representation of the the model we created. + """) + return + + +@app.cell +def _(mo, simple_ddm_model): + graph_simulated_main = simple_ddm_model.graph() + # For marimo display + png_bytes_main = graph_simulated_main.pipe(format="png") + mo.image(png_bytes_main) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + This is the simplest model we can build. The graph above follows **plate notation**, commonly used for **probabilistic graphical models**. + + - We have our basic parameters (unobserved, **white nodes**), these are *random variables* in the model and we want to estimate them + - Our observed reaction times and choices (`SSMRandomVariable`, **grey node**), are fixed (or conditioned on). + - **Rounded rectangles** provide us with information about dimensionality of objects + - **Rectangles with sharp edges** represent *deterministic*, but *computed* quantities (not shown here, but in later models) + + This notation is helpful to get a quick overview of the structure of a given model we construct. + + The `graph()` function of course becomes a lot more interesting and useful for more complicated models! + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Sample from the Model + + We can now call the `.sample()` function, to get posterior samples. The main arguments you may want to change are listed in the function call below. + + Importantly, multiple backends are possible. We choose the `nuts_numpyro` backend below, + which in turn compiles the model to a [`JAX`](https://github.com/google/jax) function. + """) + return + + +@app.cell +def _(simple_ddm_model): + infer_data_simple_ddm_model = simple_ddm_model.sample( + sampler="mcmc", # type of sampler to choose, 'nuts_numpyro', + # 'nuts_blackjax' of default pymc nuts sampler + cores=1, # how many cores to use + chains=2, # how many chains to run + draws=500, # number of draws from the markov chain + tune=1000, # number of burn-in samples + idata_kwargs=dict(log_likelihood=True), # return log likelihood + mp_ctx="spawn", + ) # mp_ctx="forkserver") + return (infer_data_simple_ddm_model,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We sampled from the model, let's look at the output... + """) + return + + +@app.cell +def _(infer_data_simple_ddm_model): + type(infer_data_simple_ddm_model) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Errr... a closer look might be needed here! + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Inference Data / What gets returned from the sampler? + + The sampler returns an [ArviZ](https://python.arviz.org/en/stable/) `InferenceData` object. + + To understand all the logic behind these objects and how they mesh with the Bayesian Workflow, we refer you to the [ArviZ Documentation](https://python.arviz.org/en/stable/getting_started/index.html). + + `InferenceData` is build on top of [xarrays](https://docs.xarray.dev/en/stable/index.html). The [xarray documentation](https://docs.xarray.dev/en/stable/index.html) will help you understand in more detail how to manipulate these objects. + + But let's take a quick high-level look to understand roughly what we are dealing with here! + """) + return + + +@app.cell +def _(infer_data_simple_ddm_model): + infer_data_simple_ddm_model + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We see that in our case, `infer_data_simple_ddm_model` contains four basic types of data (note: this is extensible!) + + - `posterior` + - `log_likelihood` + - `sample_stats` + - `observed_data` + + The `posterior` object contains our traces for each of the parameters in the model. The `log_likelihood` field contains the trial wise log-likelihoods for each sample from the posterior. The `sample_stats` field contains information about the sampler run. This can be important for chain diagnostics, but we will not dwell on this here. Finally we retreive our `observed_data`. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Basic Manipulation + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Accessing groups and variables + """) + return + + +@app.cell +def _(infer_data_simple_ddm_model): + infer_data_simple_ddm_model.posterior + return + + +@app.cell +def _(infer_data_simple_ddm_model): + infer_data_simple_ddm_model.posterior.a.head() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + To simply access the underlying data as a `numpy.ndarray`, we can use `.values` (as e.g. when using `pandas.DataFrame` objects). + """) + return + + +@app.cell +def _(infer_data_simple_ddm_model): + type(infer_data_simple_ddm_model.posterior.a.values) + return + + +@app.cell +def _(): + # infer_data_simple_ddm_model.posterior.a.values + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Combine `chain` and `draw` dimension + + When operating directly on the `xarray`, you will often find it useful to collapse the `chain` and `draw` coordinates into a single coordinate. + **Arviz** makes this easy via the `extract` method. + """) + return + + +@app.cell +def _(az, infer_data_simple_ddm_model): + idata_extracted = az.extract(infer_data_simple_ddm_model) + idata_extracted + return (idata_extracted,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Since *Arviz* really just calls the `.stack()` method from *xarray*, here the corresponding example using the lower level `xarray` interface. + """) + return + + +@app.cell +def _(infer_data_simple_ddm_model): + infer_data_simple_ddm_model.posterior.stack(sample=("chain", "draw")) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Making use of ArviZ + + Working with the `InferenceData` directly, is very helpful if you want to include custom computations into your workflow. + For a basic Bayesian Workflow however, you will often find that standard functionality available through [ArviZ](https://python.arviz.org/en/stable/) + suffices. + + Below we provide a few examples of useful **Arviz** outputs, which come handy for analyzing your traces (MCMC samples). + + #### Summary table + + Let's take a look at a summary table for our posterior. + """) + return + + +@app.cell +def _(az, infer_data_simple_ddm_model, simple_ddm_model): + az.summary( + infer_data_simple_ddm_model, + var_names=[var_name.name for var_name in simple_ddm_model.pymc_model.free_RVs], + ) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + This table returns the parameter-wise mean of our posterior and a few extra statistics. + + Of these extra statistics, the one-stop shop for flagging convergence issues is the `r_hat` value, which + is reported in the right-most column. + + To navigate this statistic, here is a rule of thumb widely used in applied Bayesian statistics. + + If you find an `r_hat` value `> 1.01`, it warrants investigation. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Trace plot + """) + return + + +@app.cell +def _(az, infer_data_simple_ddm_model, mo, param_dict_init, plt): + ax_trace = az.plot_trace( + infer_data_simple_ddm_model, # we exclude the log_likelihood traces here + lines=[(key_, {}, param_dict_init[key_]) for key_ in param_dict_init], + ) + + fig_trace = plt.gcf() + + plt.tight_layout() + mo.mpl.interactive(fig_trace) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + The `.sample()` function also sets a `trace` attribute, on our `hssm` class, so instead, we could call the plot like so: + """) + return + + +@app.cell +def _(az, mo, param_dict_init, plt, simple_ddm_model): + az.plot_trace( + simple_ddm_model.traces, + lines=[(key_, {}, param_dict_init[key_]) for key_ in param_dict_init], + ); + + fig_trace2 = plt.gcf() + + plt.tight_layout() + mo.mpl.interactive(fig_trace2) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + In this tutorial we are most often going to use the latter way of accessing the traces, but there is no preferred option. + + Let's look at a few more plots. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Forest Plot + + The forest plot is commonly used for a quick visual check of the marginal posteriors. It is very effective for intuitive communication of results. + """) + return + + +@app.cell +def _(az, simple_ddm_model): + az.plot_forest(simple_ddm_model.traces) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ##### Combining Chains + By default, chains are separated out into *separate caterpillars*, however + sometimes, especially if you are looking at a forest plot which includes many posterior parameters at once, you want to declutter and collapse the chains into single caterpillars. + In this case you can `combine` chains instead. + """) + return + + +@app.cell +def _(az, simple_ddm_model): + az.plot_forest(simple_ddm_model.traces, combined=True) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Basic Marginal Posterior Plot + + Another way to view the marginal posteriors is provided by the `plot_posterior()` function. It shows the mean and by default the $94\%$ HDIs. + """) + return + + +@app.cell +def _(az, simple_ddm_model): + az.plot_posterior(simple_ddm_model.traces) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Especially for parameter recovery studies, you may want to include **reference values** for the parameters of interest. + + You can do so using the `ref_val` argument. See the example below: + """) + return + + +@app.cell +def _(az, param_dict_init, simple_ddm_model): + az.plot_posterior( + simple_ddm_model.traces, + ref_val=[ + param_dict_init[var_name] + for var_name in simple_ddm_model.traces.posterior.data_vars + ], + ) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Since it is sometimes useful, especially for more complex cases, below an alternative approach in which we pass `ref_val` as a dictionary. + """) + return + + +@app.cell +def _(az, param_dict_init, simple_ddm_model): + az.plot_posterior( + simple_ddm_model.traces, + ref_val={ + "v": [{"ref_val": param_dict_init["v"]}], + "a": [{"ref_val": param_dict_init["a"]}], + "z": [{"ref_val": param_dict_init["z"]}], + "t": [{"ref_val": param_dict_init["t"]}], + }, + ) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Posterior Pair Plot + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + The posterior pair plot show us bi-variate traceplots and is useful to check for simple parameter tradeoffs that may emerge. The simplest (linear) tradeoff may be a high correlation between two parameters. + This can be very helpful in diagnosing sampler issues for example. If such tradeoffs exist, one often see extremely *wide marginal distributions*. + + In our `ddm` example, we see a little bit of a tradeoff between `a` and `t`, as well as between `v` and `z`, however nothing concerning. + """) + return + + +@app.cell +def _(az, mo, param_dict_init, plt, simple_ddm_model): + az.plot_pair( + simple_ddm_model.traces, + kind="kde", + reference_values=param_dict_init, + marginals=True, + ); + + pair_plot = plt.gcf() + + plt.tight_layout() + mo.mpl.interactive(pair_plot) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + The few plot we showed here are just the beginning: [ArviZ](https://python.arviz.org/en/stable/) has a much broader spectrum of graphs and other convenience function available. Just check the [documentation](https://python.arviz.org/en/stable/). + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Compute Quantities from idata + + #### Example: Mean and Covariance of Posterior Parameters + + As a simple example, let us calculate the covariance matrix for our posterior samples. + """) + return + + +@app.cell +def _(idata_extracted, np, plt): + # Calculate the correlation matrix + posterior_correlation_matrix = np.corrcoef( + np.stack( + [idata_extracted[var_].values for var_ in idata_extracted.data_vars.variables] + ) + ) + num_vars = posterior_correlation_matrix.shape[0] + + # Make heatmap + fig, ax = plt.subplots(1, 1) + cax = ax.imshow(posterior_correlation_matrix, cmap="coolwarm", vmin=-1, vmax=1) + fig.colorbar(cax, ax=ax) + ax.set_title("Posterior Correlation Matrix") + + # Add ticks + ax.set_xticks(range(posterior_correlation_matrix.shape[0])) + ax.set_xticklabels([var_ for var_ in idata_extracted.data_vars.variables]) + ax.set_yticks(range(posterior_correlation_matrix.shape[0])) + ax.set_yticklabels([var_ for var_ in idata_extracted.data_vars.variables]) + + # Annotate heatmap + for i_cor in range(num_vars): + for j_cor in range(num_vars): + ax.text( + j_cor, + i_cor, + f"{posterior_correlation_matrix[i_cor, j_cor]:.2f}", + ha="center", + va="center", + color="black", + ) + + plt.show() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## HSSM Model based on LAN likelihood + + With HSSM you can switch between pre-supplied models with a simple change of argument. The type of likelihood that will be accessed might change in the background for you. + + Here we see an example in which the underlying likelihood is now a [LAN](https://elifesciences.org/articles/65074). + + We will talk more about different types of likelihood functions and backends later in the tutorial. For now just keep the following in mind: + + There are three types of likelihoods + + 1. `analytic` + 2. `approx_differentiable` + 3. `blackbox` + + To check which type is used in your HSSM model simple type: + """) + return + + +@app.cell +def _(simple_ddm_model): + simple_ddm_model.loglik_kind + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Ah... we were using an `analytical` likelihood with the DDM model in the last section. + Now let's see something different! + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Simulating Angle Data + + Again, let us simulate a simple dataset. This time we will use the `angle` model (passed via the `model` argument to the `simulator()` function). + + + This model is distinguished from the basic `ddm` model by an additional `theta` parameter which specifies the angle with which the decision boundaries collapse over time. + +
+ + DDMs with collapsing bounds have been of significant interest in the theoretical literature, but applications were rare due to a lack of analytical likelihoods. HSSM facilitates inference with such models via the our `approx_differentiable` likelihoods. HSSM ships with a few predefined models based on [LANs](https://elifesciences.org/articles/65074), but really we don't want to overemphasize those. They reflect the research interest of our and adjacent labs to a great extend. + + Instead, we encourage the community to contribute to this model reservoir (more on this later). + """) + return + + +@app.cell +def _(hssm): + # Simulate angle data + v_angle_true = 0.5 + a_angle_true = 1.5 + z_angle_true = 0.5 + t_angle_true = 0.2 + theta_angle_true = 0.2 + + param_dict_angle = dict(v=0.5, a=1.5, z=0.5, t=0.2, theta=0.2) + + lines_list_angle = [(key_, {}, param_dict_angle[key_]) for key_ in param_dict_angle] + + dataset_angle = hssm.simulate_data(model="angle", theta=param_dict_angle, size=1000) + return dataset_angle, lines_list_angle + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We pass a single additional argument to our `HSSM` class and set `model='angle'`. + """) + return + + +@app.cell +def _(dataset_angle, hssm): + model_angle = hssm.HSSM(data=dataset_angle, model="angle") + + model_angle + return (model_angle,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + The model graph now show us an additional parameter `theta`! + """) + return + + +@app.cell +def _(mo, model_angle): + model_angle_graph = model_angle.graph() + png_bytes_angle = model_angle_graph.pipe(format="png") + mo.image(png_bytes_angle) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Let's check the type of likelihood that is used under the hood ... + """) + return + + +@app.cell +def _(model_angle): + model_angle.loglik_kind + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Ok so here we rely on a likelihood of the `approx_differentiable` kind. + + As discussed, with the initial set of pre-supplied likelihoods, this implies that we are using a [LAN](https://elifesciences.org/articles/65074) in the background. + """) + return + + +@app.cell +def _(jax, model_angle): + jax.config.update("jax_enable_x64", False) + infer_data_angle = model_angle.sample( + sampler="nuts_numpyro", + chains=2, + cores=2, + draws=500, + tune=500, + idata_kwargs=dict(log_likelihood=False), # no need to return likelihoods here + mp_ctx="spawn", + ) + return + + +@app.cell +def _(az, lines_list_angle, mo, model_angle, plt): + az.plot_trace(model_angle.traces, lines=lines_list_angle) + plt.tight_layout() + + plot_trace3 = plt.gcf() + + plt.tight_layout() + mo.mpl.interactive(plot_trace3) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Choosing Priors + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + HSSM allows you to specify priors quite freely. If you used HDDM previously, you may feel relieved to read that your hands are now untied! + + +
+ + With HSSM we have multiple routes to priors. But let's first consider a special case: + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Fixing a parameter to a given value + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Assume that instead of fitting all parameters of the DDM, + +
+ + we instead want to fit only the `v` (drift) parameter, setting all other parameters to fixed scalar values. + +
+ + HSSM makes this extremely easy! + """) + return + + +@app.cell +def _(param_dict_init): + param_dict_init + return + + +@app.cell +def _(dataset_simulated_main, hssm, param_dict_init): + ddm_model_only_v = hssm.HSSM( + data=dataset_simulated_main, + model="ddm", + a=param_dict_init["a"], + t=param_dict_init["t"], + z=param_dict_init["z"], + ) + return (ddm_model_only_v,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Since we fix all but one parameter, we therefore estimate only one parameter. This should be reflected in our model graph, where we expect only one free random variable `v`: + """) + return + + +@app.cell +def _(ddm_model_only_v, mo): + ddm_model_only_v_graph = ddm_model_only_v.graph() + ddm_model_only_v_graph_png = ddm_model_only_v_graph.pipe(format="png") + mo.image(ddm_model_only_v_graph_png) + return + + +@app.cell +def _(ddm_model_only_v): + ddm_model_only_v.sample( + sampler="mcmc", + chains=2, + cores=2, + draws=500, + tune=500, + idata_kwargs=dict(log_likelihood=False), # no need to return likelihoods here + mp_ctx="spawn", + ) + return + + +@app.cell +def _(az, ddm_model_only_v, param_dict_init, plt): + az.plot_trace( + ddm_model_only_v.traces.posterior, lines=[("v", {}, param_dict_init["v"])] + ); + plt.gcf() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Instead of the trace on the right, a useful alternative / complement is the **rank plot**. + As a rule of thumb, if the rank plots within chains look *uniformly distributed*, then our chains generally exhibit *good mixing*. + """) + return + + +@app.cell +def _(az, ddm_model_only_v): + az.plot_trace(ddm_model_only_v.traces, kind="rank_bars") + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Named priors + + We can choose any [PyMC](https://www.pymc.io/welcome.html) `Distribution` to specify a prior for a given parameter. + + Even better, if natural *parameter bounds* are provided, HSSM *automatically truncates the prior distribution* so that it respect these bounds. + + Below is an example in which we specify a *Normal* prior on the `v` parameter of the DDM. + + We choose a *ridiculously low* $\sigma$ value, to illustrate it's regularizing effect on the parameter (just so we see a difference and you are convinced that something changed). + """) + return + + +@app.cell +def _(dataset_simulated_main, hssm): + model_normal = hssm.HSSM( + data=dataset_simulated_main, + include=[ + { + "name": "v", + "prior": {"name": "Normal", "mu": 0, "sigma": 0.01}, + } + ], + ) + return (model_normal,) + + +@app.cell +def _(model_normal): + model_normal + return + + +@app.cell +def _(model_normal): + infer_data_normal = model_normal.sample( + sampler="mcmc", + chains=2, + cores=2, + draws=500, + tune=500, + idata_kwargs=dict(log_likelihood=False), # no need to return likelihoods here + mp_ctx="spawn", + ) + return + + +@app.cell +def _(az, model_normal, param_dict_init): + az.plot_trace( + model_normal.traces, + lines=[(key_, {}, param_dict_init[key_]) for key_ in param_dict_init], + ) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Observe how we reused our previous dataset with underlying parameters + + - `v = 0.5` + - `a = 1.5` + - `z = 0.5` + - `t = 0.2` + + In contrast to our previous sampler round, in which we used Uniform priors, here the `v` estimate is shrunk severley towared $0$ and the `t` and `z` parameter estimates are very biased to make up for this distortion. Also, overall we see a lot of divergences now, which is a sign of poor sampler performance. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## HSSM Model with Regression + + +
+ + Crucial to the scope of HSSM is the ability to link parameters with trial-by-trial covariates via (hierarchical, but more on this later) general linear models. + + In this section we explore how HSSM deals with these models. No big surprise here... it's simple! + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Case 1: One parameter is a Regression Target + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Simulating Data + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Let's first simulate some data, where the trial-by-trial parameters of the `v` parameter in our model are driven by a simple linear regression model. + + + The regression model is driven by two (random) covariates `x` and `y`, respectively with coefficients of $0.8$ and $0.3$ which are also simulated below. + We set the intercept to $0.3$. + + The rest of the parameters are fixed to single values as before. + """) + return + + +@app.cell +def _(hssm, np): + # Set up trial by trial parameters + v_intercept = 0.3 + x = np.random.uniform(-1, 1, size=1000) + v_x = 0.8 + y = np.random.uniform(-1, 1, size=1000) + v_y = 0.3 + v_reg_v = v_intercept + (v_x * x) + (v_y * y) + + # rest + a_reg_v = 1.5 + z_reg_v = 0.5 + t_reg_v = 0.1 + + param_dict_reg_v = dict( + a=1.5, z=0.5, t=0.1, v=v_reg_v, v_x=v_x, v_y=v_y, v_Intercept=v_intercept, theta=0.0 + ) + + # base dataset + dataset_reg_v = hssm.simulate_data(model="ddm", theta=param_dict_reg_v, size=1) + + # Adding covariates into the datsaframe + dataset_reg_v["x"] = x + dataset_reg_v["y"] = y + return dataset_reg_v, param_dict_reg_v, v_intercept, v_x, v_y, x, y + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Basic Model + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We now create the `HSSM` model. + + Notice how we set the `include` argument. The include argument expects a list of dictionaries, one dictionary for each parameter to be specified via a regression model. + + Four `keys` are expected to be set: + + - The `name` of the parameter, + - Potentially a `prior` for each of the regression level parameters ($\beta$'s), + - The regression `formula` + - A `link` function. + + The regression formula follows the syntax in the [formulae](https://pypi.org/project/formulae/) python package (as used by the [Bambi](https://bambinos.github.io/bambi/) package for building Bayesian Hierarchical Regression Models. + + [Bambi](https://bambinos.github.io/bambi/) forms the main model-construction backend of HSSM. + """) + return + + +@app.cell +def _(dataset_reg_v, hssm): + model_reg_v_simple = hssm.HSSM( + data=dataset_reg_v, include=[{"name": "v", "formula": "v ~ 1 + x + y"}] + ) + return (model_reg_v_simple,) + + +@app.cell +def _(model_reg_v_simple): + model_reg_v_simple + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ##### `Param` class + As illustrated below, there is an alternative way of specifying the parameter specific data via the `Param` class. + """) + return + + +@app.cell +def _(dataset_reg_v, hssm): + model_reg_v_simple_new = hssm.HSSM( + data=dataset_reg_v, include=[hssm.Param(name="v", formula="v ~ 1 + x + y")] + ) + return (model_reg_v_simple_new,) + + +@app.cell +def _(model_reg_v_simple_new): + model_reg_v_simple_new + return + + +@app.cell +def _(mo, model_reg_v_simple): + model_reg_v_simple_graph = model_reg_v_simple.graph() + + model_reg_v_simple_png = model_reg_v_simple_graph.pipe(format="png") + mo.image(model_reg_v_simple_png) + return + + +@app.cell +def _(model_reg_v_simple): + print(model_reg_v_simple) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + #### Custom Model + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + These were the defaults, with a little extra labor, we can e.g. customize the choice of priors for each parameter in the model. + """) + return + + +@app.cell +def _(dataset_reg_v, hssm): + model_reg_v = hssm.HSSM( + data=dataset_reg_v, + include=[ + { + "name": "v", + "prior": { + "Intercept": {"name": "Uniform", "lower": -3.0, "upper": 3.0}, + "x": {"name": "Uniform", "lower": -1.0, "upper": 1.0}, + "y": {"name": "Uniform", "lower": -1.0, "upper": 1.0}, + }, + "formula": "v ~ 1 + x + y", + "link": "identity", + } + ], + ) + return (model_reg_v,) + + +@app.cell +def _(model_reg_v): + model_reg_v + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Notice how `v` is now set as a regression. + """) + return + + +@app.cell +def _(model_reg_v): + infer_data_reg_v = model_reg_v.sample( + sampler="mcmc", + chains=2, + cores=2, + draws=500, + tune=500, + mp_ctx="spawn", + ) + return (infer_data_reg_v,) + + +@app.cell +def _(infer_data_reg_v): + infer_data_reg_v + return + + +@app.cell +def _(): + # az.plot_forest(model_reg_v.traces) + return + + +@app.cell +def _(az, model_reg_v, param_dict_reg_v): + az.plot_trace( + model_reg_v.traces, + var_names=["~v"], + lines=[(key_, {}, param_dict_reg_v[key_]) for key_ in param_dict_reg_v], + ) + return + + +@app.cell +def _(az, model_reg_v, param_dict_reg_v, plt): + az.plot_trace( + model_reg_v.traces, + var_names=["~v"], + lines=[(key_, {}, param_dict_reg_v[key_]) for key_ in param_dict_reg_v], + ) + plt.tight_layout() + plt.gcf() + return + + +@app.cell +def _(az, model_reg_v): + # Looks like parameter recovery was successful + az.summary(model_reg_v.traces, var_names=["~v"]) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Case 2: One parameter is a Regression (LAN) + + We can do the same thing with the `angle` model. + + **Note**: + + Our dataset was generated from the basic DDM here, so since the DDM assumes stable bounds, we expect the `theta` (angle of linear collapse) parameter to be recovered as close to $0$. + """) + return + + +@app.cell +def _(dataset_reg_v, hssm): + model_reg_v_angle = hssm.HSSM( + data=dataset_reg_v, + model="angle", + include=[ + { + "name": "v", + "prior": { + "Intercept": { + "name": "Uniform", + "lower": -3.0, + "upper": 3.0, + }, + "x": { + "name": "Uniform", + "lower": -1.0, + "upper": 1.0, + }, + "y": {"name": "Uniform", "lower": -1.0, "upper": 1.0}, + }, + "formula": "v ~ 1 + x + y", + "link": "identity", + } + ], + ) + return (model_reg_v_angle,) + + +@app.cell +def _(mo, model_reg_v_angle): + model_reg_v_angle_graph = model_reg_v_angle.graph() + + model_reg_v_angle_png = model_reg_v_angle_graph.pipe(format="png") + mo.image(model_reg_v_angle_png) + return + + +@app.cell +def _(model_reg_v_angle): + trace_reg_v_angle = model_reg_v_angle.sample( + sampler="mcmc", + chains=1, + cores=1, + draws=1000, + tune=500, + mp_ctx="spawn", + ) + return + + +@app.cell +def _(az, model_reg_v_angle, param_dict_reg_v, plt): + az.plot_trace( + model_reg_v_angle.traces, + var_names=["~v"], + lines=[(key_, {}, param_dict_reg_v[key_]) for key_ in param_dict_reg_v], + ) + plt.tight_layout() + plt.gcf() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Great! `theta` is recovered correctly, on top of that, we have reasonable recovery for all other parameters! + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Case 3: Multiple Parameters are Regression Targets (LAN) + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Let's get a bit more ambitious. We may, for example, want to try a regression on a few of our basic model parameters at once. Below we show an example where we model both the `a` and the `v` parameters with a regression. + + **NOTE:** + + In our dataset of this section, only `v` is *actually* driven by a trial-by-trial regression, so we expect the regression coefficients for `a` to hover around $0$ in our posterior. + """) + return + + +@app.cell +def _(dataset_reg_v, hssm, param_dict_reg_v): + # Instantiate our hssm model + from copy import deepcopy + + param_dict_reg_v_a = deepcopy(param_dict_reg_v) + param_dict_reg_v_a["a_Intercept"] = param_dict_reg_v_a["a"] + param_dict_reg_v_a["a_x"] = 0 + param_dict_reg_v_a["a_y"] = 0 + + hssm_reg_v_a_angle = hssm.HSSM( + data=dataset_reg_v, + model="angle", + include=[ + { + "name": "v", + "prior": { + "Intercept": {"name": "Uniform", "lower": -3.0, "upper": 3.0}, + "x": {"name": "Uniform", "lower": -1.0, "upper": 1.0}, + "y": {"name": "Uniform", "lower": -1.0, "upper": 1.0}, + }, + "formula": "v ~ 1 + x + y", + }, + { + "name": "a", + "prior": { + "Intercept": {"name": "Uniform", "lower": 0.5, "upper": 3.0}, + "x": {"name": "Uniform", "lower": -1.0, "upper": 1.0}, + "y": {"name": "Uniform", "lower": -1.0, "upper": 1.0}, + }, + "formula": "a ~ 1 + x + y", + }, + ], + ) + return hssm_reg_v_a_angle, param_dict_reg_v_a + + +@app.cell +def _(hssm_reg_v_a_angle): + hssm_reg_v_a_angle + return + + +@app.cell +def _(hssm_reg_v_a_angle, mo): + hssm_reg_v_a_angle_graph = hssm_reg_v_a_angle.graph() + + hssm_reg_v_a_angle_png = hssm_reg_v_a_angle_graph.pipe(format="png") + mo.image(hssm_reg_v_a_angle_png) + return + + +@app.cell +def _(hssm_reg_v_a_angle): + infer_data_reg_v_a = hssm_reg_v_a_angle.sample( + sampler="mcmc", + chains=2, + cores=1, + draws=1000, + tune=1000, + mp_ctx="spawn", + ) + return (infer_data_reg_v_a,) + + +@app.cell +def _(az, infer_data_reg_v_a): + az.summary( + infer_data_reg_v_a, var_names=["~a", "~v"] + ) # , var_names=["~rt,response_a"]) + return + + +@app.cell +def _(az, hssm_reg_v_a_angle, param_dict_reg_v_a, plt): + az.plot_trace( + hssm_reg_v_a_angle.traces, + var_names=["~v", "~a"], + lines=[(key_, {}, param_dict_reg_v_a[key_]) for key_ in param_dict_reg_v_a], + ) + plt.tight_layout() + plt.gcf() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We successfully recover our regression betas for `a`! Moreover, no warning signs concerning our chains. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Case 4: Categorical covariates + """) + return + + +@app.cell +def _(hssm, np): + # Set up trial by trial parameters + x_cat = np.random.choice(4, size=1000).astype(int) + x_offset_cat = np.array([0, 1, -0.5, 0.75]) + + y_cat = np.random.uniform(-1, 1, size=1000) + v_y_cat = 0.3 + v_reg_v_cat = 0 + (v_y_cat * y_cat) + x_offset_cat[x_cat] + + # rest + a_reg_v_cat = 1.5 + z_reg_v_cat = 0.5 + t_reg_v_cat = 0.1 + + # base dataset + dataset_reg_v_cat = hssm.simulate_data( + model="ddm", theta=dict(v=v_reg_v_cat, a=a_reg_v_cat, z=z_reg_v_cat, t=t_reg_v_cat), size=1 + ) + + # Adding covariates into the datsaframe + dataset_reg_v_cat["x"] = x_cat + dataset_reg_v_cat["y"] = y_cat + return (dataset_reg_v_cat,) + + +@app.cell +def _(dataset_reg_v_cat, hssm): + model_reg_v_cat = hssm.HSSM( + data=dataset_reg_v_cat, + model="angle", + include=[ + { + "name": "v", + "formula": "v ~ 0 + C(x) + y", + "link": "identity", + } + ], + ) + return (model_reg_v_cat,) + + +@app.cell +def _(mo, model_reg_v_cat): + model_reg_v_cat_graph = model_reg_v_cat.graph() + + model_reg_v_cat_png = model_reg_v_cat_graph.pipe(format="png") + mo.image(model_reg_v_cat_png) + return + + +@app.cell +def _(model_reg_v_cat): + infer_data_reg_v_cat = model_reg_v_cat.sample( + sampler="mcmc", + chains=2, + cores=1, + draws=1000, + tune=500, + mp_ctx="spawn", + ) + return (infer_data_reg_v_cat,) + + +@app.cell +def _(az, infer_data_reg_v_cat): + az.plot_forest(infer_data_reg_v_cat, var_names=["~v"]) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Hierarchical Inference + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Let's try to fit a hierarchical model now. We will simulate a dataset with $15$ participants, with $200$ observations / trials for each participant. + + We define a group mean `mean_v` and a group standard deviation `sd_v` for the intercept parameter of the regression on `v`, which we sample from a corresponding normal distribution for each participant. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Simulate Data + """) + return + + +@app.cell +def _(hssm, np, pd): + # Make some hierarchical data + n_participants = 15 # number of participants + n_trials = 200 # number of trials per participant + + sd_v = 0.5 # sd for v-intercept + mean_v = 0.5 # mean for v-intercept + + data_list = [] + for i in range(n_participants): + # Make parameters for participant i + v_intercept_hier = np.random.normal(mean_v, sd_v, size=1) + x_hier = np.random.uniform(-1, 1, size=n_trials) + v_x_hier = 0.8 + y_hier = np.random.uniform(-1, 1, size=n_trials) + v_y_hier = 0.3 + v_hier = v_intercept_hier + (v_x_hier * x_hier) + (v_y_hier * y_hier) + + a_hier = 1.5 + t_hier = 0.5 + z_hier = 0.5 + + # true_values = np.column_stack( + # [v, np.repeat([[1.5, 0.5, 0.5, 0.0]], axis=0, repeats=n_trials)] + # ) + + data_tmp = hssm.simulate_data( + model="ddm", theta=dict(v=v_hier, a=a_hier, z=z_hier, t=t_hier), size=1 + ) + data_tmp["participant_id"] = i + data_tmp["x"] = x_hier + data_tmp["y"] = y_hier + + data_list.append(data_tmp) + + # Make single dataframe out of participant-wise datasets + dataset_reg_v_hier = pd.concat(data_list) + dataset_reg_v_hier + return (dataset_reg_v_hier,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We can now define our `HSSM` model. + + We specify the regression as `v ~ 1 + (1|participant_id) + x + y`. + + `(1|participant_id)` tells the model to create a *participant-wise* offset for the intercept parameter. The rest of the regression $\beta$'s is fit globally. + + As an **R** user you may recognize this syntax from the [lmer](https://www.rdocumentation.org/packages/lme4/versions/1.1-33/topics/lmer) package. + + Our [Bambi](https://bambinos.github.io/bambi/) backend is essentially a Bayesian version of [lmer](https://www.rdocumentation.org/packages/lme4/versions/1.1-33/topics/lmer), quite like the [BRMS](https://cran.r-project.org/web/packages/brms/index.html) package in **R**, which operates on top of [STAN](https://mc-stan.org/). + + As a previous [HDDM](https://hddm.readthedocs.io/en/latest/) user, you may recognize that now proper mixed-effect models are viable! + + You should be able to handle between and within participant effects naturally now! + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Basic Hierarchical Model + """) + return + + +@app.cell +def _(dataset_reg_v_hier, hssm): + model_reg_v_angle_hier = hssm.HSSM( + data=dataset_reg_v_hier, + model="angle", + noncentered=True, + include=[ + { + "name": "v", + "prior": { + "Intercept": { + "name": "Normal", + "mu": 0.0, + "sigma": 0.5, + }, + "x": {"name": "Normal", "mu": 0.0, "sigma": 0.5}, + "y": {"name": "Normal", "mu": 0.0, "sigma": 0.5}, + }, + "formula": "v ~ 1 + (1|participant_id) + x + y", + "link": "identity", + } + ], + ) + return (model_reg_v_angle_hier,) + + +@app.cell +def _(mo, model_reg_v_angle_hier): + model_reg_v_angle_hier_graph = model_reg_v_angle_hier.graph() + + model_reg_v_angle_hier_graph_png = model_reg_v_angle_hier_graph.pipe(format="png") + mo.image(model_reg_v_angle_hier_graph_png) + return + + +@app.cell +def _(jax, model_reg_v_angle_hier): + jax.config.update("jax_enable_x64", False) + model_reg_v_angle_hier.sample( + sampler="mcmc", + chains=2, + cores=2, + draws=500, + tune=500, + mp_ctx="spawn", + ) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Let's look at the posteriors! + """) + return + + +@app.cell +def _(az, model_reg_v_angle_hier): + az.plot_forest(model_reg_v_angle_hier.traces, var_names=["~v", "~a"], combined=False) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Model Comparison + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Fitting single models is all well and good. We are however, often interested in comparing how well a few different models account for the same data. + + Through [ArviZ](https://python.arviz.org/en/stable/index.html), we have out of the box access to modern Bayesian Model Comparison. We will keep it simple here, just to illustrate the basic idea. + + ### Scenario + + The following scenario is explored. + + First we generate data from a `ddm` model with fixed parameters, specifically we set the `a` parameter to $1.5$. + + We then define two `HSSM` models: + + 1. A model which allows fitting all but the `a` parameter, which is fixed to $1.0$ (wrong) + 2. A model which allows fitting all but the `a` parameter, which is fixed to $1.5$ (correct) + + We then use the [ArviZ](https://python.arviz.org/en/stable/index.html)'s `compare()` function, to perform model comparison via `elpd_loo`. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Data Simulation + """) + return + + +@app.cell +def _(hssm): + # Parameters + param_dict_mod_comp = dict(v=0.5, a=1.5, z=0.5, t=0.2) + + # Simulation + dataset_model_comp = hssm.simulate_data( + model="ddm", theta=param_dict_mod_comp, size=500 + ) + + print(dataset_model_comp) + return (dataset_model_comp,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Defining the Models + """) + return + + +@app.cell +def _(dataset_model_comp, hssm): + # 'wrong' model + model_model_comp_1 = hssm.HSSM( + data=dataset_model_comp, + model="angle", + a=1.0, + ) + return (model_model_comp_1,) + + +@app.cell +def _(dataset_model_comp, hssm): + # 'correct' model + model_model_comp_2 = hssm.HSSM( + data=dataset_model_comp, + model="angle", + a=1.5, + ) + return (model_model_comp_2,) + + +@app.cell +def _(dataset_model_comp, hssm): + # 'wrong' model ddm + model_model_comp_3 = hssm.HSSM( + data=dataset_model_comp, + model="ddm", + a=1.0, + ) + return (model_model_comp_3,) + + +@app.cell +def _(model_model_comp_1): + infer_data_model_comp_1 = model_model_comp_1.sample( + sampler="mcmc", + cores=1, + chains=2, + draws=1000, + tune=1000, + idata_kwargs=dict( + log_likelihood=True + ), # model comparison metrics usually need this! + mp_ctx="spawn", + ) + return + + +@app.cell +def _(model_model_comp_2): + infer_data_model_comp_2 = model_model_comp_2.sample( + sampler="mcmc", + cores=1, + chains=2, + draws=1000, + tune=1000, + idata_kwargs=dict( + log_likelihood=True + ), # model comparison metrics usually need this! + mp_ctx="spawn", + ) + return + + +@app.cell +def _(model_model_comp_3): + infer_data_model_comp_3 = model_model_comp_3.sample( + sampler="mcmc", + cores=1, + chains=2, + draws=1000, + tune=1000, + idata_kwargs=dict( + log_likelihood=True + ), # model comparison metrics usually need this! + mp_ctx="spawn", + ) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Compare + """) + return + + +@app.cell +def _(az, model_model_comp_1, model_model_comp_2, model_model_comp_3): + compare_data = az.compare( + { + "a_fixed_1(wrong)": model_model_comp_1.traces, + "a_fixed_1.5(correct)": model_model_comp_2.traces, + "a_fixed_1_ddm(wrong)": model_model_comp_3.traces, + } + ) + + compare_data + return (compare_data,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Notice how the posterior weight on the `correct` model is close to (or equal to ) $1$ here. + In other words model comparison points us to the correct model with + a very high degree of certainty here! + + + We can also use the `.plot_compare()` function to illustrate the model comparison visually. + """) + return + + +@app.cell +def _(az, compare_data): + az.plot_compare(compare_data) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Using the forest plot we can take a look at what goes wrong for the "wrong" model. + + To make up for the mistplaced setting of the `a` parameter, the posterior seems to compensate by + mis-estimating the other parameters. + """) + return + + +@app.cell +def _(az, model_model_comp_1, model_model_comp_2, model_model_comp_3): + az.plot_forest( + [model_model_comp_1.traces, model_model_comp_2.traces, model_model_comp_3.traces], + model_names=["a_fixed_1(wrong)", "a_fixed_1.5(correct)", "a_fixed_1(wrong)_ddm"], + ) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## Closer look! + +
+ """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We have seen a few examples of HSSM models at this point. Add a model via a string, maybe toy a bit with with the priors and set regression functions for a given parameter. Turn it hierarchical... Here we begin to peak a bit under the hood. + + After all, we want to encourage you to contribute models to the package yourself. + + Let's remind ourself of the `model_config` dictionaries that define model properties for us. Again let's start with the DDM. + """) + return + + +@app.cell +def _(hssm): + hssm.config.default_model_config["ddm"].keys() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + The dictionary has a few high level keys. + + 1. `response` + + 2. `list_params` + + 3. `description` + + 4. `likelihoods` + + + Let us take a look at the available `likelihoods`: + """) + return + + +@app.cell +def _(hssm): + hssm.config.default_model_config["ddm"]["likelihoods"] + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + For the DDM we have available all three types of likelihoods that HSSM deals with: + + 1. `analytical` + 2. `approx_differentiable` + 3. `blackbox` + + Let's expand the dictionary contents more: + """) + return + + +@app.cell +def _(hssm): + hssm.config.default_model_config["ddm"]["likelihoods"]["analytical"] + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We see three properties (key) in this dictionary, of which two are essential: + + - The `loglik` field, which points to the likelihood function + - The `backend` field, which can be either `None` (defaulting to pytensor for `analytical` likelihoods), `jax` or `pytensor` + - The `bounds` field, which specifies bounds on a subset of the model parameters + - The `default_priors` field, which specifies parameter wise priors + + If you provide `bounds` for a parameter, but no `default_priors`, a *Uniform* prior that respects the specified bounds will be applied. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Next, let's look at the `approx_differentiable` part. + The likelihood in this part is based on a [LAN]() which was available in [HDDM]() through the [LAN extension](). + """) + return + + +@app.cell +def _(hssm): + hssm.config.default_model_config["ddm"]["likelihoods"]["approx_differentiable"] + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We see that the `loglik` field is now a string that points to a `.onnx` file. + [Onnx](https://onnx.ai/) is a meta framework for Neural Network specification, that allows translation between deep learning Frameworks. This is the preferred format for the neural networks we store in our model reservoir on [HuggingFace](https://huggingface.co/). + + Moreover notice that we now have a `backend` field. We allow for two primary backends in the `approx_differentiable` field. + + 1. `pytensor` + 2. `jax` + + The `jax` backend assumes that your likelihood is described as a jax function, the `pytensor` backend assumes that your likelihood is described as a `pytensor` function. Ok not that surprising... + + We won't dwell on this here, however the key idea is to provide users with a large degree of flexibility in describing their likelihood functions and moreover to allow targeted optimization towards MCMC sampler types that [PyMC]() allows us to access. + + You can find a [dedicated tutorial](https://lnccbrown.github.io/HSSM/tutorial_likelihoods/#3-kinds-of-likelihoods) in the documentation, which describes the different likelihoods in much more detail. + + Instead, let's take a quick look at how these newfound insights can be used for custom model definition. + """) + return + + +@app.cell +def _(dataset_simulated, hssm): + hssm_alternative_model = hssm.HSSM( + data=dataset_simulated, + model="ddm", + loglik_kind="approx_differentiable", + ) + return (hssm_alternative_model,) + + +@app.cell +def _(hssm_alternative_model): + hssm_alternative_model.loglik_kind + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + In this case we actually built the model class with an `approx_differentiable` LAN likelihood, instead of the default `analytical` likelihood we used in the beginning of the tutorial. The assumed generative model remains the `ddm` however! + """) + return + + +@app.cell +def _(hssm_alternative_model): + hssm_alternative_model.sample( + sampler="mcmc", + cores=1, + chains=2, + draws=1000, + tune=1000, + idata_kwargs=dict( + log_likelihood=False + ), # model comparison metrics usually need this! + mp_ctx="spawn", + ) + return + + +@app.cell +def _(az, hssm_alternative_model): + az.plot_forest(hssm_alternative_model.traces) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We can take this further and specify a completely custom likelihood. See the [dedicated tutorial](https://lnccbrown.github.io/HSSM/tutorial_likelihoods/#using-custom-likelihoods) for more examples! + + We will see one specific example below to illustrate another type of likelihood function we have available for model building in HSSM, the *Blackbox* likelihood. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## 'Blackbox' Likelihoods + +
+ """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### What is a **Blackbox Likelihood Function**? + + A *Blackbox Likelihood Function* is essentially any Python `callable` (function) that provides trial by trial likelihoods for your model of interest. What kind of computations are performed in this Python function is completely arbitrary. + + E.g. you could built a function that performs forward simulation from you model, constructs are kernel-density estimate for the resulting likelihood functions and evaluates your datapoints on this ad-hoc generated approximate likelihood. + + What I just described is a once state-of-the-art method of performing simulation based inference on Sequential Sampling models, a precursor to LANs if you will. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We will do something simpler to keep it short and sweet, but really... the possibilities are endless! + +

+
+

+ """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Simulating simple dataset from the DDM + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + As always, let's begin by generating some simple dataset. + """) + return + + +@app.cell +def _(hssm): + # Set parameters + param_dict_blackbox = dict(v=0.5, a=1.5, z=0.5, t=0.5) + + # Simulate + dataset_blackbox = hssm.simulate_data(model="ddm", theta=param_dict_blackbox, size=1000) + return dataset_blackbox, param_dict_blackbox + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Define the likelihood + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Now the fun part... we simply define a Python function `my_blackbox_loglik` which takes in our `data` as well as a bunch of model parameters (in our case the familiar `v`,`a`, `z`, `t` from the DDM). + + The function then does some arbitrary computation inside (in our case e.g. we pass the data and parameters to the DDM log-likelihood from our predecessor package HDDM). + + The important part is that inside `my_blackbox_loglik` anything can happen. We happen to call a little custom function that defines the likelihood of a DDM. + + **Fun fact:** + It is de-facto the likelihood which is called by [HDDM](https://hddm.readthedocs.io/en/latest/). + """) + return + + +@app.cell +def _(hddm_wfpt, np): + def my_blackbox_loglik(data, v, a, z, t, err=1e-8): + """Create a custom blackbox likelihood function.""" + data = data[:, 0] * data[:, 1] + data_nrows = data.shape[0] + # Our function expects inputs as float64, but they are not guaranteed to + # come in as such --> we type convert + return hddm_wfpt.wfpt.wiener_logp_array( + np.float64(data), + (np.ones(data_nrows) * v).astype(np.float64), + np.ones(data_nrows) * 0, + (np.ones(data_nrows) * 2 * a).astype(np.float64), + (np.ones(data_nrows) * z).astype(np.float64), + np.ones(data_nrows) * 0, + (np.ones(data_nrows) * t).astype(np.float64), + np.ones(data_nrows) * 0, + err, + 1, + ) + return (my_blackbox_loglik,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Define HSSM class with our Blackbox Likelihood + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We can now define our HSSM model class as usual, however passing our `my_blackbox_loglik()` function to the `loglik` argument, and passing as `loglik_kind = blackbox`. + + The rest of the model config is as usual. Here we can reuse our `ddm` model config, and simply specify bounds on the parameters (e.g. your Blackbox Likelihood might be trustworthy only on a restricted parameters space). + """) + return + + +@app.cell +def _(bmb, dataset_blackbox, hssm, my_blackbox_loglik): + blackbox_model = hssm.HSSM( + data=dataset_blackbox, + model="ddm", + loglik=my_blackbox_loglik, + loglik_kind="blackbox", + model_config={ + "bounds": { + "v": (-10.0, 10.0), + "a": (0.5, 5.0), + "z": (0.0, 1.0), + } + }, + t=bmb.Prior("Uniform", lower=0.0, upper=2.0), + ) + return (blackbox_model,) + + +@app.cell +def _(blackbox_model, mo): + blackbox_model_graph = blackbox_model.graph() + + blackbox_model_graph_png = blackbox_model_graph.pipe(format="png") + mo.image(blackbox_model_graph_png) + return + + +@app.cell +def _(blackbox_model): + sample = blackbox_model.sample() + return (sample,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + **NOTE**: + + Since *Blackbox likelihood functions* are assumed to not be differentiable, our default sampler for such likelihood functions is a `Slice` sampler. HSSM allows you to choose any other suitable sampler from the PyMC package instead. A bunch of options are available for gradient-free samplers. + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Results + """) + return + + +@app.cell +def _(az, sample): + az.summary(sample) + return + + +@app.cell +def _(az, param_dict_blackbox, plt, sample): + az.plot_trace( + sample, + lines=[(key_, {}, param_dict_blackbox[key_]) for key_ in param_dict_blackbox], + ) + plt.tight_layout() + plt.gcf() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ## HSSM Random Variables in PyMC + + We covered a lot of ground in this tutorial so far. You are now a sophisticated HSSM user. + + It is therefore time to reveal a secret. We can actuallly peel back one more layer... +

+
+

+ + Instead of letting HSSM help you build the entire model, we can instead use HSSM to construct valid [PyMC](https://www.pymc.io/welcome.html) distributions and then proceed to build a custom PyMC model by ourselves... +

+
+

+ + We will illustrate the simplest example below. It sets a pattern that can be exploited for much more complicated modeling exercises, which importantly go far beyond what our basic HSSM class may facilitate for you! + + See the [dedicated tutorial](https://lnccbrown.github.io/HSSM/notebooks/pymc/) in the [documentation](https://lnccbrown.github.io/HSSM/) if you are interested. + + Let's start by importing a few convenience functions: + """) + return + + +@app.cell +def _(): + # DDM models (the Wiener First-Passage Time distribution) + from hssm.distribution_utils import make_distribution + from hssm.likelihoods import DDM + return DDM, make_distribution + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Simulate some data + """) + return + + +@app.cell +def _(hssm): + # Simulate + param_dict_pymc = dict(v=0.5, a=1.5, z=0.5, t=0.5) + + dataset_pymc = hssm.simulate_data(model="ddm", theta=param_dict_pymc, size=1000) + return dataset_pymc, param_dict_pymc + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Build a custom PyMC Model + """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + We can now use our custom random variable `DDM` directly in a PyMC model. + """) + return + + +@app.cell +def _(DDM, dataset_pymc): + import pymc as pm + + with pm.Model() as ddm_pymc: + v_custom = pm.Uniform("v", lower=-10.0, upper=10.0) + a_custom = pm.HalfNormal("a", sigma=2.0) + z_custom = pm.Uniform("z", lower=0.01, upper=0.99) + t_custom = pm.Uniform("t", lower=0.0, upper=0.6) + + ddm = DDM( + "DDM", observed=dataset_pymc[["rt", "response"]].values, v=v_custom, a=a_custom, z=z_custom, t=t_custom, + ) + return ddm_pymc, pm + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Let's check the model graph: + """) + return + + +@app.cell +def _(ddm_pymc, mo, pm): + ddm_pymc_graph = pm.model_to_graphviz(model=ddm_pymc) + + ddm_pymc_graph_png = ddm_pymc_graph.pipe(format="png") + mo.image(ddm_pymc_graph_png) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Looks remarkably close to our HSSM version! + + We can use PyMC directly to sample and finally return to ArviZ for some plotting! + """) + return + + +@app.cell +def _(ddm_pymc, pm): + with ddm_pymc: + ddm_pymc_trace = pm.sample() + return (ddm_pymc_trace,) + + +@app.cell +def _(az, ddm_pymc_trace, param_dict_pymc, plt): + az.plot_trace( + ddm_pymc_trace, + lines=[(key_, {}, param_dict_pymc[key_]) for key_ in param_dict_pymc], + ) + + plt.tight_layout() + plt.gcf() + return + + +@app.cell +def _(az, ddm_pymc_trace): + az.plot_forest(ddm_pymc_trace) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Alternative Models with PyMC + + With very little extra work, we can in fact load any of the models accessible via HSSM. Here is an example, where we load the `angle` model instead. + + We first construction the likelihood function, using `make_likelihood_callable()`. + + Then we produce a valid `pymc.distribution` using the + `make_distribution()` utility function. + + Just like the `DDM` class above, we can then use this distribution inside a **PyMC** model. + """) + return + + +@app.cell +def _(hssm, make_distribution): + from hssm.distribution_utils import make_likelihood_callable + + angle_loglik_alt = make_likelihood_callable( + loglik="angle.onnx", + loglik_kind="approx_differentiable", + backend="jax", + params_is_reg=[0, 0, 0, 0, 0], + ) + + ANGLE_alt = make_distribution( + "angle", + loglik=angle_loglik_alt, + list_params=hssm.defaults.default_model_config["angle"]["list_params"], + ) + return (make_likelihood_callable,) + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + Note that we need to supply the `params_is_reg` argument ("reg" for "regression"). + This is a boolean vector, which specifies for each input to the likelihood function, whether or not it is defined to be "trial-wise", as is expected if the parameter + is the output e.g. of a regression function. + """) + return + + +@app.cell +def _(ANGLE, dataset_pymc, pm): + # Angle pymc + with pm.Model() as angle_pymc: + # Define parameters + v_alt = pm.Uniform("v", lower=-10.0, upper=10.0) + a_alt = pm.Uniform("a", lower=0.5, upper=2.5) + z_alt = pm.Uniform("z", lower=0.01, upper=0.99) + t_alt = pm.Uniform("t", lower=0.0, upper=0.6) + theta_alt = pm.Uniform("theta", lower=-0.1, upper=1.0) + + # Our RV + angle_alt = ANGLE( + "ANGLE", + v=v_alt, + a=a_alt, + z=z_alt, + t=t_alt, + theta=theta_alt, + observed=dataset_pymc[["rt", "response"]].values, + ) + return (angle_pymc,) + + +@app.cell +def _(angle_pymc, pm): + with angle_pymc: + idata_object = pm.sample(nuts_sampler="numpyro") + return (idata_object,) + + +@app.cell +def _(az, idata_object, param_dict_pymc, plt): + az.plot_trace( + idata_object, lines=[(key_, {}, param_dict_pymc[key_]) for key_ in param_dict_pymc] + ) + + plt.tight_layout() + plt.gcf() + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + ### Regression via PyMC + + Finally to illustrate the usage of PyMC a little more elaborately, let us build a PyMC model with regression components. + """) + return + + +@app.cell +def _(): + from typing import Optional + + + def make_params_is_reg_vec( + reg_parameters: Optional[list] = None, parameter_names: Optional[list] = None + ): + """Make a list of Trues and Falses to indicate which parameters are vectors.""" + if (not isinstance(reg_parameters, list)) or ( + not isinstance(parameter_names, list) + ): + raise ValueError("Both reg_parameters and parameter_names should be lists") + + bool_list = [0] * len(parameter_names) + for param in reg_parameters: + bool_list[parameter_names.index(param)] = 1 + return bool_list + return (make_params_is_reg_vec,) + + +@app.cell +def _( + hssm, + make_distribution, + make_likelihood_callable, + make_params_is_reg_vec, + np, + v_intercept, + v_x, + v_y, + x, + y, +): + # Set up trial by trial parameters + v_intercept_pymc_reg = 0.3 + x_pymc_reg = np.random.uniform(-1, 1, size=1000) + v_x_pymc_reg = 0.8 + y_pymc_reg = np.random.uniform(-1, 1, size=1000) + v_y_pymc_reg = 0.3 + v_pymc_reg = v_intercept + (v_x * x) + (v_y * y) + + param_dict_pymc_reg = dict( + v_Intercept=v_intercept_pymc_reg, + v_x=v_x_pymc_reg, + v_y=v_y_pymc_reg, + v=v_pymc_reg, + a=1.5, + z=0.5, + t=0.1, + theta=0.0, + ) + + # base dataset + pymc_reg_data = hssm.simulate_data(model="ddm", theta=param_dict_pymc_reg, size=1) + + # Adding covariates into the datsaframe + pymc_reg_data["x"] = x + pymc_reg_data["y"] = y + + # Make the boolean vector for params_is_reg argument + bool_param_reg = make_params_is_reg_vec( + reg_parameters=["v"], + parameter_names=hssm.defaults.default_model_config["angle"]["list_params"], + ) + + angle_loglik_reg = make_likelihood_callable( + loglik="angle.onnx", + loglik_kind="approx_differentiable", + backend="jax", + params_is_reg=bool_param_reg, + ) + + ANGLE_reg = make_distribution( + "angle", + loglik=angle_loglik_reg, + list_params=hssm.defaults.default_model_config["angle"]["list_params"], + ) + return (pymc_reg_data,) + + +@app.cell +def _(ANGLE, pm, pymc_reg_data): + import pytensor.tensor as pt + + with pm.Model( + coords={ + "idx": pymc_reg_data.index, + "resp": ["rt", "response"], + "features": ["x", "y"], + } + ) as pymc_model_reg: + # Features + x_ = pm.Data("x", pymc_reg_data["x"].values, dims="idx") + y_ = pm.Data("y", pymc_reg_data["y"].values, dims="idx") + # Target + obs = pm.Data("obs", pymc_reg_data[["rt", "response"]].values, dims=("idx", "resp")) + + # Priors + a_reg = pm.Uniform("a", lower=0.5, upper=2.5) + z_reg = pm.Uniform("z", lower=0.01, upper=0.99) + t_reg = pm.Uniform("t", lower=0.0, upper=0.6) + theta_reg = pm.Uniform("theta", lower=-0.1, upper=1.0) + v_Intercept = pm.Uniform("v_Intercept", lower=-3, upper=3) + v_betas = pm.Normal("v_beta", mu=[0, 0], sigma=0.5, dims=("features")) + + # Regression equation + v = pm.Deterministic( + "v", v_Intercept + pt.stack([x_, y_], axis=1) @ v_betas, dims="idx" + ) + + # Our RV + angle_reg = ANGLE( + "angle", + v=v.squeeze(), + a=a_reg, + z=z_reg, + t=t_reg, + theta=theta_reg, + observed=obs, + dims=("idx", "resp"), + ) + return (pymc_model_reg,) + + +@app.cell +def _(pm, pymc_model_reg): + with pymc_model_reg: + idata_pymc_reg = pm.sample( + nuts_sampler="numpyro", idata_kwargs={"log_likelihood": True} + ) + return (idata_pymc_reg,) + + +@app.cell +def _(az, idata_pymc_reg): + az.plot_forest(idata_pymc_reg, var_names=["~v"]) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + All layers peeled back, the only limit in your modeling endeavors becomes the limit of the PyMC universe! + +

+ +
+ + +
Enjoy the exploration!
+ """) + return + + +@app.cell(hide_code=True) +def _(mo): + mo.md(r""" + # End + """) + return + + +if __name__ == "__main__": + app.run() diff --git a/docs/tutorials/public/ANGLE_pic.png b/docs/tutorials/public/ANGLE_pic.png new file mode 100644 index 000000000..be84cc81d Binary files /dev/null and b/docs/tutorials/public/ANGLE_pic.png differ diff --git a/docs/tutorials/public/ANGLE_with_params_pic.png b/docs/tutorials/public/ANGLE_with_params_pic.png new file mode 100644 index 000000000..ac42a6e04 Binary files /dev/null and b/docs/tutorials/public/ANGLE_with_params_pic.png differ diff --git a/docs/tutorials/public/DDM_only_v_pic.png b/docs/tutorials/public/DDM_only_v_pic.png new file mode 100644 index 000000000..beac829cd Binary files /dev/null and b/docs/tutorials/public/DDM_only_v_pic.png differ diff --git a/docs/tutorials/public/DDM_pic.png b/docs/tutorials/public/DDM_pic.png new file mode 100644 index 000000000..fe1a7f133 Binary files /dev/null and b/docs/tutorials/public/DDM_pic.png differ diff --git a/docs/tutorials/public/DDM_with_params_pic.png b/docs/tutorials/public/DDM_with_params_pic.png new file mode 100644 index 000000000..ecfe4bca9 Binary files /dev/null and b/docs/tutorials/public/DDM_with_params_pic.png differ diff --git a/docs/tutorials/public/HSSM_logo.png b/docs/tutorials/public/HSSM_logo.png new file mode 100644 index 000000000..7488d8e84 Binary files /dev/null and b/docs/tutorials/public/HSSM_logo.png differ diff --git a/docs/tutorials/public/arviz.png b/docs/tutorials/public/arviz.png new file mode 100644 index 000000000..6f04c9ee4 Binary files /dev/null and b/docs/tutorials/public/arviz.png differ diff --git a/docs/tutorials/public/bambi.png b/docs/tutorials/public/bambi.png new file mode 100644 index 000000000..69a2af71e Binary files /dev/null and b/docs/tutorials/public/bambi.png differ diff --git a/docs/tutorials/public/blackbox.png b/docs/tutorials/public/blackbox.png new file mode 100644 index 000000000..37c4c27ed Binary files /dev/null and b/docs/tutorials/public/blackbox.png differ diff --git a/docs/tutorials/public/hierarchical_modeling.png b/docs/tutorials/public/hierarchical_modeling.png new file mode 100644 index 000000000..2f20195c5 Binary files /dev/null and b/docs/tutorials/public/hierarchical_modeling.png differ diff --git a/docs/tutorials/public/onnx.png b/docs/tutorials/public/onnx.png new file mode 100644 index 000000000..d575d91f4 Binary files /dev/null and b/docs/tutorials/public/onnx.png differ diff --git a/docs/tutorials/public/pytensor_jax.png b/docs/tutorials/public/pytensor_jax.png new file mode 100644 index 000000000..68101e227 Binary files /dev/null and b/docs/tutorials/public/pytensor_jax.png differ diff --git a/pyproject.toml b/pyproject.toml index 996f7ac35..e2faa8647 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ dependencies = [ "hddm-wfpt>=0.1.6", "huggingface-hub>=0.34.0", "jaxonnxruntime>=0.3.0", + "marimo>=0.18.3", "numpyro>=0.19", "onnx>=1.16.0", "pandas>=2.2,<3",