Skip to content

Commit 25bf4cc

Browse files
authored
Rewrite the README, fix the docs badge and the dark-mode live_info table (#502)
* Rewrite the README, fix the docs badge and the dark-mode live_info table - Restructure the README: centered logo and title, the animations right after a plain summary, a short feature list, a quick start with a script and a Jupyter example, a learner table, executors, documentation links, and a table of the optional extras. - Use the shields.io Read the Docs badge; the readthedocs.org badge redirects and does not load as an image. Add a tests badge and drop the GitHub stars badge. - Drop the doctoc table of contents (GitHub shows an outline) and the TOC generator workflow that maintained it. - In dark mode, give the white widget card the light theme colors, so the rows of the live_info table are no longer dark. * Rewrite the README in plain prose, drop the Zensical footer credit Go back to the voice of the original README: plain sentences instead of a bold-labelled feature list and tagline, the learner list instead of a table, and the installation and development steps as before. The docs home page no longer includes the removed feature list. Set extra.generator = false so the footer no longer says "Made with Zensical". * Address the README review: runnable script example, scope, executors - Make the script example self-contained (it used peak from the notebook example) and show to_numpy() in it. - Say that adaptive is meant for functions of a few parameters. - Explain what the loss function is and point to the built-in alternatives and the custom loss tutorial. - Say that the runners use all local cores by default, how to pass another executor, and link the parallelism tutorial. - Install with plain pip install adaptive; the [notebook] extra adds live plotting and pandas for to_dataframe(). - Development: add the test command; the notebook git filter needs nbconvert and only matters for example-notebook.ipynb. - Move the animation caption into the summary snippet, so the docs home page shows it too; label the conda downloads badge; fix the CQUAD link. - Parallelism tutorial: drop the stale claim that Windows defaults to distributed.Client; loky is the default everywhere.
1 parent e74ac3b commit 25bf4cc

6 files changed

Lines changed: 79 additions & 121 deletions

File tree

‎.github/workflows/toc.yaml‎

Lines changed: 0 additions & 10 deletions
This file was deleted.

‎README.md‎

Lines changed: 70 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,42 @@
1-
21
# ![logo](https://adaptive.readthedocs.io/en/latest/_static/logo.png) *Adaptive*: Parallel Active Learning of Mathematical Functions
32
<!-- --8<-- [start:badges] -->
43

5-
[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/python-adaptive/adaptive/main?filepath=example-notebook.ipynb)
6-
[![Conda](https://img.shields.io/badge/install%20with-conda-green.svg)](https://anaconda.org/conda-forge/adaptive)
4+
[![Tests](https://img.shields.io/github/actions/workflow/status/python-adaptive/adaptive/nox.yml?branch=main&label=tests)](https://github.com/python-adaptive/adaptive/actions/workflows/nox.yml)
5+
[![PyPI](https://img.shields.io/pypi/v/adaptive.svg)](https://pypi.org/project/adaptive/)
6+
[![Conda](https://img.shields.io/conda/vn/conda-forge/adaptive.svg)](https://anaconda.org/conda-forge/adaptive)
7+
[![Python](https://img.shields.io/pypi/pyversions/adaptive.svg)](https://pypi.org/project/adaptive/)
8+
[![Documentation](https://img.shields.io/readthedocs/adaptive)](https://adaptive.readthedocs.io/en/latest/)
79
[![Coverage](https://img.shields.io/codecov/c/github/python-adaptive/adaptive)](https://codecov.io/gh/python-adaptive/adaptive)
10+
[![Downloads](https://img.shields.io/conda/dn/conda-forge/adaptive.svg?label=conda%20downloads)](https://anaconda.org/conda-forge/adaptive)
811
[![DOI](https://img.shields.io/badge/doi-10.5281%2Fzenodo.1182437-blue.svg)](https://doi.org/10.5281/zenodo.1182437)
9-
[![Documentation](https://readthedocs.org/projects/adaptive/badge/?version=latest)](https://adaptive.readthedocs.io/en/latest/?badge=latest)
10-
[![Downloads](https://img.shields.io/conda/dn/conda-forge/adaptive.svg)](https://anaconda.org/conda-forge/adaptive)
11-
[![GitHub](https://img.shields.io/github/stars/python-adaptive/adaptive.svg?style=social)](https://github.com/python-adaptive/adaptive/stargazers)
12-
[![PyPI](https://img.shields.io/pypi/v/adaptive.svg)](https://pypi.python.org/pypi/adaptive)
13-
[![Python](https://img.shields.io/pypi/pyversions/adaptive.svg)](https://pypi.python.org/pypi/adaptive)
12+
[![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/python-adaptive/adaptive/main?filepath=example-notebook.ipynb)
1413

1514
<!-- --8<-- [end:badges] -->
1615

1716
<!-- --8<-- [start:summary] -->
1817

19-
Adaptive is an open-source Python library that streamlines adaptive parallel function evaluations.
20-
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.
21-
With minimal code, you can perform evaluations on a computing cluster, display live plots, and optimize the adaptive sampling algorithm.
22-
23-
Adaptive is most efficient for computations where each function evaluation takes at least ≈50ms due to the overhead of selecting potentially interesting points.
24-
25-
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/).
26-
27-
<!-- --8<-- [end:summary] -->
28-
29-
<details><summary><b>Table of contents</b></summary>
30-
31-
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
32-
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
33-
34-
- [Key features](#key-features)
35-
- [Example usage](#example-usage)
36-
- [Exporting Data](#exporting-data)
37-
- [Implemented Algorithms](#implemented-algorithms)
38-
- [Installation](#installation)
39-
- [Faster triangulation (optional)](#faster-triangulation-optional)
40-
- [Development](#development)
41-
- [Documentation](#documentation)
42-
- [Citing](#citing)
43-
- [Draft Paper](#draft-paper)
44-
- [Credits](#credits)
45-
46-
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
18+
`adaptive` is an open-source Python library for adaptive parallel function evaluation.
19+
You supply a function and its bounds, and `adaptive` evaluates it at the "best" points in parameter space, instead of at *all* points of a dense grid.
20+
With a few lines of code you can run the evaluations on a computing cluster, live-plot the data as it comes in, and fine-tune the sampling algorithm.
4721

48-
</details>
22+
`adaptive` works best when each function evaluation takes *at least* ≈50 ms, because picking the next points has some overhead.
23+
It is meant for functions of a few parameters: with more dimensions, `LearnerND` quickly becomes slower and less effective.
4924

50-
<!-- --8<-- [start:key-features] -->
25+
Try the example notebook [on Binder](https://mybinder.org/v2/gh/python-adaptive/adaptive/main?filepath=example-notebook.ipynb) or read the [tutorial](https://adaptive.readthedocs.io/en/latest/tutorial/tutorial/).
5126

52-
## Key features
27+
With the same number of points, adaptive sampling resolves features that a homogeneous grid misses:
5328

54-
- **Intelligent Adaptive Sampling**: Adaptive focuses on areas of interest within a function, ensuring better results with fewer evaluations, saving time, and computational resources.
55-
- **Parallel Execution**: The library leverages parallel processing for faster function evaluations, making optimal use of available computational resources.
56-
- **Live Plotting and Info Widgets**: When working in Jupyter notebooks, Adaptive offers real-time visualization of the learning process, making it easier to monitor progress and identify areas of improvement.
57-
- **Customizable Loss Functions**: Adaptive supports various loss functions and allows customization, enabling users to tailor the learning process according to their specific needs.
58-
- **Support for Multidimensional Functions**: The library can handle functions with scalar or vector outputs in one or multiple dimensions, providing flexibility for a wide range of problems.
59-
- **Seamless Integration**: Adaptive offers a simple and intuitive interface, making it easy to integrate with existing Python projects and workflows.
60-
- **Flexible Data Export**: The library provides options to export learned data as NumPy arrays or Pandas DataFrames, ensuring compatibility with various data processing tools.
61-
- **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.
29+
<!-- --8<-- [end:summary] -->
6230

63-
<!-- --8<-- [end:key-features] -->
31+
<p align="center">
32+
<img src="https://raw.githubusercontent.com/python-adaptive/adaptive/main/docs/_static/readme/learner1d.gif" width="43%" alt="Learner1D: homogeneous grid versus adaptive sampling of a sharp peak">
33+
<img src="https://raw.githubusercontent.com/python-adaptive/adaptive/main/docs/_static/readme/learner2d.gif" width="36%" alt="Learner2D: homogeneous grid versus adaptive triangulation of a ring">
34+
<img src="https://raw.githubusercontent.com/python-adaptive/adaptive/main/docs/_static/readme/learnerND.gif" width="19%" alt="LearnerND: sampled points concentrate on a spherical shell">
35+
</p>
6436

65-
## Example usage
37+
## Example
6638

67-
Adaptively learning a 1D function and live-plotting the process in a Jupyter notebook:
39+
Learning a 1D function and live-plotting the process in a Jupyter notebook:
6840

6941
```python
7042
from adaptive import notebook_extension, Runner, Learner1D
@@ -82,82 +54,82 @@ runner.live_info()
8254
runner.live_plot()
8355
```
8456

85-
With the same number of points, adaptive sampling resolves features that a homogeneous grid misses:
57+
The `Runner` works in the background, so the notebook stays usable while it runs.
58+
In a script, use `BlockingRunner`, which returns once the goal is reached:
8659

87-
<p align="center">
88-
<img src="https://raw.githubusercontent.com/python-adaptive/adaptive/main/docs/_static/readme/learner1d.gif" width="43%" alt="Learner1D: homogeneous grid versus adaptive sampling of a sharp peak">
89-
<img src="https://raw.githubusercontent.com/python-adaptive/adaptive/main/docs/_static/readme/learner2d.gif" width="36%" alt="Learner2D: homogeneous grid versus adaptive triangulation of a ring">
90-
<img src="https://raw.githubusercontent.com/python-adaptive/adaptive/main/docs/_static/readme/learnerND.gif" width="19%" alt="LearnerND: sampled points concentrate on a spherical shell">
91-
</p>
92-
93-
### Exporting Data
60+
```python
61+
from adaptive import BlockingRunner, Learner1D
9462

95-
You can export the learned data as a NumPy array:
9663

97-
```python
98-
data = learner.to_numpy()
99-
```
64+
def peak(x, a=0.01):
65+
return x + a**2 / (a**2 + x**2)
10066

101-
If you have Pandas installed, you can also export the data as a DataFrame:
10267

103-
```python
104-
df = learner.to_dataframe()
68+
learner = Learner1D(peak, bounds=(-1, 1))
69+
BlockingRunner(learner, loss_goal=0.01)
70+
data = learner.to_numpy() # array with columns x, y
10571
```
10672

73+
`learner.to_dataframe()` returns the same data as a pandas DataFrame (pandas comes with the `[notebook]` extra).
74+
10775
<!-- --8<-- [start:implemented-algorithms] -->
10876

109-
## Implemented Algorithms
77+
## Implemented algorithms
11078

11179
The core concept in `adaptive` is the *learner*.
112-
A *learner* samples a function at the most interesting locations within its parameter space, allowing for optimal sampling of the function.
113-
As the function is evaluated at more points, the learner improves its understanding of the best locations to sample next.
80+
A learner samples a function at the points in its parameter space that tell it the most about the function.
81+
As it evaluates more points, it gets a better idea of where to sample next.
11482

115-
The definition of the "best locations" depends on your application domain.
116-
While `adaptive` provides sensible default choices, the adaptive sampling process can be fully customized.
83+
What the "best" points are depends on your application.
84+
Each learner ranks candidate points with a *loss function*.
85+
The default losses put more points where the function changes quickly; you can pass a built-in alternative, such as `curvature_loss_function()` or `resolution_loss_function()`, or write your own (see the [custom loss tutorial](https://adaptive.readthedocs.io/en/latest/tutorial/tutorial.custom_loss/)).
11786

11887
The following learners are implemented:
11988

12089
<!-- --8<-- [end:implemented-algorithms] -->
12190

122-
- `Learner1D`: for 1D functions `f: ℝ → ℝ^N`,
123-
- `Learner2D`: for 2D functions `f: ℝ^2 → ℝ^N`,
124-
- `LearnerND`: for ND functions `f: ℝ^N → ℝ^M`,
125-
- `AverageLearner`: for random variables, allowing averaging of results over multiple evaluations,
126-
- `AverageLearner1D`: for stochastic 1D functions, estimating the mean value at each point,
127-
- `IntegratorLearner`: for integrating a 1D function `f: ℝ → ℝ`,
128-
- `SequenceLearner`: for evaluating a fixed sequence of points while still using the runners, parallelism, and data export of Adaptive.
91+
- `Learner1D`, for 1D functions `f: ℝ → ℝ^N`,
92+
- `Learner2D`, for 2D functions `f: ℝ^2 → ℝ^N`,
93+
- `LearnerND`, for ND functions `f: ℝ^N → ℝ^M`,
94+
- `AverageLearner`, for random variables where you want to average the result over many evaluations,
95+
- `AverageLearner1D`, for stochastic 1D functions where you want to estimate the mean value of the function at each point,
96+
- `IntegratorLearner`, for when you want to integrate a 1D function `f: ℝ → ℝ`,
97+
- `SequenceLearner`, for when you want to evaluate a fixed sequence of points while still using the runners and data export of `adaptive`.
12998

13099
Meta-learners (to be used with other learners):
131100

132-
- `BalancingLearner`: for running several learners at once, selecting the "most optimal" one each time you get more points,
133-
- `DataSaver`: for when your function doesn't return just a scalar or a vector.
101+
- `BalancingLearner`, for when you want to run several learners at once, selecting the "best" one each time you get more points,
102+
- `DataSaver`, for when your function doesn't just return a scalar or a vector.
134103

135-
In addition to learners, `adaptive` offers primitives for parallel sampling across multiple cores or machines, with built-in support for:
104+
In addition to the learners, `adaptive` provides primitives for running the sampling across several cores and even several machines, with built-in support for
136105
[concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html),
137106
[mpi4py](https://mpi4py.readthedocs.io/en/stable/mpi4py.futures.html),
138107
[loky](https://loky.readthedocs.io/en/stable/),
139108
[ipyparallel](https://ipyparallel.readthedocs.io/en/latest/), and
140109
[distributed](https://distributed.readthedocs.io/en/latest/).
141110

111+
By default, both runners evaluate the function in parallel on all cores of the local machine, using loky.
112+
To use one of the others, pass it as `executor`, for example `Runner(learner, executor=distributed.Client())`; the [parallelism tutorial](https://adaptive.readthedocs.io/en/latest/tutorial/tutorial.parallelism/) has an example for each.
113+
142114
<!-- --8<-- [start:rest] -->
143115

144116
## Installation
145117

146-
`adaptive` works with Python 3.11 and higher on Linux, Windows, or Mac, and provides optional extensions for working with Jupyter.
118+
`adaptive` works with Python 3.11 and higher on Linux, Windows, and macOS.
147119

148-
The recommended way to install adaptive is using `conda`:
120+
Install it with `conda`:
149121

150122
```bash
151123
conda install -c conda-forge adaptive
152124
```
153125

154-
`adaptive` is also available on PyPI:
126+
or from PyPI:
155127

156128
```bash
157-
pip install "adaptive[notebook]"
129+
pip install adaptive
158130
```
159131

160-
The `[notebook]` above also installs the optional dependencies for live plotting and widgets in JupyterLab and Jupyter Notebook; no extra Jupyter extensions need to be installed.
132+
Add the `[notebook]` extra (`pip install "adaptive[notebook]"`) for live plotting and widgets in JupyterLab and Jupyter Notebook, and for `to_dataframe()`; no Jupyter extensions are needed.
161133

162134
### Faster triangulation (optional)
163135

@@ -167,38 +139,32 @@ Installing the optional [adaptive-triangulation](https://github.com/python-adapt
167139
pip install "adaptive[rust]"
168140
```
169141

170-
No code changes are needed — the Rust backend is detected and used automatically.
142+
No code changes are needed. The Rust backend is detected and used automatically.
171143
To control the selection, pass `LearnerND(..., triangulation_backend="python" | "rust" | "auto")` per learner, or set the environment variable `ADAPTIVE_TRIANGULATION_BACKEND=python` to force the pure-Python implementation globally (or to `rust` to make a missing Rust backend an error instead of a silent fallback).
172144

173145
## Development
174146

175147
Clone the repository and install it in editable mode with the optional dependencies:
176148

177149
```bash
178-
git clone git@github.com:python-adaptive/adaptive.git
150+
git clone https://github.com/python-adaptive/adaptive.git
179151
cd adaptive
180152
pip install -e ".[notebook,test,other]"
181153
```
182154

183155
We recommend a virtual environment, for example with [uv](https://docs.astral.sh/uv/) (`uv sync --extra notebook --extra test --extra other`) or Conda.
184156

185-
To avoid polluting the history with notebook output, set up the git filter by running:
186-
187-
```bash
188-
python ipynb_filter.py
189-
```
190-
191-
in the repository.
192-
193-
To maintain consistent code style, we use [pre-commit](https://pre-commit.com). Install it by running:
157+
We use [pre-commit](https://pre-commit.com) for a consistent code style; install the hooks with
194158

195159
```bash
196160
pre-commit install
197161
```
198162

199-
in the repository.
163+
Run the tests with `pytest`.
200164

201-
### Documentation
165+
If you edit `example-notebook.ipynb`, install `nbconvert` and run `python ipynb_filter.py` once, so git strips the notebook output on commit.
166+
167+
### Building the documentation
202168

203169
The documentation is built with [Zensical](https://zensical.org).
204170
The executable pages in `docs/notebooks/` are Jupyter notebooks in [jupytext's MyST Markdown format](https://jupytext.readthedocs.io/en/latest/formats-markdown.html).
@@ -209,11 +175,11 @@ uv run --group docs python docs/build_notebooks.py
209175
uv run --group docs zensical serve # preview on http://localhost:8000
210176
```
211177

212-
The animations in this README are rendered from real learner runs with `uv run --group docs python docs/make_animations.py` (requires `ffmpeg` and Chrome or Chromium).
178+
The README animations are made from real learner runs with `uv run --group docs python docs/make_animations.py`, which needs `ffmpeg` and Chrome or Chromium.
213179

214180
## Citing
215181

216-
If you used Adaptive in a scientific work, please cite it as follows.
182+
If you used `adaptive` in a scientific work, please cite it as follows.
217183

218184
```bib
219185
@misc{Nijholt2019,
@@ -225,22 +191,19 @@ If you used Adaptive in a scientific work, please cite it as follows.
225191
}
226192
```
227193

228-
## Draft Paper
229-
230-
If you're interested in the scientific background and principles behind Adaptive, we recommend taking a look at the [draft paper](https://github.com/python-adaptive/paper) that is currently being written.
231-
This paper provides a comprehensive overview of the concepts, algorithms, and applications of the Adaptive library.
194+
The algorithms are described in more detail in a [draft paper](https://github.com/python-adaptive/paper).
232195

233196
## Credits
234197

235198
We would like to give credits to the following people:
236199

237-
- 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.
238-
- Pauli Virtanen for his `AdaptiveTriSampling` script (no longer available online since SciPy Central went down) which served as inspiration for the `adaptive.Learner2D`.
200+
- Pedro Gonnet for his implementation of [CQUAD](https://www.gnu.org/software/gsl/doc/html/integration.html#cquad-doubly-adaptive-integration), "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.
201+
- Pauli Virtanen for his `AdaptiveTriSampling` script (no longer available online since SciPy Central went down), which served as inspiration for `adaptive.Learner2D`.
239202

240203
<!-- --8<-- [end:rest] -->
241204
<!-- --8<-- [start:community] -->
242205

243206
For general discussion, we have a [Gitter chat channel](https://gitter.im/python-adaptive/adaptive).
244-
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).
207+
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).
245208

246209
<!-- --8<-- [end:community] -->

‎docs/_static/extra.css‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
[data-md-color-scheme="slate"] .md-typeset .nb-output:has([data-root-id]:not(:empty)),
4545
[data-md-color-scheme="slate"] .md-typeset .nb-output:has(.plotly-graph-div),
4646
[data-md-color-scheme="slate"] .md-typeset .nb-output:has(.jupyter-widgets) {
47+
/* light theme colors, so e.g. the `live_info` table is not dark inside */
48+
--md-default-bg-color: #ffffff;
49+
--md-default-fg-color: #000000de;
50+
--md-typeset-color: #000000de;
51+
--md-typeset-table-color: #0000001f;
52+
--md-typeset-table-color--light: #00000009;
4753
background: #ffffff;
4854
color: #000000;
4955
border-radius: 0.4rem;

‎docs/index.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,3 @@ hide:
2222
[Start the tutorial](tutorial/tutorial.Learner1D.md){ .md-button .md-button--primary }
2323
[See the examples](algorithms_and_examples.md){ .md-button }
2424
[API reference](reference/adaptive.md){ .md-button }
25-
26-
--8<-- "README.md:key-features"

‎docs/notebooks/tutorial/tutorial.parallelism.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ runner.live_plot()
4545

4646
## `distributed.Client`
4747

48-
On Windows by default [`adaptive.Runner`][adaptive.Runner] uses a `distributed.Client`.
49-
5048
```python
5149
import distributed
5250

‎zensical.toml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ code = "JetBrains Mono"
134134
[project.theme.icon]
135135
repo = "fontawesome/brands/github"
136136

137+
[project.extra]
138+
generator = false # no "Made with Zensical" in the footer
139+
137140
[[project.extra.social]]
138141
icon = "fontawesome/brands/github"
139142
link = "https://github.com/python-adaptive/adaptive"

0 commit comments

Comments
 (0)