{"id":22144662,"url":"https://github.com/bat/batty","last_synced_at":"2025-06-17T08:34:50.696Z","repository":{"id":47122002,"uuid":"454796666","full_name":"bat/batty","owner":"bat","description":"BAT to Python","archived":false,"fork":false,"pushed_at":"2022-09-12T19:42:41.000Z","size":1380,"stargazers_count":9,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-27T16:48:46.106Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-02T14:00:52.000Z","updated_at":"2024-08-12T05:33:58.000Z","dependencies_parsed_at":"2022-09-01T04:12:27.719Z","dependency_job_id":null,"html_url":"https://github.com/bat/batty","commit_stats":null,"previous_names":["philippeller/batty"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bat/batty","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bat%2Fbatty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bat%2Fbatty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bat%2Fbatty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bat%2Fbatty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bat","download_url":"https://codeload.github.com/bat/batty/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bat%2Fbatty/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260322743,"owners_count":22991880,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-01T22:30:23.539Z","updated_at":"2025-06-17T08:34:50.644Z","avatar_url":"https://github.com/bat.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003e \u003cimg style=\"height:5em;\" alt=\"batty\" src=\"https://raw.githubusercontent.com/philippeller/batty/main/batty_logo.svg\"/\u003e \u003c/h1\u003e \n\n# BAT to Python (batty)\n\nA small python interface to the Bayesian Analysis Toolkit (BAT.jl) https://github.com/bat/BAT.jl\n\n\n* Please check out the minimal example to get started [below](#minimal-example)\n* To understand how to define a prior + likelihood, please read [this](#specifying-priors-and-likelihoods)\n* For experimental support of gradients, see [this](#hmc-with-gradients)\n\n# Quick Start\n\n## Installation\n\nThere are two parts to an installation, one concerning the python side, and one the julia side:\n\n* Python: `pip install batty`\n\n* Julia: `import Pkg; Pkg.add([\"PyJulia\", \"DensityInterface\", \"Distributions\", \"ValueShapes\", \"TypedTables\", \"ArraysOfArrays\", \"ChainRulesCore\", \"BAT\"])`\n\nsampler.findmodeExample\n\nThe code below is showing a minimal example:\n* using a gaussian likelihood and a uniform prior\n* generating samples via Metropolis-Hastings\n* plotting the resulting sampes\n* \u003cs\u003eestimating the integral value via BridgeSampling\u003c/s\u003e\n\n\n```python\n%load_ext autoreload\n%autoreload 2\n```\n\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\n%matplotlib inline\nfrom batty import BAT_sampler, BAT, Distributions, jl\nimport juliacall\n```\n\n\n```python\nsampler = BAT_sampler(llh=lambda x : -0.5 * x**2, prior_specs=Distributions.Uniform(-3, 3))\nsampler.sample();\nsampler.corner();\n```\n\n\n    \n![png](https://raw.githubusercontent.com/bat/batty/main/README_files/README_4_0.png)\n    \n\n\n# Usage\n\n## Using Different Algotihms\n\nThere are a range of algorihtms available within BAT, and those can be further customized via arguments. Here are just a few examples:\n\n### MCMC Sampling:\n\n\n```python\nresults = {}\n```\n\n* Metropolis-Hastings:\n\n\n```python\nresults['Metropolis-Hastings'] = sampler.sample(strategy=BAT.MCMCSampling(nsteps=10_000, nchains=2))\n```\n\n* Metropolis-Hastings with Accept-Reject weighting:\n\n\n```python\nresults['Accept-Reject Weighting'] = sampler.sample(strategy=BAT.MCMCSampling(mcalg=BAT.MetropolisHastings(weighting=BAT.ARPWeighting()), nsteps=10_000, nchains=2))\n```\n\n* Prior Importance Sampling:\n\n\n```python\nresults['Prior Importance Sampling'] = sampler.sample(strategy=BAT.PriorImportanceSampler(nsamples=10_000))\n```\n\n* Sobol Sampler:\n\n\n```python\nresults['Sobol Quasi Random Numbers'] = sampler.sample(strategy=BAT.SobolSampler(nsamples=10_000))\n```\n\n* Grid Sampler:\n\n\n```python\nresults['Grid Points'] = sampler.sample(strategy=BAT.GridSampler(ppa=1000))\n```\n\nPlotting the different results:\n\n\n```python\nfig = plt.figure(figsize=(9,6))\nbins=np.linspace(-3, 3, 100)\nfor key, item in results.items():\n    plt.hist(item.v, weights=item.weight, bins=bins, density=True, histtype=\"step\", label=key);\nplt.legend()\n```\n\n\n\n\n    \u003cmatplotlib.legend.Legend at 0x7fdfc061a220\u003e\n\n\n\n\n    \n![png](https://raw.githubusercontent.com/bat/batty/main/README_files/README_19_1.png)\n    \n\n\n# Specifying Priors and Likelihoods\n\nPriors are specified via Julia `Distributions`, multiple Dimensions can be defined via a `dict`, where the `key` is the dimension name and the value the distribution, or as a list in case flat vectors with paraeter names are used.\n\nBelow the example *with* parameter names\n\n\n```python\ns = np.array([[0.25, 0.4], [0.9, 0.75]])\nprior_specs = {'a' : Distributions.Uniform(-3,3), 'b' : Distributions.MvNormal(np.array([1.,1.]), jl.Array(s@s.T))}\n```\n\nThe log-likelihood (`llh`) can be any python callable, that returns the log-likelihood values. The first argument to the function is the object with paramneter values, here `x`. If the prior is simple (i.e. like in the example in the beginning, `x` is directly the parameter value). If the prior is specified via a `dict`, then `x` contains a field per parameter with the value.\nAny additional `args` to the llh can be given in the sampler, such as here `d` for data:\n\n\n```python\ndef llh(x, d):\n    return -0.5 * ((x.b[0] - d[0])**2 + (x.b[1] - d[1])**2/4) - x.a\n```\n\nOr alternatively *without* parameter names (this will result in a flat vector):\n\n\n```python\n# prior_specs = [Distributions.Uniform(-3,3), Distributions.MvNormal(np.array([1.,1.]), jl.Array(s@s.T))]\n# def llh(x, d):\n#     return -0.5 * ((x[1] - d[0])**2 + (x[2] - d[1])**2/4) - x[0]\n```\n\n\n```python\nd = [-1, 1]\n```\n\n\n```python\nsampler = BAT_sampler(llh=llh, prior_specs=prior_specs, llh_args=(d,))\n```\n\nLet us generate a few samples:\n\n\n```python\nsampler.sample(strategy=BAT.MCMCSampling(nsteps=10_000, nchains=2));\n```\n\n### Some interface to plotting tools are available\n\n* The **G**reat **T**riangular **C**onfusion (GTC) plot:\n\n\n```python\nsampler.gtc(figureSize=8, customLabelFont={'size':14}, customTickFont={'size':10});\n```\n\n    findfont: Font family ['Arial'] not found. Falling back to DejaVu Sans.\n    findfont: Font family ['Arial'] not found. Falling back to DejaVu Sans.\n\n\n\n    \n![png](https://raw.githubusercontent.com/bat/batty/main/README_files/README_31_1.png)\n    \n\n\n* The corner plot:\n\n\n```python\nsampler.corner(color='green');\n```\n\n\n    \n![png](https://raw.githubusercontent.com/bat/batty/main/README_files/README_33_0.png)\n    \n\n\n## HMC with Gradients\n\nFirst let's look at an example using flat vectors:\n\n\n```python\nllh = lambda x : -0.5 * np.dot(x, x)\ngrad = lambda x : -x\nsampler = BAT_sampler(llh=llh, prior_specs=[Distributions.Uniform(-3, 3),], grad=grad, )\n\n# Or alternatively:\n# llh_and_grad = lambda x: (-0.5 * np.dot(x, x), -x)\n# sampler = BAT_sampler(llh=llh, prior_specs=[Distributions.Uniform(-3, 3),], llh_and_grad=llh_and_grad)\n```\n\n\n```python\nsampler.sample(strategy=BAT.MCMCSampling(mcalg=BAT.HamiltonianMC()));\nsampler.corner();\n```\n\n\n    \n![png](https://raw.githubusercontent.com/bat/batty/main/README_files/README_36_0.png)\n    \n\n\n\n```python\nsampler.findmode()\n```\n\n\n\n\n    (result = [0.00012339715218110216], result_trafo = [0.00012339715218110216], trafo = identity ∘ identity, trace_trafo = NamedTuple{(:v,), Tuple{Vector{Float64}}}[(v = [2.5003780712463737],), (v = [2.5003780712463737],), (v = [1.225189035623187],), (v = [-0.04999999999999982],), (v = [-0.04999999999999982],), (v = [0.02969931472644935],), (v = [0.009774486044837057],), (v = [0.004793278874433983],), (v = [-0.00018792829596908991],), (v = [-0.00018792829596908991],)], info = Results of Optimization Algorithm\n     * Algorithm: Nelder-Mead\n     * Starting Point: [2.5003780712463737]\n     * Maximizer: [0.00012339715218110216]\n     * Maximum: -1.791759e+00\n     * Iterations: 9\n     * Convergence: true\n       *  √(Σ(yᵢ-ȳ)²)/n \u003c 1.0e-08: true\n       * Reached Maximum Number of Iterations: false\n     * Objective Calls: 21, optargs = (algorithm = NelderMeadOpt{DoNotTransform, InitFromTarget}\n      trafo: DoNotTransform DoNotTransform()\n      init: InitFromTarget InitFromTarget()\n    ,), kwargs = NamedTuple())\n\n\n\n\n```python\nsampler.findmode(BAT.LBFGSOpt())\n```\n\n\n\n\n    (result = [4.654232554912596e-11], result_trafo = [1.9443995892542976e-11], trafo = DistributionTransform(BAT.StandardMvNormal{Float64}(_dim=1), ValueShapes.UnshapedNTD{NamedTupleDist{(:p0,), Tuple{Uniform{Float64}}, Tuple{ValueAccessor{ScalarShape{Real}}}, NamedTuple}}(\n    shaped: NamedTupleDist((p0 = Uniform{Float64}(a=-3.0, b=3.0),))\n    )\n    ), trace_trafo = NamedTuple{(:v, :logd, :grad_logd), Tuple{Vector{Float64}, Float64, Vector{Float64}}}[(v = [-0.6587150350244174], logd = -2.21599390599995, grad_logd = [3.4906771750114083]), (v = [0.23765672881802102], logd = -1.105977679254204, grad_logd = [-1.5490570022891985]), (v = [0.001027968548749203], logd = -0.9189420888411827, grad_logd = [-0.006917790331040427]), (v = [1.9443995892542976e-11], logd = -0.9189385332046728, grad_logd = [-1.3085020483106803e-10])], info = Results of Optimization Algorithm\n     * Algorithm: L-BFGS\n     * Starting Point: [-0.6587150350244174]\n     * Maximizer: [1.9443995892542976e-11]\n     * Maximum: -9.189385e-01\n     * Iterations: 3\n     * Convergence: true\n       * |x - x'| ≤ 0.0e+00: false \n         |x - x'| = 1.03e-03 \n       * |f(x) - f(x')| ≤ 0.0e+00 |f(x)|: false\n         |f(x) - f(x')| = 3.87e-06 |f(x)|\n       * |g(x)| ≤ 1.0e-08: true \n         |g(x)| = 1.31e-10 \n       * Stopped by an decreasing objective: false\n       * Reached Maximum Number of Iterations: false\n     * Objective Calls: 8\n     * Gradient Calls: 8, optargs = (algorithm = LBFGSOpt{PriorToGaussian, InitFromTarget}\n      trafo: PriorToGaussian PriorToGaussian()\n      init: InitFromTarget InitFromTarget()\n    ,), kwargs = NamedTuple())\n\n\n\nOr with parameter names (here the gradient function needs to be able to return named tuples!):\n\n\n```python\nfrom collections import namedtuple\nprior = {'a':Distributions.Uniform(-3, 3), 'b': Distributions.Cauchy()}\nllh = lambda x : -0.5 * x.a**2 + x.b\n    \nv = namedtuple('v', 'a b')\n\ndef grad(x):\n    return v(a = -x.a, b=1.)\n```\n\n\n```python\nsampler = BAT_sampler(llh=llh, prior_specs=prior, grad=grad, )\n```\n\n\n```python\nsampler.findmode(BAT.LBFGSOpt())\n```\n\n\n\n\n    (result = (a = -2.774359870100099, b = 1.3748233863972102e15), result_trafo = [-1.779160961167169, 8.292361075813613], trafo = DistributionTransform(BAT.StandardMvNormal{Float64}(_dim=2), NamedTupleDist{(:a, :b)}(…)), trace_trafo = NamedTuple{(:v, :logd, :grad_logd), Tuple{Vector{Float64}, Float64, Vector{Float64}}}[(v = [-1.2587536135732944, -1.7223257853024079], logd = -14.379301063532187, grad_logd = [3.8337762241448323, 17.76625871401564]), (v = [0.7635387123418593, 7.649261536696631], logd = 3.1433087080088902e13, grad_logd = [-3.740473440116247, 2.4394275174682822e14]), (v = [0.7635382664426248, 2.908025324267957e7], logd = 9.519928220680188e14, grad_logd = [-3.740472581583452, -2.908025324267957e7]), (v = [-2.314123355320277, 5.153011945433553e6], logd = 1.361546620342311e15, grad_logd = [2.797466899034834, -5.153011945433553e6]), (v = [0.35941433317089366, 1.2642107455691537e6], logd = 1.3740242719926018e15, grad_logd = [-2.2491330410508144, -1.2642107455691537e6]), (v = [-1.9095295505340744, 314587.89939169737], logd = 1.3747739036239808e15, grad_logd = [3.0041932888082328, -314587.89939169737]), (v = [1.0862253500010608, 78558.91268333828], logd = 1.3748203006458245e15, grad_logd = [-3.962855864264687, -78558.91268333828]), (v = [-2.8774313584103415, 19637.15728740389], logd = 1.3748231935882265e15, grad_logd = [2.991336448955899, -19637.15728740389]), (v = [0.11302692230648326, 4911.984602697699], logd = 1.374823374333412e15, grad_logd = [-0.7551326673718901, -4911.984602697699]), (v = [-0.6418462549610223, 1231.0062794741957], logd = 1.374823385639519e15, grad_logd = [3.4413763327035025, -1231.0062794741957]), (v = [2.7908181536295023, 310.85380281622554], logd = 1.374823386348885e15, grad_logd = [-2.936232052477065, -310.85380281622554]), (v = [-0.1160917967360473, 80.96146595642469], logd = 1.374823386393931e15, grad_logd = [0.7753005443326515, -80.96146595642469]), (v = [0.638783237264492, 23.19797499535367], logd = 1.3748233863969382e15, grad_logd = [-3.432151104065695, -23.19797499535367]), (v = [-2.175796434545086, 9.380111523275037], logd = 1.3748233863971578e15, grad_logd = [2.829155556024242, -9.380111523275037])], info = Results of Optimization Algorithm\n     * Algorithm: L-BFGS\n     * Starting Point: [-1.2587536135732944,-1.7223257853024079]\n     * Maximizer: [-1.779160961167169,8.292361075813613]\n     * Maximum: 1.374823e+15\n     * Iterations: 14\n     * Convergence: false\n       * |x - x'| ≤ 0.0e+00: false \n         |x - x'| = 1.09e+00 \n       * |f(x) - f(x')| ≤ 0.0e+00 |f(x)|: false\n         |f(x) - f(x')| = 8.00e-15 |f(x)|\n       * |g(x)| ≤ 1.0e-08: false \n         |g(x)| = 8.29e+00 \n       * Stopped by an decreasing objective: false\n       * Reached Maximum Number of Iterations: false\n     * Objective Calls: 204\n     * Gradient Calls: 204, optargs = (algorithm = LBFGSOpt{PriorToGaussian, InitFromTarget}\n      trafo: PriorToGaussian PriorToGaussian()\n      init: InitFromTarget InitFromTarget()\n    ,), kwargs = NamedTuple())\n\n\n\nOr a simple llh with no vector nor tuple:\n\n\n```python\nllh = lambda x : -0.5 * np.dot(x, x)\ngrad = lambda x : -x\nsampler = BAT_sampler(llh=llh, prior_specs=Distributions.Uniform(-3, 3), grad=grad, )\n```\n\n\n```python\nsampler.findmode(BAT.LBFGSOpt())\n```\n\n\n\n\n    (result = -4.440892098500626e-16, result_trafo = [-9.599424391232986e-17], trafo = Base.Fix2{typeof(unshaped), ScalarShape{Real}}(ValueShapes.unshaped, ScalarShape{Real}()) ∘ DistributionTransform(BAT.StandardUvNormal{Float64}(), Uniform{Float64}(a=-3.0, b=3.0)), trace_trafo = NamedTuple{(:v, :logd, :grad_logd), Tuple{Vector{Float64}, Float64, Vector{Float64}}}[(v = [0.19839644385007574], logd = -1.0499145108671066, grad_logd = [-1.3057027231751668]), (v = [-0.1257368729646586], logd = -0.9718972381306173, grad_logd = [0.8386048377455525]), (v = [-9.167475784471746e-6], logd = -0.9189385334874584, grad_logd = [6.169324290536366e-5]), (v = [-9.599424391232986e-17], logd = -0.9189385332046728, grad_logd = [1.1589900163878561e-15])], info = Results of Optimization Algorithm\n     * Algorithm: L-BFGS\n     * Starting Point: [0.19839644385007574]\n     * Maximizer: [-9.599424391232986e-17]\n     * Maximum: -9.189385e-01\n     * Iterations: 3\n     * Convergence: true\n       * |x - x'| ≤ 0.0e+00: false \n         |x - x'| = 9.17e-06 \n       * |f(x) - f(x')| ≤ 0.0e+00 |f(x)|: false\n         |f(x) - f(x')| = 3.08e-10 |f(x)|\n       * |g(x)| ≤ 1.0e-08: true \n         |g(x)| = 1.16e-15 \n       * Stopped by an decreasing objective: false\n       * Reached Maximum Number of Iterations: false\n     * Objective Calls: 7\n     * Gradient Calls: 7, optargs = (algorithm = LBFGSOpt{PriorToGaussian, InitFromTarget}\n      trafo: PriorToGaussian PriorToGaussian()\n      init: InitFromTarget InitFromTarget()\n    ,), kwargs = NamedTuple())\n\n\n\n\n```python\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbat%2Fbatty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbat%2Fbatty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbat%2Fbatty/lists"}