Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/Docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Documentation

on:
push:
branches:
# Build the master branch.
- master
tags: '*'
pull_request:

concurrency:
# Skip intermediate builds: always.
# Cancel intermediate builds: only if it is a pull request build.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}

jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@latest
with:
version: '1'
- name: Install dependencies
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
- name: Build and deploy
env:
GKSwstype: nul # GR backend issues
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key
JULIA_DEBUG: Documenter # Print `@debug` statements (https://github.com/JuliaDocs/Documenter.jl/issues/955)
run: julia --project=docs/ docs/make.jl
26 changes: 26 additions & 0 deletions .github/workflows/DocsPreviewCleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Doc Preview Cleanup

on:
pull_request:
types: [closed]

jobs:
doc-preview-cleanup:
runs-on: ubuntu-latest
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v2
with:
ref: gh-pages
- name: Delete preview and history + push changes
run: |
if [ -d "previews/PR$PRNUM" ]; then
git config user.name "Documenter.jl"
git config user.email "documenter@juliadocs.github.io"
git rm -rf "previews/PR$PRNUM"
git commit -m "delete preview"
git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree})
git push --force origin gh-pages-new:gh-pages
fi
env:
PRNUM: ${{ github.event.number }}
2 changes: 1 addition & 1 deletion .github/workflows/TagBot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ jobs:
- uses: JuliaRegistries/TagBot@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

