From 335002a77c54cc08640e7ffe5775cb668265fe6f Mon Sep 17 00:00:00 2001 From: Bas Nijholt Date: Tue, 13 Oct 2026 23:38:46 -0700 Subject: [PATCH 01/13] Set up Zensical docs skeleton and move static pages --- .gitignore | 6 +- README.md | 23 +- docs/.gitignore | 7 +- docs/CHANGELOG.md | 1 + docs/Makefile | 27 -- .../example_uses/battle_for_majoranas.jpeg | Bin .../example_uses/quasi_majorana_paper.jpeg | Bin .../example_uses/spin_orbit_paper.jpeg | Bin .../_static/example_uses/zigzag_paper.jpeg | Bin .../_static/custom.css => _static/extra.css} | 0 docs/{source => }/_static/logo.png | Bin docs/{source => }/_static/logo_docs.png | Bin docs/docs.md | 7 + docs/environment.yml | 28 -- docs/{source => }/faq.md | 36 +-- docs/{source => }/gallery.md | 20 +- docs/index.md | 20 ++ docs/logo.py | 66 ----- .../algorithms_and_examples.md | 0 docs/{source => notebooks}/benchmarks.md | 0 .../tutorial/tutorial.AverageLearner.md | 0 .../tutorial/tutorial.AverageLearner1D.md | 0 .../tutorial/tutorial.BalancingLearner.md | 0 .../tutorial/tutorial.DataSaver.md | 0 .../tutorial/tutorial.IntegratorLearner.md | 0 .../tutorial/tutorial.Learner1D.md | 0 .../tutorial/tutorial.Learner2D.md | 0 .../tutorial/tutorial.LearnerND.md | 0 .../tutorial/tutorial.SequenceLearner.md | 0 .../tutorial/tutorial.advanced-topics.md | 0 .../tutorial/tutorial.custom_loss.md | 0 .../tutorial/tutorial.md | 0 .../tutorial/tutorial.parallelism.md | 0 .../adaptive.learner.average_learner.md | 0 .../adaptive.learner.average_learner1D.md | 0 .../adaptive.learner.balancing_learner.md | 0 .../adaptive.learner.base_learner.md | 0 .../reference/adaptive.learner.data_saver.md | 0 .../adaptive.learner.integrator_learner.md | 0 .../reference/adaptive.learner.learner1D.md | 0 .../reference/adaptive.learner.learner2D.md | 0 .../reference/adaptive.learner.learnerND.md | 0 .../adaptive.learner.sequence_learner.md | 0 .../adaptive.learner.triangulation.md | 0 .../adaptive.learner.triangulation_backend.md | 0 docs/{source => }/reference/adaptive.md | 0 .../adaptive.notebook_integration.md | 0 .../reference/adaptive.runner.AsyncRunner.md | 0 .../reference/adaptive.runner.BaseRunner.md | 0 .../adaptive.runner.BlockingRunner.md | 0 docs/reference/adaptive.runner.Runner.md | 3 + .../reference/adaptive.runner.extras.md | 0 docs/{source => }/reference/adaptive.utils.md | 0 docs/source/CHANGELOG.md | 1 - docs/source/_static/js/theme.js | 262 ------------------ docs/source/_templates/base.html | 110 -------- docs/source/conf.py | 107 ------- docs/source/docs.md | 15 - docs/source/index.md | 49 ---- .../reference/adaptive.runner.Runner.md | 8 - pyproject.toml | 10 + zensical.toml | 191 +++++++++++++ 62 files changed, 262 insertions(+), 735 deletions(-) create mode 120000 docs/CHANGELOG.md delete mode 100644 docs/Makefile rename docs/{source => }/_static/example_uses/battle_for_majoranas.jpeg (100%) rename docs/{source => }/_static/example_uses/quasi_majorana_paper.jpeg (100%) rename docs/{source => }/_static/example_uses/spin_orbit_paper.jpeg (100%) rename docs/{source => }/_static/example_uses/zigzag_paper.jpeg (100%) rename docs/{source/_static/custom.css => _static/extra.css} (100%) rename docs/{source => }/_static/logo.png (100%) rename docs/{source => }/_static/logo_docs.png (100%) create mode 100644 docs/docs.md delete mode 100644 docs/environment.yml rename docs/{source => }/faq.md (68%) rename docs/{source => }/gallery.md (71%) create mode 100644 docs/index.md delete mode 100644 docs/logo.py rename docs/{source => notebooks}/algorithms_and_examples.md (100%) rename docs/{source => notebooks}/benchmarks.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.AverageLearner.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.AverageLearner1D.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.BalancingLearner.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.DataSaver.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.IntegratorLearner.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.Learner1D.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.Learner2D.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.LearnerND.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.SequenceLearner.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.advanced-topics.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.custom_loss.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.md (100%) rename docs/{source => notebooks}/tutorial/tutorial.parallelism.md (100%) rename docs/{source => }/reference/adaptive.learner.average_learner.md (100%) rename docs/{source => }/reference/adaptive.learner.average_learner1D.md (100%) rename docs/{source => }/reference/adaptive.learner.balancing_learner.md (100%) rename docs/{source => }/reference/adaptive.learner.base_learner.md (100%) rename docs/{source => }/reference/adaptive.learner.data_saver.md (100%) rename docs/{source => }/reference/adaptive.learner.integrator_learner.md (100%) rename docs/{source => }/reference/adaptive.learner.learner1D.md (100%) rename docs/{source => }/reference/adaptive.learner.learner2D.md (100%) rename docs/{source => }/reference/adaptive.learner.learnerND.md (100%) rename docs/{source => }/reference/adaptive.learner.sequence_learner.md (100%) rename docs/{source => }/reference/adaptive.learner.triangulation.md (100%) rename docs/{source => }/reference/adaptive.learner.triangulation_backend.md (100%) rename docs/{source => }/reference/adaptive.md (100%) rename docs/{source => }/reference/adaptive.notebook_integration.md (100%) rename docs/{source => }/reference/adaptive.runner.AsyncRunner.md (100%) rename docs/{source => }/reference/adaptive.runner.BaseRunner.md (100%) rename docs/{source => }/reference/adaptive.runner.BlockingRunner.md (100%) create mode 100644 docs/reference/adaptive.runner.Runner.md rename docs/{source => }/reference/adaptive.runner.extras.md (100%) rename docs/{source => }/reference/adaptive.utils.md (100%) delete mode 120000 docs/source/CHANGELOG.md delete mode 100644 docs/source/_static/js/theme.js delete mode 100644 docs/source/_templates/base.html delete mode 100644 docs/source/conf.py delete mode 100644 docs/source/docs.md delete mode 100644 docs/source/index.md delete mode 100644 docs/source/reference/adaptive.runner.Runner.md create mode 100644 zensical.toml diff --git a/.gitignore b/.gitignore index a562a9918..0d49ab4f1 100644 --- a/.gitignore +++ b/.gitignore @@ -61,8 +61,6 @@ instance/ # Scrapy stuff: .scrapy -# Sphinx documentation -docs/_build/ # PyBuilder target/ @@ -81,6 +79,7 @@ celerybeat-schedule # virtualenv venv/ +.venv/ ENV/ # Spyder project settings @@ -99,3 +98,6 @@ benchmarks/results/ # vscode configuration .vscode/ + +# Zensical +site/ diff --git a/README.md b/README.md index 23989bc53..c66febf06 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ![logo](https://adaptive.readthedocs.io/en/latest/_static/logo.png) *Adaptive*: Parallel Active Learning of Mathematical Functions - + [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/python-adaptive/adaptive/main?filepath=example-notebook.ipynb) [![Conda](https://img.shields.io/badge/install%20with-conda-green.svg)](https://anaconda.org/conda-forge/adaptive) @@ -12,9 +12,9 @@ [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/python-adaptive/adaptive) [![PyPI](https://img.shields.io/pypi/v/adaptive.svg)](https://pypi.python.org/pypi/adaptive) - + - + Adaptive is an open-source Python library that streamlines adaptive parallel function evaluations. Rather than calculating all points on a dense grid, it intelligently selects the "best" points in the parameter space based on your provided function and bounds. @@ -24,7 +24,7 @@ Adaptive is most efficient for computations where each function evaluation takes To see Adaptive in action, try the [example notebook on Binder](https://mybinder.org/v2/gh/python-adaptive/adaptive/main?filepath=example-notebook.ipynb) or explore the [tutorial on Read the Docs](https://adaptive.readthedocs.io/en/latest/tutorial/tutorial). - +
[ToC] 📚 @@ -46,7 +46,7 @@ To see Adaptive in action, try the [example notebook on Binder](https://mybinder
- + ## Key features @@ -59,7 +59,7 @@ To see Adaptive in action, try the [example notebook on Binder](https://mybinder - 💾 **Flexible Data Export**: The library provides options to export learned data as NumPy arrays or Pandas DataFrames, ensuring compatibility with various data processing tools. - 🌐 **Open-Source and Community-Driven**: Adaptive is an open-source project, encouraging contributions from the community to continuously improve and expand the library's features and capabilities. - + ## Example usage @@ -97,7 +97,7 @@ If you have Pandas installed, you can also export the data as a DataFrame: df = learner.to_dataframe() ``` - + ## Implemented Algorithms @@ -110,7 +110,7 @@ While `adaptive` provides sensible default choices, the adaptive sampling proces The following learners are implemented: - + - `Learner1D`: for 1D functions `f: ℝ → ℝ^N`, - `Learner2D`: for 2D functions `f: ℝ^2 → ℝ^N`, @@ -132,7 +132,7 @@ In addition to learners, `adaptive` offers primitives for parallel sampling acro [ipyparallel](https://ipyparallel.readthedocs.io/en/latest/), and [distributed](https://distributed.readthedocs.io/en/latest/). - + ## Installation @@ -224,7 +224,10 @@ We would like to give credits to the following people: - Pedro Gonnet for his implementation of [CQUAD](https://www.gnu.org/software/gsl/manual/html_node/CQUAD-doubly_002dadaptive-integration.html), “Algorithm 4” as described in “Increasing the Reliability of Adaptive Quadrature Using Explicit Interpolants”, P. Gonnet, ACM Transactions on Mathematical Software, 37 (3), art. no. 26, 2010. - Pauli Virtanen for his `AdaptiveTriSampling` script (no longer available online since SciPy Central went down) which served as inspiration for the `adaptive.Learner2D`. - + + For general discussion, we have a [Gitter chat channel](https://gitter.im/python-adaptive/adaptive). If you find any bugs or have any feature suggestions please file a GitHub [issue](https://github.com/python-adaptive/adaptive/issues/new) or submit a [pull request](https://github.com/python-adaptive/adaptive/pulls). + + diff --git a/docs/.gitignore b/docs/.gitignore index ece50848c..73612fb04 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,2 +1,5 @@ -build/* -source/_static/holoviews.* +# Rendered from docs/notebooks/ by docs/build_notebooks.py +/algorithms_and_examples.md +/benchmarks.md +/tutorial/ +*.ipynb diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md new file mode 120000 index 000000000..04c99a55c --- /dev/null +++ b/docs/CHANGELOG.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 2c7e55394..000000000 --- a/docs/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -j auto -SPHINXBUILD = sphinx-build -SPHINXPROJ = adaptive -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -source/_static/logo_docs.png: logo.py - python logo.py - -# Fake target to avoid the catch-all target -logo.py: - @echo "never executed" - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile source/_static/logo_docs.png - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/source/_static/example_uses/battle_for_majoranas.jpeg b/docs/_static/example_uses/battle_for_majoranas.jpeg similarity index 100% rename from docs/source/_static/example_uses/battle_for_majoranas.jpeg rename to docs/_static/example_uses/battle_for_majoranas.jpeg diff --git a/docs/source/_static/example_uses/quasi_majorana_paper.jpeg b/docs/_static/example_uses/quasi_majorana_paper.jpeg similarity index 100% rename from docs/source/_static/example_uses/quasi_majorana_paper.jpeg rename to docs/_static/example_uses/quasi_majorana_paper.jpeg diff --git a/docs/source/_static/example_uses/spin_orbit_paper.jpeg b/docs/_static/example_uses/spin_orbit_paper.jpeg similarity index 100% rename from docs/source/_static/example_uses/spin_orbit_paper.jpeg rename to docs/_static/example_uses/spin_orbit_paper.jpeg diff --git a/docs/source/_static/example_uses/zigzag_paper.jpeg b/docs/_static/example_uses/zigzag_paper.jpeg similarity index 100% rename from docs/source/_static/example_uses/zigzag_paper.jpeg rename to docs/_static/example_uses/zigzag_paper.jpeg diff --git a/docs/source/_static/custom.css b/docs/_static/extra.css similarity index 100% rename from docs/source/_static/custom.css rename to docs/_static/extra.css diff --git a/docs/source/_static/logo.png b/docs/_static/logo.png similarity index 100% rename from docs/source/_static/logo.png rename to docs/_static/logo.png diff --git a/docs/source/_static/logo_docs.png b/docs/_static/logo_docs.png similarity index 100% rename from docs/source/_static/logo_docs.png rename to docs/_static/logo_docs.png diff --git a/docs/docs.md b/docs/docs.md new file mode 100644 index 000000000..360a9ca4f --- /dev/null +++ b/docs/docs.md @@ -0,0 +1,7 @@ +# 🛠️ Installation and development + +--8<-- "README.md:rest" + +--8<-- "AUTHORS.md" + +--8<-- "README.md:community" diff --git a/docs/environment.yml b/docs/environment.yml deleted file mode 100644 index caa8badcf..000000000 --- a/docs/environment.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: adaptive-docs - -channels: - - conda-forge - -dependencies: - - python=3.11 - - sortedcollections=2.1.0 - - scipy=1.10.1 - - holoviews=1.18.3 - - bokeh=3.3.4 - - panel=1.3.8 - - pandas=2.0.0 - - plotly=5.14.1 - - ipywidgets=8.0.6 - - myst-nb=0.17.1 - - sphinx_fontawesome=0.0.6 - - sphinx=5.3.0 - - ffmpeg=5.1.2 - - cloudpickle=2.2.1 - - loky=3.3.0 - - furo=2023.3.27 - - myst-parser=0.18.1 - - dask=2024.2.0 - - emoji=2.2.0 - - versioningit=2.2.0 - - distributed=2024.2.0 - - param=2.0.2 diff --git a/docs/source/faq.md b/docs/faq.md similarity index 68% rename from docs/source/faq.md rename to docs/faq.md index cfb35d476..a8ddd1787 100644 --- a/docs/source/faq.md +++ b/docs/faq.md @@ -2,7 +2,7 @@ ## Where can I learn more about the algorithm used? -Read our [draft paper](https://gitlab.kwant-project.org/qt/adaptive-paper/builds/artifacts/master/file/paper.pdf?job=make) or the source code on [GitHub](https://github.com/python-adaptive/adaptive/). +Read our [draft paper](https://github.com/python-adaptive/paper) or the source code on [GitHub](https://github.com/python-adaptive/adaptive/). ## How do I get the data? @@ -10,19 +10,19 @@ Check `learner.data`. ## How do I learn more than one value per point? -Use the {class}`adaptive.DataSaver`. +Use the [`DataSaver`][adaptive.DataSaver]. ## My runner failed, how do I get the error message? Check `runner.task.print_stack()`. -## How do I get a {class}`~adaptive.Learner2D`'s data on a grid? +## How do I get a `Learner2D`'s data on a grid? Use `learner.interpolated_on_grid()` optionally with a argument `n` to specify the the amount of points in `x` and `y`. ## Why can I not use a `lambda` with a learner? -When using the {class}`~adaptive.Runner` the learner's function is evaluated in different Python processes. +When using the [`Runner`][adaptive.Runner] the learner's function is evaluated in different Python processes. Therefore, the `function` needs to be serialized (pickled) and send to the other Python processes; `lambda`s cannot be pickled. Instead you can probably use `functools.partial` to accomplish what you want to do. @@ -56,32 +56,4 @@ Adaptive is much more simple-minded and it relies only on the local properties o We'd say that Bayesian modeling is good for really computationally expensive data, regular grids for really cheap data, and local adaptive algorithms are somewhere in the middle. -% I get "``concurrent.futures.process.BrokenProcessPool``: A process in the process pool was terminated abruptly while the future was running or pending." what does it mean? -% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -% -% XXX: add answer! -% -% What is the difference with Kriging? -% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -% -% XXX: add answer! -% -% -% What is the difference with adaptive meshing in CFD or computer graphics? -% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -% -% XXX: add answer! -% -% -% Can I use this to tune my hyper parameters for machine learning models? -% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -% -% XXX: add answer! -% -% -% How to use Adaptive with MATLAB? -% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -% -% XXX: add answer! - Missing a question that you think belongs here? Let us [know](https://github.com/python-adaptive/adaptive/issues/new). diff --git a/docs/source/gallery.md b/docs/gallery.md similarity index 71% rename from docs/source/gallery.md rename to docs/gallery.md index 360889db4..03cec095c 100644 --- a/docs/source/gallery.md +++ b/docs/gallery.md @@ -6,19 +6,13 @@ Adaptive has been used in the following scientific publications: by A. Vuik, B. Nijholt, A. R. Akhmerov, M. Wimmer [arXiv:1806.02801](https://arxiv.org/abs/1806.02801) and the [source-code](https://zenodo.org/record/1285177) -```{image} _static/example_uses/quasi_majorana_paper.jpeg -:alt: Reproducing topological properties with quasi-Majorana states -:width: 500 -``` +![Reproducing topological properties with quasi-Majorana states](_static/example_uses/quasi_majorana_paper.jpeg){ width="500" loading=lazy } **Enhanced proximity effect in zigzag-shaped Majorana Josephson junctions** by Tom Laeven, Bas Nijholt, Anton R. Akhmerov, Michael Wimmer [arXiv:1903.06168](https://arxiv.org/abs/1903.06168) and the [source-code](https://zenodo.org/record/2578027) -```{image} _static/example_uses/zigzag_paper.jpeg -:alt: Enhanced proximity effect in zigzag-shaped Majorana Josephson junctions -:width: 500 -``` +![Enhanced proximity effect in zigzag-shaped Majorana Josephson junctions](_static/example_uses/zigzag_paper.jpeg){ width="500" loading=lazy } **Spin-Orbit Protection of Induced Superconductivity in Majorana Nanowires** @@ -26,10 +20,7 @@ by Jouri D.S. Bommer, Hao Zhang, Önder Gül, Bas Nijholt, Michael Wimmer, Filip [arXiv:1807.01940](https://arxiv.org/abs/1807.01940) -```{image} _static/example_uses/spin_orbit_paper.jpeg -:alt: Spin-Orbit Protection of Induced Superconductivity in Majorana Nanowires -:width: 500 -``` +![Spin-Orbit Protection of Induced Superconductivity in Majorana Nanowires](_static/example_uses/spin_orbit_paper.jpeg){ width="500" loading=lazy } Other examples: @@ -41,9 +32,6 @@ by Accidentally leaving the cluster running over the weekend without a `runner.goal` and with a bug in the simulation parameters led to this beautiful mess. -```{image} _static/example_uses/battle_for_majoranas.jpeg -:alt: Battle for Majoranas -:width: 500 -``` +![Battle for Majoranas](_static/example_uses/battle_for_majoranas.jpeg){ width="500" loading=lazy } Did you use Adaptive for something cool? Let us [know](https://github.com/python-adaptive/adaptive/issues/new) and we will add it to this gallery. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..a05ef5098 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,20 @@ +--- +hide: + - navigation +--- + +# ![logo](_static/logo.png){ width="40" } *Adaptive*: Parallel Active Learning of Mathematical Functions + +--8<-- "README.md:badges" + + + +--8<-- "README.md:summary" + +[Start the tutorial](tutorial/tutorial.Learner1D.md){ .md-button .md-button--primary } +[See the examples](algorithms_and_examples.md){ .md-button } +[API reference](reference/adaptive.md){ .md-button } + +--8<-- "README.md:key-features" diff --git a/docs/logo.py b/docs/logo.py deleted file mode 100644 index 384c71065..000000000 --- a/docs/logo.py +++ /dev/null @@ -1,66 +0,0 @@ -import os -import sys - -import holoviews -import matplotlib.pyplot as plt -import matplotlib.tri as mtri -import numpy as np -from PIL import Image, ImageDraw - -sys.path.insert(0, os.path.abspath("..")) # to get adaptive on the path - -import adaptive # noqa: E402, isort:skip - -holoviews.notebook_extension("matplotlib") - - -def create_and_run_learner(): - def ring(xy): - import numpy as np - - x, y = xy - a = 0.2 - return x + np.exp(-((x**2 + y**2 - 0.75**2) ** 2) / a**4) - - learner = adaptive.Learner2D(ring, bounds=[(-1, 1), (-1, 1)]) - adaptive.runner.simple(learner, loss_goal=0.01) - return learner - - -def plot_learner_and_save(learner, fname): - fig, ax = plt.subplots() - tri = learner.interpolator(scaled=True).tri - triang = mtri.Triangulation(*tri.points.T, triangles=tri.vertices) - ax.triplot(triang, c="k", lw=0.8) - data = learner.interpolated_on_grid() - ax.imshow(np.vstack(data), extent=(-0.5, 0.5, -0.5, 0.5)) - ax.set_xticks([]) - ax.set_yticks([]) - plt.savefig(fname, bbox_inches="tight", transparent=True, dpi=300, pad_inches=-0.1) - - -def add_rounded_corners(fname, rad): - im = Image.open(fname) - circle = Image.new("L", (rad * 2, rad * 2), 0) - draw = ImageDraw.Draw(circle) - draw.ellipse((0, 0, rad * 2, rad * 2), fill=255) - alpha = Image.new("L", im.size, 255) - w, h = im.size - alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0)) - alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad)) - alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0)) - alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad)) - im.putalpha(alpha) - return im - - -def main(fname="source/_static/logo_docs.png"): - learner = create_and_run_learner() - plot_learner_and_save(learner, fname) - im = add_rounded_corners(fname, rad=200) - im.thumbnail((200, 200), Image.ANTIALIAS) # resize - im.save(fname) - - -if __name__ == "__main__": - main() diff --git a/docs/source/algorithms_and_examples.md b/docs/notebooks/algorithms_and_examples.md similarity index 100% rename from docs/source/algorithms_and_examples.md rename to docs/notebooks/algorithms_and_examples.md diff --git a/docs/source/benchmarks.md b/docs/notebooks/benchmarks.md similarity index 100% rename from docs/source/benchmarks.md rename to docs/notebooks/benchmarks.md diff --git a/docs/source/tutorial/tutorial.AverageLearner.md b/docs/notebooks/tutorial/tutorial.AverageLearner.md similarity index 100% rename from docs/source/tutorial/tutorial.AverageLearner.md rename to docs/notebooks/tutorial/tutorial.AverageLearner.md diff --git a/docs/source/tutorial/tutorial.AverageLearner1D.md b/docs/notebooks/tutorial/tutorial.AverageLearner1D.md similarity index 100% rename from docs/source/tutorial/tutorial.AverageLearner1D.md rename to docs/notebooks/tutorial/tutorial.AverageLearner1D.md diff --git a/docs/source/tutorial/tutorial.BalancingLearner.md b/docs/notebooks/tutorial/tutorial.BalancingLearner.md similarity index 100% rename from docs/source/tutorial/tutorial.BalancingLearner.md rename to docs/notebooks/tutorial/tutorial.BalancingLearner.md diff --git a/docs/source/tutorial/tutorial.DataSaver.md b/docs/notebooks/tutorial/tutorial.DataSaver.md similarity index 100% rename from docs/source/tutorial/tutorial.DataSaver.md rename to docs/notebooks/tutorial/tutorial.DataSaver.md diff --git a/docs/source/tutorial/tutorial.IntegratorLearner.md b/docs/notebooks/tutorial/tutorial.IntegratorLearner.md similarity index 100% rename from docs/source/tutorial/tutorial.IntegratorLearner.md rename to docs/notebooks/tutorial/tutorial.IntegratorLearner.md diff --git a/docs/source/tutorial/tutorial.Learner1D.md b/docs/notebooks/tutorial/tutorial.Learner1D.md similarity index 100% rename from docs/source/tutorial/tutorial.Learner1D.md rename to docs/notebooks/tutorial/tutorial.Learner1D.md diff --git a/docs/source/tutorial/tutorial.Learner2D.md b/docs/notebooks/tutorial/tutorial.Learner2D.md similarity index 100% rename from docs/source/tutorial/tutorial.Learner2D.md rename to docs/notebooks/tutorial/tutorial.Learner2D.md diff --git a/docs/source/tutorial/tutorial.LearnerND.md b/docs/notebooks/tutorial/tutorial.LearnerND.md similarity index 100% rename from docs/source/tutorial/tutorial.LearnerND.md rename to docs/notebooks/tutorial/tutorial.LearnerND.md diff --git a/docs/source/tutorial/tutorial.SequenceLearner.md b/docs/notebooks/tutorial/tutorial.SequenceLearner.md similarity index 100% rename from docs/source/tutorial/tutorial.SequenceLearner.md rename to docs/notebooks/tutorial/tutorial.SequenceLearner.md diff --git a/docs/source/tutorial/tutorial.advanced-topics.md b/docs/notebooks/tutorial/tutorial.advanced-topics.md similarity index 100% rename from docs/source/tutorial/tutorial.advanced-topics.md rename to docs/notebooks/tutorial/tutorial.advanced-topics.md diff --git a/docs/source/tutorial/tutorial.custom_loss.md b/docs/notebooks/tutorial/tutorial.custom_loss.md similarity index 100% rename from docs/source/tutorial/tutorial.custom_loss.md rename to docs/notebooks/tutorial/tutorial.custom_loss.md diff --git a/docs/source/tutorial/tutorial.md b/docs/notebooks/tutorial/tutorial.md similarity index 100% rename from docs/source/tutorial/tutorial.md rename to docs/notebooks/tutorial/tutorial.md diff --git a/docs/source/tutorial/tutorial.parallelism.md b/docs/notebooks/tutorial/tutorial.parallelism.md similarity index 100% rename from docs/source/tutorial/tutorial.parallelism.md rename to docs/notebooks/tutorial/tutorial.parallelism.md diff --git a/docs/source/reference/adaptive.learner.average_learner.md b/docs/reference/adaptive.learner.average_learner.md similarity index 100% rename from docs/source/reference/adaptive.learner.average_learner.md rename to docs/reference/adaptive.learner.average_learner.md diff --git a/docs/source/reference/adaptive.learner.average_learner1D.md b/docs/reference/adaptive.learner.average_learner1D.md similarity index 100% rename from docs/source/reference/adaptive.learner.average_learner1D.md rename to docs/reference/adaptive.learner.average_learner1D.md diff --git a/docs/source/reference/adaptive.learner.balancing_learner.md b/docs/reference/adaptive.learner.balancing_learner.md similarity index 100% rename from docs/source/reference/adaptive.learner.balancing_learner.md rename to docs/reference/adaptive.learner.balancing_learner.md diff --git a/docs/source/reference/adaptive.learner.base_learner.md b/docs/reference/adaptive.learner.base_learner.md similarity index 100% rename from docs/source/reference/adaptive.learner.base_learner.md rename to docs/reference/adaptive.learner.base_learner.md diff --git a/docs/source/reference/adaptive.learner.data_saver.md b/docs/reference/adaptive.learner.data_saver.md similarity index 100% rename from docs/source/reference/adaptive.learner.data_saver.md rename to docs/reference/adaptive.learner.data_saver.md diff --git a/docs/source/reference/adaptive.learner.integrator_learner.md b/docs/reference/adaptive.learner.integrator_learner.md similarity index 100% rename from docs/source/reference/adaptive.learner.integrator_learner.md rename to docs/reference/adaptive.learner.integrator_learner.md diff --git a/docs/source/reference/adaptive.learner.learner1D.md b/docs/reference/adaptive.learner.learner1D.md similarity index 100% rename from docs/source/reference/adaptive.learner.learner1D.md rename to docs/reference/adaptive.learner.learner1D.md diff --git a/docs/source/reference/adaptive.learner.learner2D.md b/docs/reference/adaptive.learner.learner2D.md similarity index 100% rename from docs/source/reference/adaptive.learner.learner2D.md rename to docs/reference/adaptive.learner.learner2D.md diff --git a/docs/source/reference/adaptive.learner.learnerND.md b/docs/reference/adaptive.learner.learnerND.md similarity index 100% rename from docs/source/reference/adaptive.learner.learnerND.md rename to docs/reference/adaptive.learner.learnerND.md diff --git a/docs/source/reference/adaptive.learner.sequence_learner.md b/docs/reference/adaptive.learner.sequence_learner.md similarity index 100% rename from docs/source/reference/adaptive.learner.sequence_learner.md rename to docs/reference/adaptive.learner.sequence_learner.md diff --git a/docs/source/reference/adaptive.learner.triangulation.md b/docs/reference/adaptive.learner.triangulation.md similarity index 100% rename from docs/source/reference/adaptive.learner.triangulation.md rename to docs/reference/adaptive.learner.triangulation.md diff --git a/docs/source/reference/adaptive.learner.triangulation_backend.md b/docs/reference/adaptive.learner.triangulation_backend.md similarity index 100% rename from docs/source/reference/adaptive.learner.triangulation_backend.md rename to docs/reference/adaptive.learner.triangulation_backend.md diff --git a/docs/source/reference/adaptive.md b/docs/reference/adaptive.md similarity index 100% rename from docs/source/reference/adaptive.md rename to docs/reference/adaptive.md diff --git a/docs/source/reference/adaptive.notebook_integration.md b/docs/reference/adaptive.notebook_integration.md similarity index 100% rename from docs/source/reference/adaptive.notebook_integration.md rename to docs/reference/adaptive.notebook_integration.md diff --git a/docs/source/reference/adaptive.runner.AsyncRunner.md b/docs/reference/adaptive.runner.AsyncRunner.md similarity index 100% rename from docs/source/reference/adaptive.runner.AsyncRunner.md rename to docs/reference/adaptive.runner.AsyncRunner.md diff --git a/docs/source/reference/adaptive.runner.BaseRunner.md b/docs/reference/adaptive.runner.BaseRunner.md similarity index 100% rename from docs/source/reference/adaptive.runner.BaseRunner.md rename to docs/reference/adaptive.runner.BaseRunner.md diff --git a/docs/source/reference/adaptive.runner.BlockingRunner.md b/docs/reference/adaptive.runner.BlockingRunner.md similarity index 100% rename from docs/source/reference/adaptive.runner.BlockingRunner.md rename to docs/reference/adaptive.runner.BlockingRunner.md diff --git a/docs/reference/adaptive.runner.Runner.md b/docs/reference/adaptive.runner.Runner.md new file mode 100644 index 000000000..89b3bbd8d --- /dev/null +++ b/docs/reference/adaptive.runner.Runner.md @@ -0,0 +1,3 @@ +# adaptive.Runner + +::: adaptive.Runner diff --git a/docs/source/reference/adaptive.runner.extras.md b/docs/reference/adaptive.runner.extras.md similarity index 100% rename from docs/source/reference/adaptive.runner.extras.md rename to docs/reference/adaptive.runner.extras.md diff --git a/docs/source/reference/adaptive.utils.md b/docs/reference/adaptive.utils.md similarity index 100% rename from docs/source/reference/adaptive.utils.md rename to docs/reference/adaptive.utils.md diff --git a/docs/source/CHANGELOG.md b/docs/source/CHANGELOG.md deleted file mode 120000 index 03cb73106..000000000 --- a/docs/source/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../../CHANGELOG.md diff --git a/docs/source/_static/js/theme.js b/docs/source/_static/js/theme.js deleted file mode 100644 index 7bf9f6a40..000000000 --- a/docs/source/_static/js/theme.js +++ /dev/null @@ -1,262 +0,0 @@ -// The MIT License (MIT) - -// Copyright (c) 2013-2018 Dave Snider, Read the Docs, Inc. & contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// var jQuery = (typeof(window) != 'undefined') ? window.jQuery : require('jquery'); - -// Sphinx theme nav state -function ThemeNav () { - - var nav = { - navBar: null, - win: null, - winScroll: false, - winResize: false, - linkScroll: false, - winPosition: 0, - winHeight: null, - docHeight: null, - isRunning: false - }; - - nav.enable = function (withStickyNav) { - var self = this; - - // TODO this can likely be removed once the theme javascript is broken - // out from the RTD assets. This just ensures old projects that are - // calling `enable()` get the sticky menu on by default. All other cals - // to `enable` should include an argument for enabling the sticky menu. - if (typeof(withStickyNav) == 'undefined') { - withStickyNav = true; - } - - if (self.isRunning) { - // Only allow enabling nav logic once - return; - } - - self.isRunning = true; - jQuery(function ($) { - self.init($); - - self.reset(); - self.win.on('hashchange', self.reset); - - if (withStickyNav) { - // Set scroll monitor - self.win.on('scroll', function () { - if (!self.linkScroll) { - if (!self.winScroll) { - self.winScroll = true; - requestAnimationFrame(function() { self.onScroll(); }); - } - } - }); - } - - // Set resize monitor - self.win.on('resize', function () { - if (!self.winResize) { - self.winResize = true; - requestAnimationFrame(function() { self.onResize(); }); - } - }); - - self.onResize(); - }); - - }; - - // TODO remove this with a split in theme and Read the Docs JS logic as - // well, it's only here to support 0.3.0 installs of our theme. - nav.enableSticky = function() { - this.enable(true); - }; - - nav.init = function ($) { - var doc = $(document), - self = this; - - this.navBar = $('div.wy-side-scroll:first'); - this.win = $(window); - - // Set up javascript UX bits - $(document) - // Shift nav in mobile when clicking the menu. - .on('click', "[data-toggle='wy-nav-top']", function() { - $("[data-toggle='wy-nav-shift']").toggleClass("shift"); - $("[data-toggle='rst-versions']").toggleClass("shift"); - }) - - // Nav menu link click operations - .on('click', ".wy-menu-vertical .current ul li a", function() { - var target = $(this); - // Close menu when you click a link. - $("[data-toggle='wy-nav-shift']").removeClass("shift"); - $("[data-toggle='rst-versions']").toggleClass("shift"); - // Handle dynamic display of l3 and l4 nav lists - self.toggleCurrent(target); - self.hashChange(); - }) - .on('click', "[data-toggle='rst-current-version']", function() { - $("[data-toggle='rst-versions']").toggleClass("shift-up"); - }) - - // Make tables responsive - $("table.docutils:not(.field-list,.footnote,.citation)") - .wrap("
"); - - // Add extra class to responsive tables that contain - // footnotes or citations so that we can target them for styling - $("table.docutils.footnote") - .wrap("
"); - $("table.docutils.citation") - .wrap("
"); - - // Add expand links to all parents of nested ul - $('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () { - var link = $(this); - expand = $(''); - expand.on('click', function (ev) { - self.toggleCurrent(link); - ev.stopPropagation(); - return false; - }); - link.prepend(expand); - }); - }; - - nav.reset = function () { - // Get anchor from URL and open up nested nav - var anchor = encodeURI(window.location.hash) || '#'; - - try { - var vmenu = $('.wy-menu-vertical'); - var link = vmenu.find('[href="' + anchor + '"]'); - if (link.length === 0) { - // this link was not found in the sidebar. - // Find associated id element, then its closest section - // in the document and try with that one. - var id_elt = $('.document [id="' + anchor.substring(1) + '"]'); - var closest_section = id_elt.closest('div.section'); - link = vmenu.find('[href="#' + closest_section.attr("id") + '"]'); - if (link.length === 0) { - // still not found in the sidebar. fall back to main section - link = vmenu.find('[href="#"]'); - } - } - // If we found a matching link then reset current and re-apply - // otherwise retain the existing match - if (link.length > 0) { - $('.wy-menu-vertical .current').removeClass('current'); - link.addClass('current'); - link.closest('li.toctree-l1').addClass('current'); - link.closest('li.toctree-l1').parent().addClass('current'); - link.closest('li.toctree-l1').addClass('current'); - link.closest('li.toctree-l2').addClass('current'); - link.closest('li.toctree-l3').addClass('current'); - link.closest('li.toctree-l4').addClass('current'); - link[0].scrollIntoView(); - } - } - catch (err) { - console.log("Error expanding nav for anchor", err); - } - - }; - - nav.onScroll = function () { - this.winScroll = false; - var newWinPosition = this.win.scrollTop(), - winBottom = newWinPosition + this.winHeight, - navPosition = this.navBar.scrollTop(), - newNavPosition = navPosition + (newWinPosition - this.winPosition); - if (newWinPosition < 0 || winBottom > this.docHeight) { - return; - } - this.navBar.scrollTop(newNavPosition); - this.winPosition = newWinPosition; - }; - - nav.onResize = function () { - this.winResize = false; - this.winHeight = this.win.height(); - this.docHeight = $(document).height(); - }; - - nav.hashChange = function () { - this.linkScroll = true; - this.win.one('hashchange', function () { - this.linkScroll = false; - }); - }; - - nav.toggleCurrent = function (elem) { - var parent_li = elem.closest('li'); - parent_li.siblings('li.current').removeClass('current'); - parent_li.siblings().find('li.current').removeClass('current'); - parent_li.find('> ul li.current').removeClass('current'); - parent_li.toggleClass('current'); - } - - return nav; -}; - -module.exports.ThemeNav = ThemeNav(); - -if (typeof(window) != 'undefined') { - window.SphinxRtdTheme = { - Navigation: module.exports.ThemeNav, - // TODO remove this once static assets are split up between the theme - // and Read the Docs. For now, this patches 0.3.0 to be backwards - // compatible with a pre-0.3.0 layout.html - StickyNav: module.exports.ThemeNav, - }; -} - - -// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel -// https://gist.github.com/paulirish/1579671 -// MIT license - -(function() { - var lastTime = 0; - var vendors = ['ms', 'moz', 'webkit', 'o']; - for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { - window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; - window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] - || window[vendors[x]+'CancelRequestAnimationFrame']; - } - - if (!window.requestAnimationFrame) - window.requestAnimationFrame = function(callback, element) { - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = window.setTimeout(function() { callback(currTime + timeToCall); }, - timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - - if (!window.cancelAnimationFrame) - window.cancelAnimationFrame = function(id) { - clearTimeout(id); - }; -}()); diff --git a/docs/source/_templates/base.html b/docs/source/_templates/base.html deleted file mode 100644 index 5423b63ba..000000000 --- a/docs/source/_templates/base.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - {%- block site_meta -%} - - - - - {%- if metatags %}{{ metatags }}{% endif -%} - - {%- block linktags %} - {%- if hasdoc('about') -%} - - {%- endif -%} - {%- if hasdoc('genindex') -%} - - {%- endif -%} - {%- if hasdoc('search') -%} - - {%- endif -%} - {%- if hasdoc('copyright') -%} - - {%- endif -%} - {%- if next -%} - - {%- endif -%} - {%- if prev -%} - - {%- endif -%} - {#- rel="canonical" (set by html_baseurl) -#} - {%- if pageurl %} - - {%- endif %} - {%- endblock linktags %} - - {# Favicon #} - {%- if favicon_url -%} - - {%- endif -%} - - {#- Generator banner -#} - - - {%- endblock site_meta -%} - - {#- Site title -#} - {%- block htmltitle -%} - {% if not docstitle %} - {{ title|striptags|e }} - {% elif pagename == master_doc %} - {{ docstitle|striptags|e }} - {% else %} - {{ title|striptags|e }} - {{ docstitle|striptags|e }} - {% endif %} - {%- endblock -%} - - {%- block styles -%} - - {# Custom stylesheets #} - {%- block regular_styles -%} - {%- for css in css_files -%} - {% if css|attr("filename") -%} - {{ css_tag(css) }} - {%- else -%} - - {%- endif %} - {% endfor -%} - {%- endblock regular_styles -%} - - {#- Theme-related stylesheets -#} - {%- block theme_styles %} - {% include "partials/_head_css_variables.html" with context %} - {%- endblock -%} - - {%- block extra_styles %} - {%- endblock -%} - - {%- endblock styles -%} - - {#- Custom front matter #} - {%- block extrahead -%}{%- endblock -%} - - {# Custom JS #} - {%- block regular_scripts -%} - {% for path in script_files -%} - {{ js_tag(path) }} - {% endfor -%} - {%- endblock regular_scripts -%} - - {# Theme-related JavaScript code #} - {%- block theme_scripts -%} - {%- endblock -%} - - - - {% block body %} - - {% endblock %} - - {%- block scripts -%} - {%- endblock scripts -%} - - diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index 5ea9e6ef7..000000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,107 +0,0 @@ -# -- Path setup -------------------------------------------------------------- - -import os -import sys -from pathlib import Path - -package_path = Path("../..").resolve() -# Insert into sys.path so that we can import adaptive here -sys.path.insert(0, str(package_path)) -# Insert into PYTHONPATH so that jupyter-sphinx will pick it up -os.environ["PYTHONPATH"] = ":".join( - (str(package_path), os.environ.get("PYTHONPATH", "")), -) -# Insert `docs/` such that we can run the logo scripts -docs_path = Path("..").resolve() -sys.path.insert(1, str(docs_path)) - - -import adaptive # noqa: E402, isort:skip - -# -- Project information ----------------------------------------------------- - -project = "adaptive" -copyright = "2018-2023, Adaptive Authors" -author = "Adaptive Authors" - -# The short X.Y version -version = ".".join(adaptive.__version__.split(".")[:3]) -version = version -# The full version, including alpha/beta/rc tags -release = version - -extensions = [ - "sphinx.ext.autodoc", - "sphinx.ext.autosummary", - "sphinx.ext.autosectionlabel", - "sphinx.ext.intersphinx", - "sphinx.ext.mathjax", - "sphinx.ext.viewcode", - "sphinx.ext.napoleon", - "myst_nb", - "sphinx_fontawesome", -] -source_parsers = {} -templates_path = ["_templates"] -source_suffix = [".rst", ".md"] -master_doc = "index" -language = None -exclude_patterns = [] -pygments_style = "sphinx" -# TODO: change to "furo" when https://github.com/executablebooks/MyST-NB/issues/54 is fixed (again) -html_theme = "furo" -html_static_path = ["_static"] -htmlhelp_basename = "adaptivedoc" - - -# -- Extension configuration ------------------------------------------------- - -default_role = "autolink" - -intersphinx_mapping = { - "python": ("https://docs.python.org/3", None), - "distributed": ("https://distributed.readthedocs.io/en/stable/", None), - "holoviews": ("https://holoviews.org/", None), - "ipyparallel": ("https://ipyparallel.readthedocs.io/en/stable/", None), - "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), - "loky": ("https://loky.readthedocs.io/en/stable/", None), -} -html_js_files = [ - "https://cdn.bokeh.org/bokeh/release/bokeh-2.4.0.min.js", - "https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.0.min.js", - "https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.0.min.js", - "https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.0.min.js", - "https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.0.min.js", - "https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js", -] -html_logo = "_static/logo_docs.png" - - -# myst-nb configuration -nb_execution_mode = "cache" -# Generating the logo animation (logo.md) takes ~3 minutes on Read the Docs -# builders, which intermittently exceeded the previous 180 s limit. -nb_execution_timeout = 600 -nb_execution_raise_on_error = True - - -def replace_named_emojis(input_file: Path, output_file: Path) -> None: - """Replace named emojis in a file with unicode emojis.""" - import emoji - - with input_file.open("r") as infile: - content = infile.read() - content_with_emojis = emoji.emojize(content, language="alias") - - with output_file.open("w") as outfile: - outfile.write(content_with_emojis) - - -# Call the function to replace emojis in the README.md file -input_file = package_path / "README.md" -output_file = docs_path / "README.md" -replace_named_emojis(input_file, output_file) - - -def setup(app): - app.add_css_file("custom.css") # For the `live_info` widget diff --git a/docs/source/docs.md b/docs/source/docs.md deleted file mode 100644 index 4d1fa479c..000000000 --- a/docs/source/docs.md +++ /dev/null @@ -1,15 +0,0 @@ -```{include} ../README.md ---- -start-after: -end-before: ---- -``` - -```{include} ../../AUTHORS.md -``` - -```{include} ../README.md ---- -start-after: ---- -``` diff --git a/docs/source/index.md b/docs/source/index.md deleted file mode 100644 index b1bfe8977..000000000 --- a/docs/source/index.md +++ /dev/null @@ -1,49 +0,0 @@ -# ![logo](https://adaptive.readthedocs.io/en/latest/_static/logo.png) *Adaptive*: Parallel Active Learning of Mathematical Functions - -```{include} ../README.md ---- -start-after: -end-before: ---- -``` - -```{include} logo.md -``` - -```{include} ../README.md ---- -start-after: -end-before: ---- -``` - -```{include} ../README.md ---- -start-after: -end-before: ---- -``` - -```{tip} -Start with the {ref}`1D function learning tutorial`. -``` - -```{toctree} -:hidden: true - -self -``` - -```{toctree} -:hidden: true -:maxdepth: 2 - -algorithms_and_examples -docs -tutorial/tutorial -benchmarks -gallery -reference/adaptive -CHANGELOG -faq -``` diff --git a/docs/source/reference/adaptive.runner.Runner.md b/docs/source/reference/adaptive.runner.Runner.md deleted file mode 100644 index 132705429..000000000 --- a/docs/source/reference/adaptive.runner.Runner.md +++ /dev/null @@ -1,8 +0,0 @@ -# adaptive.Runner - -```{eval-rst} -.. autoclass:: adaptive.Runner - :members: - :undoc-members: - :show-inheritance: -``` diff --git a/pyproject.toml b/pyproject.toml index bdad24739..b0363738b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,6 +76,16 @@ nox = [ "nox", "pytest-github-actions-annotate-failures", ] +docs = [ + "adaptive[notebook,other]", + "zensical", + "mkdocstrings-python", + "jupytext", + "nbclient", + "nbformat", + "pillow", + "pytest", +] [tool.setuptools.packages.find] include = ["adaptive.*", "adaptive"] diff --git a/zensical.toml b/zensical.toml new file mode 100644 index 000000000..1d93e77b1 --- /dev/null +++ b/zensical.toml @@ -0,0 +1,191 @@ +# Adaptive documentation, built with Zensical (https://zensical.org). +# Executable pages live in docs/notebooks/ and are rendered into docs/ by +# docs/build_notebooks.py before running `zensical build`. + +[project] +site_name = "Adaptive" +site_description = "Parallel active learning of mathematical functions" +site_author = "Adaptive Authors" +site_url = "https://adaptive.readthedocs.io/" +copyright = "Copyright © 2018-2026 Adaptive Authors" +repo_url = "https://github.com/python-adaptive/adaptive" +repo_name = "python-adaptive/adaptive" +edit_uri = "edit/main/docs/" +docs_dir = "docs" +exclude_docs = """ +notebooks/ +*.py +""" + +nav = [ + { "Home" = "index.md" }, + { "Algorithms and examples" = "algorithms_and_examples.md" }, + { "Tutorial" = [ + "tutorial/tutorial.md", + "tutorial/tutorial.Learner1D.md", + "tutorial/tutorial.Learner2D.md", + "tutorial/tutorial.custom_loss.md", + "tutorial/tutorial.AverageLearner.md", + "tutorial/tutorial.BalancingLearner.md", + "tutorial/tutorial.DataSaver.md", + "tutorial/tutorial.IntegratorLearner.md", + "tutorial/tutorial.LearnerND.md", + "tutorial/tutorial.AverageLearner1D.md", + "tutorial/tutorial.SequenceLearner.md", + "tutorial/tutorial.parallelism.md", + "tutorial/tutorial.advanced-topics.md", + ] }, + { "Benchmarks" = "benchmarks.md" }, + { "Gallery" = "gallery.md" }, + { "API reference" = [ + "reference/adaptive.md", + { "Learners" = [ + "reference/adaptive.learner.learner1D.md", + "reference/adaptive.learner.learner2D.md", + "reference/adaptive.learner.learnerND.md", + "reference/adaptive.learner.average_learner.md", + "reference/adaptive.learner.average_learner1D.md", + "reference/adaptive.learner.balancing_learner.md", + "reference/adaptive.learner.data_saver.md", + "reference/adaptive.learner.integrator_learner.md", + "reference/adaptive.learner.sequence_learner.md", + "reference/adaptive.learner.base_learner.md", + ] }, + { "Runners" = [ + "reference/adaptive.runner.Runner.md", + "reference/adaptive.runner.AsyncRunner.md", + "reference/adaptive.runner.BlockingRunner.md", + "reference/adaptive.runner.BaseRunner.md", + "reference/adaptive.runner.extras.md", + ] }, + { "Other" = [ + "reference/adaptive.learner.triangulation.md", + "reference/adaptive.notebook_integration.md", + "reference/adaptive.utils.md", + ] }, + ] }, + { "Changelog" = "CHANGELOG.md" }, + { "FAQ" = "faq.md" }, + { "Contributing" = "docs.md" }, +] + +extra_css = ["_static/extra.css"] + +[project.theme] +language = "en" +logo = "_static/logo_docs.png" +favicon = "_static/logo.png" +features = [ + "content.action.edit", + "content.action.view", + "content.code.annotate", + "content.code.copy", + "content.footnote.tooltips", + "content.tabs.link", + "content.tooltips", + "navigation.footer", + "navigation.indexes", + "navigation.path", + "navigation.sections", + "navigation.top", + "navigation.tracking", + "search.highlight", + "toc.follow", +] + +[[project.theme.palette]] +media = "(prefers-color-scheme)" +toggle.icon = "lucide/sun-moon" +toggle.name = "Switch to light mode" + +[[project.theme.palette]] +media = "(prefers-color-scheme: light)" +scheme = "default" +primary = "custom" +accent = "custom" +toggle.icon = "lucide/sun" +toggle.name = "Switch to dark mode" + +[[project.theme.palette]] +media = "(prefers-color-scheme: dark)" +scheme = "slate" +primary = "custom" +accent = "custom" +toggle.icon = "lucide/moon-star" +toggle.name = "Switch to system preference" + +[project.theme.font] +text = "Inter" +code = "JetBrains Mono" + +[project.theme.icon] +repo = "fontawesome/brands/github" + +[[project.extra.social]] +icon = "fontawesome/brands/github" +link = "https://github.com/python-adaptive/adaptive" + +[[project.extra.social]] +icon = "fontawesome/brands/python" +link = "https://pypi.org/project/adaptive/" + +[project.plugins.mkdocstrings.handlers.python] +paths = ["."] +inventories = [ + "https://docs.python.org/3/objects.inv", + "https://docs.scipy.org/doc/scipy/objects.inv", + "https://holoviews.org/objects.inv", + "https://loky.readthedocs.io/en/stable/objects.inv", +] + +[project.plugins.mkdocstrings.handlers.python.options] +docstring_style = "numpy" +docstring_section_style = "table" +show_root_heading = true +show_root_full_path = false +show_source = true +show_bases = true +show_signature_annotations = true +separate_signature = true +signature_crossrefs = true +merge_init_into_class = true +members_order = "source" +filters = ["!^_"] +heading_level = 2 + +# Zensical replaces its default extension set when this table is present, +# so the defaults are listed explicitly next to `pymdownx.snippets`. +[project.markdown_extensions.abbr] +[project.markdown_extensions.admonition] +[project.markdown_extensions.attr_list] +[project.markdown_extensions.def_list] +[project.markdown_extensions.footnotes] +[project.markdown_extensions.md_in_html] +[project.markdown_extensions.toc] +permalink = true +[project.markdown_extensions.pymdownx.arithmatex] +generic = true +[project.markdown_extensions.pymdownx.betterem] +[project.markdown_extensions.pymdownx.caret] +[project.markdown_extensions.pymdownx.details] +[project.markdown_extensions.pymdownx.emoji] +emoji_index = "zensical.extensions.emoji.twemoji" +emoji_generator = "zensical.extensions.emoji.to_svg" +[project.markdown_extensions.pymdownx.highlight] +anchor_linenums = true +line_spans = "__span" +pygments_lang_class = true +[project.markdown_extensions.pymdownx.inlinehilite] +[project.markdown_extensions.pymdownx.keys] +[project.markdown_extensions.pymdownx.magiclink] +[project.markdown_extensions.pymdownx.mark] +[project.markdown_extensions.pymdownx.smartsymbols] +[project.markdown_extensions.pymdownx.snippets] +check_paths = true +[project.markdown_extensions.pymdownx.superfences] +[project.markdown_extensions.pymdownx.tabbed] +alternate_style = true +combine_header_slug = true +[project.markdown_extensions.pymdownx.tasklist] +custom_checkbox = true +[project.markdown_extensions.pymdownx.tilde] From c44a7de3775b8e958291689d0110a5ca46edbdc7 Mon Sep 17 00:00:00 2001 From: Bas Nijholt Date: Tue, 13 Oct 2026 23:42:31 -0700 Subject: [PATCH 02/13] Add notebook execution and rendering pipeline for Zensical docs --- docs/build_notebooks.py | 213 +++++++++++++++++++++++++++++++++++ docs/test_build_notebooks.py | 114 +++++++++++++++++++ 2 files changed, 327 insertions(+) create mode 100644 docs/build_notebooks.py create mode 100644 docs/test_build_notebooks.py diff --git a/docs/build_notebooks.py b/docs/build_notebooks.py new file mode 100644 index 000000000..6c0b3297c --- /dev/null +++ b/docs/build_notebooks.py @@ -0,0 +1,213 @@ +"""Execute the notebooks in docs/notebooks/ and render them for Zensical. + +Every ``docs/notebooks/.md`` (a jupytext MyST notebook) becomes +``docs/.md`` with its outputs embedded as raw HTML, plus a +``docs/.ipynb`` download without outputs. Executed notebooks are cached +in ``.cache/notebooks/`` keyed by their source text. + +Usage: python docs/build_notebooks.py [docs/notebooks/.md ...] +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import re +import sys +import time +from concurrent.futures import ThreadPoolExecutor +from pathlib import Path + +import jupytext +import nbformat +from nbclient import NotebookClient + +DOCS_DIR = Path(__file__).parent +SOURCE_DIR = DOCS_DIR / "notebooks" +CACHE_DIR = DOCS_DIR.parent / ".cache" / "notebooks" + +# Richest representation first, like nbconvert's HTML exporter. +MIME_PRIORITY = [ + "application/vnd.jupyter.widget-view+json", + "application/javascript", + "text/html", + "text/markdown", + "image/svg+xml", + "image/png", + "image/jpeg", + "text/latex", + "text/plain", +] +WIDGET_VIEW = "application/vnd.jupyter.widget-view+json" +WIDGET_STATE = "application/vnd.jupyter.widget-state+json" +WIDGET_LOADER = ( + '' +) +ANSI = re.compile(r"\x1b\[[0-9;]*[A-Za-z]") +HIDE_LABELS = { + "hide-cell": "Show code cell", + "hide-input": "Show code", + "hide-output": "Show output", +} + + +def _script_json(value: object) -> str: + # " element early; "<\\/" is the same JSON. + return json.dumps(value).replace(" str: + return f'
\n{html_text.strip()}\n
' + + +def _code_block(text: str, lang: str = "") -> str: + fence = "````" if "```" in text else "```" + return f"{fence}{lang}\n{text.rstrip()}\n{fence}" + + +def _details(label: str, body: str) -> str: + return ( + f'
\n{label}\n\n' + f"{body}\n\n
" + ) + + +def _render_data(data: dict, has_widget_state: bool) -> str: + for mime in MIME_PRIORITY: + if mime not in data or (mime == WIDGET_VIEW and not has_widget_state): + continue + value = data[mime] + if mime == WIDGET_VIEW: + return _raw(f'') + if mime == "application/javascript": + return _raw(f'') + if mime == "text/html": + return _raw(value) + if mime == "text/markdown": + return value + if mime == "image/svg+xml": + return _raw(value) + if mime in ("image/png", "image/jpeg"): + src = f"data:{mime};base64,{value.strip()}" + return _raw(f'output') + if mime == "text/latex": + return value + return _code_block(ANSI.sub("", value), "text") + return "" + + +def _render_output(output: dict, has_widget_state: bool) -> str: + kind = output["output_type"] + if kind == "stream": + return _code_block(ANSI.sub("", output["text"]), "text") + if kind == "error": + return _code_block(ANSI.sub("", "\n".join(output["traceback"])), "text") + return _render_data(output.get("data", {}), has_widget_state) + + +def _render_code_cell(cell: dict, has_widget_state: bool) -> str: + tags = set(cell.get("metadata", {}).get("tags", [])) + if "remove-cell" in tags: + return "" + source = "" if "remove-input" in tags else _code_block(cell["source"], "python") + outputs = ( + [] + if "remove-output" in tags + else [_render_output(o, has_widget_state) for o in cell.get("outputs", [])] + ) + outputs_md = "\n\n".join(o for o in outputs if o) + if "hide-cell" in tags: + return _details(HIDE_LABELS["hide-cell"], f"{source}\n\n{outputs_md}".strip()) + if "hide-input" in tags and source: + source = _details(HIDE_LABELS["hide-input"], source) + if "hide-output" in tags and outputs_md: + outputs_md = _details(HIDE_LABELS["hide-output"], outputs_md) + return "\n\n".join(part for part in (source, outputs_md) if part) + + +def _download_note(ipynb_name: str) -> str: + return ( + '!!! tip "Run this page yourself"\n' + f" Download this page as a Jupyter notebook: [{ipynb_name}]({ipynb_name})." + ) + + +def render_notebook(nb: nbformat.NotebookNode, ipynb_name: str) -> str: + """Render an (executed) notebook as Zensical Markdown.""" + widget_state = nb.metadata.get("widgets", {}).get(WIDGET_STATE) + has_widget_state = bool(widget_state and widget_state.get("state")) + parts = [] + for cell in nb.cells: + if cell.cell_type == "markdown": + parts.append(cell.source) + elif cell.cell_type == "code": + parts.append(_render_code_cell(cell, has_widget_state)) + md = "\n\n".join(p for p in parts if p.strip()) + + if any(cell.cell_type == "code" for cell in nb.cells): + note = _download_note(ipynb_name) + title = re.search(r"^# .*$", md, flags=re.MULTILINE) + if title: + md = f"{md[: title.end()]}\n\n{note}{md[title.end() :]}" + else: + md = f"{note}\n\n{md}" + + if has_widget_state: + state = _script_json(widget_state) + md += "\n\n" + _raw( + f'\n{WIDGET_LOADER}' + ) + return md + "\n" + + +def _execute(nb: nbformat.NotebookNode, cwd: Path) -> nbformat.NotebookNode: + client = NotebookClient( + nb, + timeout=600, + kernel_name="python3", + resources={"metadata": {"path": str(cwd)}}, + store_widget_state=True, + ) + return client.execute() + + +def execute_cached(source: Path) -> nbformat.NotebookNode: + """Execute a jupytext notebook, reusing the cached result if unchanged.""" + text = source.read_text() + cached = CACHE_DIR / f"{hashlib.sha256(text.encode()).hexdigest()}.ipynb" + if cached.exists(): + return nbformat.read(cached, as_version=4) + nb = _execute(jupytext.reads(text, fmt="md:myst"), source.parent) + CACHE_DIR.mkdir(parents=True, exist_ok=True) + nbformat.write(nb, cached) + return nb + + +def build(source: Path) -> Path: + """Execute and render one notebook; return the written Markdown path.""" + start = time.monotonic() + target = DOCS_DIR / source.relative_to(SOURCE_DIR) + target.parent.mkdir(parents=True, exist_ok=True) + ipynb = target.with_suffix(".ipynb") + nb = execute_cached(source) + target.write_text(render_notebook(nb, ipynb.name)) + if any(cell.cell_type == "code" for cell in nb.cells): + jupytext.write(jupytext.read(source), ipynb) + print(f"{source.relative_to(DOCS_DIR)}: {time.monotonic() - start:.1f}s") + return target + + +def main(argv: list[str] | None = None) -> None: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("sources", nargs="*", type=Path) + parser.add_argument("-j", "--jobs", type=int, default=4) + args = parser.parse_args(argv) + sources = [p.resolve() for p in args.sources] or sorted(SOURCE_DIR.rglob("*.md")) + with ThreadPoolExecutor(args.jobs) as pool: + list(pool.map(build, sources)) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/docs/test_build_notebooks.py b/docs/test_build_notebooks.py new file mode 100644 index 000000000..31d8a06db --- /dev/null +++ b/docs/test_build_notebooks.py @@ -0,0 +1,114 @@ +"""Tests for docs/build_notebooks.py. + +Run with: uv run --group docs pytest docs/test_build_notebooks.py -o addopts="" +""" + +import json +import sys +from pathlib import Path + +from nbformat.v4 import new_code_cell, new_markdown_cell, new_notebook, new_output + +sys.path.insert(0, str(Path(__file__).parent)) + +import build_notebooks as bn # noqa: E402 + +WIDGET_VIEW = {"model_id": "abc", "version_major": 2, "version_minor": 0} + + +def render(*cells, metadata=None, ipynb_name="page.ipynb"): + nb = new_notebook(cells=list(cells), metadata=metadata or {}) + return bn.render_notebook(nb, ipynb_name) + + +def test_hide_cell_wraps_in_details(): + cell = new_code_cell("import adaptive", metadata={"tags": ["hide-cell"]}) + md = render(cell) + assert '
' in md + assert "```python\nimport adaptive\n```" in md + assert md.index("") + + +def test_remove_input_keeps_output(): + out = new_output("stream", name="stdout", text="hi there\n") + cell = new_code_cell("print('hi there')", outputs=[out]) + cell.metadata["tags"] = ["remove-input"] + md = render(cell) + assert "print(" not in md + assert "hi there" in md + + +def test_html_output_wrapped_raw(): + out = new_output("display_data", data={"text/html": "x", "text/plain": "X"}) + md = render(new_code_cell("x", outputs=[out])) + assert '
\nx\n
' in md + assert "X" not in md.replace("x", "") + + +def test_widget_without_state_falls_back(): + data = {"application/vnd.jupyter.widget-view+json": WIDGET_VIEW, "text/plain": "VBox()"} + md = render(new_code_cell("w", outputs=[new_output("display_data", data=data)])) + assert "widget-view+json" not in md + assert "VBox()" in md + + +def test_widget_with_state_embeds_view_and_state(): + data = {"application/vnd.jupyter.widget-view+json": WIDGET_VIEW, "text/plain": "VBox()"} + state = {"state": {"abc": {}}, "version_major": 2, "version_minor": 0} + metadata = {"widgets": {"application/vnd.jupyter.widget-state+json": state}} + cell = new_code_cell("w", outputs=[new_output("display_data", data=data)]) + md = render(cell, metadata=metadata) + assert '" + data = {"application/vnd.jupyter.widget-view+json": WIDGET_VIEW, "text/plain": "HTML()"} + state = {"state": {"abc": {"state": {"value": value}}}, "version_major": 2} + metadata = {"widgets": {"application/vnd.jupyter.widget-state+json": state}} + md = render(new_code_cell("w", outputs=[new_output("display_data", data=data)]), metadata=metadata) + start = md.index('", start)] + assert json.loads(content) == state From 42aff250494a0921b5260f93e1384b3102c750a2 Mon Sep 17 00:00:00 2001 From: Bas Nijholt Date: Tue, 13 Oct 2026 23:54:19 -0700 Subject: [PATCH 03/13] Convert notebook sources from MyST to Zensical Markdown --- docs/_static/extra.css | 101 ++++++++++-------- docs/_static/katex.js | 11 ++ docs/build_notebooks.py | 17 ++- docs/notebooks/algorithms_and_examples.md | 47 ++++---- docs/notebooks/benchmarks.md | 35 +++--- docs/notebooks/tutorial/data/example_file.p | Bin 0 -> 4555 bytes .../tutorial/data/periodic_example.p | Bin 0 -> 174 bytes .../tutorial/tutorial.AverageLearner.md | 13 +-- .../tutorial/tutorial.AverageLearner1D.md | 15 ++- .../tutorial/tutorial.BalancingLearner.md | 17 ++- docs/notebooks/tutorial/tutorial.DataSaver.md | 15 ++- .../tutorial/tutorial.IntegratorLearner.md | 15 ++- docs/notebooks/tutorial/tutorial.Learner1D.md | 22 ++-- docs/notebooks/tutorial/tutorial.Learner2D.md | 13 +-- docs/notebooks/tutorial/tutorial.LearnerND.md | 13 +-- .../tutorial/tutorial.SequenceLearner.md | 13 +-- .../tutorial/tutorial.advanced-topics.md | 44 ++++---- .../tutorial/tutorial.custom_loss.md | 43 ++++---- docs/notebooks/tutorial/tutorial.md | 26 +---- .../tutorial/tutorial.parallelism.md | 10 +- docs/test_build_notebooks.py | 8 ++ zensical.toml | 74 +++++++------ 22 files changed, 268 insertions(+), 284 deletions(-) create mode 100644 docs/_static/katex.js create mode 100644 docs/notebooks/tutorial/data/example_file.p create mode 100644 docs/notebooks/tutorial/data/periodic_example.p diff --git a/docs/_static/extra.css b/docs/_static/extra.css index 0c1e64483..a752e8f9d 100644 --- a/docs/_static/extra.css +++ b/docs/_static/extra.css @@ -1,62 +1,79 @@ -.ignore-css { - all: unset !important; +/* Viridis-inspired palette, matching the logo */ +[data-md-color-primary="custom"] { + --md-primary-fg-color: #3b528b; + --md-primary-fg-color--light: #5a6fa8; + --md-primary-fg-color--dark: #2c3e6b; + --md-primary-bg-color: #ffffff; + --md-primary-bg-color--light: #ffffffb3; +} +[data-md-color-accent="custom"] { + --md-accent-fg-color: #21918c; + --md-accent-fg-color--transparent: #21918c1a; + --md-accent-bg-color: #ffffff; + --md-accent-bg-color--light: #ffffffb3; +} +[data-md-color-scheme="slate"][data-md-color-primary="custom"] { + --md-typeset-a-color: #7ea6e0; } -/* https://gitter.im/pyviz/pyviz?at=5e8efb2b16f84f0461683446 */ -.panel-widget-box.bk form { - display: none !important; - margin-left: auto !important; - margin-right: auto !important; - width: 25%; +/* Animated logo on the home page */ +.adaptive-logo-video { + display: block; + width: 320px; + max-width: 100%; + margin: 1.5rem auto; +} + +/* Notebook outputs rendered by docs/build_notebooks.py */ +.md-typeset .nb-output { + margin: 0 0 1.5em; + overflow-x: auto; +} +.md-typeset .highlight.nb-output-text pre { + border-left: 0.2rem solid var(--md-accent-fg-color); +} +.md-typeset .highlight.nb-output-text code { + background: transparent; +} + +/* Bokeh plots and widgets are designed for a light background */ +[data-md-color-scheme="slate"] .md-typeset .nb-output:has([data-root-id]), +[data-md-color-scheme="slate"] .md-typeset .nb-output:has(.plotly-graph-div), +[data-md-color-scheme="slate"] .md-typeset .nb-output:has(.jupyter-widgets) { + background: #ffffff; + color: #000000; + border-radius: 0.4rem; + padding: 0.5rem; } -/* Some additional styling taken form the Jupyter notebook CSS */ -/* but changed `rendered_html` to `text_html` */ +/* `live_info` and `live_plot` cancel buttons do nothing on a static page */ +.md-typeset .nb-output .widget-button { + display: none !important; +} -div.text_html table { +/* pandas DataFrames */ +.md-typeset .nb-output table.dataframe { border: none; border-collapse: collapse; border-spacing: 0; - /* color: black; */ - font-size: 12px; + font-size: 0.7rem; table-layout: fixed; } -div.text_html thead { - border-bottom: 1px solid; +.md-typeset .nb-output table.dataframe thead { + border-bottom: 1px solid var(--md-default-fg-color--lighter); vertical-align: bottom; } -div.text_html tr, -div.text_html th, -div.text_html td { +.md-typeset .nb-output table.dataframe :is(tr, th, td) { text-align: right; vertical-align: middle; - padding: 0.5em 0.5em; + padding: 0.4em 0.6em; line-height: normal; white-space: normal; - max-width: none; border: none; } -div.text_html th { - font-weight: bold; -} - -/* alternating color light theme */ -body[data-theme="light"] div.text_html tbody tr:nth-child(odd) { - background: #f5f5f5; -} -body[data-theme="light"] div.text_html tbody tr:hover { - background: rgba(66, 165, 245, 0.2); +.md-typeset .nb-output table.dataframe tbody tr:nth-child(odd) { + background: var(--md-code-bg-color); } - -/* alternating color dark theme */ -body[data-theme="dark"] div.text_html tbody tr:nth-child(odd) { - background: #696969; -} -body[data-theme="dark"] div.text_html tbody tr:hover { - background: rgba(175, 175, 175, 0.2); -} - -/* for rendered markdown on meta_data.md docs */ -body[data-theme="dark"] .widget-html-content { - color: #f5f5f5; +.md-typeset .nb-output table.dataframe tbody tr:hover { + background: var(--md-accent-fg-color--transparent); } diff --git a/docs/_static/katex.js b/docs/_static/katex.js new file mode 100644 index 000000000..861ed7592 --- /dev/null +++ b/docs/_static/katex.js @@ -0,0 +1,11 @@ +// Render the math that pymdownx.arithmatex wraps in `.arithmatex` elements. +document$.subscribe(({ body }) => { + for (const element of body.querySelectorAll(".arithmatex")) { + renderMathInElement(element, { + delimiters: [ + { left: "\\(", right: "\\)", display: false }, + { left: "\\[", right: "\\]", display: true }, + ], + }); + } +}); diff --git a/docs/build_notebooks.py b/docs/build_notebooks.py index 6c0b3297c..b38075384 100644 --- a/docs/build_notebooks.py +++ b/docs/build_notebooks.py @@ -46,6 +46,8 @@ '@jupyter-widgets/html-manager@1/dist/embed.js" crossorigin="anonymous">' ) ANSI = re.compile(r"\x1b\[[0-9;]*[A-Za-z]") +# adaptive calls plotly.offline.init_notebook_mode(), which inlines plotly.js. +PLOTLY_BUNDLE = re.compile(r"\* plotly\.js v(\d+\.\d+\.\d+)") HIDE_LABELS = { "hide-cell": "Show code cell", "hide-input": "Show code", @@ -62,11 +64,15 @@ def _raw(html_text: str) -> str: return f'
\n{html_text.strip()}\n
' -def _code_block(text: str, lang: str = "") -> str: +def _code_block(text: str, lang: str) -> str: fence = "````" if "```" in text else "```" return f"{fence}{lang}\n{text.rstrip()}\n{fence}" +def _text_output(text: str) -> str: + return _code_block(ANSI.sub("", text), " { .text .nb-output-text }") + + def _details(label: str, body: str) -> str: return ( f'
\n{label}\n\n' @@ -84,6 +90,9 @@ def _render_data(data: dict, has_widget_state: bool) -> str: if mime == "application/javascript": return _raw(f'') if mime == "text/html": + if bundle := PLOTLY_BUNDLE.search(value): + url = f"https://cdn.plot.ly/plotly-{bundle.group(1)}.min.js" + value = f'' return _raw(value) if mime == "text/markdown": return value @@ -94,16 +103,16 @@ def _render_data(data: dict, has_widget_state: bool) -> str: return _raw(f'output') if mime == "text/latex": return value - return _code_block(ANSI.sub("", value), "text") + return _text_output(value) return "" def _render_output(output: dict, has_widget_state: bool) -> str: kind = output["output_type"] if kind == "stream": - return _code_block(ANSI.sub("", output["text"]), "text") + return _text_output(output["text"]) if kind == "error": - return _code_block(ANSI.sub("", "\n".join(output["traceback"])), "text") + return _text_output("\n".join(output["traceback"])) return _render_data(output.get("data", {}), has_widget_state) diff --git a/docs/notebooks/algorithms_and_examples.md b/docs/notebooks/algorithms_and_examples.md index 0aff9f1fa..03633514f 100644 --- a/docs/notebooks/algorithms_and_examples.md +++ b/docs/notebooks/algorithms_and_examples.md @@ -10,25 +10,22 @@ kernelspec: name: python3 --- -```{include} ../README.md ---- -start-after: -end-before: ---- -``` +# 🧪 Algorithms and examples + +--8<-- "README.md:implemented-algorithms" -- {class}`~adaptive.Learner1D`, for 1D functions `f: ℝ → ℝ^N`, -- {class}`~adaptive.Learner2D`, for 2D functions `f: ℝ^2 → ℝ^N`, -- {class}`~adaptive.LearnerND`, for ND functions `f: ℝ^N → ℝ^M`, -- {class}`~adaptive.AverageLearner`, for random variables where you want to average the result over many evaluations, -- {class}`~adaptive.AverageLearner1D`, for stochastic 1D functions where you want to estimate the mean value of the function at each point, -- {class}`~adaptive.IntegratorLearner`, for when you want to intergrate a 1D function `f: ℝ → ℝ`. -- {class}`~adaptive.BalancingLearner`, for when you want to run several learners at once, selecting the “best” one each time you get more points. +- [`Learner1D`][adaptive.Learner1D], for 1D functions `f: ℝ → ℝ^N`, +- [`Learner2D`][adaptive.Learner2D], for 2D functions `f: ℝ^2 → ℝ^N`, +- [`LearnerND`][adaptive.LearnerND], for ND functions `f: ℝ^N → ℝ^M`, +- [`AverageLearner`][adaptive.AverageLearner], for random variables where you want to average the result over many evaluations, +- [`AverageLearner1D`][adaptive.AverageLearner1D], for stochastic 1D functions where you want to estimate the mean value of the function at each point, +- [`IntegratorLearner`][adaptive.IntegratorLearner], for when you want to integrate a 1D function `f: ℝ → ℝ`. +- [`BalancingLearner`][adaptive.BalancingLearner], for when you want to run several learners at once, selecting the “best” one each time you get more points. Meta-learners (to be used with other learners): -- {class}`~adaptive.BalancingLearner`, for when you want to run several learners at once, selecting the “best” one each time you get more points, -- {class}`~adaptive.DataSaver`, for when your function doesn't just return a scalar or a vector. +- [`BalancingLearner`][adaptive.BalancingLearner], for when you want to run several learners at once, selecting the “best” one each time you get more points, +- [`DataSaver`][adaptive.DataSaver], for when your function doesn't just return a scalar or a vector. In addition to the learners, `adaptive` also provides primitives for running the sampling across several cores and even several machines, with built-in support for [concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html), @@ -37,10 +34,10 @@ In addition to the learners, `adaptive` also provides primitives for running the [ipyparallel](https://ipyparallel.readthedocs.io/en/latest/), and [distributed](https://distributed.readthedocs.io/en/latest/). -# 💡 Examples +## 💡 Examples Here are some examples of how Adaptive samples vs. homogeneous sampling. -Click on the *Play* {fa}`play` button or move the sliders. +Click on the *Play* :fontawesome-solid-play: button or move the sliders. ```{code-cell} ipython3 :tags: [hide-cell] @@ -53,11 +50,11 @@ import numpy as np import adaptive from adaptive.learner.learner1D import default_loss, uniform_loss -adaptive.notebook_extension() +adaptive.notebook_extension(_inline_js=False) hv.output(holomap="scrubber") ``` -## {class}`adaptive.Learner1D` +### `adaptive.Learner1D` The `Learner1D` class is designed for adaptively learning 1D functions of the form `f: ℝ → ℝ^N`. It focuses on sampling points where the function is less well understood to improve the overall approximation. This learner is well-suited for functions with localized features or varying degrees of complexity across the domain. @@ -69,18 +66,14 @@ from adaptive import notebook_extension, Runner, Learner1D notebook_extension() # enables notebook integration - def peak(x, a=0.01): # function to "learn" return x + a**2 / (a**2 + x**2) - learner = Learner1D(peak, bounds=(-1, 1)) - def goal(learner): return learner.loss() < 0.01 # continue until loss is small enough - runner = Runner(learner, goal) # start calculation on all CPU cores runner.live_info() # shows a widget with status information runner.live_plot() @@ -126,7 +119,7 @@ layout = plot_homo + plot_adaptive layout.opts(hv.opts.Scatter(active_tools=["box_zoom", wheel_zoom])) ``` -## {class}`adaptive.Learner2D` +### `adaptive.Learner2D` The `Learner2D` class is tailored for adaptively learning 2D functions of the form `f: ℝ^2 → ℝ^N`. Similar to `Learner1D`, it concentrates on sampling points with higher uncertainty to provide a better approximation. This learner is ideal for functions with complex features or varying behavior across a 2D domain. @@ -162,7 +155,7 @@ plot = hv.HoloMap(plots, kdims=["npoints"]).collate() plot.opts(hv.opts.Image(active_tools=[wheel_zoom])) ``` -## {class}`adaptive.AverageLearner` +### `adaptive.AverageLearner` The `AverageLearner` class is designed for situations where you want to average the result of a function over multiple evaluations. This is particularly useful when working with random variables or stochastic functions, as it helps to estimate the mean value of the function. @@ -191,7 +184,7 @@ hm = hv.HoloMap(plots, kdims=["npoints"]) hm.opts(hv.opts.Histogram(active_tools=[wheel_zoom])) ``` -## {class}`adaptive.LearnerND` +### `adaptive.LearnerND` The `LearnerND` class is intended for adaptively learning ND functions of the form `f: ℝ^N → ℝ^M`. It extends the adaptive learning capabilities of the 1D and 2D learners to functions with more dimensions, allowing for efficient exploration of complex, high-dimensional spaces. @@ -226,4 +219,4 @@ scatter["x"], scatter["y"], scatter["z"], scatter.marker["color"] = zip(*coords_ fig ``` -see more in the {ref}`Tutorial Adaptive`. +see more in the [tutorial](tutorial/tutorial.md). diff --git a/docs/notebooks/benchmarks.md b/docs/notebooks/benchmarks.md index 1e8cc4441..d21ba94bf 100644 --- a/docs/notebooks/benchmarks.md +++ b/docs/notebooks/benchmarks.md @@ -13,9 +13,8 @@ kernelspec: # Benchmarks -```{tip} -This page is a Jupyter notebook that can be downloaded and run locally. [^download] -``` +!!! tip + This page is a Jupyter notebook that can be downloaded and run locally. Adaptive sampling is a powerful technique for approximating functions with varying degrees of complexity across their domain. This approach is particularly useful for functions with sharp features or rapid changes, as it focuses on calculating more points around those areas. @@ -28,27 +27,25 @@ We will also present benchmarking results to highlight the advantages (and disad Look below where we demonstrate the use of the adaptive package to perform adaptive sampling and visualize the results. By the end of this benchmarking showcase, you should better understand of the benefits of adaptive sampling and in which cases you could to apply this technique to your own simulations or functions. -```{note} -> Note on error estimates +!!! note + > Note on error estimates -The error is estimated using the L1 norm of the difference between the true function values and the interpolated values. Here's a step-by-step explanation of how the error is calculated: + The error is estimated using the L1 norm of the difference between the true function values and the interpolated values. Here's a step-by-step explanation of how the error is calculated: -1. For each benchmark function, two learners are created: the adaptive learner and a homogeneous learner. The adaptive learner uses adaptive sampling, while the homogeneous learner uses a uniform grid of points. + 1. For each benchmark function, two learners are created: the adaptive learner and a homogeneous learner. The adaptive learner uses adaptive sampling, while the homogeneous learner uses a uniform grid of points. -2. After the adaptive learning is complete, the error is calculated by comparing the interpolated values obtained from the adaptive learner to the true function values evaluated at the points used by the homogeneous learner. + 2. After the adaptive learning is complete, the error is calculated by comparing the interpolated values obtained from the adaptive learner to the true function values evaluated at the points used by the homogeneous learner. -3. To calculate the error, the L1 norm is used. The L1 norm represents the average of the absolute differences between the true function values and the interpolated values. Specifically, it is calculated as the square root of the mean of the squared differences between the true function values and the interpolated values. + 3. To calculate the error, the L1 norm is used. The L1 norm represents the average of the absolute differences between the true function values and the interpolated values. Specifically, it is calculated as the square root of the mean of the squared differences between the true function values and the interpolated values. -Note that the choice of the L1 norm is somewhat arbitrary. -**Please judge the results for yourself by looking at the plots** and observe the significantly better function approximation obtained by the adaptive learner. -``` + Note that the choice of the L1 norm is somewhat arbitrary. + **Please judge the results for yourself by looking at the plots** and observe the significantly better function approximation obtained by the adaptive learner. -```{warning} -> Note on benchmark functions +!!! warning + > Note on benchmark functions -The benchmark functions used in this tutorial are analytical and cheap to evaluate. -In real-world applications ([see the gallery](gallery)), adaptive sampling is often more beneficial for expensive simulations where function evaluations are computationally demanding or time-consuming. -``` + The benchmark functions used in this tutorial are analytical and cheap to evaluate. + In real-world applications ([see the gallery](gallery)), adaptive sampling is often more beneficial for expensive simulations where function evaluations are computationally demanding or time-consuming. ## Benchmarks 1D @@ -66,7 +63,7 @@ from scipy.interpolate import interp1d import adaptive -adaptive.notebook_extension() +adaptive.notebook_extension(_inline_js=False) benchmarks = {} benchmarks_2d = {} @@ -511,5 +508,3 @@ df[["npoints", "error_ratio"]] ```{code-cell} ipython3 plot_benchmarks(df) ``` - -[^download]: This notebook can be downloaded as **{nb-download}`benchmarks.ipynb`** and {download}`benchmarks.md`. diff --git a/docs/notebooks/tutorial/data/example_file.p b/docs/notebooks/tutorial/data/example_file.p new file mode 100644 index 0000000000000000000000000000000000000000..ff7995b25426e8ecd5153898f1e54900a9fa3fda GIT binary patch literal 4555 zcmV;+5j5@}iwFS4B+qIB|2Wv8S? zmP(1TMN*7HNhw-Sl(Ho4d)n7mZ)F)Y=JQ?e^LD0Rf84+4J!GlMQ2P=)r;YJ&89cmQ1@1W7jZibC1cy62kh1|Mg%zs9HWGJK{kK&0)E8pn3FAxi!VE6# zCY~<#N%y&Xq-QYv5qD=L<7e75OEOmXquOX^?*%nR4IUP)X;gV)}&JFPxq9*2m3qp zC-!Zj`)YXt%>J~T;%G!*L>M|9`Q1f!Ls|~ zb2TR+hF2n8e%Sj26%}}*+op}(z7xM8oi&iy8I@C$lb;|>BC4#uyM4#6KG?ZZ)O_Wk zMJ7)@kfs`OR?V#8me-B5h>7?x`PH}yGwoZ5i8ZWduCwJB)mmc8eWt;%jm%5DdWD$s zUa>HWoon~5&?4?4d3cLh;zJ8Z%fq_Fu7zwo5ap1AXuNm1b^SmqvCCh)wpSSYpbl*> z#%5e~A#NrjR^-$tE3j_`acl7;w|{m+OREzxV{y~U(f!)R?(io5Uk1aR`;B#~MzL9o zHT8utMLi0BCw@fo=O(d?k`wC77uyr}l-3L&7NdS-sFA~9VqSNnySl6>Ks~#!uy$G9 ziP-txibp1>`H-)V^Oj&k3u&L*=y%U=6B=*%5%WBH&EiyiDr)tBjfF+rXks3(HKzVp za~f+->m^y=`cBO4di#rN%WQ!Fp%E_nHD`z&5I(=_l74dbsNTfPgwNH>^hRyYMDLuo zs`}FX@h)J3%dT17YCVWKh&9c9hL)WlfDM(kfo3d=nBrk*YfbEk@UXElQ76l!12KUB zEd7-{v7mV~f+=#EYy4B=)FPDMu`!1Ci_K8jO{Vd2YJJR!ofVZ?{iQnY`cXjKZn38B z(cW19zMY6G`(iz@l=Ar1CE<4vv9d|!FPhO-WxJAoc6vXDcxao4Jn;8V!R1f9h+BwU z5q}|d(|O|0;}#cg&KpKdYLxoNi0ZdV?KOG> zQpyC&lzzSM!6vH_FAe43j~DgNR)kqG%^OWYEWO+na&oh@C9R4Rn2n_LM)+2+Es* z)(eo{nnLVpNN|qp+6dxllGE>CY)ijkI2rikeQ?&Vi(;-4E8e|bH{y@C#PbA(=lQrj z)F`(go-GhNJ6&zGS!62las{%4^@Cw%w|&$-^kB8JTwu62S4|ma0(e&}>5BrW8slu> zvJ;&vlK?3U#&GvdUqjJx@0_LAV4U#PvvoqtG%BL=u@pu_SeLYq2$b~T?Nt~tt@U5} zEdWppJ}o@Fn(}+%IyI8ZAiJ6m#%|pL7|K{$g4$?W`a-=#uQ#Z_?Fo!tQ8^#>5U*P; zB^Ac1Aiv|?-B8$VPgva=yXDpQ>;UF%K6Ba7`3Y+4aSNqCK&|?Cr}f?E!+8-OmMw4i zU@#KRsLXpN43=Aar~!RiAvGM*RPpk)(W9FvBym&TSeNmB!ZR#ZMr<~W@i+hRxdS8- zQDxQV+_-+l3*yR%DU9Rpqum4bL5R}MzraXVHR_;QLQG_k<%N5`xvgbHtn|C$?|;4tg0>2<4!x!>PoQ z2965Q+60S?0LWpW|1B0&+#~#Bb^KcvmN| z`7F`hWi0ZE)nI#K7bohPCN#pseCxNCQ$x*ws|pacPeyir*Daa*G=x~Fz^KQ54o2D? z0WuyEM&a}XWBD+B?f@KHY!Xs8awKlb6PdR`01&&MqE+C0wa%I1hsH;V`AZ&Z;9ji< zsg$~ihV26S-IZ<;P29J2Y{|mEqKMfx zTNIA!`4T<&sGG-91x0#RZv3Bl3tX*?rKUi`uEe(qY$;UPJn5qbf_eS)d^_y{?}@z( z3w+tI1xL7w_{jFoaP8g$K3|sNj1tZMR6Mj~*%0Du1d5jQj!$jBVgYd_hT~r8gNJ<> zlnd&=QqyI}r6GXj%rR*VweN=#-!0bU{l3sB&5ej3m+%k-{qhfkj{1hb0DBRy(W|Ub ztAFUGrnI1X%|#{De7}>MpXyG`Qrxs|L`;%vDhhI+*eAQ$vIs0Z@9+J0hC|Ah-cNfTp#q3IFL10} z_0{q(T2KyK1cq0avETFv~giwgVtnpz)Iv=H+?+d>|er<-!xP zIlI=%xh0a=BEdTqw;mlGSm{sPOY%?;64YwaxTYJB5O+mRqvX5GgW}MP8w8(LJzb|g z{^$;9(I|()nl2#U0_$HiCwD>T?vZ`&ZyN;MXt4Nsq34Xl#IH+lH9}Ao+TQ#YK*X*l zH16#ffxdWC5cbG43XW9@PN~c=pR=&nHR4H9yF=3X4VXgQ{AX}y8*mYayBoi-g zLt|ci^!E6&igADxDLH{KEF1dxPDGZ=1saz}2gC$jh=tLH0K8mfmCY2l(Vz)|{MmzB zH_q)1E+`e)TS_KsYwWB*hywjeDo%}(ebE8g2^`CewDVMxs}j!;ER(Tp--&x?5cwkE zb5Z|0X0pgC3|Vbx%nQO@V|tvui!nzc;r7Jeyjih3NOc48*V2+);;H|Js(6}UXC<-$ z95S=wO_yl>MEs?6(>pLm4+#2ZGm3b=V2Avra}Fn|heMDHmdUM4aWaWAC7vT#FUP6d z;obAXi5=YVII(&m2E%u!vsOm<;9e;b8r#A!n%HyoWQ49v+W7>Gl|PsS_lNLk5{TV& z`whw7f}6w>7{i@<{;P@&1joC*X!$=sNkFM~=z5KfsW- zK`+ZcC3gEd@EBefEc5P{%cZWS@UTHtctanxl|`M(L5M=L)rH2ND9Fa>QLUss7oM=tOKHcDUcae!=ci3n&nJqaY<~+`WZhD`givfH9`wY|T4Uz>ZKv z71o6g8wn$WvX@g}xQ|)ttSAX($3Y&Hw74|J%>*=^)Uk6z z4^8t~Oni}G>QbLa*S<{yd?|GTvXlO)b-qzwOfDy(Y+jul0R$MkU|%*JZ9&jUO>sE|!(mpoCp7-p~dS?Qd$h+i+XJh0b-y&BBNr|@aR!w^4Uf{oyJ z`AYj4JHv6r*#U|HJ_5HGp_lb}I;M%6Lbt3_5Bb$4+yMThE95DVr2cq9x7iR}g0kfx)gF2)dhb^oF9oty$c}egM7m z!N$K}<)iOAFfR-64KE~$0QmqD`UXd!?A1Lug)xc?i z8*y`?9150inrvj!wo^sujn5oEnm2KFpTXH~wm%8Eu*-6yK@Uz*8 zFS`=+QCy-UxGBS9t!z{pWKUQdSMqxcXLwKVSwZ}vPz4WOA51=Qa5C|e(&~TU)fkP{kP4vPZ-)$B}ep ptx)g&5?^2>PvoY9*jDVbNhtH`3mfN^J<{Jl{{NXksM3fS004O33Z(!5 literal 0 HcmV?d00001 diff --git a/docs/notebooks/tutorial/data/periodic_example.p b/docs/notebooks/tutorial/data/periodic_example.p new file mode 100644 index 0000000000000000000000000000000000000000..60e2358f839d4c2fe04f0831a3777ac7ca9b6fdf GIT binary patch literal 174 zcmV;f08#%RiwFSEB+qIB|7&2Kx|NXu3~HxnxZ7`YIuXgOn1aN(T$S(pa<2t~!2ksa zhW$;TN}bjTNQ~DI)kus-Vqg=I7#B8ySxAhRFzs;0z1blBuaFqWU=D*bu3<2iVK5%R ztbj8`. +We recommend to start with the [`Learner1D` tutorial](tutorial.Learner1D.md). -```{note} -Because this documentation consists of static html, the `live_plot` and `live_info` widget is not live. -Download the notebooks in order to see the real behaviour. -``` - -```{toctree} -:hidden: true - -tutorial.Learner1D -tutorial.Learner2D -tutorial.custom_loss -tutorial.AverageLearner -tutorial.BalancingLearner -tutorial.DataSaver -tutorial.IntegratorLearner -tutorial.LearnerND -tutorial.AverageLearner1D -tutorial.SequenceLearner -tutorial.parallelism -tutorial.advanced-topics -``` +!!! note + Because this documentation consists of static html, the `live_plot` and `live_info` widget is not live. + Download the notebooks in order to see the real behaviour. diff --git a/docs/notebooks/tutorial/tutorial.parallelism.md b/docs/notebooks/tutorial/tutorial.parallelism.md index 9ca43ddf2..f6daeefd2 100644 --- a/docs/notebooks/tutorial/tutorial.parallelism.md +++ b/docs/notebooks/tutorial/tutorial.parallelism.md @@ -16,8 +16,8 @@ Often you will want to evaluate the function on some remote computing resources. ## `concurrent.futures` -By default {class}`adaptive.Runner` creates a `loky.get_reusable_executor`, which serializes functions by value so it also works with functions defined interactively (e.g. in a notebook). -You can also pass a {class}`~concurrent.futures.ProcessPoolExecutor` explicitly, e.g. to limit the number of workers, but then the function must be importable from `__main__` by the worker processes: +By default [`adaptive.Runner`][adaptive.Runner] creates a [`loky.get_reusable_executor`][loky.get_reusable_executor], which serializes functions by value so it also works with functions defined interactively (e.g. in a notebook). +You can also pass a [`ProcessPoolExecutor`][concurrent.futures.ProcessPoolExecutor] explicitly, e.g. to limit the number of workers, but then the function must be importable from `__main__` by the worker processes: ```python from concurrent.futures import ProcessPoolExecutor @@ -45,7 +45,7 @@ runner.live_plot() ## `distributed.Client` -On Windows by default {class}`adaptive.Runner` uses a `distributed.Client`. +On Windows by default [`adaptive.Runner`][adaptive.Runner] uses a `distributed.Client`. ```python import distributed @@ -58,7 +58,7 @@ runner.live_info() runner.live_plot(update_interval=0.1) ``` -Also check out the {ref}`Custom parallelization` section in the {ref}`advanced topics tutorial` for more control over caching and parallelization. +Also check out the [Custom parallelization](tutorial.advanced-topics.md#custom-parallelization-using-coroutines) section in the [advanced topics tutorial](tutorial.advanced-topics.md) for more control over caching and parallelization. ## `mpi4py.futures.MPIPoolExecutor` @@ -123,7 +123,7 @@ srun -n $SLURM_NTASKS --mpi=pmi2 ~/miniconda3/envs/py37_min/bin/python -m mpi4py ## `loky.get_reusable_executor` -This executor is basically a powered-up version of {class}`~concurrent.futures.ProcessPoolExecutor`, check its [documentation](https://loky.readthedocs.io/). +This executor is basically a powered-up version of [`ProcessPoolExecutor`][concurrent.futures.ProcessPoolExecutor], check its [documentation](https://loky.readthedocs.io/). Among other things, it allows to *reuse* the executor and uses `cloudpickle` for serialization. This means you can even learn closures, lambdas, or other functions that are not picklable with `pickle`. diff --git a/docs/test_build_notebooks.py b/docs/test_build_notebooks.py index 31d8a06db..b17f0cc80 100644 --- a/docs/test_build_notebooks.py +++ b/docs/test_build_notebooks.py @@ -112,3 +112,11 @@ def test_widget_state_round_trips_html_values(): start = md.index('", start)] assert json.loads(content) == state + + +def test_inline_plotly_bundle_replaced_by_cdn(): + bundle = "\n" + out = new_output("display_data", data={"text/html": bundle, "text/plain": ""}) + md = render(new_code_cell("learner.plot_3D()", outputs=[out])) + assert '" - data = {"application/vnd.jupyter.widget-view+json": WIDGET_VIEW, "text/plain": "HTML()"} + data = { + "application/vnd.jupyter.widget-view+json": WIDGET_VIEW, + "text/plain": "HTML()", + } state = {"state": {"abc": {"state": {"value": value}}}, "version_major": 2} metadata = {"widgets": {"application/vnd.jupyter.widget-state+json": state}} - md = render(new_code_cell("w", outputs=[new_output("display_data", data=data)]), metadata=metadata) + md = render( + new_code_cell("w", outputs=[new_output("display_data", data=data)]), + metadata=metadata, + ) start = md.index('", start)] assert json.loads(content) == state def test_inline_plotly_bundle_replaced_by_cdn(): - bundle = "\n" + bundle = ( + "\n" + ) out = new_output("display_data", data={"text/html": bundle, "text/plain": ""}) md = render(new_code_cell("learner.plot_3D()", outputs=[out])) assert '' + '@jupyter-widgets/html-manager@1.0.15/dist/embed.js" crossorigin="anonymous">' ) ANSI = re.compile(r"\x1b\[[0-9;]*[A-Za-z]") # adaptive calls plotly.offline.init_notebook_mode(), which inlines plotly.js. @@ -126,14 +127,27 @@ def _render_code_cell(cell: dict, has_widget_state: bool) -> str: if "remove-output" in tags else [_render_output(o, has_widget_state) for o in cell.get("outputs", [])] ) - outputs_md = "\n\n".join(o for o in outputs if o) - if "hide-cell" in tags: - return _details(HIDE_LABELS["hide-cell"], f"{source}\n\n{outputs_md}".strip()) - if "hide-input" in tags and source: + # Raw HTML is escaped inside a `markdown="1"`
, so hidden cells + # only hide their source and text outputs; raw outputs follow the block. + raw = "\n\n".join(o for o in outputs if o.startswith('
str: + return "\n\n".join(part for part in parts if part) def _download_note(ipynb_name: str) -> str: @@ -182,10 +196,17 @@ def _execute(nb: nbformat.NotebookNode, cwd: Path) -> nbformat.NotebookNode: return client.execute() +def _library_versions() -> str: + # Outputs embed these libraries' versions (e.g. BokehJS CDN URLs). + packages = ("adaptive", "bokeh", "holoviews", "ipywidgets", "panel", "plotly") + return " ".join(f"{name}=={version(name)}" for name in packages) + + def execute_cached(source: Path) -> nbformat.NotebookNode: """Execute a jupytext notebook, reusing the cached result if unchanged.""" text = source.read_text() - cached = CACHE_DIR / f"{hashlib.sha256(text.encode()).hexdigest()}.ipynb" + key = hashlib.sha256(f"{_library_versions()}\n{text}".encode()).hexdigest() + cached = CACHE_DIR / f"{key}.ipynb" if cached.exists(): return nbformat.read(cached, as_version=4) nb = _execute(jupytext.reads(text, fmt="md:myst"), source.parent) @@ -201,7 +222,9 @@ def build(source: Path) -> Path: target.parent.mkdir(parents=True, exist_ok=True) ipynb = target.with_suffix(".ipynb") nb = execute_cached(source) - target.write_text(render_notebook(nb, ipynb.name)) + # Read by docs/overrides/partials/actions.html to link "Edit" to the source. + front_matter = f"---\nnotebook_source: {source.relative_to(DOCS_DIR)}\n---\n\n" + target.write_text(front_matter + render_notebook(nb, ipynb.name)) if any(cell.cell_type == "code" for cell in nb.cells): jupytext.write(jupytext.read(source), ipynb) print(f"{source.relative_to(DOCS_DIR)}: {time.monotonic() - start:.1f}s") diff --git a/docs/griffe_sphinx_refs.py b/docs/griffe_sphinx_refs.py index 1cfec2e78..197304d40 100644 --- a/docs/griffe_sphinx_refs.py +++ b/docs/griffe_sphinx_refs.py @@ -41,6 +41,7 @@ def sphinx_refs_to_autorefs(text: str, public: frozenset[str]) -> str: if i + 1 < len(lines) and re.fullmatch(r"-{3,}", lines[i + 1].strip()): section = line.strip() elif section in FIELD_SECTIONS and line.strip() and not line[0].isspace(): + line = re.sub(r"``([^`]+)``", r"\1", line) lines[i] = SPHINX_REF.sub(lambda m: m.group(2), line) else: lines[i] = _link_refs(line, public) diff --git a/docs/notebooks/algorithms_and_examples.md b/docs/notebooks/algorithms_and_examples.md index 7f5397e19..56adb1e9b 100644 --- a/docs/notebooks/algorithms_and_examples.md +++ b/docs/notebooks/algorithms_and_examples.md @@ -66,14 +66,18 @@ from adaptive import notebook_extension, Runner, Learner1D notebook_extension() # enables notebook integration + def peak(x, a=0.01): # function to "learn" return x + a**2 / (a**2 + x**2) + learner = Learner1D(peak, bounds=(-1, 1)) + def goal(learner): return learner.loss() < 0.01 # continue until loss is small enough + runner = Runner(learner, goal) # start calculation on all CPU cores runner.live_info() # shows a widget with status information runner.live_plot() diff --git a/docs/notebooks/benchmarks.md b/docs/notebooks/benchmarks.md index d21ba94bf..838089450 100644 --- a/docs/notebooks/benchmarks.md +++ b/docs/notebooks/benchmarks.md @@ -13,9 +13,6 @@ kernelspec: # Benchmarks -!!! tip - This page is a Jupyter notebook that can be downloaded and run locally. - Adaptive sampling is a powerful technique for approximating functions with varying degrees of complexity across their domain. This approach is particularly useful for functions with sharp features or rapid changes, as it focuses on calculating more points around those areas. By concentrating points where they are needed most, adaptive sampling can provide an accurate representation of the function with fewer points compared to uniform sampling. @@ -27,9 +24,7 @@ We will also present benchmarking results to highlight the advantages (and disad Look below where we demonstrate the use of the adaptive package to perform adaptive sampling and visualize the results. By the end of this benchmarking showcase, you should better understand of the benefits of adaptive sampling and in which cases you could to apply this technique to your own simulations or functions. -!!! note - > Note on error estimates - +!!! note "Note on error estimates" The error is estimated using the L1 norm of the difference between the true function values and the interpolated values. Here's a step-by-step explanation of how the error is calculated: 1. For each benchmark function, two learners are created: the adaptive learner and a homogeneous learner. The adaptive learner uses adaptive sampling, while the homogeneous learner uses a uniform grid of points. @@ -41,11 +36,9 @@ By the end of this benchmarking showcase, you should better understand of the be Note that the choice of the L1 norm is somewhat arbitrary. **Please judge the results for yourself by looking at the plots** and observe the significantly better function approximation obtained by the adaptive learner. -!!! warning - > Note on benchmark functions - +!!! warning "Note on benchmark functions" The benchmark functions used in this tutorial are analytical and cheap to evaluate. - In real-world applications ([see the gallery](gallery)), adaptive sampling is often more beneficial for expensive simulations where function evaluations are computationally demanding or time-consuming. + In real-world applications ([see the gallery](gallery.md)), adaptive sampling is often more beneficial for expensive simulations where function evaluations are computationally demanding or time-consuming. ## Benchmarks 1D diff --git a/docs/notebooks/tutorial/tutorial.advanced-topics.md b/docs/notebooks/tutorial/tutorial.advanced-topics.md index fd6ee5076..99355b7e1 100644 --- a/docs/notebooks/tutorial/tutorial.advanced-topics.md +++ b/docs/notebooks/tutorial/tutorial.advanced-topics.md @@ -499,9 +499,11 @@ The simplest way to accomplish this is simply to use the [`BlockingRunner`][adap ```python import adaptive + def f(x): return x + learner = adaptive.Learner1D(f, (-1, 1)) adaptive.BlockingRunner(learner, loss_goal=0.1) diff --git a/docs/overrides/partials/actions.html b/docs/overrides/partials/actions.html new file mode 100644 index 000000000..14bbbfed2 --- /dev/null +++ b/docs/overrides/partials/actions.html @@ -0,0 +1,34 @@ +{#- + Zensical's partials/actions.html, but pages rendered by docs/build_notebooks.py + link "Edit" and "View" to their notebook source in docs/notebooks/. +-#} +{% set edit_url = page.edit_url %} +{% if page.meta and page.meta.notebook_source and edit_url %} + {% set edit_uri = (config.edit_uri ~ "/") | replace("//", "/") %} + {% set edit_url = config.repo_url ~ "/" ~ edit_uri ~ page.meta.notebook_source %} +{% endif %} +{% if "content.action.copy" in features and page.markdown_url %} + +{% endif %} +{% if edit_url %} + {% if "content.action.edit" in features %} + + {% set icon = config.theme.icon.edit or "material/file-edit-outline" %} + {% include ".icons/" ~ icon ~ ".svg" %} + + {% endif %} + {% if "content.action.view" in features %} + {% if "/blob/" in edit_url %} + {% set part = "/blob/" %} + {% else %} + {% set part = "/edit/" %} + {% endif %} + + {% set icon = config.theme.icon.view or "material/file-eye-outline" %} + {% include ".icons/" ~ icon ~ ".svg" %} + + {% endif %} +{% endif %} diff --git a/docs/test_build_notebooks.py b/docs/test_build_notebooks.py index dabb0240d..635f69128 100644 --- a/docs/test_build_notebooks.py +++ b/docs/test_build_notebooks.py @@ -7,6 +7,7 @@ import sys from pathlib import Path +import markdown # type: ignore[import-untyped] from nbformat.v4 import new_code_cell, new_markdown_cell, new_notebook, new_output sys.path.insert(0, str(Path(__file__).parent)) @@ -136,3 +137,49 @@ def test_inline_plotly_bundle_replaced_by_cdn(): md = render(new_code_cell("learner.plot_3D()", outputs=[out])) assert '