Skip to content

Commit

Permalink
Merge branch 'tutorial' into 'master'
Browse files Browse the repository at this point in the history
add tutorials

See merge request qt/adaptive!129
  • Loading branch information
basnijholt committed Oct 18, 2018
2 parents 77ec068 + 76f7f85 commit 987b5f9
Show file tree
Hide file tree
Showing 22 changed files with 1,354 additions and 8 deletions.
2 changes: 1 addition & 1 deletion adaptive/notebook_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def notebook_extension():
try:
import ipywidgets
import holoviews
holoviews.notebook_extension('bokeh')
holoviews.notebook_extension('bokeh', logo=False)
_plotting_enabled = True
except ModuleNotFoundError:
warnings.warn("holoviews and (or) ipywidgets are not installed; plotting "
Expand Down
4 changes: 2 additions & 2 deletions adaptive/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ class BlockingRunner(BaseRunner):
of cores available in `executor`.
log : bool, default: False
If True, record the method calls made to the learner by this runner.
shutdown_executor : Bool, default: False
shutdown_executor : bool, default: False
If True, shutdown the executor when the runner has completed. If
`executor` is not provided then the executor created internally
by the runner is shut down, regardless of this parameter.
Expand Down Expand Up @@ -367,7 +367,7 @@ class AsyncRunner(BaseRunner):
of cores available in `executor`.
log : bool, default: False
If True, record the method calls made to the learner by this runner.
shutdown_executor : Bool, default: False
shutdown_executor : bool, default: False
If True, shutdown the executor when the runner has completed. If
`executor` is not provided then the executor created internally
by the runner is shut down, regardless of this parameter.
Expand Down
1 change: 1 addition & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build/*
source/_static/holoviews.*
1 change: 1 addition & 0 deletions docs/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ dependencies:
- scikit-optimize
- pip:
- sphinx_rtd_theme
- git+https://github.com/basnijholt/jupyter-sphinx.git@widgets_execute
1 change: 1 addition & 0 deletions docs/source/_static/jquery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// This file is empty because we are already loading jQuery with holoviews in the <head>
6 changes: 6 additions & 0 deletions docs/source/_templates/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% extends "!layout.html" %}
{% block extrahead %}
{%- for scriptfile in holoviews_js_files %}
{{ js_tag(scriptfile) }}
{%- endfor %}
{% endblock %}
35 changes: 30 additions & 5 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
'jupyter_sphinx.execute',
]

source_parsers = {}
Expand Down Expand Up @@ -86,6 +87,7 @@
#
html_theme = 'sphinx_rtd_theme'


# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
Expand Down Expand Up @@ -113,13 +115,36 @@
# Output file base name for HTML help builder.
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),
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),
}


def get_holoviews_js_css():
from holoviews.plotting import Renderer
dependencies = {**Renderer.core_dependencies,
**Renderer.extra_dependencies}
required = ['jQueryUI', 'jQuery', 'require']
js = [url for name in required for url in dependencies[name].get('js', [])]
css = [url for name in required for url in dependencies[name].get('css', [])]
return js, css


js, css = get_holoviews_js_css()
html_context = {'holoviews_js_files': js}


def setup(app):
for url in css:
app.add_stylesheet(url)

app.add_javascript("https://unpkg.com/@jupyter-widgets/html-manager@0.14.4/dist/embed-amd.js")
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
:hidden:

rest_of_readme
tutorial/tutorial
reference/adaptive
1 change: 1 addition & 0 deletions docs/source/reference/adaptive.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Runners
adaptive.runner.Runner
adaptive.runner.AsyncRunner
adaptive.runner.BlockingRunner
adaptive.runner.extras

Other
-----
Expand Down
18 changes: 18 additions & 0 deletions docs/source/reference/adaptive.runner.extras.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
adaptive.runner.simple
======================

Simple executor
---------------

.. autofunction:: adaptive.runner.simple

Sequential excecutor
--------------------

.. autofunction:: adaptive.runner.SequentialExecutor


Replay log
----------

.. autofunction:: adaptive.runner.replay_log
57 changes: 57 additions & 0 deletions docs/source/tutorial/tutorial.AverageLearner.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Tutorial `~adaptive.AverageLearner`
-----------------------------------

.. note::
Because this documentation consists of static html, the ``live_plot``
and ``live_info`` widget is not live. Download the notebook
in order to see the real behaviour.

.. seealso::
The complete source code of this tutorial can be found in
:jupyter-download:notebook:`AverageLearner`

.. execute::
:hide-code:
:new-notebook: AverageLearner

import adaptive
adaptive.notebook_extension()

The next type of learner averages a function until the uncertainty in
the average meets some condition.

This is useful for sampling a random variable. The function passed to
the learner must formally take a single parameter, which should be used
like a “seed” for the (pseudo-) random variable (although in the current
implementation the seed parameter can be ignored by the function).

.. execute::

def g(n):
import random
from time import sleep
sleep(random.random() / 1000)
# Properly save and restore the RNG state
state = random.getstate()
random.seed(n)
val = random.gauss(0.5, 1)
random.setstate(state)
return val

.. execute::

learner = adaptive.AverageLearner(g, atol=None, rtol=0.01)
runner = adaptive.Runner(learner, goal=lambda l: l.loss() < 2)

.. execute::
:hide-code:

await runner.task # This is not needed in a notebook environment!

.. execute::

runner.live_info()

.. execute::

runner.live_plot(update_interval=0.1)
83 changes: 83 additions & 0 deletions docs/source/tutorial/tutorial.BalancingLearner.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
Tutorial `~adaptive.BalancingLearner`
-------------------------------------

.. note::
Because this documentation consists of static html, the ``live_plot``
and ``live_info`` widget is not live. Download the notebook
in order to see the real behaviour.

.. seealso::
The complete source code of this tutorial can be found in
:jupyter-download:notebook:`BalancingLearner`

.. execute::
:hide-code:
:new-notebook: BalancingLearner

import adaptive
adaptive.notebook_extension()

import holoviews as hv
import numpy as np
from functools import partial
import random

The balancing learner is a “meta-learner” that takes a list of learners.
When you request a point from the balancing learner, it will query all
of its “children” to figure out which one will give the most
improvement.

The balancing learner can for example be used to implement a poor-man’s
2D learner by using the `~adaptive.Learner1D`.

.. execute::

def h(x, offset=0):
a = 0.01
return x + a**2 / (a**2 + (x - offset)**2)

learners = [adaptive.Learner1D(partial(h, offset=random.uniform(-1, 1)),
bounds=(-1, 1)) for i in range(10)]

bal_learner = adaptive.BalancingLearner(learners)
runner = adaptive.Runner(bal_learner, goal=lambda l: l.loss() < 0.01)

.. execute::
:hide-code:

await runner.task # This is not needed in a notebook environment!

.. execute::

runner.live_info()

.. execute::

plotter = lambda learner: hv.Overlay([L.plot() for L in learner.learners])
runner.live_plot(plotter=plotter, update_interval=0.1)

Often one wants to create a set of ``learner``\ s for a cartesian
product of parameters. For that particular case we’ve added a
``classmethod`` called ``~adaptive.BalancingLearner.from_product``.
See how it works below

.. execute::

from scipy.special import eval_jacobi

def jacobi(x, n, alpha, beta): return eval_jacobi(n, alpha, beta, x)

combos = {
'n': [1, 2, 4, 8],
'alpha': np.linspace(0, 2, 3),
'beta': np.linspace(0, 1, 5),
}

learner = adaptive.BalancingLearner.from_product(
jacobi, adaptive.Learner1D, dict(bounds=(0, 1)), combos)

runner = adaptive.BlockingRunner(learner, goal=lambda l: l.loss() < 0.01)

# The `cdims` will automatically be set when using `from_product`, so
# `plot()` will return a HoloMap with correctly labeled sliders.
learner.plot().overlay('beta').grid().select(y=(-1, 3))
74 changes: 74 additions & 0 deletions docs/source/tutorial/tutorial.DataSaver.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Tutorial `~adaptive.DataSaver`
------------------------------

.. note::
Because this documentation consists of static html, the ``live_plot``
and ``live_info`` widget is not live. Download the notebook
in order to see the real behaviour.

.. seealso::
The complete source code of this tutorial can be found in
:jupyter-download:notebook:`DataSaver`

.. execute::
:hide-code:
:new-notebook: DataSaver

import adaptive
adaptive.notebook_extension()

If the function that you want to learn returns a value along with some
metadata, you can wrap your learner in an `adaptive.DataSaver`.

In the following example the function to be learned returns its result
and the execution time in a dictionary:

.. execute::

from operator import itemgetter

def f_dict(x):
"""The function evaluation takes roughly the time we `sleep`."""
import random
from time import sleep

waiting_time = random.random()
sleep(waiting_time)
a = 0.01
y = x + a**2 / (a**2 + x**2)
return {'y': y, 'waiting_time': waiting_time}

# Create the learner with the function that returns a 'dict'
# This learner cannot be run directly, as Learner1D does not know what to do with the 'dict'
_learner = adaptive.Learner1D(f_dict, bounds=(-1, 1))

# Wrapping the learner with 'adaptive.DataSaver' and tell it which key it needs to learn
learner = adaptive.DataSaver(_learner, arg_picker=itemgetter('y'))

``learner.learner`` is the original learner, so
``learner.learner.loss()`` will call the correct loss method.

.. execute::

runner = adaptive.Runner(learner, goal=lambda l: l.learner.loss() < 0.1)

.. execute::
:hide-code:

await runner.task # This is not needed in a notebook environment!

.. execute::

runner.live_info()

.. execute::

runner.live_plot(plotter=lambda l: l.learner.plot(), update_interval=0.1)

Now the ``DataSavingLearner`` will have an dictionary attribute
``extra_data`` that has ``x`` as key and the data that was returned by
``learner.function`` as values.

.. execute::

learner.extra_data

0 comments on commit 987b5f9

Please sign in to comment.