Skip to content

Commit f5890a1

Browse files
Introduction of model_typed and model_warntype in DebugUtils (#708)
* added InteractiveUtils.jl as a dep + `model_typed` and `model_warntype` for the checking of the model's evaluator * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * added `optimize` kwarg to `model_typed` and `model_warntype` * formatting Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * expanded docstring for `model_warntype` and `model_codetyped` and added to docs * added testing for `model_codetyped` and `model_warntype` * bump patch version * added tests for `model_codetyped` and `model_warntype` for model with kwargs too * added test/debug_utils.jl to test/runtests.jl * renamed `model_codetyped` to `model_typed` to be consistent with the naming * avoid usage of macros within `model_warntype` and `model_typed` due to (what seems like) escaping issues * formatting Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * renamed `_make_evaluate_args_and_kwargs` to `gen_evaluator_call_with_types` + added docs, as requested by my dear @willtebbutt * formatting Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * bump patch version * Update src/debug_utils.jl --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent d6e2147 commit f5890a1

File tree

5 files changed

+111
-1
lines changed

5 files changed

+111
-1
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "DynamicPPL"
22
uuid = "366bfd00-2699-11ea-058f-f148b4cae6d8"
3-
version = "0.30.4"
3+
version = "0.30.5"
44

55
[deps]
66
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
@@ -14,6 +14,7 @@ Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
1414
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
1515
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1616
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
17+
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
1718
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1819
LogDensityProblems = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c"
1920
LogDensityProblemsAD = "996a588d-648d-4e1f-a8f0-a84b347e47b1"

docs/src/api.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,19 @@ And some which might be useful to determine certain properties of the model base
212212
DynamicPPL.has_static_constraints
213213
```
214214

215+
For determining whether one might have type instabilities in the model, the following can be useful
216+
217+
```@docs
218+
DynamicPPL.DebugUtils.model_warntype
219+
DynamicPPL.DebugUtils.model_typed
220+
```
221+
222+
Interally, the type-checking methods make use of the following method for construction of the call with the argument types:
223+
224+
```@docs
225+
DynamicPPL.DebugUtils.gen_evaluator_call_with_types
226+
```
227+
215228
## Advanced
216229

217230
### Variable names

src/debug_utils.jl

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ using ..DynamicPPL: broadcast_safe, AbstractContext, childcontext
55

66
using Random: Random
77
using Accessors: Accessors
8+
using InteractiveUtils: InteractiveUtils
89

910
using DocStringExtensions
1011
using Distributions
@@ -678,4 +679,83 @@ function has_static_constraints(
678679
return all_the_same(transforms)
679680
end
680681

682+
"""
683+
gen_evaluator_call_with_types(model[, varinfo, context])
684+
685+
Generate the evaluator call and the types of the arguments.
686+
687+
# Arguments
688+
- `model::Model`: The model whose evaluator is of interest.
689+
- `varinfo::AbstractVarInfo`: The varinfo to use when evaluating the model. Default: `VarInfo(model)`.
690+
- `context::AbstractContext`: The context to use when evaluating the model. Default: [`DefaultContext`](@ref).
691+
692+
# Returns
693+
A 2-tuple with the following elements:
694+
- `f`: This is either `model.f` or `Core.kwcall`, depending on whether
695+
the model has keyword arguments.
696+
- `argtypes::Type{<:Tuple}`: The types of the arguments for the evaluator.
697+
"""
698+
function gen_evaluator_call_with_types(
699+
model::Model,
700+
varinfo::AbstractVarInfo=VarInfo(model),
701+
context::AbstractContext=DefaultContext(),
702+
)
703+
args, kwargs = DynamicPPL.make_evaluate_args_and_kwargs(model, varinfo, context)
704+
return if isempty(kwargs)
705+
(model.f, Base.typesof(args...))
706+
else
707+
(Core.kwcall, Tuple{typeof(kwargs),Core.Typeof(model.f),map(Core.Typeof, args)...})
708+
end
709+
end
710+
711+
"""
712+
model_warntype(model[, varinfo, context]; optimize=true)
713+
714+
Check the type stability of the model's evaluator, warning about any potential issues.
715+
716+
This simply calls `@code_warntype` on the model's evaluator, filling in internal arguments where needed.
717+
718+
# Arguments
719+
- `model::Model`: The model to check.
720+
- `varinfo::AbstractVarInfo`: The varinfo to use when evaluating the model. Default: `VarInfo(model)`.
721+
- `context::AbstractContext`: The context to use when evaluating the model. Default: [`DefaultContext`](@ref).
722+
723+
# Keyword Arguments
724+
- `optimize::Bool`: Whether to generate optimized code. Default: `false`.
725+
"""
726+
function model_warntype(
727+
model::Model,
728+
varinfo::AbstractVarInfo=VarInfo(model),
729+
context::AbstractContext=DefaultContext();
730+
optimize::Bool=false,
731+
)
732+
ftype, argtypes = gen_evaluator_call_with_types(model, varinfo, context)
733+
return InteractiveUtils.code_warntype(ftype, argtypes; optimize=optimize)
734+
end
735+
736+
"""
737+
model_typed(model[, varinfo, context]; optimize=true)
738+
739+
Return the type inference for the model's evaluator.
740+
741+
This simply calls `@code_typed` on the model's evaluator, filling in internal arguments where needed.
742+
743+
# Arguments
744+
- `model::Model`: The model to check.
745+
- `varinfo::AbstractVarInfo`: The varinfo to use when evaluating the model. Default: `VarInfo(model)`.
746+
- `context::AbstractContext`: The context to use when evaluating the model. Default: [`DefaultContext`](@ref).
747+
748+
# Keyword Arguments
749+
- `optimize::Bool`: Whether to generate optimized code. Default: `true`.
750+
"""
751+
function model_typed(
752+
model::Model,
753+
varinfo::AbstractVarInfo=VarInfo(model),
754+
context::AbstractContext=DefaultContext();
755+
optimize::Bool=true,
756+
)
757+
ftype, argtypes = gen_evaluator_call_with_types(model, varinfo, context)
758+
return only(InteractiveUtils.code_typed(ftype, argtypes; optimize=optimize))
759+
end
760+
681761
end

test/debug_utils.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,18 @@
186186
@test check_model(model; error_on_failure=true)
187187
end
188188
end
189+
190+
@testset "model_warntype & model_codetyped" begin
191+
@model demo_without_kwargs(x) = y ~ Normal(x, 1)
192+
@model demo_with_kwargs(x; z=1) = y ~ Normal(x, z)
193+
194+
for model in [demo_without_kwargs(1.0), demo_with_kwargs(1.0)]
195+
codeinfo, retype = DynamicPPL.DebugUtils.model_typed(model)
196+
@test codeinfo isa Core.CodeInfo
197+
@test retype <: Tuple
198+
199+
# Just make sure the following is runnable.
200+
@test (DynamicPPL.DebugUtils.model_warntype(model); true)
201+
end
202+
end
189203
end

test/runtests.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ include("test_util.jl")
6161
include("pointwise_logdensities.jl")
6262

6363
include("lkj.jl")
64+
65+
include("debug_utils.jl")
6466
end
6567

6668
@testset "compat" begin

0 commit comments

Comments
 (0)