AlgebraicJulia / AlgebraicJulia/Catlab.jl
Markov Experiment
- Dominant language
- Julia
- Stars
- 724
- Forks
- 73
- PR merge metrics
- No merged PRs in 30d
Description
I was thinking about the Markov experiment today. I think implementing Brendan's causal theories is a good first step. Based on this reference it seems like Markov = Stoch [panangaden1999markov.pdf](https://github.com/epatters/Catlab.jl/files/4441621/panangaden1999markov.pdf), but I didn't look to carefully at that so let me know if there is a difference.
Steps to close this issue:
- [ ] Use the theory of SMC+Diagonals as a Doctrine for causal theories
- [ ] Implement a syntax that does the appropriate amount of normalizing
- [ ] Implement an instance with Distributions.jl
- [ ] Tests
- [ ] Example notebook makes a distribution and draws some samples
I think we would want a `MarkovKernel` Type for capturing a conditional dependence / parameters
- Ob↦Vector{Type}
- Hom(X,Y)↦(x::X)->d::Distribution where d takes values of type Y
- They already have [Product Distributions](https://juliastats.org/Distributions.jl/latest/multivariate/#Product-distributions-1)
- We need a `CompositeDistribution` satisfying `rand(Composite(P,Q))(args) = rand(Q(rand(P(args)))`
- CopyDistribution(X)::X→X×X a
Sketch:
```julia
struct MarkovDom
vars::Vector{DataType}
end
abstract type MarkovMap end
struct GeneratorMarkovMap <: MarkovMap
dom::MarkovDom
codom::MarkovDom
map::Function # this returns a distribution of taking values over codom
end
struct CompositeMarkovMap <: MarkovMap
maps::Vector{MarkovMap}
end
struct ProductMarkovMap <: MarkovMap
maps::Vector{MarkovMap}
end
struct CopyMarkovMap <: MarkovMap
dom::MarkovDom
end
rand(f::GeneratorMarkovMap, args...) = rand(f.map(args...))
rand(f::CompositeMarkovMap, args...) = begin
length(f.maps) <= 0 && error("Sampling from empty composite")
if length(f.maps) == 1
return rand(f.maps[1], args...)
else
return rand(f.maps[end], rand(CompositeMarkovMap(f.maps[1:end-1]), args...))
end
end
rand(f::ProductMarkovMap, args...) = begin
length(f.maps) <= 0 && error("Sampling from empty product")
partition(i, args) = begin
i₁ = sum(map(length∘dom, f.maps[1:i-1]))
i₂ = i₁ + length(dom(f.maps[i]))
args[i₁:i₂]
end
map(enumerate(f.maps)) do (i,m)
rand(m, partition(i, args))
end
end
rand(f::CopyMarkovMap, args...) = [args..., args...]
```
Distributions comes in for the generators, a GeneratorMarkovMap has as its function, a function that returns a Distributions.jl distribution.
Aside: What is a [Mixture Model](https://juliastats.org/Distributions.jl/latest/mixture/#Distributions.MixtureModel) in CT gadgets? I feel like it should be a monoid on homs like + in GLA because you can mix two distributions by averaging their pdf, right? You would need a version of mixture that is evenly weighted combination of `n` components in order to get associative properties.
Contributor guide
Assessment
This issue has not been assessed yet.