@@ -57,7 +57,7 @@ julia> getvalue(vals, @varname(x[1])) # different from `getindex`
57571.0
5858
5959julia> getvalue(vals, @varname(x[2]))
60- ERROR: BoundsError: attempt to access 1-element Vector{Float64} at index [2]
60+ ERROR: getvalue: x[2] was not found in the values provided
6161[...]
6262```
6363
@@ -74,7 +74,7 @@ julia> getvalue(vals, @varname(x[1])) # different from `getindex`
74741.0
7575
7676julia> getvalue(vals, @varname(x[2]))
77- ERROR: BoundsError: attempt to access 1-element Vector{Float64} at index [2]
77+ ERROR: getvalue: x[2] was not found in the values provided
7878[...]
7979```
8080
@@ -91,16 +91,53 @@ julia> getvalue(vals, @varname(x[1][1])) # different from `getindex`
91911.0
9292
9393julia> getvalue(vals, @varname(x[1][2]))
94- ERROR: BoundsError: attempt to access 1-element Vector{Float64} at index [2]
94+ ERROR: getvalue: x[1][2] was not found in the values provided
9595[...]
9696
9797julia> getvalue(vals, @varname(x[2][1]))
98- ERROR: KeyError: key x[2][1] not found
98+ ERROR: getvalue: x[2][1] was not found in the values provided
9999[...]
100100```
101101"""
102- getvalue (vals:: NamedTuple , vn:: VarName ) = get (vals, vn)
103- getvalue (vals:: AbstractDict , vn:: VarName ) = nested_getindex (vals, vn)
102+ function getvalue (vals:: NamedTuple , vn:: VarName{sym} ) where {sym}
103+ optic = getoptic (vn)
104+ if haskey (vals, sym) && canview (optic, getproperty (vals, sym))
105+ return optic (vals[sym])
106+ else
107+ error (" getvalue: $(vn) was not found in the values provided" )
108+ end
109+ end
110+ # For the Dict case, it is more complicated. There are two cases:
111+ # 1. `vn` itself is already a key of `vals` (the easy case)
112+ # 2. `vn` is not a key of `vals`, but some parent of `vn` is a key of `vals`
113+ # (the harder case). For example, if `vn` is `x[1][2]`, then we need to
114+ # check if either `x` or `x[1]` is a key of `vals`, and if so, whether
115+ # we can index into the corresponding value.
116+ function getvalue (vals:: AbstractDict{<:VarName} , vn:: VarName{sym} ) where {sym}
117+ # First we check if `vn` is present as is.
118+ haskey (vals, vn) && return vals[vn]
119+
120+ # Otherwise, we start by testing the bare `vn` (e.g., if `vn` is `x[1][2]`,
121+ # we start by checking if `x` is present). We will then keep adding optics
122+ # to `test_optic`, either until we find a key that is present, or until we
123+ # run out of optics to test (which is determined by _inner(test_optic) ==
124+ # identity).
125+ test_vn = VarName {sym} ()
126+ test_optic = getoptic (vn)
127+
128+ while _inner (test_optic) != identity
129+ if haskey (vals, test_vn) && canview (test_optic, vals[test_vn])
130+ return test_optic (vals[test_vn])
131+ else
132+ # Move the innermost optic into test_vn
133+ test_optic_outer = _outer (test_optic)
134+ test_optic_inner = _inner (test_optic)
135+ test_vn = VarName {sym} (test_optic_inner ∘ getoptic (test_vn))
136+ test_optic = test_optic_outer
137+ end
138+ end
139+ return error (" getvalue: $(vn) was not found in the values provided" )
140+ end
104141
105142"""
106143 hasvalue(vals::NamedTuple, vn::VarName)
@@ -168,13 +205,6 @@ false
168205function hasvalue (vals:: NamedTuple , vn:: VarName{sym} ) where {sym}
169206 return haskey (vals, sym) && canview (getoptic (vn), getproperty (vals, sym))
170207end
171-
172- # For the Dict case, it is more complicated. There are two cases:
173- # 1. `vn` itself is already a key of `vals` (the easy case)
174- # 2. `vn` is not a key of `vals`, but some parent of `vn` is a key of `vals`
175- # (the harder case). For example, if `vn` is `x[1][2]`, then we need to
176- # check if either `x` or `x[1]` is a key of `vals`, and if so, whether
177- # we can index into the corresponding value.
178208function hasvalue (vals:: AbstractDict{<:VarName} , vn:: VarName{sym} ) where {sym}
179209 # First we check if `vn` is present as is.
180210 haskey (vals, vn) && return true
@@ -186,12 +216,8 @@ function hasvalue(vals::AbstractDict{<:VarName}, vn::VarName{sym}) where {sym}
186216 # identity).
187217 test_vn = VarName {sym} ()
188218 test_optic = getoptic (vn)
189-
219+
190220 while _inner (test_optic) != identity
191- @show test_vn, test_optic
192- if haskey (vals, test_vn)
193- @show canview (test_optic, vals[test_vn])
194- end
195221 if haskey (vals, test_vn) && canview (test_optic, vals[test_vn])
196222 return true
197223 else
@@ -204,68 +230,3 @@ function hasvalue(vals::AbstractDict{<:VarName}, vn::VarName{sym}) where {sym}
204230 end
205231 return false
206232end
207- # TODO (penelopeysm): Figure out tuple / namedtuple distributions, and LKJCholesky (grr)
208- # function hasvalue(vals::AbstractDict, vn::VarName, dist::Distribution)
209- # @warn "`hasvalue(vals, vn, dist)` is not implemented for $(typeof(dist)); falling back to `hasvalue(vals, vn)`."
210- # return hasvalue(vals, vn)
211- # end
212- # hasvalue(vals::AbstractDict, vn::VarName, ::UnivariateDistribution) = hasvalue(vals, vn)
213- # function hasvalue(
214- # vals::AbstractDict{<:VarName},
215- # vn::VarName{sym},
216- # dist::Union{MultivariateDistribution,MatrixDistribution},
217- # ) where {sym}
218- # # If `vn` is present as-is, then we are good
219- # hasvalue(vals, vn) && return true
220- # # If not, then we need to check inside `vals` to see if a subset of
221- # # `vals` is enough to reconstruct `vn`. For example, if `vals` contains
222- # # `x[1]` and `x[2]`, and `dist` is `MvNormal(zeros(2), I)`, then we
223- # # can reconstruct `x`. If `dist` is `MvNormal(zeros(3), I)`, then we
224- # # can't.
225- # # To do this, we get the size of the distribution and iterate over all
226- # # possible indices. If every index can be found in `subsumed_keys`, then we
227- # # can return true.
228- # sz = size(dist)
229- # for idx in Iterators.product(map(Base.OneTo, sz)...)
230- # new_optic = if getoptic(vn) === identity
231- # Accessors.IndexLens(idx)
232- # else
233- # Accessors.IndexLens(idx) ∘ getoptic(vn)
234- # end
235- # new_vn = VarName{sym}(new_optic)
236- # hasvalue(vals, new_vn) || return false
237- # end
238- # return true
239- # end
240-
241- # """
242- # nested_getindex(values::AbstractDict, vn::VarName)
243- #
244- # Return value corresponding to `vn` in `values` by also looking
245- # in the the actual values of the dict.
246- # """
247- # function nested_getindex(values::AbstractDict, vn::VarName)
248- # maybeval = get(values, vn, nothing)
249- # if maybeval !== nothing
250- # return maybeval
251- # end
252- #
253- # # Split the optic into the key / `parent` and the extraction optic / `child`.
254- # parent, child, issuccess = splitoptic(getoptic(vn)) do optic
255- # o = optic === nothing ? identity : optic
256- # haskey(values, VarName(vn, o))
257- # end
258- # # When combined with `VarInfo`, `nothing` is equivalent to `identity`.
259- # keyoptic = parent === nothing ? identity : parent
260- #
261- # # If we found a valid split, then we can extract the value.
262- # if !issuccess
263- # # At this point we just throw an error since the key could not be found.
264- # throw(KeyError(vn))
265- # end
266- #
267- # # TODO : Should we also check that we `canview` the extracted `value`
268- # # rather than just let it fail upon `get` call?
269- # value = values[VarName(vn, keyoptic)]
270- # return child(value)
271- # end
0 commit comments