Metadata-Version: 2.4
Name: pyhs3
Version: 0.4.2
Summary: pure-Python HS3 implementation with tensors and autodiff
Project-URL: Documentation, https://pyhs3.readthedocs.io/
Project-URL: Homepage, https://github.com/scipp-atlas/pyhs3
Project-URL: Bug Tracker, https://github.com/scipp-atlas/pyhs3/issues
Project-URL: Discussions, https://github.com/scipp-atlas/pyhs3/discussions
Project-URL: Changelog, https://github.com/scipp-atlas/pyhs3/releases
Author-email: Giordon Stark <kratsg@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 1 - Planning
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: hist>=2.7.0
Requires-Dist: numpy
Requires-Dist: pydantic>=2.12
Requires-Dist: pytensor>=2.33.0
Requires-Dist: rich
Requires-Dist: rustworkx
Requires-Dist: sympy
Provides-Extra: dev
Requires-Dist: pytest-cov>=3; extra == 'dev'
Requires-Dist: pytest>=9; extra == 'dev'
Requires-Dist: tbump>=6.7.0; extra == 'dev'
Provides-Extra: develop
Requires-Dist: furo>=2023.08.17; extra == 'develop'
Requires-Dist: hist[plot]>2.7.0; extra == 'develop'
Requires-Dist: intersphinx-registry>=0.2411.17; extra == 'develop'
Requires-Dist: ipywidgets; extra == 'develop'
Requires-Dist: matplotlib; extra == 'develop'
Requires-Dist: myst-parser>=0.13; extra == 'develop'
Requires-Dist: pydocstyle; extra == 'develop'
Requires-Dist: pydot; extra == 'develop'
Requires-Dist: pyhf>=0.7.6; extra == 'develop'
Requires-Dist: pytensor[jax]; extra == 'develop'
Requires-Dist: pytest-cov>=3; extra == 'develop'
Requires-Dist: pytest>=9; extra == 'develop'
Requires-Dist: scikit-hep-testdata>=0.5.7; extra == 'develop'
Requires-Dist: sphinx-autodoc-typehints; extra == 'develop'
Requires-Dist: sphinx-click; extra == 'develop'
Requires-Dist: sphinx-copybutton!=0.5.1,>=0.3.2; extra == 'develop'
Requires-Dist: sphinx-issues; extra == 'develop'
Requires-Dist: sphinx>=7.0; extra == 'develop'
Requires-Dist: sphinxcontrib-bibtex; extra == 'develop'
Requires-Dist: sphinxcontrib-doxylink; extra == 'develop'
Requires-Dist: sphinxcontrib-mermaid; extra == 'develop'
Requires-Dist: tbump>=6.7.0; extra == 'develop'
Provides-Extra: docs
Requires-Dist: furo>=2023.08.17; extra == 'docs'
Requires-Dist: hist[plot]>2.7.0; extra == 'docs'
Requires-Dist: intersphinx-registry>=0.2411.17; extra == 'docs'
Requires-Dist: ipywidgets; extra == 'docs'
Requires-Dist: matplotlib; extra == 'docs'
Requires-Dist: myst-parser>=0.13; extra == 'docs'
Requires-Dist: sphinx-autodoc-typehints; extra == 'docs'
Requires-Dist: sphinx-click; extra == 'docs'
Requires-Dist: sphinx-copybutton!=0.5.1,>=0.3.2; extra == 'docs'
Requires-Dist: sphinx-issues; extra == 'docs'
Requires-Dist: sphinx>=7.0; extra == 'docs'
Requires-Dist: sphinxcontrib-bibtex; extra == 'docs'
Requires-Dist: sphinxcontrib-doxylink; extra == 'docs'
Requires-Dist: sphinxcontrib-mermaid; extra == 'docs'
Provides-Extra: jax
Requires-Dist: pytensor[jax]; extra == 'jax'
Provides-Extra: test
Requires-Dist: pydocstyle; extra == 'test'
Requires-Dist: pydot; extra == 'test'
Requires-Dist: pyhf>=0.7.6; extra == 'test'
Requires-Dist: pytest-cov>=3; extra == 'test'
Requires-Dist: pytest>=9; extra == 'test'
Requires-Dist: scikit-hep-testdata>=0.5.7; extra == 'test'
Description-Content-Type: text/x-rst

..
  Comment: SPHINX-START

pure-python implementation of HS3
=================================

|GitHub Project| |GitHub Discussion|

|Docs from latest| |Docs from main|

|PyPI version| |Conda-forge version| |Supported Python versions| |PyPI platforms|

