DynamicPPL.jl icon indicating copy to clipboard operation
DynamicPPL.jl copied to clipboard

Transition to `Accessors.jl`

Open sunxd3 opened this issue 10 months ago • 1 comments

sunxd3 avatar Apr 05 '24 11:04 sunxd3

current error caused by https://github.com/TuringLang/AbstractPPL.jl/pull/93

sunxd3 avatar Apr 07 '24 10:04 sunxd3

Pull Request Test Coverage Report for Build 8740059589

Details

  • 78 of 95 (82.11%) changed or added relevant lines in 7 files are covered.
  • 103 unchanged lines in 10 files lost coverage.
  • Overall coverage decreased (-3.1%) to 81.855%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/varinfo.jl 5 6 83.33%
src/model_utils.jl 2 4 50.0%
src/simple_varinfo.jl 16 18 88.89%
src/utils.jl 42 45 93.33%
src/threadsafe.jl 9 18 50.0%
<!-- Total: 78 95
Files with Coverage Reduction New Missed Lines %
src/sampler.jl 1 94.12%
ext/DynamicPPLForwardDiffExt.jl 1 77.78%
src/contexts.jl 2 77.27%
src/logdensityfunction.jl 2 55.56%
src/prob_macro.jl 4 84.67%
src/abstract_varinfo.jl 5 82.68%
src/context_implementations.jl 8 61.96%
src/model_utils.jl 10 19.64%
src/loglikelihoods.jl 16 54.84%
src/varinfo.jl 54 86.72%
<!-- Total: 103
Totals Coverage Status
Change from base Build 8740001884: -3.1%
Covered Lines: 2621
Relevant Lines: 3202

💛 - Coveralls

coveralls avatar Apr 12 '24 08:04 coveralls

Pull Request Test Coverage Report for Build 8658853351

Details

  • 74 of 95 (77.89%) changed or added relevant lines in 7 files are covered.
  • 104 unchanged lines in 11 files lost coverage.
  • Overall coverage decreased (-4.0%) to 80.823%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/varinfo.jl 5 6 83.33%
src/model_utils.jl 2 4 50.0%
src/simple_varinfo.jl 16 18 88.89%
src/utils.jl 42 45 93.33%
src/threadsafe.jl 5 18 27.78%
<!-- Total: 74 95
Files with Coverage Reduction New Missed Lines %
src/compiler.jl 1 93.69%
src/sampler.jl 1 94.12%
ext/DynamicPPLForwardDiffExt.jl 1 77.78%
src/contexts.jl 2 77.27%
src/logdensityfunction.jl 2 55.56%
src/prob_macro.jl 4 84.67%
src/abstract_varinfo.jl 5 81.97%
src/context_implementations.jl 8 61.96%
src/model_utils.jl 10 19.64%
src/loglikelihoods.jl 16 54.84%
<!-- Total: 104
Totals Coverage Status
Change from base Build 8111716086: -4.0%
Covered Lines: 2592
Relevant Lines: 3207

💛 - Coveralls

coveralls avatar Apr 12 '24 08:04 coveralls

With https://github.com/TuringLang/AbstractPPL.jl/pull/96, all the DynamicPPL tests pass

sunxd3 avatar Apr 12 '24 09:04 sunxd3

@torfjelde Actually, what do you mean by

