From 0a03b30c4c14285065215e9ed7ab3b518a20e83b Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 20 Nov 2021 20:40:04 +0100 Subject: [PATCH 01/22] Use `Base.to_indices` to concretize index lenses. --- src/varname.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/varname.jl b/src/varname.jl index 48312ae..1a49fd7 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -424,11 +424,13 @@ _issubrange(i::Colon, j::ConcreteIndex) = true Return `l` instantiated on `x`, i.e. any runtime information evaluated using `x`. """ concretize(I::Lens, x) = I +concretize(I::IndexLens, x) = IndexLens(Base.to_indices(x, I.indices)) concretize(I::DynamicIndexLens, x) = IndexLens(I.f(x)) function concretize(I::ComposedLens, x) x_inner = get(x, I.outer) return ComposedLens(concretize(I.outer, x), concretize(I.inner, x_inner)) end + """ concretize(vn::VarName, x) From 9e696e1a58b0b2d49b1969e8b03d107b97b4d789 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 20 Nov 2021 20:45:00 +0100 Subject: [PATCH 02/22] Fix doctest --- src/varname.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index 1a49fd7..b488b3f 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -438,10 +438,10 @@ Return `vn` instantiated on `x`, i.e. any runtime information evaluated using `x # Examples ```jldoctest; setup=:(using Setfield) -julia> x = (a = [1.0 2.0;], ); +julia> x = (a = [1.0 2.0; 3.0 4.0], ); -julia> AbstractPPL.concretize(@varname(x.a[1, end][:]), x) -x.a[1,2][:] +julia> AbstractPPL.concretize(@varname(x.a[1:end, end][:]), x) +x.a[1:2,2][Base.Slice(Base.OneTo(2))] ``` """ concretize(vn::VarName, x) = VarName(vn, concretize(getlens(vn), x)) From 3897231e14242fe0dcc5c762ecea71fbac218dfc Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sun, 28 Nov 2021 12:20:07 +0100 Subject: [PATCH 03/22] Normalize all recovered range types (better printing and equivalence) --- src/varname.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index b488b3f..43d87c9 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -418,14 +418,18 @@ _issubrange(i::ConcreteIndex, j::Colon) = true # we preserve the status quo, but I'm confused. _issubrange(i::Colon, j::ConcreteIndex) = true +"""Turn any `AbstractRange` into an equivalent `UnitRange` or `StepRange`.""" +_normalizerange(r::AbstractRange) = (:)(r...) +_normalizerange(x) = x + """ concretize(l::Lens, x) Return `l` instantiated on `x`, i.e. any runtime information evaluated using `x`. """ concretize(I::Lens, x) = I -concretize(I::IndexLens, x) = IndexLens(Base.to_indices(x, I.indices)) -concretize(I::DynamicIndexLens, x) = IndexLens(I.f(x)) +concretize(I::IndexLens, x) = IndexLens(_normalizerange.(Base.to_indices(x, I.indices))) +concretize(I::DynamicIndexLens, x) = IndexLens(_normalizerange.(I.f(x))) function concretize(I::ComposedLens, x) x_inner = get(x, I.outer) return ComposedLens(concretize(I.outer, x), concretize(I.inner, x_inner)) @@ -441,7 +445,7 @@ Return `vn` instantiated on `x`, i.e. any runtime information evaluated using `x julia> x = (a = [1.0 2.0; 3.0 4.0], ); julia> AbstractPPL.concretize(@varname(x.a[1:end, end][:]), x) -x.a[1:2,2][Base.Slice(Base.OneTo(2))] +x.a[1:2,2][1:2] ``` """ concretize(vn::VarName, x) = VarName(vn, concretize(getlens(vn), x)) From 36ce5a3700317ae97de38b80c43a9371ffebfc30 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Mon, 13 Dec 2021 10:32:12 +0100 Subject: [PATCH 04/22] Trade-off between to_indices and strange range types; add explicit concretization flag to macro --- src/varname.jl | 95 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index 43d87c9..55dce64 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -172,6 +172,7 @@ _print_application(io::IO, l::DynamicIndexLens) = print(io, l, "(_)") prettify_index(x) = string(x) prettify_index(::Colon) = ":" +prettify_index(::Base.Slice) = ":" """ Symbol(vn::VarName) @@ -418,18 +419,35 @@ _issubrange(i::ConcreteIndex, j::Colon) = true # we preserve the status quo, but I'm confused. _issubrange(i::Colon, j::ConcreteIndex) = true -"""Turn any `AbstractRange` into an equivalent `UnitRange` or `StepRange`.""" -_normalizerange(r::AbstractRange) = (:)(r...) -_normalizerange(x) = x +_concretize(x, inds) = _concretize_indices(inds, Base.to_indices(x, inds)) +@generated function _concretize_indices( + orig_inds::TO, + conv_inds::TC +) where {N, TO<:Tuple{Vararg{Any, N}}, TC<:Tuple{Vararg{Any, N}}} + converted = map(1:N, TO.parameters, TC.parameters) do n, Ti, Tj + if Ti <: Colon + :(Base.Slice(UnitRange(conv_inds[$n].indices))) + else + :(conv_inds[$n]) + end + end + + return Expr(:tuple, converted...) +end """ concretize(l::Lens, x) -Return `l` instantiated on `x`, i.e. any runtime information evaluated using `x`. +Return `l` instantiated on `x`, i.e. any information related to the runtime shape of `x` is +evaluated. This concerns `begin`, `end`, and `:` slices. + +Basically, every index is converted to a concrete value using `Base.to_index` on `x`. However, `:` +slices are only converted to `UnitRange`s (`a:b`) wrapped in `Base.Slice` (as opposed to +`Base.OneTo`), to keep the result close to the original indexing. """ concretize(I::Lens, x) = I -concretize(I::IndexLens, x) = IndexLens(_normalizerange.(Base.to_indices(x, I.indices))) -concretize(I::DynamicIndexLens, x) = IndexLens(_normalizerange.(I.f(x))) +concretize(I::DynamicIndexLens, x) = IndexLens(I.f(x)) +concretize(I::IndexLens, x) = IndexLens(_concretize(x, I.indices)) function concretize(I::ComposedLens, x) x_inner = get(x, I.outer) return ComposedLens(concretize(I.outer, x), concretize(I.inner, x_inner)) @@ -438,45 +456,57 @@ end """ concretize(vn::VarName, x) -Return `vn` instantiated on `x`, i.e. any runtime information evaluated using `x`. +Return `vn` concretized on `x`, i.e. any information related to the runtime shape of `x` is +evaluated. This concerns `begin`, `end`, and `:` slices. # Examples ```jldoctest; setup=:(using Setfield) -julia> x = (a = [1.0 2.0; 3.0 4.0], ); +julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], ); + +julia> getlens(@varname(x.a[1:end, end][:], true)) # concrete=true required for @varname +(@lens _.a[1:3, 2][Base.Slice(1:3)]) -julia> AbstractPPL.concretize(@varname(x.a[1:end, end][:]), x) -x.a[1:2,2][1:2] +julia> y = zeros(10, 10); + +julia> @varname(y[:], true) +y[:] + +julia> AbstractPPL.getlens(AbstractPPL.concretize(@varname(y[:]), y)).indices +(Base.Slice(1:100),) ``` """ concretize(vn::VarName, x) = VarName(vn, concretize(getlens(vn), x)) """ - @varname(expr) + @varname(expr, concretize=false) A macro that returns an instance of [`VarName`](@ref) given a symbol or indexing expression `expr`. If `concretize` is `true`, the resulting expression will be wrapped in a [`concretize`](@ref) call. -Note that expressions involving dynamic indexing, i.e. `begin` and/or `end`, will need to be -resolved as `VarName` only supports non-dynamic indexing as determined by +Note that expressions involving dynamic indexing, i.e. `begin` and/or `end`, will always need to be +concretized as `VarName` only supports non-dynamic indexing as determined by [`is_static_index`](@ref). See examples below. ## Examples ### Dynamic indexing ```jldoctest -julia> # Dynamic indexing is not allowed in `VarName` - @varname(x[end]) -ERROR: UndefVarError: x not defined +julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], ); + +julia> @varname(x.a[1:end, end][:], true) +x.a[1:3,2][:] + +julia> @varname(x.a[end]) +ERROR: LoadError: Variable name `x.a[end]` is dynamic and requires concretization! [...] -julia> # To be able to resolve `end` we need `x` to be available. - x = randn(2); @varname(x[end]) -x[2] +julia> @varname(x.a[end], true) +x.a[6] julia> # Note that "dynamic" here refers to usage of `begin` and/or `end`, # _not_ "information only available at runtime", i.e. the following works. - [@varname(x[i]) for i = 1:length(x)][end] -x[2] + [@varname(x.a[i]) for i = 1:length(x.a)][end] +x.a[6] ``` ### General indexing @@ -509,7 +539,7 @@ julia> getlens(@varname(x.a)) julia> getlens(@varname(x.a[1])) (@lens _.a[1]) -julia> x = (a = [(b = rand(2), )], ); getlens(@varname(x.a[1].b[end])) +julia> x = (a = [(b = rand(2), )], ); getlens(@varname(x.a[1].b[end], true)) (@lens _.a[1].b[2]) ``` @@ -517,12 +547,12 @@ julia> x = (a = [(b = rand(2), )], ); getlens(@varname(x.a[1].b[end])) Using `begin` in an indexing expression to refer to the first index requires at least Julia 1.5. """ -macro varname(expr::Union{Expr,Symbol}) - return varname(expr) +macro varname(expr::Union{Expr,Symbol}, concretize::Bool=false) + return varname(expr, concretize) end -varname(sym::Symbol) = :($(AbstractPPL.VarName){$(QuoteNode(sym))}()) -function varname(expr::Expr) +varname(sym::Symbol, concretize=false) = :($(AbstractPPL.VarName){$(QuoteNode(sym))}()) +function varname(expr::Expr, concretize=false) if Meta.isexpr(expr, :ref) || Meta.isexpr(expr, :.) # Split into object/base symbol and lens. sym_escaped, lens = Setfield.parse_obj_lens(expr) @@ -530,17 +560,19 @@ function varname(expr::Expr) # to call `QuoteNode` on it. sym = drop_escape(sym_escaped) - return if Setfield.need_dynamic_lens(expr) - :( + if concretize + return :( $(AbstractPPL.VarName){$(QuoteNode(sym))}( $(AbstractPPL.concretize)($lens, $sym_escaped) ) ) + elseif !concretize && Setfield.need_dynamic_lens(expr) + error("Variable name `$(expr)` is dynamic and requires concretization!") else :($(AbstractPPL.VarName){$(QuoteNode(sym))}($lens)) end else - error("Malformed variable name $(expr)!") + error("Malformed variable name `$(expr)`!") end end @@ -577,7 +609,8 @@ end vsym(expr) Return name part of the [`@varname`](@ref)-compatible expression `expr` as a symbol for input of the -[`VarName`](@ref) constructor.""" +[`VarName`](@ref) constructor. +""" function vsym end vsym(expr::Symbol) = expr @@ -585,6 +618,6 @@ function vsym(expr::Expr) if Meta.isexpr(expr, :ref) || Meta.isexpr(expr, :.) return vsym(expr.args[1]) else - error("Malformed variable name $(expr)!") + error("Malformed variable name `$(expr)`!") end end From e854b17731fde03d172d7749197454a17d633d77 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Mon, 13 Dec 2021 14:12:15 +0100 Subject: [PATCH 05/22] Remove Slice wrappers --- src/varname.jl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index 55dce64..cc542c1 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -172,7 +172,6 @@ _print_application(io::IO, l::DynamicIndexLens) = print(io, l, "(_)") prettify_index(x) = string(x) prettify_index(::Colon) = ":" -prettify_index(::Base.Slice) = ":" """ Symbol(vn::VarName) @@ -426,7 +425,7 @@ _concretize(x, inds) = _concretize_indices(inds, Base.to_indices(x, inds)) ) where {N, TO<:Tuple{Vararg{Any, N}}, TC<:Tuple{Vararg{Any, N}}} converted = map(1:N, TO.parameters, TC.parameters) do n, Ti, Tj if Ti <: Colon - :(Base.Slice(UnitRange(conv_inds[$n].indices))) + :(UnitRange(conv_inds[$n].indices)) else :(conv_inds[$n]) end @@ -442,8 +441,8 @@ Return `l` instantiated on `x`, i.e. any information related to the runtime shap evaluated. This concerns `begin`, `end`, and `:` slices. Basically, every index is converted to a concrete value using `Base.to_index` on `x`. However, `:` -slices are only converted to `UnitRange`s (`a:b`) wrapped in `Base.Slice` (as opposed to -`Base.OneTo`), to keep the result close to the original indexing. +slices are only converted to `UnitRange`s (`a:b`) (as opposed to `Base.Slice{Base.OneTo}`), to keep +the result close to the original indexing. """ concretize(I::Lens, x) = I concretize(I::DynamicIndexLens, x) = IndexLens(I.f(x)) @@ -464,15 +463,15 @@ evaluated. This concerns `begin`, `end`, and `:` slices. julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], ); julia> getlens(@varname(x.a[1:end, end][:], true)) # concrete=true required for @varname -(@lens _.a[1:3, 2][Base.Slice(1:3)]) +(@lens _.a[1:3, 2][1:3]) julia> y = zeros(10, 10); julia> @varname(y[:], true) -y[:] +y[1:100] julia> AbstractPPL.getlens(AbstractPPL.concretize(@varname(y[:]), y)).indices -(Base.Slice(1:100),) +(1:100,) ``` """ concretize(vn::VarName, x) = VarName(vn, concretize(getlens(vn), x)) @@ -494,7 +493,7 @@ concretized as `VarName` only supports non-dynamic indexing as determined by julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], ); julia> @varname(x.a[1:end, end][:], true) -x.a[1:3,2][:] +x.a[1:3,2][1:3] julia> @varname(x.a[end]) ERROR: LoadError: Variable name `x.a[end]` is dynamic and requires concretization! From 65346a9fa6964c8e0982d8e63deafb1a853ffbe0 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 5 Feb 2022 10:14:36 +0100 Subject: [PATCH 06/22] Add doc(test) for surprising range normalization --- src/varname.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/varname.jl b/src/varname.jl index f38944d..2bc5e1f 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -505,6 +505,10 @@ julia> # Note that "dynamic" here refers to usage of `begin` and/or `end`, # _not_ "information only available at runtime", i.e. the following works. [@varname(x.a[i]) for i = 1:length(x.a)][end] x.a[6] + +julia> # Potentially surprising behaviour, but this is equivalent to what Base does: + @varname(x[2:2:5]), 2:2:5 +(x[2:2:4], 2:2:4) ``` ### General indexing From 82c914c2e52ffcfff7ca481c06f8cb6b1c3f1e2a Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 5 Feb 2022 15:10:13 +0100 Subject: [PATCH 07/22] Add proper VarName tests; some refactoring --- src/AbstractPPL.jl | 16 ++++++++++- src/varname.jl | 72 +++++++++++++++++++++------------------------- test/Project.toml | 2 ++ test/runtests.jl | 3 +- 4 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/AbstractPPL.jl b/src/AbstractPPL.jl index ee9dfab..e6f9a06 100644 --- a/src/AbstractPPL.jl +++ b/src/AbstractPPL.jl @@ -1,7 +1,21 @@ module AbstractPPL # VarName -export VarName, getsym, getlens, inspace, subsumes, varname, vsym, @varname, @vsym +export VarName, + getsym, + getlens, + inspace, + subsumes, + subsumedby, + ⊑, + ⊒, + ⋣, + ⋢, + ≍, + varname, + vsym, + @varname, + @vsym # Abstract model functions diff --git a/src/varname.jl b/src/varname.jl index 2bc5e1f..3db9bfd 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -274,8 +274,9 @@ end # `PropertyLens{:a}` and `PropertyLens{:b}` we immediately know that they do not subsume # each other since at the same level/depth they access different properties. # E.g. `x`, `x[1]`, i.e. `u` is always subsumed by `t` -subsumes(t::IdentityLens, u::Lens) = true -subsumes(t::Lens, u::IdentityLens) = false +subsumes(::IdentityLens, ::IdentityLens) = true +subsumes(::IdentityLens, ::Lens) = true +subsumes(::Lens, ::IdentityLens) = false subsumes(t::ComposedLens, u::ComposedLens) = subsumes(t.outer, u.outer) && subsumes(t.inner, u.inner) @@ -297,10 +298,18 @@ subsumes(t::PropertyLens, u::PropertyLens) = false # FIXME: Does not support `DynamicIndexLens`. # FIXME: Does not correctly handle cases such as `subsumes(x, x[:])` # (but neither did old implementation). -subsumes(t::IndexLens, u::IndexLens) = _issubindex(t.indices, u.indices) -subsumes(t::ComposedLens{<:IndexLens}, u::ComposedLens{<:IndexLens}) = subsumes_index(t, u) -subsumes(t::IndexLens, u::ComposedLens{<:IndexLens}) = subsumes_index(t, u) -subsumes(t::ComposedLens{<:IndexLens}, u::IndexLens) = subsumes_index(t, u) +subsumes( + t::Union{IndexLens,ComposedLens{<:IndexLens}}, + u::Union{IndexLens,ComposedLens{<:IndexLens}} +) = subsumes_index(t, u) + + +const subsumedby = (t, u) -> subsumes(u, t) +const ⊒ = subsumes +const ⊑ = subsumedby +const ⋣ = !subsumes +const ⋢ = !subsumedby +const ≍ = (t, u) -> t ⋢ u && u ⋢ t # Since expressions such as `x[:][:][:][1]` and `x[1]` are equal, # the indexing behavior must be considered jointly. @@ -396,42 +405,25 @@ Currently _not_ supported are: subsumes_index(::Tuple{}, ::Tuple{}) = true # x subsumes x subsumes_index(::Tuple{}, ::Tuple) = true # x subsumes x[1] subsumes_index(::Tuple, ::Tuple{}) = false # x[1] does not subsume x -function subsumes_index(t::Tuple, u::Tuple) # does x[i]... subsume x[j]...? - return _issubindex(first(t), first(u)) && subsumes_index(Base.tail(t), Base.tail(u)) +function subsumes_index(t1::Tuple, t2::Tuple) # does x[i]... subsume x[j]...? + first_subsumed = all(issubset(j, i) || checkindex(Bool, j, i) for (i, j) in zip(t1, t2)) + return first_subsumed && subsumes_index(Base.tail(t1), Base.tail(t2)) end -const AnyIndex = Union{Int,AbstractVector{Int},Colon} -_issubindex_(::Tuple{Vararg{AnyIndex}}, ::Tuple{Vararg{AnyIndex}}) = false -function _issubindex(t::NTuple{N,AnyIndex}, u::NTuple{N,AnyIndex}) where {N} - return all(_issubrange(j, i) for (i, j) in zip(t, u)) -end -const ConcreteIndex = Union{Int,AbstractVector{Int}} # this include all kinds of ranges - -"""Determine whether indices `i` are contained in `j`, treating `:` as universal set.""" -_issubrange(i::ConcreteIndex, j::ConcreteIndex) = issubset(i, j) -_issubrange(i::Colon, j::Colon) = true -_issubrange(i::ConcreteIndex, j::Colon) = true -# FIXME: [2021-07-31] This is wrong but we have tests in DPPL that tell -# us that it SHOULD be correct. I'll leave it as is for now to ensure that -# we preserve the status quo, but I'm confused. -_issubrange(i::Colon, j::ConcreteIndex) = true - -_concretize(x, inds) = _concretize_indices(inds, Base.to_indices(x, inds)) -@generated function _concretize_indices( - orig_inds::TO, - conv_inds::TC -) where {N, TO<:Tuple{Vararg{Any, N}}, TC<:Tuple{Vararg{Any, N}}} - converted = map(1:N, TO.parameters, TC.parameters) do n, Ti, Tj - if Ti <: Colon - :(UnitRange(conv_inds[$n].indices)) - else - :(conv_inds[$n]) - end - end +""" + concretize_index(original_index, lowered_index) - return Expr(:tuple, converted...) -end +Create the index to be emitted in `concretize`. `original_index` is the original, unconcretized +index, and `lowered_index` the respective position of the result of `to_indices`. + +The only purpose of this are special cases like `:`, which we want to avoid becoming a +`Base.Slice(OneTo(...))` -- it would confuse people when printed. Instead, we concretize to a +`UnitRange` based on the `lowered_index`, just what you'd get with an explicit `begin:end` +""" +reconcretize_index(original_index, lowered_index) = lowered_index +reconcretize_index(original_index::Colon, lowered_index::Base.Slice{<:Base.OneTo}) = + UnitRange(lowered_index.indices) """ concretize(l::Lens, x) @@ -444,8 +436,8 @@ slices are only converted to `UnitRange`s (`a:b`) (as opposed to `Base.Slice{Bas the result close to the original indexing. """ concretize(I::Lens, x) = I -concretize(I::DynamicIndexLens, x) = IndexLens(I.f(x)) -concretize(I::IndexLens, x) = IndexLens(_concretize(x, I.indices)) +concretize(I::DynamicIndexLens, x) = concretize(IndexLens(I.f(x)), x) +concretize(I::IndexLens, x) = IndexLens(map(reconcretize_index, I.indices, to_indices(x, I.indices))) function concretize(I::ComposedLens, x) x_inner = get(x, I.outer) return ComposedLens(concretize(I.outer, x), concretize(I.inner, x_inner)) diff --git a/test/Project.toml b/test/Project.toml index f0592fe..3f712c0 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,7 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +InvertedIndices = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" +OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/runtests.jl b/test/runtests.jl index 9efca34..09ac1d3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -12,7 +12,8 @@ using Test @testset "AbstractPPL.jl" begin include("deprecations.jl") - + include("varname.jl") + @testset "doctests" begin DocMeta.setdocmeta!( AbstractPPL, From 7c6719ddd57a2d6508ebe33dad35b2d3b5c099d7 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 5 Feb 2022 15:29:15 +0100 Subject: [PATCH 08/22] Require newer Setfield version (fixed equality) --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c973f66..80776eb 100644 --- a/Project.toml +++ b/Project.toml @@ -13,5 +13,5 @@ Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" [compat] AbstractMCMC = "2, 3" DensityInterface = "0.4" -Setfield = "0.7.1, 0.8" +Setfield = "0.8.1" julia = "1" From 63a8191832f43ef7bb489559821a18a66c5aee85 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 5 Feb 2022 15:49:53 +0100 Subject: [PATCH 09/22] Actually add test file... --- test/varname.jl | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 test/varname.jl diff --git a/test/varname.jl b/test/varname.jl new file mode 100644 index 0000000..2105be8 --- /dev/null +++ b/test/varname.jl @@ -0,0 +1,74 @@ +using InvertedIndices +using OffsetArrays +using Setfield + + +macro test_strict_subsumption(x, y) + quote + @test $((varname(x))) ⊑ $((varname(y))) + @test $((varname(x))) ⋣ $((varname(y))) + end +end + +@testset "varnames" begin + @testset "construction & concretization" begin + i = 1:10 + j = 2:2:5 + @test @varname(A[1].b[i]) == @varname(A[1].b[1:10]) + @test @varname(A[j]) == @varname(A[2:2:5]) + + @test @varname(A[:, 1][1+1]) == @varname(A[:, 1][2]) + @test(@varname(A[:, 1][2]) == + VarName{:A}(@lens(_[:, 1]) ∘ @lens(_[2])) == + VarName{:A}(@lens(_[:, 1])) ∘ @lens(_[2]) == + VarName{:A}() ∘ @lens(_[:, 1]) ∘ @lens(_[2])) + + # concretization + y = zeros(10, 10) + x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], ); + + @test @varname(y[begin, i], true) == @varname(y[1, 1:10]) + @test @varname(y[:], true) == @varname(y[1:100]) + @test @varname(y[:, begin], true) == @varname(y[1:10, 1]) + @test getlens(AbstractPPL.concretize(@varname(y[:]), y)).indices === (1:100,) + @test @varname(x.a[1:end, end][:], true) == @varname(x.a[1:3,2][1:3]) + end + + @testset "subsumption with standard indexing" begin + # x ⊑ x + @test @varname(x) ⊑ @varname(x) + @test @varname(x[1]) ⊑ @varname(x[1]) + @test @varname(x.a) ⊑ @varname(x.a) + + # x ≍ y + @test @varname(x) ≍ @varname(y) + @test @varname(x.a) ≍ @varname(y.a) + @test @varname(a.x) ≍ @varname(a.y) + @test @varname(x[1]) ≍ @varname(y[1]) + + # x ∘ ℓ ⊑ x + @test_strict_subsumption x.a x + @test_strict_subsumption x[1] x + @test_strict_subsumption x[2:2:5] x + @test_strict_subsumption x[10, 20] x + + # x ∘ ℓ₁ ⊑ x ∘ ℓ₂ ⇔ ℓ₁ ⊑ ℓ₂ + @test_strict_subsumption x.a.b x.a + @test_strict_subsumption x[1].a x[1] + @test_strict_subsumption x.a[1] x.a + @test_strict_subsumption x[1:10][2] x[1:10] + + @test_strict_subsumption x[1] x[1:10] + @test_strict_subsumption x[1:5] x[1:10] + @test_strict_subsumption x[4:6] x[1:10] + @test_strict_subsumption x[iseven.(1:10)] x[1:10] + end + + @testset "non-standard indexing" begin + A = rand(10, 10) + @test @varname(A[1, Not(3)], true) == @varname(A[1, [1, 2, 4, 5, 6, 7, 8, 9, 10]]) + + B = OffsetArray(A, -5, -5) # indices -4:5×-4:5 + @test @varname(B[1, :], true) == @varname(B[1, -4:5]) + end +end From 34c3868f993545a94f6cfe1fa329060b551d4fa6 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 5 Feb 2022 15:50:20 +0100 Subject: [PATCH 10/22] Shorter reconcretization --- src/varname.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index 3db9bfd..cc183ca 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -422,8 +422,8 @@ The only purpose of this are special cases like `:`, which we want to avoid beco `UnitRange` based on the `lowered_index`, just what you'd get with an explicit `begin:end` """ reconcretize_index(original_index, lowered_index) = lowered_index -reconcretize_index(original_index::Colon, lowered_index::Base.Slice{<:Base.OneTo}) = - UnitRange(lowered_index.indices) +reconcretize_index(original_index::Colon, lowered_index::Base.Slice) = + UnitRange(lowered_index) """ concretize(l::Lens, x) From ab5c80301affa0456ddede9e7342329ac0d4369f Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 5 Feb 2022 17:09:16 +0100 Subject: [PATCH 11/22] Fix remaining bugs? --- src/varname.jl | 15 +++++++++++---- test/varname.jl | 14 +++++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index cc183ca..b5bc262 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -406,7 +406,15 @@ subsumes_index(::Tuple{}, ::Tuple{}) = true # x subsumes x subsumes_index(::Tuple{}, ::Tuple) = true # x subsumes x[1] subsumes_index(::Tuple, ::Tuple{}) = false # x[1] does not subsume x function subsumes_index(t1::Tuple, t2::Tuple) # does x[i]... subsume x[j]...? - first_subsumed = all(issubset(j, i) || checkindex(Bool, j, i) for (i, j) in zip(t1, t2)) + first_subsumed = all(zip(first(t1), first(t2))) do (i, j) + if j isa Colon + error("Colons cannot be subsumed") + elseif i isa Colon + return true + else + return issubset(j, i) + end + end return first_subsumed && subsumes_index(Base.tail(t1), Base.tail(t2)) end @@ -422,8 +430,7 @@ The only purpose of this are special cases like `:`, which we want to avoid beco `UnitRange` based on the `lowered_index`, just what you'd get with an explicit `begin:end` """ reconcretize_index(original_index, lowered_index) = lowered_index -reconcretize_index(original_index::Colon, lowered_index::Base.Slice) = - UnitRange(lowered_index) +reconcretize_index(original_index::Colon, lowered_index::Base.Slice) = (UnitRange(lowered_index)) """ concretize(l::Lens, x) @@ -439,7 +446,7 @@ concretize(I::Lens, x) = I concretize(I::DynamicIndexLens, x) = concretize(IndexLens(I.f(x)), x) concretize(I::IndexLens, x) = IndexLens(map(reconcretize_index, I.indices, to_indices(x, I.indices))) function concretize(I::ComposedLens, x) - x_inner = get(x, I.outer) + x_inner = get(x, I.outer) # TODO: get view here return ComposedLens(concretize(I.outer, x), concretize(I.inner, x_inner)) end diff --git a/test/varname.jl b/test/varname.jl index 2105be8..46502c6 100644 --- a/test/varname.jl +++ b/test/varname.jl @@ -61,7 +61,19 @@ end @test_strict_subsumption x[1] x[1:10] @test_strict_subsumption x[1:5] x[1:10] @test_strict_subsumption x[4:6] x[1:10] - @test_strict_subsumption x[iseven.(1:10)] x[1:10] + + @test_strict_subsumption x[[2,3,5]] x[[7,6,5,4,3,2,1]] + + # boolean indexing works as long as it is concretized + A = rand(10, 10) + @test @varname(A[iseven.(1:10), 1], true) ⊑ @varname(A[1:10, 1]) + @test @varname(A[iseven.(1:10), 1], true) ⋣ @varname(A[1:10, 1]) + + # we can reasonably allow colons on the right side ("universal set") + @test @varname(x[1]) ⊑ @varname(x[:]) + @test @varname(x[1:10, 1]) ⊑ @varname(x[:, 1:10]) + @test_throws ErrorException (@varname(x[:]) ⊑ @varname(x[1])) + @test_throws ErrorException (@varname(x[:]) ⊑ @varname(x[:])) end @testset "non-standard indexing" begin From 477254df670d30e72e213ff86088d19719269700 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Mon, 7 Feb 2022 17:15:31 +0100 Subject: [PATCH 12/22] Refactor subsumption; concretize into ConcretizedSlice; implement suggestions; un-export unicode operators --- src/AbstractPPL.jl | 5 --- src/varname.jl | 85 +++++++++++++++++++++++++++++----------------- test/varname.jl | 8 ++++- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/AbstractPPL.jl b/src/AbstractPPL.jl index e6f9a06..4560e43 100644 --- a/src/AbstractPPL.jl +++ b/src/AbstractPPL.jl @@ -7,11 +7,6 @@ export VarName, inspace, subsumes, subsumedby, - ⊑, - ⊒, - ⋣, - ⋢, - ≍, varname, vsym, @varname, diff --git a/src/varname.jl b/src/varname.jl index b5bc262..3d459ca 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -304,12 +304,13 @@ subsumes( ) = subsumes_index(t, u) -const subsumedby = (t, u) -> subsumes(u, t) +subsumedby(t, u) = subsumes(u, t) +uncomparable(t, u) = t ⋢ u && u ⋢ t const ⊒ = subsumes const ⊑ = subsumedby const ⋣ = !subsumes const ⋢ = !subsumedby -const ≍ = (t, u) -> t ⋢ u && u ⋢ t +const ≍ = uncomparable # Since expressions such as `x[:][:][:][1]` and `x[1]` are equal, # the indexing behavior must be considered jointly. @@ -358,7 +359,7 @@ function subsumes_index(t::Lens, u::Lens) u_indices, u_next = combine_indices(u) # If we already know that `u` is not subsumed by `t`, return early. - if !subsumes_index(t_indices, u_indices) + if !subsumes_indices(t_indices, u_indices) return false end @@ -392,35 +393,54 @@ function combine_indices(lens::ComposedLens{<:IndexLens}) end """ - subsumes_index(left_index::Tuple, right_index::Tuple) + subsumes_indices(left_indices::Tuple, right_indices::Tuple) -Return `true` if `right_index` is subsumed by `left_index`. +Return `true` if `right_indices` is subsumed by `left_indices`. `left_indices` is assumed to be +concretized and consist of either `Int`s or `AbstractArray`s of scalar indices that are supported +by array A. Currently _not_ supported are: - Boolean indexing, literal `CartesianIndex` (these could be added, though) - Linear indexing of multidimensional arrays: `x[4]` does not subsume `x[2, 2]` for a matrix `x` - Trailing ones: `x[2, 1]` does not subsume `x[2]` for a vector `x` -- Dynamic indexing, e.g. `x[1]` does not subsume `x[begin]`. -""" -subsumes_index(::Tuple{}, ::Tuple{}) = true # x subsumes x -subsumes_index(::Tuple{}, ::Tuple) = true # x subsumes x[1] -subsumes_index(::Tuple, ::Tuple{}) = false # x[1] does not subsume x -function subsumes_index(t1::Tuple, t2::Tuple) # does x[i]... subsume x[j]...? - first_subsumed = all(zip(first(t1), first(t2))) do (i, j) - if j isa Colon - error("Colons cannot be subsumed") - elseif i isa Colon - return true - else - return issubset(j, i) - end - end - return first_subsumed && subsumes_index(Base.tail(t1), Base.tail(t2)) +""" +subsumes_indices(::Tuple{}, ::Tuple{}) = true # x subsumes x +subsumes_indices(::Tuple{}, ::Tuple) = true # x subsumes x... +subsumes_indices(::Tuple, ::Tuple{}) = false # x... does not subsume x +function subsumes_indices(t1::Tuple, t2::Tuple) # does x[i]... subsume x[j]...? + first_subsumed = all(Base.splat(subsumes_index), zip(first(t1), first(t2))) + return first_subsumed && subsumes_indices(Base.tail(t1), Base.tail(t2)) end +subsumes_index(i::Colon, ::Colon) = error("Colons cannot be subsumed") +subsumes_index(i, ::Colon) = error("Colons cannot be subsumed") +subsumes_index(i::Colon, j) = true +subsumes_index(i::AbstractArray, j) = issubset(j, i) +subsumes_index(i, j) = i == j + + +struct ConcretizedSlice{T, R} <: AbstractVector{T} + range::R +end + +ConcretizedSlice(s::Base.Slice{R}) where {R} = ConcretizedSlice{eltype(s.indices), R}(s.indices) +Base.show(io::IO, s::ConcretizedSlice) = print(io, ":") +Base.show(io::IO, ::MIME"text/plain", s::ConcretizedSlice) = print(io, "ConcretizedSlice($(s.range))") +Base.IteratorEltype(::Type{<:ConcretizedSlice}) = Base.HasEltype() +Base.eltype(s::ConcretizedSlice{T}) where {T} = T +Base.IteratorSize(::Type{<:ConcretizedSlice}) = Base.HasLength() +Base.length(s::ConcretizedSlice) = length(s.range) +Base.size(s::ConcretizedSlice) = size(s.range) +Base.iterate(s::ConcretizedSlice, state...) = Base.iterate(s.range, state...) +Base.collect(s::ConcretizedSlice) = collect(s.range) +Base.hasfastin(::Type{<:ConcretizedSlice}) = true +Base.in(i, s::ConcretizedSlice) = i in s.range + +# and this is the reason why we are doing this: +Base.to_index(A, s::ConcretizedSlice) = Base.Slice(s.range) """ - concretize_index(original_index, lowered_index) + reconcretize_index(original_index, lowered_index) Create the index to be emitted in `concretize`. `original_index` is the original, unconcretized index, and `lowered_index` the respective position of the result of `to_indices`. @@ -430,13 +450,15 @@ The only purpose of this are special cases like `:`, which we want to avoid beco `UnitRange` based on the `lowered_index`, just what you'd get with an explicit `begin:end` """ reconcretize_index(original_index, lowered_index) = lowered_index -reconcretize_index(original_index::Colon, lowered_index::Base.Slice) = (UnitRange(lowered_index)) +reconcretize_index(original_index::Colon, lowered_index::Base.Slice) = + ConcretizedSlice(lowered_index) + """ concretize(l::Lens, x) Return `l` instantiated on `x`, i.e. any information related to the runtime shape of `x` is -evaluated. This concerns `begin`, `end`, and `:` slices. +evaluated. This concerns `begin`, `end`, and `:` slices. Basically, every index is converted to a concrete value using `Base.to_index` on `x`. However, `:` slices are only converted to `UnitRange`s (`a:b`) (as opposed to `Base.Slice{Base.OneTo}`), to keep @@ -444,7 +466,7 @@ the result close to the original indexing. """ concretize(I::Lens, x) = I concretize(I::DynamicIndexLens, x) = concretize(IndexLens(I.f(x)), x) -concretize(I::IndexLens, x) = IndexLens(map(reconcretize_index, I.indices, to_indices(x, I.indices))) +concretize(I::IndexLens, x) = IndexLens(reconcretize_index.(I.indices, to_indices(x, I.indices))) function concretize(I::ComposedLens, x) x_inner = get(x, I.outer) # TODO: get view here return ComposedLens(concretize(I.outer, x), concretize(I.inner, x_inner)) @@ -461,15 +483,16 @@ evaluated. This concerns `begin`, `end`, and `:` slices. julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], ); julia> getlens(@varname(x.a[1:end, end][:], true)) # concrete=true required for @varname -(@lens _.a[1:3, 2][1:3]) +(@lens _.a[1:3, 2][:]) julia> y = zeros(10, 10); julia> @varname(y[:], true) -y[1:100] +y[:] -julia> AbstractPPL.getlens(AbstractPPL.concretize(@varname(y[:]), y)).indices -(1:100,) +julia> # The underlying value is conretized, though: + AbstractPPL.getlens(AbstractPPL.concretize(@varname(y[:]), y)).indices[1] +ConcretizedSlice(Base.OneTo(100)) ``` """ concretize(vn::VarName, x) = VarName(vn, concretize(getlens(vn), x)) @@ -491,7 +514,7 @@ concretized as `VarName` only supports non-dynamic indexing as determined by julia> x = (a = [1.0 2.0; 3.0 4.0; 5.0 6.0], ); julia> @varname(x.a[1:end, end][:], true) -x.a[1:3,2][1:3] +x.a[1:3,2][:] julia> @varname(x.a[end]) ERROR: LoadError: Variable name `x.a[end]` is dynamic and requires concretization! @@ -567,7 +590,7 @@ function varname(expr::Expr, concretize=false) $(AbstractPPL.concretize)($lens, $sym_escaped) ) ) - elseif !concretize && Setfield.need_dynamic_lens(expr) + elseif Setfield.need_dynamic_lens(expr) error("Variable name `$(expr)` is dynamic and requires concretization!") else :($(AbstractPPL.VarName){$(QuoteNode(sym))}($lens)) diff --git a/test/varname.jl b/test/varname.jl index 46502c6..d9b52db 100644 --- a/test/varname.jl +++ b/test/varname.jl @@ -2,6 +2,8 @@ using InvertedIndices using OffsetArrays using Setfield +using AbstractPPL: ⊑, ⊒, ⋢, ⋣, ≍ + macro test_strict_subsumption(x, y) quote @@ -30,7 +32,8 @@ end @test @varname(y[begin, i], true) == @varname(y[1, 1:10]) @test @varname(y[:], true) == @varname(y[1:100]) @test @varname(y[:, begin], true) == @varname(y[1:10, 1]) - @test getlens(AbstractPPL.concretize(@varname(y[:]), y)).indices === (1:100,) + @test getlens(AbstractPPL.concretize(@varname(y[:]), y)).indices[1] === + AbstractPPL.ConcretizedSlice(to_indices(y, (:,))[1]) @test @varname(x.a[1:end, end][:], true) == @varname(x.a[1:3,2][1:3]) end @@ -64,6 +67,8 @@ end @test_strict_subsumption x[[2,3,5]] x[[7,6,5,4,3,2,1]] + @test_strict_subsumption x[:a][1] x[:a] + # boolean indexing works as long as it is concretized A = rand(10, 10) @test @varname(A[iseven.(1:10), 1], true) ⊑ @varname(A[1:10, 1]) @@ -82,5 +87,6 @@ end B = OffsetArray(A, -5, -5) # indices -4:5×-4:5 @test @varname(B[1, :], true) == @varname(B[1, -4:5]) + end end From 5ef7e1a398037340f7e8d6eb35ee41772ed7e380 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Mon, 7 Feb 2022 17:28:14 +0100 Subject: [PATCH 13/22] Rename confusing leftover (subsumes_index -> subsumes_indices) --- src/varname.jl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index 3d459ca..0274725 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -301,7 +301,7 @@ subsumes(t::PropertyLens, u::PropertyLens) = false subsumes( t::Union{IndexLens,ComposedLens{<:IndexLens}}, u::Union{IndexLens,ComposedLens{<:IndexLens}} -) = subsumes_index(t, u) +) = subsumes_indices(t, u) subsumedby(t, u) = subsumes(u, t) @@ -317,7 +317,7 @@ const ≍ = uncomparable # Therefore we must recurse until we reach something that is NOT # indexing, and then consider the sequence of indices leading up to this. """ - subsumes_index(t::Lens, u::Lens) + subsumes_indices(t::Lens, u::Lens) Return `true` if the indexing represented by `t` subsumes `u`. @@ -325,26 +325,26 @@ This is mostly useful for comparing compositions involving `IndexLens` e.g. `_[1][2].a[2]` and `_[1][2].a`. In such a scenario we do the following: 1. Combine `[1][2]` into a `Tuple` of indices using [`combine_indices`](@ref). 2. Do the same for `[1][2]`. -3. Compare the two tuples from (1) and (2) using `subsumes_index`. +3. Compare the two tuples from (1) and (2) using `subsumes_indices`. 4. Since we're still undecided, we call `subsume(@lens(_.a[2]), @lens(_.a))` which then returns `false`. # Example -```jldoctest; setup=:(using Setfield; using AbstractPPL: subsumes_index) +```jldoctest; setup=:(using Setfield; using AbstractPPL: subsumes_indices) julia> t = @lens(_[1].a); u = @lens(_[1]); -julia> subsumes_index(t, u) +julia> subsumes_indices(t, u) false -julia> subsumes_index(u, t) +julia> subsumes_indices(u, t) true julia> # `IdentityLens` subsumes all. - subsumes_index(@lens(_), t) + subsumes_indices(@lens(_), t) true julia> # None subsumes `IdentityLens`. - subsumes_index(t, @lens(_)) + subsumes_indices(t, @lens(_)) false julia> AbstractPPL.subsumes(@lens(_[1][2].a[2]), @lens(_[1][2].a)) @@ -354,7 +354,7 @@ julia> AbstractPPL.subsumes(@lens(_[1][2].a), @lens(_[1][2].a[2])) true ``` """ -function subsumes_index(t::Lens, u::Lens) +function subsumes_indices(t::Lens, u::Lens) t_indices, t_next = combine_indices(t) u_indices, u_next = combine_indices(u) @@ -383,7 +383,7 @@ end Return sequential indexing into a single `Tuple` of indices, e.g. `x[:][1][2]` becomes `((Colon(), ), (1, ), (2, ))`. -The result is compatible with [`subsumes_index`](@ref) for `Tuple` input. +The result is compatible with [`subsumes_indices`](@ref) for `Tuple` input. """ combine_indices(lens::Lens) = (), lens combine_indices(lens::IndexLens) = (lens.indices,), nothing @@ -415,7 +415,7 @@ end subsumes_index(i::Colon, ::Colon) = error("Colons cannot be subsumed") subsumes_index(i, ::Colon) = error("Colons cannot be subsumed") subsumes_index(i::Colon, j) = true -subsumes_index(i::AbstractArray, j) = issubset(j, i) +subsumes_index(i::AbstractVector, j) = issubset(j, i) subsumes_index(i, j) = i == j From 48d00c2dce387595dba25dc0bb7765ce76a046f8 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Wed, 9 Feb 2022 18:29:07 +0100 Subject: [PATCH 14/22] Apply review suggestions --- src/varname.jl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index 0274725..9db9a3d 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -425,14 +425,12 @@ end ConcretizedSlice(s::Base.Slice{R}) where {R} = ConcretizedSlice{eltype(s.indices), R}(s.indices) Base.show(io::IO, s::ConcretizedSlice) = print(io, ":") -Base.show(io::IO, ::MIME"text/plain", s::ConcretizedSlice) = print(io, "ConcretizedSlice($(s.range))") -Base.IteratorEltype(::Type{<:ConcretizedSlice}) = Base.HasEltype() -Base.eltype(s::ConcretizedSlice{T}) where {T} = T -Base.IteratorSize(::Type{<:ConcretizedSlice}) = Base.HasLength() -Base.length(s::ConcretizedSlice) = length(s.range) +Base.show(io::IO, ::MIME"text/plain", s::ConcretizedSlice) = + print(io, "ConcretizedSlice(", s.range, ")") Base.size(s::ConcretizedSlice) = size(s.range) Base.iterate(s::ConcretizedSlice, state...) = Base.iterate(s.range, state...) Base.collect(s::ConcretizedSlice) = collect(s.range) +Base.getindex(s::ConcretizedSlice, i) = s.range[i] Base.hasfastin(::Type{<:ConcretizedSlice}) = true Base.in(i, s::ConcretizedSlice) = i in s.range From 98eed6502e143ee52d57605e05466da3153f15e3 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Sat, 12 Feb 2022 08:58:51 +0100 Subject: [PATCH 15/22] Change pretty printing indices to repr (fixes #50) --- src/varname.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/varname.jl b/src/varname.jl index 9db9a3d..0836627 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -169,7 +169,7 @@ _print_application(io::IO, l::IndexLens) = # `concretize` anyways. _print_application(io::IO, l::DynamicIndexLens) = print(io, l, "(_)") -prettify_index(x) = string(x) +prettify_index(x) = repr(x) prettify_index(::Colon) = ":" """ From 2888395d7ffe5ad557461e749abfcb07c7eb7562 Mon Sep 17 00:00:00 2001 From: Hong Ge Date: Sun, 13 Feb 2022 19:40:30 +0000 Subject: [PATCH 16/22] Update CI.yml --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c70076d..261aec4 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,7 +20,7 @@ jobs: matrix: version: - '1' - - '1.0' + - '1.6' - 'nightly' os: - ubuntu-latest From 358583bad02ed3b40ce80ec2e8298135bc5b9031 Mon Sep 17 00:00:00 2001 From: Hong Ge Date: Sun, 13 Feb 2022 19:41:23 +0000 Subject: [PATCH 17/22] Update bors.toml --- bors.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bors.toml b/bors.toml index 8fcc206..e88cfc8 100644 --- a/bors.toml +++ b/bors.toml @@ -2,9 +2,9 @@ status = [ "Julia 1.% - ubuntu-latest - x64", "Julia 1.% - macOS-latest - x64", "Julia 1.% - windows-latest - x64", - "Julia 1 - ubuntu-latest - x64", - "Julia 1 - macOS-latest - x64", - "Julia 1 - windows-latest - x64", + "Julia 1.6 - ubuntu-latest - x64", + "Julia 1.6 - macOS-latest - x64", + "Julia 1.6 - windows-latest - x64", "DynamicPPL.jl", "format" ] From d83148dfc9803edf6024bf762e0a5084d3df353d Mon Sep 17 00:00:00 2001 From: Hong Ge Date: Sun, 13 Feb 2022 19:52:05 +0000 Subject: [PATCH 18/22] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 40b5bdd..09bab69 100644 --- a/Project.toml +++ b/Project.toml @@ -15,4 +15,4 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" AbstractMCMC = "2, 3" DensityInterface = "0.4" Setfield = "0.8.1" -julia = "1" +julia = "1.6, 1.7" From 412e1bfa7c616d0b9490b0aa196875228850a3f5 Mon Sep 17 00:00:00 2001 From: Hong Ge Date: Sun, 13 Feb 2022 20:49:10 +0000 Subject: [PATCH 19/22] Update Project.toml Co-authored-by: David Widmann --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 09bab69..14cbf57 100644 --- a/Project.toml +++ b/Project.toml @@ -15,4 +15,4 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" AbstractMCMC = "2, 3" DensityInterface = "0.4" Setfield = "0.8.1" -julia = "1.6, 1.7" +julia = "1.6" From 44a26156d648f6867312fc247754ab7a56acd98e Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Wed, 5 Oct 2022 12:08:47 +0200 Subject: [PATCH 20/22] Fix some docstrings --- src/varname.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/varname.jl b/src/varname.jl index 0836627..47d97b7 100644 --- a/src/varname.jl +++ b/src/varname.jl @@ -368,7 +368,7 @@ function subsumes_indices(t::Lens, u::Lens) # or something left for `u`, i.e. `t` indeed `subsumes` `u`. return true elseif u_next === nothing - # If `t_next` is not `nothing` but `u_ntext` is, then + # If `t_next` is not `nothing` but `u_next` is, then # `t` does not subsume `u`. return false end @@ -419,6 +419,12 @@ subsumes_index(i::AbstractVector, j) = issubset(j, i) subsumes_index(i, j) = i == j +""" + ConcretizedSlice(::Base.Slice) + +An indexing object wrapping the range of a `Base.Slice` object representing the concrete indices a +`:` indicates. Behaves the same, but prints differently, namely, still as `:`. +""" struct ConcretizedSlice{T, R} <: AbstractVector{T} range::R end @@ -445,7 +451,7 @@ index, and `lowered_index` the respective position of the result of `to_indices` The only purpose of this are special cases like `:`, which we want to avoid becoming a `Base.Slice(OneTo(...))` -- it would confuse people when printed. Instead, we concretize to a -`UnitRange` based on the `lowered_index`, just what you'd get with an explicit `begin:end` +`ConcretizedSlice` based on the `lowered_index`, just what you'd get with an explicit `begin:end` """ reconcretize_index(original_index, lowered_index) = lowered_index reconcretize_index(original_index::Colon, lowered_index::Base.Slice) = @@ -459,7 +465,7 @@ Return `l` instantiated on `x`, i.e. any information related to the runtime shap evaluated. This concerns `begin`, `end`, and `:` slices. Basically, every index is converted to a concrete value using `Base.to_index` on `x`. However, `:` -slices are only converted to `UnitRange`s (`a:b`) (as opposed to `Base.Slice{Base.OneTo}`), to keep +slices are only converted to `ConcretizedSlice` (as opposed to `Base.Slice{Base.OneTo}`), to keep the result close to the original indexing. """ concretize(I::Lens, x) = I From e8683ceca11807ca3606ba4b79493a210c073076 Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Wed, 5 Oct 2022 14:52:17 +0200 Subject: [PATCH 21/22] Fix merge mess --- Project.toml | 4 ++-- bors.toml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Project.toml b/Project.toml index ddf1d56..6d6ef1f 100644 --- a/Project.toml +++ b/Project.toml @@ -13,7 +13,7 @@ Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] -AbstractMCMC = "2, 3" +AbstractMCMC = "2, 3, 4" DensityInterface = "0.4" Setfield = "0.8.1" -julia = "1.6" +julia = "~1.6.6, 1.7.3" diff --git a/bors.toml b/bors.toml index e88cfc8..7a44aea 100644 --- a/bors.toml +++ b/bors.toml @@ -2,9 +2,9 @@ status = [ "Julia 1.% - ubuntu-latest - x64", "Julia 1.% - macOS-latest - x64", "Julia 1.% - windows-latest - x64", - "Julia 1.6 - ubuntu-latest - x64", - "Julia 1.6 - macOS-latest - x64", - "Julia 1.6 - windows-latest - x64", + "Julia 1 - ubuntu-latest - x64", + "Julia 1 - macOS-latest - x64", + "Julia 1 - windows-latest - x64", "DynamicPPL.jl", "format" ] @@ -15,4 +15,4 @@ required_approvals = 1 use_squash_merge = true # Uncomment this to use a two hour timeout. # The default is one hour. -timeout_sec = 7200 +timeout_sec = 7200 \ No newline at end of file From af291d3980244d8416cf952aabc949753216e8db Mon Sep 17 00:00:00 2001 From: Philipp Gabler Date: Wed, 5 Oct 2022 14:52:32 +0200 Subject: [PATCH 22/22] Bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 6d6ef1f..a9cda69 100644 --- a/Project.toml +++ b/Project.toml @@ -3,7 +3,7 @@ uuid = "7a57a42e-76ec-4ea3-a279-07e840d6d9cf" keywords = ["probablistic programming"] license = "MIT" desc = "Common interfaces for probabilistic programming" -version = "0.5.3" +version = "0.6" [deps] AbstractMCMC = "80f14c24-f653-4e6a-9b94-39d6b0f70001"