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

More Hutchinson layers / restricted chaos games #65

Open
leios opened this issue Apr 4, 2023 · 2 comments
Open

More Hutchinson layers / restricted chaos games #65

leios opened this issue Apr 4, 2023 · 2 comments

Comments

@leios
Copy link
Owner

leios commented Apr 4, 2023

As a note, the Hutchinson redesign (#64) currently allows for users to specify hutchinson operators (and technically shaders) like so:

H = Hutchinson(f_1, (f_2, f_3, f_4, f_5), f_6)

Which means: execute f_1, then choose between f_2 -> f_5, then execute f_6, but we could imagine:

H = Hutchinson(f_1, ((f_2, f_3), f_4, f_5), f_6)

Which would mean: execute f_1, then choose between (f_2, f_3), f_4, or f_5, then execute f_6. This Cannot be done right now because I don't have a way to reason about a choice between f_2 and f_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:

struct NullOperator <: FractalOperator
    prob::Number
    fos::Tuple{FractalOperator}
end

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 like fstarts = [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...

    H = Hutchinson(f_1, (fo(f_2, f_3; prob = 0.33), f_4, f_5), f_6)

With fo(fos::Tuple{FractalOperator}; prob = 0) = NullOperator(prob, fos)

Or something.

@leios
Copy link
Owner Author

leios commented Jul 1, 2023

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?

@leios
Copy link
Owner Author

leios commented Jul 1, 2023

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 fids to accept conditional probabilities and such.

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