Skip to content

Commit

Permalink
Merge pull request #1 from UCL/mmg/add-docs
Browse files Browse the repository at this point in the history
Add MkDocs documentation
  • Loading branch information
matt-graham authored Apr 26, 2024
2 parents bfcfa09 + d8c407f commit 9a13a33
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 29 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Documentation

on:
push:
branches:
- main
pull_request:

jobs:
docs:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Cache tox
uses: actions/cache@v4
with:
path: .tox
key: tox-${{ hashFiles('pyproject.toml') }}
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: Install tox
run: python -m pip install tox
- name: Build HTML documentation with tox
run: tox -e docs
- name: Publish documentation on GitHub pages
if: success() && github.event_name != 'pull_request'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: site
publish_branch: gh-pages
user_name: "github-actions[bot]"
user_email: "github-actions[bot]@users.noreply.github.com"
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The MIT License (MIT)

Copyright (c) 2023 Matt Graham
Copyright (c) 2023 University College London

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
39 changes: 25 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
[![Tests status][tests-badge]][tests-link]
[![Linting status][linting-badge]][linting-link]
[![Documentation status][docs-badge]][docs-link]
[![License][license-badge]](./LICENSE.md)
[![Documentation](https://img.shields.io/badge/MkDocs-documentation-blue?logo=materialformkdocs&logoColor=white)](https://github-pages.ucl.ac.uk/calibr/)

<!--
[![PyPI version][pypi-version]][pypi-link]
Expand All @@ -16,6 +18,8 @@
[tests-link]: https://github.com/UCL/calibr/actions/workflows/tests.yml
[linting-badge]: https://github.com/UCL/calibr/actions/workflows/linting.yml/badge.svg
[linting-link]: https://github.com/UCL/calibr/actions/workflows/linting.yml
[docs-badge]: https://github.com/UCL/calibr/actions/workflows/docs.yml/badge.svg
[docs-link]: https://github.com/UCL/calibr/actions/workflows/docs.yml
[conda-badge]: https://img.shields.io/conda/vn/conda-forge/calibr
[conda-link]: https://github.com/conda-forge/calibr-feedstock
[pypi-link]: https://pypi.org/project/calibr/
Expand Down Expand Up @@ -53,18 +57,7 @@ likelihood evaluations. Expect lots of rough edges!

This project is developed in collaboration with the [Centre for Advanced Research Computing](https://ucl.ac.uk/arc), University College London.

## About

### Project Team

- Matt Graham ([matt-graham](https://github.com/matt-graham))

### Research Software Engineering Contact

Centre for Advanced Research Computing, University College London
([[email protected]](mailto:[email protected]))

## Getting Started
## Getting started

### Prerequisites

Expand All @@ -90,9 +83,9 @@ and then install in editable mode by running
pip install -e .
```

### Running locally
### Documentation

How to run the application on your local system.
Documentation for the package is available at <https://github-pages.ucl.ac.uk/calibr/>.

### Running tests

Expand All @@ -111,6 +104,24 @@ pytest tests

again from the root of the repository.

### Building documentation

The MkDocs HTML documentation can be built locally by running

```sh
tox -e docs
```

from the root of the repository. The built documentation will be written to
`site`.

Alternatively to build and preview the documentation locally, in a Python
environment with the optional `docs` dependencies installed, run

```sh
mkdocs serve
```

## Acknowledgements

This work was funded by a grant from the ExCALIBUR programme.
1 change: 1 addition & 0 deletions docs/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{! include-markdown "../LICENSE.md" !}
3 changes: 3 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# API reference

::: calibr
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{! include-markdown "../README.md" rewrite-relative-urls=false !}
67 changes: 67 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
site_name: calibr
site_description: "Documentation website for calibr"
site_author: "Matt Graham"
copyright: "Copyright © 2024 University College London"
repo_url: "https://github.com/UCL/calibr/"
repo_name: "UCL/calibr"
edit_uri: edit/main/docs/

validation:
omitted_files: warn
absolute_links: warn
unrecognized_links: warn

theme:
name: "material"
features:
- content.action.edit
palette:
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Switch to light mode
- media: "(prefers-color-scheme: light)"
scheme: default
toggle:
icon: material/brightness-7
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
toggle:
icon: material/brightness-4
name: Switch to system preference
icon:
repo: fontawesome/brands/github

nav:
- Overview: index.md
- API reference: api.md
- License: LICENSE.md

markdown_extensions:
- pymdownx.tasklist

plugins:
- search
- mkdocstrings:
default_handler: python
handlers:
python:
docstring_style: google
import:
- "https://docs.python.org/3/objects.inv"
- "https://numpy.org/doc/stable/objects.inv"
- "https://jax.readthedocs.io/en/latest/objects.inv"
paths: [src]
options:
show_submodules: true
separate_signature: true
line_length: 88
- include-markdown:
opening_tag: "{!"
closing_tag: "!}"

extra:
social:
- icon: fontawesome/brands/github
link: "https://github.com/UCL"
24 changes: 20 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,22 @@ optional-dependencies = {dev = [
"ruff",
"tox>=4",
"twine",
], docs = [
"black",
"mkdocs",
"mkdocs-include-markdown-plugin",
"mkdocs-material",
"mkdocstrings",
"mkdocstrings-python",
], test = [
"pytest",
"pytest-cov",
]}
readme = "README.md"
requires-python = ">=3.10"
license.file = "LICENSE.md"
urls.homepage = "https://github.com/matt-graham/calibr"
urls.documentation = "https://github-pages.ucl.ac.uk/calibr"
urls.homepage = "https://github.com/UCL/calibr"

[tool.coverage]
report = {skip_covered = true, sort = "cover"}
Expand Down Expand Up @@ -119,9 +130,14 @@ legacy_tox_ini = """
[testenv]
commands =
pytest --cov --cov-report=xml
deps =
pytest
pytest-cov
extras =
test
[testenv:docs]
commands =
mkdocs build --strict
extras =
docs
[tox]
env_list =
Expand Down
2 changes: 1 addition & 1 deletion src/calibr/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"""An example file."""
"""Bayesian calibration of simulations using Gaussian process emulation."""
6 changes: 3 additions & 3 deletions src/calibr/calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
GaussianProcessParameterFitter,
fit_gaussian_process_parameters_map,
)
from .optimization import GlobalMinimizer, minimize_with_restarts
from .optimization import GlobalMinimizer, GlobalMinimizerKwarg, minimize_with_restarts

#: Type alias for function generating random initial values for inputs.
InitialInputSampler: TypeAlias = Callable[[Generator, int], Array]
Expand All @@ -40,7 +40,7 @@ def get_next_inputs_batch_by_joint_optimization(
batch_size: int,
*,
minimize_function: GlobalMinimizer = minimize_with_restarts,
**minimize_function_kwargs,
**minimize_function_kwargs: GlobalMinimizerKwarg,
) -> tuple[Array, float]:
"""
Get next batch of inputs to evaluate by jointly optimizing acquisition function.
Expand Down Expand Up @@ -89,7 +89,7 @@ def get_next_inputs_batch_by_greedy_optimization(
batch_size: int,
*,
minimize_function: GlobalMinimizer = minimize_with_restarts,
**minimize_function_kwargs,
**minimize_function_kwargs: GlobalMinimizerKwarg,
) -> tuple[Array, float]:
"""
Get next batch of inputs to evaluate by greedily optimizing acquisition function.
Expand Down
10 changes: 5 additions & 5 deletions src/calibr/emulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from jax.typing import ArrayLike
from numpy.random import Generator

from .optimization import GlobalMinimizer, minimize_with_restarts
from .optimization import GlobalMinimizer, GlobalMinimizerKwarg, minimize_with_restarts

try:
import mici
Expand Down Expand Up @@ -76,11 +76,11 @@ def get_gaussian_process_factory(
mean_function: Mean function for Gaussian process.
covariance_function: Covariance function for Gaussian process.
neg_log_prior_density: Negative logarithm of density of prior distribution on
vector of unconstrained parameters for Gaussian process model.
vector of unconstrained parameters for Gaussian process model.
transform_parameters: Function which maps flat unconstrained parameter vector to
a dictionary of (potential constrained) parameters, keyed by parameter name.
a dictionary of (potential constrained) parameters, keyed by parameter name.
sample_unconstrained_parameters: Function generating random values for
unconstrained vector of Gaussian process parameters.
unconstrained vector of Gaussian process parameters.
Returns:
Gaussian process factory function.
Expand Down Expand Up @@ -116,7 +116,7 @@ def fit_gaussian_process_parameters_map(
gaussian_process: GaussianProcessModel,
*,
minimize_function: GlobalMinimizer = minimize_with_restarts,
**minimize_function_kwargs,
**minimize_function_kwargs: GlobalMinimizerKwarg,
) -> ParametersDict:
"""Fit parameters of Gaussian process model by maximimizing posterior density.
Expand Down
20 changes: 19 additions & 1 deletion src/calibr/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from collections.abc import Callable
from heapq import heappush
from typing import Protocol, TypeAlias
from typing import Any, Protocol, TypeAlias

import jax
from jax.typing import ArrayLike
Expand All @@ -22,6 +22,8 @@ class ConvergenceError(Exception):
#: Type alias for function sampling initial optimization state given random generator
InitialStateSampler: TypeAlias = Callable[[Generator], ndarray]

GlobalMinimizerKwarg: TypeAlias = Any


class GlobalMinimizer(Protocol):
"""Function which attempts to find global minimum of a scalar objective function."""
Expand All @@ -31,6 +33,7 @@ def __call__(
objective_function: ObjectiveFunction,
sample_initial_state: InitialStateSampler,
rng: Generator,
**kwargs: GlobalMinimizerKwarg,
) -> tuple[jax.Array, float]:
"""
Minimize a differentiable objective function.
Expand All @@ -45,6 +48,7 @@ def __call__(
random number generator returns a random initial state for optimization
of appropriate dimension.
rng: Seeded NumPy random number generator.
**kwargs: Any keyword arguments to global minimizer function.
Returns:
Tuple with first entry the state corresponding to the minima point and the
Expand All @@ -71,6 +75,14 @@ def hvp(x: ArrayLike, v: ArrayLike) -> jax.Array:
return hvp


def _check_unknown_kwargs(unknown_kwargs: dict[str, GlobalMinimizerKwarg]) -> None:
if unknown_kwargs:
msg = ". ".join(
f"Unknown keyword argument {k}={v}" for k, v in unknown_kwargs.items()
)
raise ValueError(msg)


def minimize_with_restarts(
objective_function: ObjectiveFunction,
sample_initial_state: InitialStateSampler,
Expand All @@ -82,6 +94,7 @@ def minimize_with_restarts(
minimize_max_iterations: int | None = None,
minimize_tol: float | None = None,
logging_function: Callable[[str], None] = lambda _: None,
**unknown_kwargs: GlobalMinimizerKwarg,
) -> tuple[jax.Array, float]:
"""Minimize a differentiable objective function with random restarts.
Expand All @@ -102,6 +115,8 @@ def minimize_with_restarts(
random number generator returns a random initial state for optimization of
appropriate dimension.
rng: Seeded NumPy random number generator.
Keyword Args:
number_minima_to_find: Number of candidate minima of objective function to try
to find.
maximum_minimize_calls: Maximum number of times to try calling
Expand All @@ -120,6 +135,7 @@ def minimize_with_restarts(
Tuple with first entry the state corresponding to the best minima candidate
found and the second entry the corresponding objective function value.
"""
_check_unknown_kwargs(unknown_kwargs)
minima_found: list[tuple[jax.Array, int, jax.Array]] = []
minimize_calls = 0
while (
Expand Down Expand Up @@ -171,6 +187,7 @@ def basin_hopping(
minimize_method: str = "Newton-CG",
minimize_max_iterations: int | None = None,
minimize_tol: float | None = None,
**unknown_kwargs: GlobalMinimizerKwarg,
) -> tuple[jax.Array, float]:
"""Minimize a differentiable objective function with SciPy basin-hopping algorithm.
Expand Down Expand Up @@ -201,6 +218,7 @@ def basin_hopping(
Tuple with first entry the state corresponding to the best minima candidate
found and the second entry the corresponding objective function value.
"""
_check_unknown_kwargs(unknown_kwargs)
results = _basin_hopping(
jax.jit(objective_function),
x0=sample_initial_state(rng),
Expand Down

0 comments on commit 9a13a33

Please sign in to comment.