Open leios opened 1 year ago
I think I'm overthinking this. It should be possible for the user to implement everything they want for the "game" part of the chaos game. So, Fable handles the iteration, but the user can write custom compute kernels by abusing the fum syntax?
Otherwise, the core problem here is that we use the fid
construct to iterate over functions. This means that we generate a single random number that is used for all functions. This is nice in a way for performance, but if the user is implementing tuples of tuples where we know the probabilities, we can probably just use those instead and make a function choice on-the-fly.
I am not sure how this would play with the @generated
functions used to iterate over different fx tuples, ie:
# These functions essentially unroll the loops in the kernel because of a
# known julia bug preventing us from using for i = 1:10...
@generated function pt_loop(fxs, fid, pt, frame, fnums, kwargs)
exs = Expr[]
push!(exs, :(bit_offset = 0))
push!(exs, :(fx_offset = 0))
for i = 1:length(fnums.parameters)
ex = quote
idx = decode_fid(fid, bit_offset, fnums[$i]) + fx_offset
pt = call_pt_fx(fxs, pt, frame, kwargs, idx)
bit_offset += ceil(UInt,log2(fnums[$i]))
fx_offset += fnums[$i]
end
push!(exs, ex)
end
push!(exs, :(return pt))
# to return 3 separate colors to mix separately
# return :(Expr(:tuple, $exs...))
return Expr(:block, exs...)
end
We could either change this to do some form of DFS over the fx tuple provided (maybe some sort of stack-like implementation while unrolling the while loop?), or we allow the fid
s to accept conditional probabilities and such.
As a note, the Hutchinson redesign (#64) currently allows for users to specify hutchinson operators (and technically shaders) like so:
Which means: execute
f_1
, then choose betweenf_2 -> f_5
, then executef_6
, but we could imagine:Which would mean: execute
f_1
, then choose between(f_2, f_3)
,f_4
, orf_5
, then executef_6
. This Cannot be done right now because I don't have a way to reason about a choice betweenf_2
andf_3
as one of the choices in another IFS. A simple strategy would be to set FractalOperators as a super type and create a null struct:Then we would store
[f_1, f_null, f_4, f_5, f_2, f_3, f_null, f_6]
with fnums of[1,3,2,1]
and potentially another set of indices likefstarts = [1, 2, 5, 7]
so if we have 2 or more recursive IFS definitions, we can keep track of where we are on the list. We could probably get rid of the list of lists entirely in this case and just do everything in the kernel instead...We also need to think about how users will write down both the probability of the null operator and the other functions in a reasonable way, maybe...
With
fo(fos::Tuple{FractalOperator}; prob = 0) = NullOperator(prob, fos)
Or something.