-
Notifications
You must be signed in to change notification settings - Fork 37
VNV type stability improvements and tests #1102
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
Changes from all commits
073ec92
52edf9a
839d4ce
b110800
6972713
0b527c3
48e93ef
305b730
536ca7b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1297,6 +1297,10 @@ function _link_metadata!!( | |
| metadata = setindex_internal!!(metadata, val_new, vn, transform_from_linked) | ||
| set_transformed!(metadata, true, vn) | ||
| end | ||
| # Linking can often change the sizes of variables, causing inactive elements. We don't | ||
| # want to keep them around, since typically linking is done once and then the VarInfo | ||
| # is evaluated multiple times. Hence we contiguify here. | ||
| metadata = contiguify!(metadata) | ||
| return metadata, cumulative_logjac | ||
| end | ||
|
|
||
|
|
@@ -1465,6 +1469,10 @@ function _invlink_metadata!!( | |
| metadata = setindex_internal!!(metadata, tovec(new_val), vn, new_transform) | ||
| set_transformed!(metadata, false, vn) | ||
| end | ||
| # Linking can often change the sizes of variables, causing inactive elements. We don't | ||
| # want to keep them around, since typically linking is done once and then the VarInfo | ||
| # is evaluated multiple times. Hence we contiguify here. | ||
| metadata = contiguify!(metadata) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise. |
||
| return metadata, cumulative_inv_logjac | ||
| end | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,7 +79,7 @@ function relax_container_types(vnv::DynamicPPL.VarNamedVector, vn::VarName, val) | |
| end | ||
| function relax_container_types(vnv::DynamicPPL.VarNamedVector, vns, vals) | ||
| if need_varnames_relaxation(vnv, vns, vals) | ||
| varname_to_index_new = convert(OrderedDict{VarName,Int}, vnv.varname_to_index) | ||
| varname_to_index_new = convert(Dict{VarName,Int}, vnv.varname_to_index) | ||
| varnames_new = convert(Vector{VarName}, vnv.varnames) | ||
| else | ||
| varname_to_index_new = vnv.varname_to_index | ||
|
|
@@ -517,7 +517,7 @@ end | |
| @testset "deterministic" begin | ||
| n = 5 | ||
| vn = @varname(x) | ||
| vnv = DynamicPPL.VarNamedVector(OrderedDict(vn => [true])) | ||
| vnv = DynamicPPL.VarNamedVector(Dict(vn => [true])) | ||
| @test !DynamicPPL.has_inactive(vnv) | ||
| # Growing should not create inactive ranges. | ||
| for i in 1:n | ||
|
|
@@ -543,7 +543,7 @@ end | |
| @testset "random" begin | ||
| n = 5 | ||
| vn = @varname(x) | ||
| vnv = DynamicPPL.VarNamedVector(OrderedDict(vn => [true])) | ||
| vnv = DynamicPPL.VarNamedVector(Dict(vn => [true])) | ||
| @test !DynamicPPL.has_inactive(vnv) | ||
|
|
||
| # Insert a bunch of random-length vectors. | ||
|
|
@@ -579,6 +579,91 @@ end | |
| @test is_transformed(vnv, @varname(t[1])) | ||
| @test subset(vnv, vns) == vnv | ||
| end | ||
|
|
||
| @testset "loosen and tighten types" begin | ||
| """ | ||
| test_tightenability(vnv::VarNamedVector) | ||
|
|
||
| Test that tighten_types!! is a no-op on `vnv`. | ||
| """ | ||
| function test_tightenability(vnv::DynamicPPL.VarNamedVector) | ||
| @test vnv == DynamicPPL.tighten_types!!(deepcopy(vnv)) | ||
| # TODO(mhauru) We would like to check something more stringent here, namely that | ||
| # the operation is compiled to a direct no-op, with no instructions at all. I | ||
| # don't know how to do that though, so for now we just check that it doesn't | ||
| # allocate. | ||
| @allocations(DynamicPPL.tighten_types!!(vnv)) == 0 | ||
| return nothing | ||
|
Comment on lines
+590
to
+596
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you do something with this? julia> using DynamicPPL; vnv = DynamicPPL.VarNamedVector();
julia> ct = code_typed(DynamicPPL.tighten_types!!, (typeof(vnv),))
1-element Vector{Any}:
CodeInfo(
1 ─ nothing::Nothing
└── return vnv
) => DynamicPPL.VarNamedVector{Union{}, Union{}, Union{}, Vector{Union{}}, Vector{Union{}}, Vector{Union{}}}
julia> only(ct).first.code
2-element Vector{Any}:
nothing
:(return _2)There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wondered, but this seems brittle to me. Why is there a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
julia> ct = code_typed(DynamicPPL.loosen_types!!, (typeof(vnv), Type{Union{}}, Type{Union{}}, Type{Union{}}))
1-element Vector{Any}:
CodeInfo(
1 ─ nothing::Nothing
│ nothing::Nothing
│ nothing::Nothing
└── return vnv
) => DynamicPPL.VarNamedVector{Union{}, Union{}, Union{}, Vector{Union{}}, Vector{Union{}}, Vector{Union{}}}There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's fair. On 1.10 there's no julia> only(ct).first.code
1-element Vector{Any}:
:(return _2)I guess it's like pick your poison, either you aren't really testing what you want to test, or you have to use some language internals. Happy with either choice (let's hope There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, interesting about |
||
| end | ||
|
|
||
| vn = @varname(a[1]) | ||
| # Test that tighten_types!! is a no-op on an empty VarNamedVector. | ||
| vnv = DynamicPPL.VarNamedVector() | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| test_tightenability(vnv) | ||
| # Also check that it literally returns the same object, and both tighten and loosen | ||
| # are type stable. | ||
| @test vnv === DynamicPPL.tighten_types!!(vnv) | ||
| @inferred DynamicPPL.tighten_types!!(vnv) | ||
| @inferred DynamicPPL.loosen_types!!(vnv, VarName, Any, Any) | ||
| # Likewise for a VarNamedVector with something pushed into it. | ||
| vnv = DynamicPPL.VarNamedVector() | ||
| vnv = setindex!!(vnv, 1.0, vn) | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| test_tightenability(vnv) | ||
| @test vnv === DynamicPPL.tighten_types!!(vnv) | ||
| @inferred DynamicPPL.tighten_types!!(vnv) | ||
| @inferred DynamicPPL.loosen_types!!(vnv, VarName, Any, Any) | ||
| # Likewise for a VarNamedVector with abstract element-types, when that is needed for | ||
| # the current contents because mixed types have been pushed into it. However, this | ||
| # time, since the types are only as tight as they can be, but not actually concrete, | ||
| # tighten_types!! can't be type stable. | ||
| vnv = DynamicPPL.VarNamedVector() | ||
| vnv = setindex!!(vnv, 1.0, vn) | ||
| vnv = setindex!!(vnv, 2, @varname(b)) | ||
| @test !DynamicPPL.is_tightly_typed(vnv) | ||
| test_tightenability(vnv) | ||
| @inferred DynamicPPL.loosen_types!!(vnv, VarName, Any, Any) | ||
| # Likewise when first mixed types are pushed, but then deleted. | ||
| vnv = DynamicPPL.VarNamedVector() | ||
| vnv = setindex!!(vnv, 1.0, vn) | ||
| vnv = setindex!!(vnv, 2, @varname(b)) | ||
| @test !DynamicPPL.is_tightly_typed(vnv) | ||
| vnv = delete!!(vnv, vn) | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| test_tightenability(vnv) | ||
| @test vnv === DynamicPPL.tighten_types!!(vnv) | ||
| @inferred DynamicPPL.tighten_types!!(vnv) | ||
| @inferred DynamicPPL.loosen_types!!(vnv, VarName, Any, Any) | ||
|
|
||
| # Test that loosen_types!! does really loosen them and that tighten_types!! reverts | ||
| # that. | ||
| vnv = DynamicPPL.VarNamedVector() | ||
| vnv = setindex!!(vnv, 1.0, vn) | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| k = eltype(vnv.varnames) | ||
| e = eltype(vnv.vals) | ||
| t = eltype(vnv.transforms) | ||
| # Loosen key type. | ||
| vnv = @inferred DynamicPPL.loosen_types!!(vnv, VarName, e, t) | ||
| @test !DynamicPPL.is_tightly_typed(vnv) | ||
| vnv = DynamicPPL.tighten_types!!(vnv) | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| # Loosen element type | ||
| vnv = @inferred DynamicPPL.loosen_types!!(vnv, k, Real, t) | ||
| @test !DynamicPPL.is_tightly_typed(vnv) | ||
| vnv = DynamicPPL.tighten_types!!(vnv) | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| # Loosen transformation type | ||
| vnv = @inferred DynamicPPL.loosen_types!!(vnv, k, e, Function) | ||
| @test !DynamicPPL.is_tightly_typed(vnv) | ||
| vnv = DynamicPPL.tighten_types!!(vnv) | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| # Loosening to the same types as currently should do nothing. | ||
| vnv = @inferred DynamicPPL.loosen_types!!(vnv, k, e, t) | ||
| @test DynamicPPL.is_tightly_typed(vnv) | ||
| @allocations(DynamicPPL.loosen_types!!(vnv, k, e, t)) == 0 | ||
| end | ||
| end | ||
|
|
||
| @testset "VarInfo + VarNamedVector" begin | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm reading the code correctly, I think
contiguify!should returnnothingand this should not assign to metadata.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should
contiguify!return nothing? It doesn't have to return anything since it does its work in-place, but I think it can, see #653 (comment).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh. For sanity's sake I'd prefer single-bang to return nothing, but ok.