-
I've developed an iterative algorithm whose structure is something like: def algo():
output = dr.zeros(mi.Int, n)
# a bunch of calculation
iteration = mi.UInt32(0)
active = compute_active()
loop = mi.Loop("Iterations", lambda: (active, output, iteration))
while loop(active):
# perform calculations involving the creation of several
# variables that are only relevant to the current iteration
dr.scatter(output, ...)
iteration += 1
active = compute_active() # compute_active uses the 'output' variable
return output I developed the code first without the loop in place, so I could validate the first iteration and make sure everything's correct. Now that I've added the loop, I get this error:
This refers to one of the variables that gets created where I put the comment inside the loop. Essentially what happens is:
The So my questions:
More conceptually, I'm also a bit puzzled by the difference between placeholder and non-placeholder variables. DrJit is always recording the operations to compile them to a kernel, regardless of whether there's a loop, isn't it? And it's also unclear to me why this scatter isn't allowed/possible, at least in my case where all my variables have the same width that never changes. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Hi @tomas16 ,
Yes, however there are caveats. The first issue is that as you've encountered, you're not allowed to use a placeholder variable as a target. This in particular includes loop state variables and also variables in your body that depend on these state variables loop = mi.Loop("Iterations", lambda: (active, output, iteration))
while loop(active):
# If si depends on iteration, active or output then still placeholder
si = ...
# Not allowed!
dr.scatter(si, ...) So alternatively, you could exclude your scatter target as a loop state variable. However, you cannot attempt to evaluate the target variable if the other scatter parameters (source, index, mask) are placeholders. In fact, attempting to explicitly evaluate any placeholder variable in the loop body isn't allowed while loop(active):
# Not allowed
dr.eval(output) There's a slight nuance when it comes to target = mi.Float(0)
source = mi.Float(1)
index = mi.UInt32(0)
dr.scatter(target, source, index)
target += 1 which with Info logging gives us
So even though we're not actually evaluating the final Going back to the loop then loop = mi.Loop("Iterations", lambda: (active, iteration))
while loop(active):
# Not a state variable, so ok
dr.scatter(output, ...)
# Trying to perform "ordered" load/store - i.e. we need to perform eval
# Not allowed!
output += 1 So the rule of thumb for recorded loops is exclusively scattering (or scatter reduce) to your target will work, but attempting to do any additional arithmetic operations or otherwise will be problematic
You can alternatively just disable loop recording either globally or just for a block of code using with dr.scoped_set_flag(dr.JitFlag.LoopRecord, False):
loop = mi.Loop("Iterations", lambda: (active, output, iteration))
while loop(active):
... Loop state placeholders variables are no longer created when recording the loop body and instead a kernel is launched at each iteration.
As mentioned loop state variables will have corresponding placeholders created so this indeed won't work with recorded loops
I agree that the differences aren't super clear, but hopefully my explanation has shed some light. For what it's worth, we are in the midst of integrating Nanobind into Dr.Jit and with that includes a lot of improvements and more comprehensive documentation. In particular, I believe with this new version, we gracefully handle the case when a scatter target is a loop state variable. Additionally, the terminology for symbolic, placeholder and recorded-loops has been unified to avoid confusion. This is all still a work in progress, but thought it was nonetheless worth mentioning. |
Beta Was this translation helpful? Give feedback.
Hi @tomas16 ,
Yes, however there are caveats. The first issue is that as you've encountered, you're not allowed to use a placeholder variable as a target. This in particular includes loop state variables and also variables in your body that depend on these state variables
So alternatively, you could exclude your scatter target as a loop state variable. However, you cannot attempt to evaluat…