Skip to content
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

values_as(vi, NamedTuple) doesn't preserve structure #814

Open
penelopeysm opened this issue Feb 17, 2025 · 1 comment
Open

values_as(vi, NamedTuple) doesn't preserve structure #814

penelopeysm opened this issue Feb 17, 2025 · 1 comment

Comments

@penelopeysm
Copy link
Member

penelopeysm commented Feb 17, 2025

julia> using DynamicPPL, Distributions

julia> @model function f()
           x = (a=1, b=2)
           x.a ~ Normal()
           x.b ~ Normal()
       end
f (generic function with 2 methods)

julia> values_as(VarInfo(f()), NamedTuple)
(var"x.a" = -0.2067696145335533, var"x.b" = -2.788035859751896)

I would have liked (x = (a = ..., b = ...),).

Same thing happens with arrays:

julia> @model function f()
           x = [0.0, 1.0]
           x[1] ~ Normal()
           x[2] ~ Normal()
       end
f (generic function with 2 methods)

julia> values_as(VarInfo(f()), NamedTuple)
(var"x[1]" = -0.9522900124219256, var"x[2]" = 0.626145525096277)

I do realise this is a very non-trivial thing to fix, because of the general problem that we can't reconstruct shape from a list of varnames; but I feel like it's at least worth having a(nother?) think about it. In particular, I'm still wondering about having varnames carry info about their shape, or maybe the varinfo can even maintain a full mapping of variables that are in scope along with their values.

I suppose there are some pathological cases that can break this very idealised situation.

@model function f()
     x = [0.0, 1.0, 2.0]
     x[1] ~ Normal()
     x[3] ~ Normal()
end

values_as(VarInfo(f()), NamedTuple)
# how many entries of x should this return?

See also the last time I suggested it here #712 (comment)

@penelopeysm
Copy link
Member Author

penelopeysm commented Feb 17, 2025

The other radical proposal that I could get behind could be to just forbid NamedTuples entirely and only use OrderedDict for everything (e.g. conditioning, initialising values, ...) or maybe NamedTuple can be kept as a thin user-facing layer, but internally it always gets converted to OrderedDict before being passed into DynamicPPL internals. e.g. for condition,

model() | (x = 1, y = [2, 3])

would in turn call

model() | OrderedDict(@varname(x) => 1, @varname(y[1]) => 2, @varname(y[2]) => 3)

Btw this would also mean that rand(model) would return an OrderedDict unless otherwise specified

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant