Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Distributions GenerativeFunctions #274

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
23f79a8
first draft of core functionality
georgematheos May 17, 2020
c9b1d49
add support for address schemas
georgematheos May 17, 2020
1e0a589
update choicemap docs
georgematheos May 17, 2020
623bc8f
refactoring and tests
georgematheos May 18, 2020
83349c7
performance improvements and benchmarking
georgematheos May 19, 2020
b9b5312
benchmark for dynamic choicemap lookups
georgematheos May 19, 2020
bce5e77
inline dynamicchoicemap methods
georgematheos May 19, 2020
a985f9b
remove old version benchmark file
georgematheos May 19, 2020
1f5029c
minor testing cleanup
georgematheos May 19, 2020
eb6adf7
ensure valuechoicemap[] syntax works
georgematheos May 19, 2020
eef9417
provide some examples in the documentation
georgematheos May 19, 2020
a83adfb
fix some typos
georgematheos May 19, 2020
1bd705f
add phrase 'nesting level zero' to docs
georgematheos May 19, 2020
676828b
distribution <: GenFn; dynamic DSL simplification
georgematheos Jun 17, 2020
5bf4207
simplify static ir code
georgematheos Jun 18, 2020
61673a4
brief documentation for Dist <: GenFn
georgematheos Jun 18, 2020
298a333
short map over distribution test
georgematheos Jun 18, 2020
e34875a
default static_get_submap = EmptyChoiceMap
georgematheos Jun 18, 2020
972d455
default static_get_submap = EmptyChoiceMap
georgematheos Jun 18, 2020
ee64d12
dist performance improvements
georgematheos Jun 18, 2020
fd1991f
minor performance improvement
georgematheos Jun 18, 2020
c3d5db0
performance improvement related to zip bug
georgematheos Jun 18, 2020
f652346
Merge branch '20200516-georgematheos-valuechoicemaps' into 20200617-g…
georgematheos Jun 20, 2020
8a43845
better static retdiff checking
georgematheos Jun 20, 2020
ffd9373
add static info for dist trace type
georgematheos Jun 25, 2020
67d5e12
don't use static get_submap for staticchoicemap
georgematheos Jun 25, 2020
4966ea9
some simple MH benchmarks
georgematheos Jun 25, 2020
0909a5b
bug fix
georgematheos Jun 25, 2020
47cca59
remove ChoiceAt; bug fixes
georgematheos Jun 25, 2020
10df952
decrease iters on benchmark
georgematheos Jun 25, 2020
a79390e
merge in updated master
georgematheos Jul 3, 2020
1c6ed49
Merge branch 'master' into pr/274
alex-lew Aug 19, 2022
4fca569
Merge in additional changes from master
alex-lew Aug 19, 2022
dc7d9a9
Remove methods referring to choice nodes
alex-lew Aug 19, 2022
fc03fbd
Use Ints in trace translator tests for discrete values
alex-lew Aug 19, 2022
33b7c10
Fix choicemap equality
alex-lew Aug 19, 2022
7780c70
update has_submap tests to reflect that ValueChoiceMaps are submaps
alex-lew Aug 19, 2022
5ffad02
fix some iterator issues
alex-lew Aug 19, 2022
2845e3b
handle complement selections in project(::DistributionTrace, ...)
alex-lew Aug 19, 2022
4c93efc
Fix project_complement
alex-lew Aug 19, 2022
d2e80f5
Make DistributionTrace store a reference to the distribution
alex-lew Aug 20, 2022
e07701b
Remove dependency of benchmarks on no-longer-extant examples directory
alex-lew Aug 20, 2022
577b289
Implement `choice_gradients` and `accumulate_param_gradients!` for di…
alex-lew Aug 20, 2022
f7044a2
Delete `load_generated_functions` calls from benchmarks
alex-lew Aug 20, 2022
09dc792
Remove special handling of `Distribution` from dynamic DSL backprop code
alex-lew Aug 20, 2022
370b822
Remove special case handling of distributions from static DSL backpro…
alex-lew Aug 20, 2022
a09d1cc
Avoid "slurping" destructuring assignment, which is unavailable in ol…
alex-lew Aug 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
@@ -1,6 +1,7 @@
# Gen.jl

