diff --git a/.gitignore b/.gitignore index f57e109d9..096b0504a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ run_outputs* data .data results +docs/source/examples/ +docs/source/tutorials/ examples/*/processed examples/*/results examples/*/raw diff --git a/docs/source/_static/img/pyro_logo_wide.png b/docs/source/_static/img/pyro_logo_wide.png new file mode 100644 index 000000000..cdd87ba01 Binary files /dev/null and b/docs/source/_static/img/pyro_logo_wide.png differ diff --git a/docs/source/_templates/breadcrumbs.html b/docs/source/_templates/breadcrumbs.html new file mode 100644 index 000000000..c49d12ad3 --- /dev/null +++ b/docs/source/_templates/breadcrumbs.html @@ -0,0 +1,28 @@ +{%- extends "sphinx_rtd_theme/breadcrumbs.html" %} + +{% set display_vcs_links = display_vcs_links if display_vcs_links is defined else True %} + +{% block breadcrumbs_aside %} +
  • + {% if hasdoc(pagename) and display_vcs_links %} + {% if display_github %} + {% if check_meta and 'github_url' in meta %} + + {{ _('Edit on GitHub') }} + {% else %} + {% if 'examples/index' in pagename %} + {{ _('Edit on GitHub') }} + {% elif 'examples/' in pagename %} + {{ _('Edit on GitHub') }} + {% else %} + {{ _('Edit on GitHub') }} + {% endif %} + {% endif %} + {% elif show_source and source_url_prefix %} + {{ _('View page source') }} + {% elif show_source and has_source and sourcename %} + {{ _('View page source') }} + {% endif %} + {% endif %} +
  • +{% endblock %} diff --git a/docs/source/conf.py b/docs/source/conf.py index 73949c96e..42bfdb1ed 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,7 +1,9 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +import glob import os +import shutil import sys import sphinx_rtd_theme @@ -32,8 +34,17 @@ # The short X.Y version version = u"0.0" + +if "READTHEDOCS" not in os.environ: + # if developing locally, use funsor.__version__ as version + from funsor import __version__ # noqaE402 + + version = __version__ + + html_context = {"github_version": "master"} + # The full version, including alpha/beta/rc tags -release = u"0.0" +release = version # -- General configuration --------------------------------------------------- @@ -46,11 +57,13 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + "nbsphinx", "sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.mathjax", "sphinx.ext.viewcode", + "sphinx_gallery.gen_gallery", ] # Disable documentation inheritance so as to avoid inheriting @@ -76,7 +89,13 @@ # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = ".rst" +source_suffix = [".rst", ".ipynb"] + +# do not execute cells +nbsphinx_execute = "never" + +# Don't add .txt suffix to source files: +html_sourcelink_suffix = "" # The master toctree document. master_doc = "index" @@ -91,7 +110,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . -exclude_patterns = [] +exclude_patterns = [".ipynb_checkpoints", "examples/*ipynb", "examples/*py"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" @@ -100,6 +119,73 @@ # do not prepend module name to functions add_module_names = False + +# This is processed by Jinja2 and inserted before each notebook +nbsphinx_prolog = r""" +{% set docname = 'tutorials/' + env.doc2path(env.docname, base=None).split('/')[-1] %} +:github_url: https://github.com/pyro-ppl/funsor/blob/master/{{ docname }} + +.. raw:: html + +
    + Interactive online version: + + + Open In Colab + + +
    +""" # noqa: E501 + + +# -- Copy notebook files +# NB: tutorials and examples can be added to `index.rst` file using the paths +# tutorials/foo +# examples/foo +# without extensions .ipynb or .py +# TODO: find a solution for an example subfolder, e.g. examples/mixed_hmm folder +# +# To add thumbnail images for tutorials/examples in funsor docs, using +# .. nbgallery:: instead of .. toctree:: and add png thumnail images +# with corresponding names in _static/img/tutorials or _static/img/examples folders. +# For example, we can add minipyro.png to _static/img/examples/ folder. + +if not os.path.exists("tutorials"): + os.makedirs("tutorials") + +for src_file in glob.glob("../../tutorials/*.ipynb"): + dst_file = os.path.join("tutorials", src_file.split("/")[-1]) + shutil.copy(src_file, "tutorials/") + + +# -- Convert scripts to notebooks + +sphinx_gallery_conf = { + "examples_dirs": ["../../examples"], + "gallery_dirs": ["examples"], + # only execute files beginning with plot_ + "filename_pattern": "/plot_", + # 'ignore_pattern': '(minipyro|__init__)', + # not display Total running time of the script because we do not execute it + "min_reported_time": 1, +} + + +# -- Add thumbnails images + +nbsphinx_thumbnails = {} + +for src_file in glob.glob("../../tutorials/*.ipynb") + glob.glob("../../examples/*.py"): + toctree_path = "tutorials/" if src_file.endswith("ipynb") else "examples/" + filename = os.path.splitext(src_file.split("/")[-1])[0] + png_path = "_static/img/" + toctree_path + filename + ".png" + # use Pyro logo if not exist png file + if not os.path.exists(png_path): + png_path = "_static/img/pyro_logo_wide.png" + nbsphinx_thumbnails[toctree_path + filename] = png_path + + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for @@ -157,7 +243,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "Funsor.tex", u"Funsor Documentation", u"Uber AI Labs", "manual"), + (master_doc, "Funsor.tex", u"Funsor Documentation", u"Uber AI Labs", "manual") ] # -- Options for manual page output ------------------------------------------ @@ -180,7 +266,7 @@ "Funsor", "Functional analysis + tensors + symbolic algebra.", "Miscellaneous", - ), + ) ] diff --git a/docs/source/index.rst b/docs/source/index.rst index 16b7f6252..230a68b5d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -32,6 +32,20 @@ Funsor is a tensor-like library for functions and distributions minipyro einsum +.. toctree:: + :maxdepth: 1 + :caption: Tutorials and Examples + :name: tutorials-and-examples + + examples/discrete_hmm + examples/eeg_slds + examples/kalman_filter + examples/minipyro + examples/pcfg + examples/sensor + examples/slds + examples/vae + Indices and tables ================== diff --git a/examples/README.rst b/examples/README.rst new file mode 100644 index 000000000..ab2ec2739 --- /dev/null +++ b/examples/README.rst @@ -0,0 +1,5 @@ +Code Examples +============= + +Please check out `Sphinx-Gallery syntax `_ +for how to structure Python scripts to generate nicely rendered example pages. diff --git a/examples/discrete_hmm.py b/examples/discrete_hmm.py index f2bfc8fea..8618f9bd0 100644 --- a/examples/discrete_hmm.py +++ b/examples/discrete_hmm.py @@ -1,6 +1,12 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +""" +Example: Discrete HMM +===================== + +""" + import argparse from collections import OrderedDict diff --git a/examples/eeg_slds.py b/examples/eeg_slds.py index e826912c7..05f20b0c5 100644 --- a/examples/eeg_slds.py +++ b/examples/eeg_slds.py @@ -2,6 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 """ +Example: Switching Linear Dynamical System EEG +============================================== + We use a switching linear dynamical system [1] to model a EEG time series dataset. For inference we use a moment-matching approximation enabled by `funsor.interpretation(funsor.terms.moment_matching)`. @@ -10,6 +13,7 @@ [1] Anderson, B., and J. Moore. "Optimal filtering. Prentice-Hall, Englewood Cliffs." New Jersey (1979). """ + import argparse import time from collections import OrderedDict diff --git a/examples/kalman_filter.py b/examples/kalman_filter.py index f839566c0..1782edc3a 100644 --- a/examples/kalman_filter.py +++ b/examples/kalman_filter.py @@ -1,6 +1,12 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +""" +Example: Kalman Filter +====================== + +""" + import argparse import torch diff --git a/examples/minipyro.py b/examples/minipyro.py index ff022f0f5..15cae9847 100644 --- a/examples/minipyro.py +++ b/examples/minipyro.py @@ -1,6 +1,12 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +""" +Example: Mini Pyro +================== + +""" + import argparse import torch diff --git a/examples/mixed_hmm/model.py b/examples/mixed_hmm/model.py index 4baabea8f..b79fcc00e 100644 --- a/examples/mixed_hmm/model.py +++ b/examples/mixed_hmm/model.py @@ -24,10 +24,7 @@ def __init__(self, config): def initialize_params(self): # dictionary of guide random effect parameters - params = { - "eps_g": {}, - "eps_i": {}, - } + params = {"eps_g": {}, "eps_i": {}} N_state = self.config["sizes"]["state"] @@ -153,8 +150,7 @@ def initialize_params(self): ) params["eps_g"]["scale"] = Tensor( - torch.ones((N_state, N_state)), - OrderedDict([("y_prev", Bint[N_state])]), + torch.ones((N_state, N_state)), OrderedDict([("y_prev", Bint[N_state])]) ) # initialize individual-level random effect parameters @@ -164,12 +160,7 @@ def initialize_params(self): params["e_i"]["probs"] = Tensor( pyro.param( "probs_e_i", - lambda: torch.randn( - ( - N_c, - N_v, - ) - ).abs(), + lambda: torch.randn((N_c, N_v)).abs(), constraint=constraints.simplex, ), OrderedDict([("g", Bint[N_c])]), # different value per group @@ -329,8 +320,7 @@ def __call__(self): # initialize gamma to uniform gamma = Tensor( - torch.zeros((N_state, N_state)), - OrderedDict([("y_prev", Bint[N_state])]), + torch.zeros((N_state, N_state)), OrderedDict([("y_prev", Bint[N_state])]) ) N_v = self.config["sizes"]["random"] diff --git a/examples/pcfg.py b/examples/pcfg.py index 82bfd1047..fe5fd5144 100644 --- a/examples/pcfg.py +++ b/examples/pcfg.py @@ -1,6 +1,12 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +""" +Example: PCFG +============= + +""" + import argparse import math from collections import OrderedDict diff --git a/examples/sensor.py b/examples/sensor.py index 16af482ae..3e23e4dca 100644 --- a/examples/sensor.py +++ b/examples/sensor.py @@ -1,6 +1,12 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +""" +Example: Biased Kalman Filter +============================= + +""" + import argparse import itertools import math diff --git a/examples/slds.py b/examples/slds.py index 10aaed8ff..b9f36eb73 100644 --- a/examples/slds.py +++ b/examples/slds.py @@ -1,6 +1,12 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +""" +Example: Switching Linear Dynamical System +========================================== + +""" + import argparse import torch @@ -19,10 +25,7 @@ def main(args): ) trans_noise = funsor.Tensor( torch.tensor( - [ - 0.1, # low noise component - 1.0, # high noisy component - ], + [0.1, 1.0], # low noise component # high noisy component requires_grad=True, ) ) diff --git a/examples/vae.py b/examples/vae.py index 3f938e34e..343d413e4 100644 --- a/examples/vae.py +++ b/examples/vae.py @@ -1,6 +1,12 @@ # Copyright Contributors to the Pyro project. # SPDX-License-Identifier: Apache-2.0 +""" +Example: VAE MNIST +================== + +""" + import argparse import os from collections import OrderedDict diff --git a/funsor/__init__.py b/funsor/__init__.py index 4372f1bad..ec70808cc 100644 --- a/funsor/__init__.py +++ b/funsor/__init__.py @@ -43,7 +43,10 @@ testing, ) +__version__ = "0.4.0" + __all__ = [ + "__version__", "Array", "Bint", "Cat", diff --git a/scripts/update_headers.py b/scripts/update_headers.py index 8faa7dd8b..37a78522d 100644 --- a/scripts/update_headers.py +++ b/scripts/update_headers.py @@ -8,10 +8,7 @@ root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) blacklist = ["/build/", "/dist/"] -file_types = [ - ("*.py", "# {}"), - ("*.cpp", "// {}"), -] +file_types = [("*.py", "# {}"), ("*.cpp", "// {}")] parser = argparse.ArgumentParser() parser.add_argument("--check", action="store_true") diff --git a/setup.py b/setup.py index e94d4e205..d0b6de0e0 100644 --- a/setup.py +++ b/setup.py @@ -27,27 +27,13 @@ description="A tensor-like library for functions and distributions", packages=find_packages(include=["funsor", "funsor.*"]), url="https://github.com/pyro-ppl/funsor", - project_urls={ - "Documentation": "https://funsor.pyro.ai", - }, + project_urls={"Documentation": "https://funsor.pyro.ai"}, author="Uber AI Labs", python_requires=">=3.6", - install_requires=[ - "makefun", - "multipledispatch", - "numpy>=1.7", - "opt_einsum>=2.3.2", - ], + install_requires=["makefun", "multipledispatch", "numpy>=1.7", "opt_einsum>=2.3.2"], extras_require={ - "torch": [ - "pyro-ppl>=1.5.2", - "torch>=1.7.0", - ], - "jax": [ - "numpyro>=0.2.4", - "jax>=0.1.57", - "jaxlib>=0.1.37", - ], + "torch": ["pyro-ppl>=1.5.2", "torch>=1.7.0"], + "jax": ["numpyro>=0.2.4", "jax>=0.1.57", "jaxlib>=0.1.37"], "test": [ "black", "flake8", @@ -63,11 +49,13 @@ "black", "flake8", "isort>=5.0", + "nbsphinx", "pandas", "pytest==4.3.1", "pytest-xdist==1.27.0", "scipy", "sphinx>=2.0", + "sphinx-gallery", "sphinx_rtd_theme", "torchvision", ], diff --git a/tutorials/README.md b/tutorials/README.md new file mode 100644 index 000000000..a415f9b39 --- /dev/null +++ b/tutorials/README.md @@ -0,0 +1 @@ +# Notebook tutorials