ssh: ${{ secrets.DOCUMENTER_KEY }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the key and corresponding secret added to the repo?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, generated a new pair and added it. I don't think we have keys at the organization level ?

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
*.jl.*.cov
*.jl.mem
/Manifest.toml
/test/Manifest.toml
/test/Manifest.toml
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@
[![Coverage](https://coveralls.io/repos/github/TuringLang/AdvancedPS.jl/badge.svg?branch=master)](https://coveralls.io/github/TuringLang/AdvancedPS.jl?branch=master)
[![Code Style: Blue](https://img.shields.io/badge/code%20style-blue-4495d1.svg)](https://github.com/invenia/BlueStyle)

AdvancedPS provides an efficient implementation of common particle based Monte Carlo samplers using the [AbstractMCMC](https://github.com/TuringLang/AbstractMCMC.jl) interface.
The package also relies on [Libtask](https://github.com/TuringLang/Libtask.jl) for task manipulation.
AdvancedPS is part of the [Turing](https://turing.ml/stable/) ecosystem.

### Installation

Inside the Julia REPL
```julia
julia>] add AdvancedPS
```

### Examples

Detailed examples are available in the [documentation](https://turinglang.github.io/AdvancedPS.jl/stable/)

### Reference

1. Doucet, Arnaud, and Adam M. Johansen. "A tutorial on particle filtering and smoothing: Fifteen years later." Handbook of nonlinear filtering 12, no. 656-704 (2009): 3.
Expand All @@ -21,6 +36,3 @@

7. Del Moral, Pierre, Arnaud Doucet, and Ajay Jasra. "Sequential Monte Carlo samplers." Journal of the Royal Statistical Society: Series B (Statistical Methodology) 68, no. 3 (2006): 411-436.




1 change: 1 addition & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
build/
6 changes: 6 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"

[compat]
Documenter = "0.27"
18 changes: 18 additions & 0 deletions docs/literate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Retrieve name of example and output directory
if length(ARGS) != 2
error("please specify the name of the example and the output directory")
end
const EXAMPLE = ARGS[1]
const OUTDIR = ARGS[2]

# Activate environment
# Note that each example's Project.toml must include Literate as a dependency
using Pkg: Pkg
const EXAMPLEPATH = joinpath(@__DIR__, "..", "examples", EXAMPLE)
Pkg.activate(EXAMPLEPATH)
Pkg.instantiate()
using Literate: Literate

# Convert to markdown and notebook
const SCRIPTJL = joinpath(EXAMPLEPATH, "script.jl")
Literate.markdown(SCRIPTJL, OUTDIR; name=EXAMPLE, documenter=false, execute=true)
75 changes: 75 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#
# With minor changes from https://github.com/JuliaGaussianProcesses/AbstractGPs.jl/docs
#
### Process examples
# Always rerun examples
const EXAMPLES_OUT = joinpath(@__DIR__, "src", "examples")
ispath(EXAMPLES_OUT) && rm(EXAMPLES_OUT; recursive=true)
mkpath(EXAMPLES_OUT)

# Install and precompile all packages
# Workaround for https://github.com/JuliaLang/Pkg.jl/issues/2219
examples = filter!(isdir, readdir(joinpath(@__DIR__, "..", "examples"); join=true))
let script = "using Pkg; Pkg.activate(ARGS[1]); Pkg.instantiate()"
for example in examples
if !success(`$(Base.julia_cmd()) -e $script $example`)
error(
"project environment of example ",
basename(example),
" could not be instantiated",
)
end
end
end
# Run examples asynchronously
processes = let literatejl = joinpath(@__DIR__, "literate.jl")
map(examples) do example
return run(
pipeline(
`$(Base.julia_cmd()) $literatejl $(basename(example)) $EXAMPLES_OUT`;
stdin=devnull,
stdout=devnull,
stderr=stderr,
);
wait=false,
)::Base.Process
end
end

# Check that all examples were run successfully
isempty(processes) || success(processes) || error("some examples were not run successfully")

# Building Documenter
using Documenter
using AdvancedPS

DocMeta.setdocmeta!(AdvancedPS, :DocTestSetup, :(using AdvancedPS); recursive=true)

makedocs(;
sitename="AdvancedPS",
format=Documenter.HTML(),
modules=[AdvancedPS],
pages=[
"Home" => "index.md",
"api.md",
"Examples" => [
"example.md",
map(
(x) -> joinpath("examples", x),
filter!(filename -> endswith(filename, ".md"), readdir(EXAMPLES_OUT)),
)...,
],
],
strict=true,
checkdocs=:exports,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could use

Suggested change
checkdocs=:exports,
strict=true,
checkdocs=:exports,

to ensure that an error is thrown and the action fails if something fails or e.g. is not documented. Otherwise one always has to check the logs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, missed that. Yes let's fail instead

doctestfilters=[
# Older versions will show "0 element Array" instead of "Type[]".
r"(Any\[\]|0-element Array{.+,[0-9]+})",
# Older versions will show "Array{...,1}" instead of "Vector{...}".
r"(Array{.+,\s?1}|Vector{.+})",
# Older versions will show "Array{...,2}" instead of "Matrix{...}".
r"(Array{.+,\s?2}|Matrix{.+})",
],
)

deploydocs(; repo="github.com/TuringLang/AdvancedPS.jl.git", push_preview=true)
82 changes: 82 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# API

## Samplers

AdvancedPS introduces a few samplers extending [AbstractMCMC](https://github.com/TuringLang/AbstractMCMC.jl).
The `sample` method expects a custom type that subtypes `AbstractMCMC.AbstractModel`.
The available samplers are listed below:

### SMC

```@docs
AdvancedPS.SMC
```
The SMC sampler populates a set of particles in a [`AdvancedPS.ParticleContainer`](@ref) and performs a [`AdvancedPS.sweep!`](@ref) which
propagates the particles and provides an estimation of the log-evidence

```julia
sampler = SMC(nparticles)
chains = sample(model, sampler)
```

### Particle Gibbs
```@docs
AdvancedPS.PG
```
The Particle Gibbs introduced in [^2] runs a sequence of conditional SMC steps where a pre-selected particle, the reference particle, is replayed and propagated through
the SMC step.

```julia
sampler = PG(nparticles)
chains = sample(model, sampler, nchains)
```

For more detailed examples please refer to the [Examples](@ref) page.

## Resampling

AdvancedPS implements adaptive resampling for both [`AdvancedPS.PG`](@ref) and [`AdvancedPS.SMC`](@ref).
The following resampling schemes are implemented:
```@docs
AdvancedPS.resample_multinomial
AdvancedPS.resample_residual
AdvancedPS.resample_stratified
AdvancedPS.resample_systematic
```

Each of these schemes is wrapped in a [`AdvancedPS.ResampleWithESSThreshold`](@ref) struct to trigger a resampling step whenever the ESS is below a certain threshold.
```@docs
AdvancedPS.ResampleWithESSThreshold
```

## RNG

AdvancedPS replays the individual trajectories instead of storing the intermediate values. This way we can build efficient samplers.
However in order to replay the trajectories we need to reproduce most of the random numbers generated
during the execution of the program while also generating diverging traces after each resampling step.
To solve these two issues AdvancedPS uses counter-based RNG introduced in [^1] and widely used in large parallel systems see
[StochasticDifferentialEquations](https://github.com/SciML/StochasticDiffEq.jl) or [JAX](https://jax.readthedocs.io/en/latest/jax-101/05-random-numbers.html?highlight=random)
for other implementations.

Under the hood AdvancedPS is using [Random123](https://github.com/JuliaRandom/Random123.jl) for the generators.
Using counter-based RNG allows us to split generators thus creating new independent random streams. These generators are also wrapped in a [`AdvancedPS.TracedRNG`](@ref) type.
The `TracedRNG` keeps track of the keys generated at every `split` and can be reset to replay random streams.


```@docs
AdvancedPS.TracedRNG
AdvancedPS.split
AdvancedPS.load_state!
AdvancedPS.save_state!
```

## Internals
### Particle Sweep

```@docs
AdvancedPS.ParticleContainer
AdvancedPS.sweep!
```

[^1]: John K. Salmon, Mark A. Moraes, Ron O. Dror, and David E. Shaw. 2011. Parallel random numbers: as easy as 1, 2, 3. In Proceedings of 2011 International Conference for High Performance Computing, Networking, Storage and Analysis (SC '11). Association for Computing Machinery, New York, NY, USA, Article 16, 1–12. DOI:https://doi.org/10.1145/2063384.2063405
[^2]: Andrieu, Christophe, Arnaud Doucet, and Roman Holenstein. "Particle Markov chain Monte Carlo methods." Journal of the Royal Statistical Society: Series B (Statistical Methodology) 72, no. 3 (2010): 269-342.
3 changes: 3 additions & 0 deletions docs/src/example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Examples

The following pages walk you through some examples using AdvancedPS and the Turing ecosystem.
17 changes: 17 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# AdvancedPS: Particle Samplers for Julia

This is a lightweight package that implements particle based Monte Carlo algorithms for the [Turing](https://turing.ml/stable/) ecosystem.

### Installing from Julia

To install the package, use the following command inside the Julia REPL:
```julia
using Pkg
Pkg.add("AdvancedPS")
```

To load the package, use the command:

```julia
using AdvancedPS
```
3 changes: 3 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Examples

The examples in this directory are stored in Literate.jl format.
Loading