|Code Coverage| |CodeFactor| |pre-commit.ci Status| |Code style: black|

|Documentation Status| |GitHub Actions Status| |GitHub Actions Status: CI| |GitHub Actions Status: Docs| |GitHub Actions Status: Publish|

.. |GitHub Project| image:: https://img.shields.io/badge/GitHub--blue?style=social&logo=GitHub
   :target: https://github.com/scipp-atlas/pyhs3
.. |GitHub Discussion| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github
   :target: https://github.com/scipp-atlas/pyhs3/discussions
.. |Docs from latest| image:: https://img.shields.io/badge/docs-v0.4.2-blue.svg
   :target: https://pyhs3.readthedocs.io/en/v0.4.2/
.. |Docs from main| image:: https://img.shields.io/badge/docs-main-blue.svg
   :target: https://scipp-atlas.github.io/pyhs3
.. |PyPI version| image:: https://badge.fury.io/py/pyhs3.svg
   :target: https://badge.fury.io/py/pyhs3
.. |Conda-forge version| image:: https://img.shields.io/conda/vn/conda-forge/pyhs3.svg
   :target: https://prefix.dev/channels/conda-forge/packages/pyhs3
.. |Supported Python versions| image:: https://img.shields.io/pypi/pyversions/pyhs3.svg
   :target: https://pypi.org/project/pyhs3/
.. |PyPI platforms| image:: https://img.shields.io/pypi/pyversions/pyhs3
   :target: https://pypi.org/project/pyhs3/

.. |Code Coverage| image:: https://codecov.io/gh/scipp-atlas/pyhs3/graph/badge.svg?branch=main
   :target: https://app.codecov.io/gh/scipp-atlas/pyhs3?branch=main
.. |CodeFactor| image:: https://www.codefactor.io/repository/github/scipp-atlas/pyhs3/badge
   :target: https://www.codefactor.io/repository/github/scipp-atlas/pyhs3
.. |pre-commit.ci Status| image:: https://results.pre-commit.ci/badge/github/scipp-atlas/pyhs3/main.svg
   :target: https://results.pre-commit.ci/latest/github/scipp-atlas/pyhs3/main
   :alt: pre-commit.ci status
.. |Code style: black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
   :target: https://github.com/psf/black

.. |Documentation Status| image:: https://readthedocs.org/projects/pyhs3/badge/?version=latest
   :target: https://pyhs3.readthedocs.io/en/latest/?badge=latest
.. |GitHub Actions Status| image:: https://github.com/scipp-atlas/pyhs3/workflows/CI/badge.svg
   :target: https://github.com/scipp-atlas/pyhs3/actions
.. |GitHub Actions Status: CI| image:: https://github.com/scipp-atlas/pyhs3/actions/workflows/ci.yml/badge.svg
   :target: https://github.com/scipp-atlas/pyhs3/actions/workflows/ci.yml?query=branch%3Amain
.. |GitHub Actions Status: Docs| image:: https://github.com/scipp-atlas/pyhs3/actions/workflows/docs.yml/badge.svg
   :target: https://github.com/scipp-atlas/pyhs3/actions/workflows/docs.yml?query=branch%3Amain
.. |GitHub Actions Status: Publish| image:: https://github.com/scipp-atlas/pyhs3/actions/workflows/cd.yml/badge.svg
   :target: https://github.com/scipp-atlas/pyhs3/actions/workflows/cd.yml?query=branch%3Amain


Hello World
-----------

This section shows two ways to build the same statistical model and evaluate it: using PyHS3 Python objects directly, and using HS3 JSON-like dictionaries.

Hello World (Python)
~~~~~~~~~~~~~~~~~~~~~

This is how you use the ``pyhs3`` Python API to build a statistical model directly with objects:

