Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
version:
# - '1.3' # minimum supported version
- '1.3' # minimum supported version
- '1' # current stable version
os:
- ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ makedocs(;
r"(Array{.+,\s?1}|Vector{.+})",
# Older versions will show "Array{...,2}" instead of "Matrix{...}".
r"(Array{.+,\s?2}|Matrix{.+})",
# Errors from macros sometimes result in `LoadError: LoadError:`
# rather than `LoadError:`, depending on Julia version.
r"ERROR: LoadError: (LoadError:\s)?+",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just use

Suggested change
r"ERROR: LoadError: (LoadError:\s)?+",
r"ERROR: (LoadError:\s)+",

? And it seems you forgot to update test/runtests.jl?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just use

Is this correct though? Don't we want to match at least one LoadError?

And it seems you forgot to update test/runtests.jl?

Ah thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to match at least one LoadError?

+ matches one or more occurrences so it doesn't match only "ERROR: ":

julia> regex =  r"ERROR: (LoadError:\s)+";

julia> match(regex, "ERROR: ") === nothing
true

julia> match(regex, "ERROR: LoadError: ")
RegexMatch("ERROR: LoadError: ", 1="LoadError: ")

julia> match(regex, "ERROR: LoadError: LoadError: ")
RegexMatch("ERROR: LoadError: LoadError: ", 1="LoadError: ")

Copy link
Member Author

@torfjelde torfjelde Dec 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, yeah I knew that, hence why I used ? on the second one. Now you might ask "then why did you just say what you just did?", to which I don't have a good answer 🙃 Thanks man!

EDIT: Oh wait, now I remember why I did it! If you do (LoadError:\s)+ you'll end up comparing the output to Error: , no? While we want to compare it to Error: LoadError: , i.e. all the redundant LoadError: removed?|

EDIT 2: Nope:) I guess it removes it from both the expected output and the actual output then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doctest filters will be applied to both the expected output and the actual output and then the matches will be removed. The remaining string is checked for equality. So the LoadError: will be removed from the expected output as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my original understanding when I wrote it, but I think I must have missed some whitespace so it didn't match but instead complained that "ERROR: ...ddin't matchERROR: LoadError: ...`, i.e. the display seemed to indicate it was only removed from the expected output which confused me.

What I've learned tonight: I should not let myself be so easily swayed by displayed information:)

],
)

Expand Down
15 changes: 11 additions & 4 deletions src/submodel_macro.jl
Original file line number Diff line number Diff line change
Expand Up @@ -212,17 +212,23 @@ function submodel(prefix_expr, expr, ctx=esc(:__context__))
if prefix_left !== :prefix
error("$(prefix_left) is not a valid kwarg")
end

# The user expects `@submodel ...` to return the
# return-value of the `...`, hence we need to capture
# the return-value and handle it correctly.
@gensym retval

# `prefix=false` => don't prefix, i.e. do nothing to `ctx`.
# `prefix=true` => automatically determine prefix.
# `prefix=...` => use it.
args_assign = getargs_assignment(expr)
return if args_assign === nothing
ctx = prefix_submodel_context(prefix, ctx)
# In this case we only want to get the `__varinfo__`.
quote
$(esc(:__varinfo__)) = last(
$(DynamicPPL._evaluate!!)($(esc(expr)), $(esc(:__varinfo__)), $(ctx))
$retval, $(esc(:__varinfo__)) = $(DynamicPPL._evaluate!!)(
Copy link
Member

@yebai yebai Dec 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like returning both the retval and varinfo. I was talking with Philip that we should consider enforcing this more systematically. Roughly speaking, we can consider adopting the notation that retval refers to generated quantities and varinfo refers to model parameters. This would help clarify the submodel notation as well, i.e.

  1. x = SubModel will extract retval and assign it to LHS
  2. x ~ SubModel will extract varinfo and assign it to LHS

Following this view, we no longer need to concern ourselves what is the semantics if the returned value retval of SubModel is deterministic in case 2.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused. In both those cases we still have to concern ourselves with the return-value, no? Essentially the difference between = and ~ will be whether we have $retval or varinfo below, right?

Anyways, you're happy with this right? You're just talking about potentially also supporting ~ later?

Copy link
Member

@yebai yebai Dec 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, happy with this PR.

I think retval and varinfo provides a clear semantical distinction between = and ~. If we always return both, (e.g. we can return (, varinfo) in case retval is empty), we can extract either retval or varinfo for = or ~.

$(esc(expr)), $(esc(:__varinfo__)), $(ctx)
)
$retval
end
else
L, R = args_assign
Expand All @@ -235,9 +241,10 @@ function submodel(prefix_expr, expr, ctx=esc(:__context__))
)
end
quote
$(esc(L)), $(esc(:__varinfo__)) = $(DynamicPPL._evaluate!!)(
$retval, $(esc(:__varinfo__)) = $(DynamicPPL._evaluate!!)(
$(esc(R)), $(esc(:__varinfo__)), $(ctx)
)
$(esc(L)) = $retval
end
end
end
10 changes: 10 additions & 0 deletions test/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -570,5 +570,15 @@ end

@model demo() = x ~ Normal()
retval, svi = DynamicPPL.evaluate!!(demo(), SimpleVarInfo(), SamplingContext())

# Return-value when using `@submodel`
@model inner() = x ~ Normal()
# Without assignment.
@model outer() = @submodel inner()
@test outer()() isa Real

# With assignment.
@model outer() = @submodel x = inner()
@test outer()() isa Real
end
end