1- export SamplerBuilder, available_samplers, add_group!, build_sampler
1+ export SamplerBuilder, add_group!, build_sampler
22
33has_steploglikelihood (:: Type ) = false
44has_steploglikelihood (:: Type{<:CombinedNextReaction} ) = true
@@ -13,35 +13,34 @@ has_pathloglikelihood(::Type{MultipleDirect}) = true
1313mutable struct SamplerBuilderGroup
1414 name:: Symbol
1515 selector:: Union{Function,Nothing}
16- sampler_spec :: Tuple{Symbol }
16+ method :: Union{SamplerSpec,Nothing }
1717 instance:: SSA
18- # Constructor sets the instance to undefined.
19- SamplerBuilderGroup (name:: Symbol , selector, sampler_spec ) = new (name, selector, sampler_spec )
18+ # Constructor sets ` instance` member to undefined.
19+ SamplerBuilderGroup (name:: Symbol , selector, method ) = new (name, selector, method )
2020end
2121
2222
2323struct SamplerBuilder{K,T}
2424 clock_type:: Type{K}
2525 time_type:: Type{T}
2626 step_likelihood:: Bool
27- trajectory_likelihood :: Bool
27+ path_likelihood :: Bool
2828 debug:: Bool
2929 recording:: Bool
3030 common_random:: Bool
3131 group:: Vector{SamplerBuilderGroup}
32- samplers:: Dict{Tuple{Symbol,Vararg{Symbol}},Function}
3332 start_time:: T
3433 likelihood_cnt:: Int
3534end
3635
3736"""
3837 SamplerBuilder(::Type{K}, ::Type{T};
3938 step_likelihood=false,
40- trajectory_likelihood =false,
39+ path_likelihood =false,
4140 debug=false,
4241 recording=false,
4342 common_random=false,
44- sampler_spec=:none ,
43+ method=nothing ,
4544 start_time::T,
4645 likelihood_cnt::Int
4746 )
@@ -51,50 +50,48 @@ an initial sampler.
5150
5251 * `K` and `T` are the clock type and time type.
5352 * `step_likelihood` - whether you will call `steploglikelihood` before each `fire!`
54- * `trajectory_likelihood ` - whether you will call `pathloglikelihood`
53+ * `path_likelihood ` - whether you will call `pathloglikelihood`
5554 at the end of a simulation run.
5655 * `debug` - Print log messages at the debug level.
5756 * `recording` - Store every enable and disable for later examination.
5857 * `common_random` - Use common random numbers during sampling.
59- * `sampler_spec` - If you want a single, particular sampler, put its Symbol name here.
58+ * `method` - If you want a single, particular sampler, put its `SamplerSpec` here.
59+ It will create a group called `:all` that has this sampling method.
6060 * `start_time` - Sometimes a simulation shouldn't start at zero.
6161 * `likelihood_cnt` - The number of likelihoods to compute, corresponds to number of
62- distributions in `enable!` calls. This turns on `trajectory_likelihood `.
62+ distributions in `enable!` calls. This turns on `path_likelihood `.
6363
6464# Example
6565
6666```julia
6767builder = SamplerBuilder(Tuple,Float64)
68- add_group!(builder, :sparky => (x,d) -> x[1] == :recover, sampler_spec=(:nextreaction, ))
68+ add_group!(builder, :sparky => (x,d) -> x[1] == :recover, method=NextReaction( ))
6969add_group!(builder, :forthright=>(x,d) -> x[1] == :infect)
7070context = SamplingContext(builder, rng)
7171```
7272"""
7373function SamplerBuilder (:: Type{K} , :: Type{T} ;
7474 step_likelihood= false ,
75- trajectory_likelihood = false ,
75+ path_likelihood = false ,
7676 debug= false ,
7777 recording= false ,
7878 common_random= false ,
79- sampler_spec :: Union{Symbol,Tuple{Symbol}} = ( :none ,) , # Ask for specific sampler.
79+ method :: Union{SamplerSpec,Nothing} = nothing , # Ask for specific sampler.
8080 start_time:: T = zero (T),
8181 likelihood_cnt= 1 ,
8282) where {K,T}
8383 group = SamplerBuilderGroup[]
84- avail = make_builder_dict ()
85- trajectory_likelihood = trajectory_likelihood || likelihood_cnt > 1
84+ path_likelihood = path_likelihood || likelihood_cnt > 1
8685 builder = SamplerBuilder (
87- K, T, step_likelihood, trajectory_likelihood , debug, recording,
88- common_random, group, avail, start_time, likelihood_cnt
86+ K, T, step_likelihood, path_likelihood , debug, recording,
87+ common_random, group, start_time, likelihood_cnt
8988 )
90- if sampler_spec != ( :none , )
91- add_group! (builder, :all => (x, d) -> true ; sampler_spec = sampler_spec )
89+ if ! isnothing (method )
90+ add_group! (builder, :all => (x, d) -> true ; method = method )
9291 end
9392 return builder
9493end
9594
96- available_samplers (builder:: SamplerBuilder ) = keys (builder. samplers)
97-
9895
9996"""
10097The `selector` defines the group of clocks that go to this sampler using
@@ -103,37 +100,17 @@ an inclusion rule, so it's a function from a clock key and distribution to a Boo
103100function add_group! (
104101 builder:: SamplerBuilder ,
105102 selector:: Union{Pair,Nothing} = nothing ; # Which clocks use this sampler.
106- sampler_spec :: Union{Symbol,Tuple{Symbol}} = ( :any ,), # Ask for specific sampler.
103+ method :: Union{SamplerSpec,Nothing} = nothing , # Ask for specific sampler.
107104)
108- sampler_spec = sampler_spec isa Symbol ? (sampler_spec,) : sampler_spec
109- sampler_spec = sampler_spec == (:any ,) ? (:firsttofire ,) : sampler_spec
110- if sampler_spec ∉ keys (builder. samplers)
111- error (" Looking for a sampler in this list: $(keys (builder. samplers)) " )
112- end
113105 if length (builder. group) >= 1 && (builder. group[1 ]. selector === nothing || selector === nothing )
114106 error (" Need a selector on all samplers if there is more than one sampler." )
115107 end
116108 name = selector isa Pair ? selector. first : :all
117109 selector_func = selector isa Pair ? selector. second : selector
118- push! (builder. group, SamplerBuilderGroup (name, selector_func, sampler_spec ))
110+ push! (builder. group, SamplerBuilderGroup (name, selector_func, method ))
119111 return nothing
120112end
121113
122-
123- function make_builder_dict ()
124- return Dict ([
125- (:nextreaction ,) => (K, T) -> CombinedNextReaction {K,T} (),
126- (:direct ,) => (K, T) -> DirectCallExplicit (K, T, KeyedRemovalPrefixSearch, BinaryTreePrefixSearch),
127- (:direct , :remove , :tree ) => (K, T) -> DirectCallExplicit (K, T, KeyedRemovalPrefixSearch, BinaryTreePrefixSearch),
128- (:direct , :keep , :tree ) => (K, T) -> DirectCallExplicit (K, T, KeyedKeepPrefixSearch, BinaryTreePrefixSearch),
129- (:direct , :remove , :array ) => (K, T) -> DirectCallExplicit (K, T, KeyedRemovalPrefixSearch, CumSumPrefixSearch),
130- (:direct , :keep , :array ) => (K, T) -> DirectCallExplicit (K, T, KeyedKeepPrefixSearch, CumSumPrefixSearch),
131- (:firstreaction ,) => (K, T) -> FirstReaction {K,T} (),
132- (:firsttofire ,) => (K, T) -> FirstToFire {K,T} (),
133- (:petri ,) => (K, T) -> Petri {K,T} (),
134- ])
135- end
136-
137114"""
138115See sampler.jl for the MultiSampler to understand how we're making a chooser.
139116We would like to implement this:
@@ -149,17 +126,32 @@ function CompetingClocks.choose_sampler(
149126 return chooser. matcher (clock, distribution)
150127end
151128
129+ function auto_select_method (builder:: SamplerBuilder )
130+ # Auto-select a sampler method based on builder requirements
131+ if builder. path_likelihood
132+ return DirectMethod ()
133+ elseif builder. step_likelihood
134+ return NextReactionMethod ()
135+ else
136+ return FirstToFireMethod ()
137+ end
138+ end
139+
152140function build_sampler (builder:: SamplerBuilder )
153- isempty (builder. group) && error (" Need to add_group! on the builder." )
154141 K = builder. clock_type
155142 T = builder. time_type
156- if length (builder. group) == 1
157- sampler = builder. samplers[builder. group[1 ]. sampler_spec](K, T)
143+ if length (builder. group) == 0
144+ sampler = FirstToFireMethod ()(K, T)
145+ matcher = nothing
146+ elseif length (builder. group) == 1
147+ method = isnothing (builder. group[1 ]. method) ? auto_select_method (builder) : builder. group[1 ]. method
148+ sampler = method (K, T)
158149 matcher = nothing
159150 else
160151 competes = builder. group
161152 for compete in competes
162- compete. instance = builder. samplers[compete. sampler_spec](K, T)
153+ method = isnothing (compete. method) ? auto_select_method (builder) : compete. method
154+ compete. instance = method (K, T)
163155 end
164156 # Any direct method gets added to the others for combination.
165157 inclusion = Dict (samp. name => samp. selector for samp in competes)
0 commit comments