.. code:: pycon

   >>> import pyhs3
   >>> import scipy
   >>> import math
   >>> import numpy as np
   >>> from pyhs3.distributions import GaussianDist
   >>> from pyhs3.parameter_points import ParameterPoint, ParameterSet
   >>> from pyhs3.axes import DomainAxis
   >>> from pyhs3.domains import ProductDomain
   >>> from pyhs3.metadata import Metadata
   >>>
   >>> # Create metadata
   >>> metadata = Metadata(hs3_version="0.2")
   >>>
   >>> # Create a Gaussian distribution
   >>> gaussian_dist = GaussianDist(name="model", x="x", mean="mu", sigma="sigma")
   >>>
   >>> # Create parameter points with values
   >>> param_points = ParameterSet(
   ...     name="default_values",
   ...     parameters=[
   ...         ParameterPoint(name="x", value=0.0),
   ...         ParameterPoint(name="mu", value=0.0),
   ...         ParameterPoint(name="sigma", value=1.0),
   ...     ],
   ... )
   >>>
   >>> # Create domain with parameter bounds
   >>> domain = ProductDomain(
   ...     name="default_domain",
   ...     axes=[
   ...         dict(name="x", min=-5.0, max=5.0),
   ...         dict(name="mu", min=-2.0, max=2.0),
   ...         dict(name="sigma", min=0.1, max=3.0),
   ...     ],
   ... )
   >>>
   >>> # Build workspace from objects
   >>> ws = pyhs3.Workspace(
   ...     metadata=metadata,
   ...     distributions=[gaussian_dist],
   ...     parameter_points=[param_points],
   ...     domains=[domain],
   ... )
   >>> model = ws.model(0)
   <BLANKLINE>
   >>> print(model)
   Model(
       mode: FAST_RUN
       parameters: 3 (sigma, mu, x)
       distributions: 1 (model)
       functions: 0 ()
   )
   >>> parameters = {par.name: np.array(par.value) for par in model.parameterset}
   >>> result = -2 * model.logpdf("model", **parameters)
   >>> print(f"parameters: {parameters}")
   parameters: {'x': array(0.), 'mu': array(0.), 'sigma': array(1.)}
   >>> print(f"nll: {result:.8f}")
   nll: 1.83787707
   >>>
   >>> # Serialize workspace back to dictionary for saving/sharing
   >>> workspace_dict = ws.model_dump()
   >>> print("Serialized workspace keys:", list(workspace_dict.keys()))
   Serialized workspace keys: ['metadata', 'distributions', 'functions', 'domains', 'parameter_points', 'data', 'likelihoods', 'analyses', 'misc']

Hello World (HS3)
~~~~~~~~~~~~~~~~~~

This is the same model built using HS3 JSON-like dictionary format:

.. code:: pycon

   >>> import pyhs3
   >>> import scipy
   >>> import math
   >>> import numpy as np
   >>> workspace_data = {
   ...     "metadata": {"hs3_version": "0.2"},
   ...     "distributions": [
   ...         {
   ...             "name": "model",
   ...             "type": "gaussian_dist",
   ...             "x": "x",
   ...             "mean": "mu",
   ...             "sigma": "sigma",
   ...         }
   ...     ],
   ...     "parameter_points": [
   ...         {
   ...             "name": "default_values",
   ...             "parameters": [
   ...                 {"name": "x", "value": 0.0},
   ...                 {"name": "mu", "value": 0.0},
   ...                 {"name": "sigma", "value": 1.0},
   ...             ],
   ...         }
   ...     ],
   ...     "domains": [
   ...         {
   ...             "name": "default_domain",
   ...             "type": "product_domain",
   ...             "axes": [
   ...                 {"name": "x", "min": -5.0, "max": 5.0},
   ...                 {"name": "mu", "min": -2.0, "max": 2.0},
   ...                 {"name": "sigma", "min": 0.1, "max": 3.0},
   ...             ],
   ...         }
   ...     ],
   ... }
   >>> ws = pyhs3.Workspace(**workspace_data)
   >>> model = ws.model(0)
   <BLANKLINE>
   >>> print(model)
   Model(
       mode: FAST_RUN
       parameters: 3 (sigma, mu, x)
       distributions: 1 (model)
       functions: 0 ()
   )
   >>> parameters = {par.name: np.array(par.value) for par in model.parameterset}
   >>> result = -2 * model.logpdf("model", **parameters)
   >>> print(f"parameters: {parameters}")
   parameters: {'x': array(0.), 'mu': array(0.), 'sigma': array(1.)}
   >>> print(f"nll: {result:.8f}")
   nll: 1.83787707
   >>> result_scipy = -2 * math.log(scipy.stats.norm.pdf(0, loc=0, scale=1))
   >>> print(f"nll: {result_scipy:.8f}")
   nll: 1.83787707
   >>>
   >>> # Round-trip: serialize workspace back to dictionary
   >>> serialized_dict = ws.model_dump()
   >>> print("Round-trip successful:", serialized_dict["metadata"]["hs3_version"])
   Round-trip successful: 0.2
   >>>
   >>> # Can recreate workspace from serialized dictionary
   >>> ws_roundtrip = pyhs3.Workspace(**serialized_dict)
   >>> model_roundtrip = ws_roundtrip.model(0)
   <BLANKLINE>
   >>> print("Round-trip model:", model_roundtrip.parameterset.name)
   Round-trip model: default_values