It seems like the generated expression might still keep a reference to Accessors in the model (which it shouldn't)?

with Setfield

julia> @macroexpand @varname(x[1])
:((VarName){:x}((Setfield.compose)((Setfield.IndexLens)((1,)))))

so there are references to Setfield.

The issue seems to be that these references to Setfield gets compiled away, but with Accessors, they are not. Consider

function demo_mv(::Type{TV}=Float64) where {TV}
     m = Vector{TV}(undef, 2)
     m[1] ~ Normal()
     m[2] ~ Normal()
     return m
 end

model = demo_mv();

code_typed(model.f, (DynamicPPL.Model, DynamicPPL.AbstractVarInfo, DynamicPPL.AbstractPPL.AbstractContext, typeof(Float64)))
With Accessors
CodeInfo(
1 ── %1   = $(Expr(:static_parameter, 1))::DataType
│    %2   = Core.apply_type(Main.Vector, %1)::Type{Vector{_A}} where _A
│    %3   = (%2)(Main.undef, 2)::Vector
│    %4   = Main.Accessors::Any
│    %5   = Base.getproperty(%4, :compose)::Any
│    %6   = Main.Accessors::Any
│    %7   = Base.getproperty(%6, :IndexLens)::Any
│    %8   = (%7)((1,))::Any
│    %9   = (%5)(%8)::Any
│    %10  = (VarName{:m})(%9)::VarName{:m}
│    %11  = DynamicPPL.contextual_isassumption(__context__, %10)::Bool
└───        goto #9 if not %11
2 ── %13  = DynamicPPL.inargnames(%10, __model__)::Any
│    %14  = !%13::Any
└───        goto #4 if not %14
3 ──        goto #7
4 ── %17  = DynamicPPL.inmissings(%10, __model__)::Any
└───        goto #6 if not %17
5 ──        goto #7
6 ── %20  = Base.getindex(%3, 1)::Any
│    %21  = (%20 === Main.missing)::Bool
└───        goto #8
7 ┄─        nothing::Nothing
8 ┄─ %24  = φ (#7 => true, #6 => %21)::Bool
└───        goto #10
9 ──        nothing::Nothing
10 ┄ %27  = φ (#8 => %24, #9 => false)::Bool
│    %28  = DynamicPPL.contextual_isfixed(__context__, %10)::Bool
└───        goto #15 if not %28
11 ─ %30  = DynamicPPL.getfixed_nested(__context__, %10)::Any
│    %31  = (isa)(%3, Vector{Any})::Bool
└───        goto #13 if not %31
12 ─ %33  = π (%3, Vector{Any})
│           Base.arrayset(true, %33, %30, 1)::Vector{Any}
└───        goto #14
13 ─        Base.setindex!(%3, %30, 1)::Any
└───        goto #14
14 ┄        goto #23
15 ─        goto #17 if not %27
16 ─ %40  = DynamicPPL.tilde_assume!!(__context__, $(QuoteNode(Normal{Float64}(μ=0.0, σ=1.0))), %10, __varinfo__)::Tuple{Any, Any}
│    %41  = Base.getfield(%40, 1)::Any
│    %42  = Base.getfield(%40, 2)::Any
│    %43  = Main.Accessors::Any
│    %44  = Base.getproperty(%43, :set)::Any
│    %45  = Main.BangBang::Any
│    %46  = Base.getproperty(%45, :AccessorsImpl)::Any
│    %47  = Base.getproperty(%46, :prefermutation)::Any
│    %48  = Main.Accessors::Any
│    %49  = Base.getproperty(%48, :opticcompose)::Any
│    %50  = Main.Accessors::Any
│    %51  = Base.getproperty(%50, :IndexLens)::Any
│    %52  = (%51)((1,))::Any
│    %53  = (%49)(%52)::Any
│    %54  = (%47)(%53)::Any
│    %55  = (%44)(%3, %54, %41)::Any
└───        goto #23
17 ─ %57  = DynamicPPL.inargnames(%10, __model__)::Any
│    %58  = !%57::Any
└───        goto #22 if not %58
18 ─ %60  = DynamicPPL.getconditioned_nested(__context__, %10)::Any
│    %61  = (isa)(%3, Vector{Any})::Bool
└───        goto #20 if not %61
19 ─ %63  = π (%3, Vector{Any})
│           Base.arrayset(true, %63, %60, 1)::Vector{Any}
└───        goto #21
20 ─        Base.setindex!(%3, %60, 1)::Any
└───        goto #21
21 ┄        nothing::Nothing
22 ┄ %69  = Base.getindex(%3, 1)::Any
│    %70  = DynamicPPL.tilde_observe!!(__context__, $(QuoteNode(Normal{Float64}(μ=0.0, σ=1.0))), %69, %10, __varinfo__)::Tuple{Any, Any}
└─── %71  = Base.getfield(%70, 2)::Any
23 ┄ %72  = φ (#14 => %3, #16 => %55, #22 => %3)::Any
│    %73  = φ (#14 => __varinfo__, #16 => %42, #22 => %71)::Any
│    %74  = Main.Accessors::Any
│    %75  = Base.getproperty(%74, :opticcompose)::Any
│    %76  = Main.Accessors::Any
│    %77  = Base.getproperty(%76, :IndexLens)::Any
│    %78  = (%77)((2,))::Any
│    %79  = (%75)(%78)::Any
│    %80  = (VarName{:m})(%79)::VarName{:m}
│    %81  = DynamicPPL.contextual_isassumption(__context__, %80)::Bool
└───        goto #31 if not %81
24 ─ %83  = DynamicPPL.inargnames(%80, __model__)::Any
│    %84  = !%83::Any
└───        goto #26 if not %84
25 ─        goto #29
26 ─ %87  = DynamicPPL.inmissings(%80, __model__)::Any
└───        goto #28 if not %87
27 ─        goto #29
28 ─ %90  = Base.maybeview(%72, 2)::Any
│    %91  = (%90 === Main.missing)::Bool
└───        goto #30
29 ┄        nothing::Nothing
30 ┄ %94  = φ (#29 => true, #28 => %91)::Bool
└───        goto #32
31 ─        nothing::Nothing
32 ┄ %97  = φ (#30 => %94, #31 => false)::Bool
│    %98  = DynamicPPL.contextual_isfixed(__context__, %80)::Bool
└───        goto #34 if not %98
33 ─ %100 = DynamicPPL.getfixed_nested(__context__, %80)::Any
│           Base.setindex!(%72, %100, 2)::Any
└───        goto #39
34 ─        goto #36 if not %97
35 ─ %104 = DynamicPPL.tilde_assume!!(__context__, $(QuoteNode(Normal{Float64}(μ=0.0, σ=1.0))), %80, %73)::Tuple{Any, Any}
│    %105 = Base.getfield(%104, 1)::Any
│    %106 = Base.getfield(%104, 2)::Any
│    %107 = Main.Accessors::Any
│    %108 = Base.getproperty(%107, :set)::Any
│    %109 = Main.BangBang::Any
│    %110 = Base.getproperty(%109, :AccessorsImpl)::Any
│    %111 = Base.getproperty(%110, :prefermutation)::Any
│    %112 = Main.Accessors::Any
│    %113 = Base.getproperty(%112, :opticcompose)::Any
│    %114 = Main.Accessors::Any
│    %115 = Base.getproperty(%114, :IndexLens)::Any
│    %116 = (%115)((2,))::Any
│    %117 = (%113)(%116)::Any
│    %118 = (%111)(%117)::Any
│    %119 = (%108)(%72, %118, %105)::Any
└───        goto #39
36 ─ %121 = DynamicPPL.inargnames(%80, __model__)::Any
│    %122 = !%121::Any
└───        goto #38 if not %122
37 ─ %124 = DynamicPPL.getconditioned_nested(__context__, %80)::Any
└───        Base.setindex!(%72, %124, 2)::Any
38 ┄ %126 = Base.maybeview(%72, 2)::Any
│    %127 = DynamicPPL.tilde_observe!!(__context__, $(QuoteNode(Normal{Float64}(μ=0.0, σ=1.0))), %126, %80, %73)::Tuple{Any, Any}
└─── %128 = Base.getfield(%127, 2)::Any
39 ┄ %129 = φ (#33 => %72, #35 => %119, #38 => %72)::Any
│    %130 = φ (#33 => %73, #35 => %106, #38 => %128)::Any
│    %131 = Core.tuple(%129, %130)::Tuple{Any, Any}
└───        return %131
) => Tuple{Any, Any}
With Setfield
CodeInfo(
    1 ── %1   = $(Expr(:static_parameter, 1))::DataType
    │    %2   = Core.apply_type(Main.Vector, %1)::Type{Vector{_A}} where _A
    │    %3   = (%2)(Main.undef, 2)::Vector
    │    %4   = Main.Normal::Any
    │    %5   = (%4)()::Any
    │    %6   = (isa)(%5, NamedDist)::Bool
    └───        goto #3 if not %6
    2 ── %8   = π (%5, NamedDist)
    │    %9   = Base.getfield(%8, :name)::VarName
    └───        goto #6
    3 ──        goto #5 if not true
    4 ──        goto #6
    5 ──        Core.throw(ErrorException("fatal error in type inference (type bound)"))::Union{}
    └───        unreachable
    6 ┄─ %15  = φ (#2 => %9, #4 => $(QuoteNode(m[1])))::VarName
    │    %16  = (DynamicPPL.contextual_isassumption)(__context__, %15)::Bool
    └───        goto #14 if not %16
    7 ── %18  = (DynamicPPL.inargnames)(%15, __model__)::Any
    │    %19  = !%18::Any
    └───        goto #9 if not %19
    8 ──        goto #12
    9 ── %22  = (DynamicPPL.inmissings)(%15, __model__)::Any
    └───        goto #11 if not %22
    10 ─        goto #12
    11 ─ %25  = Base.getindex(%3, 1)::Any
    │    %26  = (%25 === Main.missing)::Bool
    └───        goto #13
    12 ┄        nothing::Nothing
    13 ┄ %29  = φ (#12 => true, #11 => %26)::Bool
    └───        goto #15
    14 ─        nothing::Nothing
    15 ┄ %32  = φ (#13 => %29, #14 => false)::Bool
    │    %33  = (DynamicPPL.contextual_isfixed)(__context__, %15)::Bool
    └───        goto #20 if not %33
    16 ─ %35  = (DynamicPPL.getfixed_nested)(__context__, %15)::Any
    │    %36  = (isa)(%3, Vector{Any})::Bool
    └───        goto #18 if not %36
    17 ─ %38  = π (%3, Vector{Any})
    │           Base.arrayset(true, %38, %35, 1)::Vector{Any}
    └───        goto #19
    18 ─        Base.setindex!(%3, %35, 1)::Any
    └───        goto #19
    19 ┄        goto #42
    20 ─        goto #29 if not %32
    21 ─ %45  = (isa)(%5, AbstractArray{<:Distributions.Distribution})::Bool
    └───        goto #23 if not %45
    22 ─ %47  = π (%5, AbstractArray{<:Distributions.Distribution})
    └───        goto #28
    23 ─ %49  = (isa)(%5, Distributions.Distribution)::Bool
    └───        goto #25 if not %49
    24 ─ %51  = π (%5, Distributions.Distribution)
    └───        goto #28
    25 ─        goto #27 if not true
    26 ─ %54  = invoke DynamicPPL.check_tilde_rhs(%5::Any)::Any
    └───        goto #28
    27 ─        Core.throw(ErrorException("fatal error in type inference (type bound)"))::Union{}
    └───        unreachable
    28 ┄ %58  = φ (#22 => %47, #24 => %51, #26 => %54)::Any
    │    %59  = (DynamicPPL.unwrap_right_vn)(%58, %15)::Tuple{Any, VarName}
    │    %60  = Core.getfield(%59, 1)::Any
    │    %61  = Core.getfield(%59, 2)::VarName
    │    %62  = (DynamicPPL.tilde_assume!!)(__context__, %60, %61, __varinfo__)::Tuple{Any, Any}
    │    %63  = Base.getfield(%62, 1)::Any
    │    %64  = Base.getfield(%62, 2)::Any
    │    %65  = (Setfield.set)(%3, $(QuoteNode(BangBang.SetfieldImpl.Lens!!{Setfield.IndexLens{Tuple{Int64}}}((@lens _[1])))), %63)::Any
    └───        goto #42
    29 ─ %67  = (DynamicPPL.inargnames)(%15, __model__)::Any
    │    %68  = !%67::Any
    └───        goto #34 if not %68
    30 ─ %70  = (DynamicPPL.getconditioned_nested)(__context__, %15)::Any
    │    %71  = (isa)(%3, Vector{Any})::Bool
    └───        goto #32 if not %71
    31 ─ %73  = π (%3, Vector{Any})
    │           Base.arrayset(true, %73, %70, 1)::Vector{Any}
    └───        goto #33
    32 ─        Base.setindex!(%3, %70, 1)::Any
    └───        goto #33
    33 ┄        nothing::Nothing
    34 ┄ %79  = (isa)(%5, AbstractArray{<:Distributions.Distribution})::Bool
    └───        goto #36 if not %79
    35 ─ %81  = π (%5, AbstractArray{<:Distributions.Distribution})
    └───        goto #41
    36 ─ %83  = (isa)(%5, Distributions.Distribution)::Bool
    └───        goto #38 if not %83
    37 ─ %85  = π (%5, Distributions.Distribution)
    └───        goto #41
    38 ─        goto #40 if not true
    39 ─ %88  = invoke DynamicPPL.check_tilde_rhs(%5::Any)::Any
    └───        goto #41
    40 ─        Core.throw(ErrorException("fatal error in type inference (type bound)"))::Union{}
    └───        unreachable
    41 ┄ %92  = φ (#35 => %81, #37 => %85, #39 => %88)::Any
    │    %93  = Base.getindex(%3, 1)::Any
    │    %94  = (DynamicPPL.tilde_observe!!)(__context__, %92, %93, %15, __varinfo__)::Tuple{Any, Any}
    └─── %95  = Base.getfield(%94, 2)::Any
    42 ┄ %96  = φ (#19 => %3, #28 => %65, #41 => %3)::Any
    │    %97  = φ (#19 => __varinfo__, #28 => %64, #41 => %95)::Any
    │    %98  = Main.Normal::Any
    │    %99  = (%98)()::Any
    │    %100 = (isa)(%99, NamedDist)::Bool
    └───        goto #44 if not %100
    43 ─ %102 = π (%99, NamedDist)
    │    %103 = Base.getfield(%102, :name)::VarName
    └───        goto #47
    44 ─        goto #46 if not true
    45 ─        goto #47
    46 ─        Core.throw(ErrorException("fatal error in type inference (type bound)"))::Union{}
    └───        unreachable
    47 ┄ %109 = φ (#43 => %103, #45 => $(QuoteNode(m[2])))::VarName
    │    %110 = (DynamicPPL.contextual_isassumption)(__context__, %109)::Bool
    └───        goto #55 if not %110
    48 ─ %112 = (DynamicPPL.inargnames)(%109, __model__)::Any
    │    %113 = !%112::Any
    └───        goto #50 if not %113
    49 ─        goto #53
    50 ─ %116 = (DynamicPPL.inmissings)(%109, __model__)::Any
    └───        goto #52 if not %116
    51 ─        goto #53
    52 ─ %119 = (Base.maybeview)(%96, 2)::Any
    │    %120 = (%119 === Main.missing)::Bool
    └───        goto #54
    53 ┄        nothing::Nothing
    54 ┄ %123 = φ (#53 => true, #52 => %120)::Bool
    └───        goto #56
    55 ─        nothing::Nothing
    56 ┄ %126 = φ (#54 => %123, #55 => false)::Bool
    │    %127 = (DynamicPPL.contextual_isfixed)(__context__, %109)::Bool
    └───        goto #58 if not %127
    57 ─ %129 = (DynamicPPL.getfixed_nested)(__context__, %109)::Any
    │           Base.setindex!(%96, %129, 2)::Any
    └───        goto #77
    58 ─        goto #67 if not %126
    59 ─ %133 = (isa)(%99, AbstractArray{<:Distributions.Distribution})::Bool
    └───        goto #61 if not %133
    60 ─ %135 = π (%99, AbstractArray{<:Distributions.Distribution})
    └───        goto #66
    61 ─ %137 = (isa)(%99, Distributions.Distribution)::Bool
    └───        goto #63 if not %137
    62 ─ %139 = π (%99, Distributions.Distribution)
    └───        goto #66
    63 ─        goto #65 if not true
    64 ─ %142 = invoke DynamicPPL.check_tilde_rhs(%99::Any)::Any
    └───        goto #66
    65 ─        Core.throw(ErrorException("fatal error in type inference (type bound)"))::Union{}
    └───        unreachable
    66 ┄ %146 = φ (#60 => %135, #62 => %139, #64 => %142)::Any
    │    %147 = (DynamicPPL.unwrap_right_vn)(%146, %109)::Tuple{Any, VarName}
    │    %148 = Core.getfield(%147, 1)::Any
    │    %149 = Core.getfield(%147, 2)::VarName
    │    %150 = (DynamicPPL.tilde_assume!!)(__context__, %148, %149, %97)::Tuple{Any, Any}
    │    %151 = Base.getfield(%150, 1)::Any
    │    %152 = Base.getfield(%150, 2)::Any
    │    %153 = (Setfield.set)(%96, $(QuoteNode(BangBang.SetfieldImpl.Lens!!{Setfield.IndexLens{Tuple{Int64}}}((@lens _[2])))), %151)::Any
    └───        goto #77
    67 ─ %155 = (DynamicPPL.inargnames)(%109, __model__)::Any
    │    %156 = !%155::Any
    └───        goto #69 if not %156
    68 ─ %158 = (DynamicPPL.getconditioned_nested)(__context__, %109)::Any
    └───        Base.setindex!(%96, %158, 2)::Any
    69 ┄ %160 = (isa)(%99, AbstractArray{<:Distributions.Distribution})::Bool
    └───        goto #71 if not %160
    70 ─ %162 = π (%99, AbstractArray{<:Distributions.Distribution})
    └───        goto #76
    71 ─ %164 = (isa)(%99, Distributions.Distribution)::Bool
    └───        goto #73 if not %164
    72 ─ %166 = π (%99, Distributions.Distribution)
    └───        goto #76
    73 ─        goto #75 if not true
    74 ─ %169 = invoke DynamicPPL.check_tilde_rhs(%99::Any)::Any
    └───        goto #76
    75 ─        Core.throw(ErrorException("fatal error in type inference (type bound)"))::Union{}
    └───        unreachable
    76 ┄ %173 = φ (#70 => %162, #72 => %166, #74 => %169)::Any
    │    %174 = (Base.maybeview)(%96, 2)::Any
    │    %175 = (DynamicPPL.tilde_observe!!)(__context__, %173, %174, %109, %97)::Tuple{Any, Any}
    └─── %176 = Base.getfield(%175, 2)::Any
    77 ┄ %177 = φ (#57 => %96, #66 => %153, #76 => %96)::Any
    │    %178 = φ (#57 => %97, #66 => %152, #76 => %176)::Any
    │    %179 = Core.tuple(%177, %178)::Tuple{Any, Any}
    └───        return %179
    ) => Tuple{Any, Any}

@yebai @devmotion

sunxd3 avatar Apr 15 '24 09:04 sunxd3

Also, all the tests pass when Accessors is exposed in Main

sunxd3 avatar Apr 15 '24 09:04 sunxd3

The issue seems to be that these references to Setfield gets compiled away, but with Accessors, they are not.

Compilation should really not affect this issue; if there's an unresolved reference, there's no way to know what to compile.

I'm wondering if something somewhere is not interpolated correctly.

E.g. consider the following:

julia> module A
           id(x) = x
       end
Main.A

julia> module B
           using ..A: A
           macro a(x)
               :(A.id($x))
           end
           macro b(x)
               :($(A.id)($x))
           end
           macro c(x)
               :($(esc(:id))($x))
           end
       end
Main.B

julia> @macroexpand B.@a 1
:((Main.B.A).id(1))

julia> @macroexpand B.@b 1
:((Main.A.id)(1))

julia> @macroexpand B.@c 1 # This will not work
:(id(1))

So could there be some unfortunate interaction with esc and some references somewhere that occur now but now before?

torfjelde avatar Apr 15 '24 11:04 torfjelde

turns out the reason is lot more stupid, fixed at https://github.com/TuringLang/AbstractPPL.jl/pull/97.

sunxd3 avatar Apr 18 '24 04:04 sunxd3

Should be okay, but probably wait for https://github.com/TuringLang/DynamicPPL.jl/pull/586

sunxd3 avatar Apr 18 '24 11:04 sunxd3

@torfjelde, can you give this a second look so we can merge it?

yebai avatar Apr 18 '24 19:04 yebai