Change RandomVariable
-in-Scan
semantics
#898
Labels
enhancement
New feature or request
help wanted
Extra attention is needed
important
random variables
Involves random variables and/or sampling
Scan
Involves the `Scan` `Op`
I'm proposing that we make all instances of a
RandomVariable
constructed within the body of aScan
necessarily draw samples per-iteration of saidScan
.Background
The current behavior of a naive loop with a random variable is demonstrated in the following graph:
The repeated output is the single sample value of
at.random.normal()
, which is equivalent to the following, more explicit graph:My contention is that the former graph should always produce a distinct sample for each iteration performed by the
Scan
Op
. If one desires a repeated value, as is currently produced, then constructing a graph like the latter is the appropriate approach.In other words, an expression like
at.random.normal()
always indicates a distinct sample within the body of aScan
, just as it would in a plain Python loop.As of now, I don't see a reason for preserving the current semantics that map the first example above to the second. This isn't an issue in any other case, because no other
Op
s are so opaquely dependent on a state object likeRandomVariable
is, so, to preserve the common semantics of random sampling,Scan
should handle this case specifically and guarantee those semantics.One Possible Solution
One quick way to accomplish this is to change the
RandomVariable.inplace
attribute of allRandomVariable
s in an inner-graph toTrue
—regardless of whether or not theirRandomType
instances are shared.This somewhat breaks the consistency of the RNG object/
RandomType
instance "evolution", which allows one to provide an RNG to aRandomVariable
and get a new RNG corresponding to the updated RNG state after sampling. The input and output RNG are supposed to be distinct—unless the in-place optimization/rewrite is performed, in which case they are the same RNG state.If we cloned the initial RNG states in a
Scan
inner-graph and performed the iterations in-place on the cloned states, then returned those, I believe that the standard RNG "evolution" semantics would be preserved. Even so, these input/output RNG states are essentially hidden from the user-level and almost never used explicitly (e.g. chaining input/output RNGs results in convoluted graphs and many cloned RNG states at runtime), so the utility of fully preserving these semantics is itself questionable.Also,
Scan
s do not have a means of returning RNG states, so they've never been able to preserve these semantics faithfully (see #738).Accomplishing the same thing without in-placing by, for example, the addition of an extra tap for the last RNG output by an earlier iteration, so that it can be used in the next, has little to no foreseeable utility—aside from, say, the case in which one desires the RNG state at every iteration in the form of a
Scan
output. Regardless, the latter case would require #738 and could easily work alongside the proposed in-place changes (e.g. by copying the RNG state when/if it's an explicit output of the inner-graph).Related Issues:
RandomVariable
s within aScan
#543RandomVariable
s are in-placed within aScan
loop body, they will be updated per-iteration. This would only partially accomplish the goals set out here, but not in a consistent fashion, because the relevant rewrite is only applied inFAST_RUN
mode and the rewrite applies to allRandomVariable
s in a graph—not just the inner-graphs of aScan
.Scan
s? #542Scan
s and shared variable RNG-based updates, and the approach described in this issue obviates the need for shared variables and automatically accounts for nestedScan
s.The text was updated successfully, but these errors were encountered: