@@ -57,7 +57,7 @@ julia> getvalue(vals, @varname(x[1])) # different from `getindex`
57
57
1.0
58
58
59
59
julia> 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
61
61
[...]
62
62
```
63
63
@@ -74,7 +74,7 @@ julia> getvalue(vals, @varname(x[1])) # different from `getindex`
74
74
1.0
75
75
76
76
julia> 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
78
78
[...]
79
79
```
80
80
@@ -91,16 +91,53 @@ julia> getvalue(vals, @varname(x[1][1])) # different from `getindex`
91
91
1.0
92
92
93
93
julia> 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
95
95
[...]
96
96
97
97
julia> 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
99
99
[...]
100
100
```
101
101
"""
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
104
141
105
142
"""
106
143
hasvalue(vals::NamedTuple, vn::VarName)
@@ -168,13 +205,6 @@ false
168
205
function hasvalue (vals:: NamedTuple , vn:: VarName{sym} ) where {sym}
169
206
return haskey (vals, sym) && canview (getoptic (vn), getproperty (vals, sym))
170
207
end
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.
178
208
function hasvalue (vals:: AbstractDict{<:VarName} , vn:: VarName{sym} ) where {sym}
179
209
# First we check if `vn` is present as is.
180
210
haskey (vals, vn) && return true
@@ -186,12 +216,8 @@ function hasvalue(vals::AbstractDict{<:VarName}, vn::VarName{sym}) where {sym}
186
216
# identity).
187
217
test_vn = VarName {sym} ()
188
218
test_optic = getoptic (vn)
189
-
219
+
190
220
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
195
221
if haskey (vals, test_vn) && canview (test_optic, vals[test_vn])
196
222
return true
197
223
else
@@ -204,68 +230,3 @@ function hasvalue(vals::AbstractDict{<:VarName}, vn::VarName{sym}) where {sym}
204
230
end
205
231
return false
206
232
end
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