[![Build Status](https://travis-ci.com/probcomp/Gen.jl.svg?branch=master)](https://travis-ci.com/probcomp/Gen.jl)

[![Build Status](https://travis-ci.com/probcomp/Gen.jl.svg?branch=master)](https://app.travis-ci.com/github/probcomp/Gen.jl)
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://probcomp.github.io/Gen.jl/stable)
[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://probcomp.github.io/Gen.jl/dev)

Expand Down
83 changes: 80 additions & 3 deletions docs/src/ref/choice_maps.md
Expand Up @@ -8,13 +8,58 @@ ChoiceMap
Choice maps are constructed by users to express observations and/or constraints on the traces of generative functions.
Choice maps are also returned by certain Gen inference methods, and are used internally by various Gen inference methods.

A choicemap a tree, whose leaf nodes store a single value, and whose internal nodes provide addresses
for sub-choicemaps. Leaf nodes have type:
```@docs
ValueChoiceMap
```

### Example Usage Overview

Choicemaps store values nested in a tree where each node posesses an address for each subtree.
A leaf-node choicemap simply contains a value, and has its value looked up via:
```julia
value = choicemap[]
```
If a choicemap has a value choicemap at address `:a`, the value it stores is looked up via:
```julia
value = choicemap[:a]
```
A choicemap may also have a non-value choicemap stored at an address. For instance,
if a choicemap has another choicemap stored at address `:a`, and this internal choicemap
has a valuechoicemap stored at address `:b` and another at `:c`, we could perform the following lookups:
```julia
value1 = choicemap[:a => :b]
value2 = choicemap[:a => :c]
```
Nesting can be arbitrarily deep, and the keys can be arbitrary values; for instance
choicemaps can be constructed with values at the following nested addresses:
```julia
value = choicemap[:a => :b => :c => 4 => 1.63 => :e]
value = choicemap[:a => :b => :a => 2 => "alphabet" => :e]
```
To get a sub-choicemap, use `get_submap`:
```julia
value1 = choicemap[:a => :b]
submap = get_submap(choicemap, :a)
value1 == submap[:b] # is true

value_submap = get_submap(choicemap, :a => :b)
value_submap[] == value1 # is true
```
One can think of `ValueChoiceMap`s at storing being a choicemap which has a value at "nesting level zero",
while other choicemaps have values at "nesting level" one or higher.

### Interface

Choice maps provide the following methods:
```@docs
get_submap
get_submaps_shallow
has_value
get_value
get_submap
get_values_shallow
get_submaps_shallow
get_nonvalue_submaps_shallow
to_array
from_array
get_selected
Expand All @@ -23,7 +68,7 @@ Note that none of these methods mutate the choice map.

Choice maps also implement:

- `Base.isempty`, which tests of there are no random choices in the choice map
- `Base.isempty`, which returns `false` if the choicemap contains no value or submaps, and `true` otherwise.

- `Base.merge`, which takes two choice maps, and returns a new choice map containing all random choices in either choice map. It is an error if the choice maps both have values at the same address, or if one choice map has a value at an address that is the prefix of the address of a value in the other choice map.

Expand All @@ -50,3 +95,35 @@ choicemap
set_value!
set_submap!
```

### Implementing custom choicemap types

To implement a custom choicemap, one must implement
`get_submap` and `get_submaps_shallow`.
To avoid method ambiguity with the default
`get_submap(::ChoiceMap, ::Pair)`, one must implement both
```julia
get_submap(::CustomChoiceMap, addr)
```
and
```julia
get_submap(::CustomChoiceMap, addr::Pair)
```
To use the default implementation of `get_submap(_, ::Pair)`,
one may define
```julia
get_submap(c::CustomChoiceMap, addr::Pair) = _get_choicemap(c, addr)
```

Once `get_submap` and `get_submaps_shallow` are defined, default
implementations are provided for:
- `has_value`
- `get_value`
- `get_values_shallow`
- `get_nonvalue_submaps_shallow`
- `to_array`
- `get_selected`

If one wishes to support `from_array`, they must implement
`_from_array`, as described in the documentation for
[`from_array`](@ref).
10 changes: 8 additions & 2 deletions docs/src/ref/distributions.md
@@ -1,7 +1,13 @@
# Probability Distributions

Gen provides a library of built-in probability distributions, and three ways of
defining custom distributions, each of which are explained below:
In Gen, a probability distribution is a generative function which makes a single random choice
and returns the value of this choice. The choicemap for a probability distribution
is always a [`ValueChoiceMap`](@ref). In addition to supporting the regular `GFI` methods,
every distribution supports the methods [`random`](@ref) and [`logpdf`](@ref), described
in the [Distribution API](@ref custom_distributions).

Gen provides a library of built-in probability distributions, and two ways of
writing custom distributions, both of which are explained below:

1. The [`@dist` constructor](@ref dist_dsl), for a distribution that can be expressed as a
simple deterministic transformation (technically, a
Expand Down
5 changes: 4 additions & 1 deletion docs/src/ref/extending.md
Expand Up @@ -110,7 +110,7 @@ Gen's Distribution interface directly, as defined below.
Probability distributions are singleton types whose supertype is `Distribution{T}`, where `T` indicates the data type of the random sample.

```julia
abstract type Distribution{T} end
abstract type Distribution{T} <: GenerativeFunction{T, DistributionTrace} end
```

A new Distribution type must implement the following methods:
Expand Down Expand Up @@ -146,6 +146,9 @@ has_output_grad
logpdf_grad
```

Any custom distribution will automatically be a `GenerativeFunction` since `Distribution <: GenerativeFunction`;
implementations of all GFI methods are automatically provided in terms of `random` and `logpdf`.

## Custom generative functions

We recommend the following steps for implementing a new type of generative function, and also looking at the implementation for the [`DynamicDSLFunction`](@ref) type as an example.
Expand Down
11 changes: 7 additions & 4 deletions src/Gen.jl
Expand Up @@ -43,18 +43,21 @@ include("backprop.jl")
include("address.jl")

# abstract and built-in concrete choice map data types
include("choice_map.jl")
include("choice_map/choice_map.jl")

# a homogeneous trie data type (not for use as choice map)
include("trie.jl")

# built-in data types for arg-diff and ret-diff values
include("diff.jl")

# generative function interface
include("gen_fn_interface.jl")

# built-in data types for arg-diff and ret-diff values
include("diff.jl")
# distribution abstract type
include("distribution.jl")

# built-in probability disributions
# built-in probability disributions; distribution dsl; combinators
include("modeling_library/modeling_library.jl")

# optimization of trainable parameters
Expand Down
3 changes: 2 additions & 1 deletion src/address.jl
Expand Up @@ -151,6 +151,7 @@ A hierarchical selection whose keys are among its type parameters.
struct StaticSelection{T,U} <: HierarchicalSelection
subselections::NamedTuple{T,U}
end
StaticSelection(::NamedTuple{(), Tuple{}}) = EmptySelection()

function Base.isempty(selection::StaticSelection{T,U}) where {T,U}
length(R) == 0 && all(isempty(node) for node in selection.subselections)
Expand Down Expand Up @@ -208,7 +209,7 @@ function StaticSelection(other::HierarchicalSelection)
(keys, subselections) = ((), ())
end
types = map(typeof, subselections)
StaticSelection{keys,Tuple{types...}}(NamedTuple{keys}(subselections))
StaticSelection(NamedTuple{keys}(subselections))
end

export StaticSelection
Expand Down