# Event handler

**URL:** <https://discourse.julialang.org/t/event-handler/59937>\
**Category:** General Usage\
**Created:** [April 24, 2021, 5:27pm UTC](https://discourse.julialang.org/t/event-handler/59937 "2021-04-24T17:27:21Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [April 24, 2021, 5:27pm UTC](https://discourse.julialang.org/t/event-handler/59937/1 "2021-04-24T17:27:21Z")

</div>

I have a number of functions, all looking a bit like that:

```julia
while true
    i = peel(Q)
    if i == 1 && mode = 1
        a, b = dosomething1(a, b)
    elseif i == 2
        b, c = dosomething2(b, c)
    elseif i == 3
        c, d = dosomething2(c, d) 
    end 
    enqueue!(Q, newevent)
end

```

so these are event handlers based on a priority queue.

To me it looks like I want to be a bit more meta here and have something like an “engine”, but I have to be a bit careful as these are hot loops. Context ZigZagBoomerang.jl. Any pointers?

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [April 24, 2021, 5:56pm UTC](https://discourse.julialang.org/t/event-handler/59937/2 "2021-04-24T17:56:15Z")

</div>

How does `newevent` relate to the other variables?

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [April 24, 2021, 6:01pm UTC](https://discourse.julialang.org/t/event-handler/59937/3 "2021-04-24T18:01:11Z")

</div>

Let me give a more serious minimal working example with two event types:  
So the Queue keeps only track of event times, and I have a vector for each event type for each element of a state

```julia
using ZigZagBoomerang: SPriorityQueue, enqueue!
using Random
function queue(τ)
    Q = SPriorityQueue{Int,eltype(τ)}()
    for i in eachindex(τ)
        enqueue!(Q, i => τ[i])
    end
    Q
end

T = 100.0
d = 10000
state = rand(d)
function handler(x, T)
    d = length(x)
    event_type = zeros(Int, d)
    t = zeros(d)
    Q = queue(randexp(d))
    while true
        i, t′ = peek(Q)
        t′ > T && break
        if event_type[i] == 0 # fast
            x[i] += (t′ - t[i]) 
            t[i] = t′
            event_type[i] = 1 - event_type[i] # next slow
            Q[i] = t[i] + randexp()
        else # slow
            x[i] += 0.5*(t′ - t[i]) 
            t[i] = t′
            event_type[i] = 1 - event_type[i] # next fast
            Q[i] = t[i] + 0.5*randexp()
        end

    end
    t, x
end
@time handler(zeros(d), T);

```

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [April 24, 2021, 6:35pm UTC](https://discourse.julialang.org/t/event-handler/59937/4 "2021-04-24T18:35:52Z")

</div>

For example, something like this seems to work

```julia
function handler(x, T, f)
    d = length(x)
    event_type = zeros(Int, d)
    t = zeros(d)
    Q = queue(randexp(d))
    
    while true
        i, t′ = peek(Q)
        t′ > T && break 
        j = event_type[i] + 1
        f[j](i, t′, t, x, event_type, Q)
    end
    t, x
end
@time handler(zeros(d), T, (f1!, f2!));

```

but the small union

```julia
  %19 = Base.getindex(f, j)::Union{typeof(f1!), typeof(f2!)}

```

relies on the compiler

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [April 24, 2021, 11:37pm UTC](https://discourse.julialang.org/t/event-handler/59937/5 "2021-04-24T23:37:33Z")

</div>

If you only have a couple of known events, I think a sequence of `if` is a decent approach. If the computation inside state transition is relatively small and the transitions between events have some structure (not all states jump to arbitrary state), maybe you can squeeze out some performance with `@goto`.

If you have many unknown event types, “JIT” approach may be useful. See, e.g., Catwalk.jl: [[ANN] Catwalk.jl - With dynamic dispatch to the moon! (an adaptive optimizer, aka JIT compiler)](https://discourse.julialang.org/t/ann-catwalk-jl-with-dynamic-dispatch-to-the-moon-an-adaptive-optimizer-aka-jit-compiler/57917)

> [@mschauer](#):
>
> but the small union
> 
> ```julia
> %19 = Base.getindex(f, j)::Union{typeof(f1!), typeof(f2!)}
> 
> ```
> 
> relies on the compiler

If you know the possible concrete types of `f[j]` statically, you can use a manual union splitting hack [like this](https://github.com/JuliaFolds/BangBang.jl/blob/eecbf8b4c1788e0f4a97f55497b0abb556bbdef8/src/dataframes_impl.jl#L61-L72). (This is a manual version of Catwalk.jl etc.). This is equivalent to plain `if`s, but it can be useful for code organization.

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [April 25, 2021, 3:29pm UTC](https://discourse.julialang.org/t/event-handler/59937/6 "2021-04-25T15:29:47Z")

</div>

So with [GitHub - tisztamo/FunctionWranglers.jl: Fast, inlined execution of arrays of functions](https://github.com/tisztamo/FunctionWranglers.jl) and some assistance of @tisztamo who added `sindex` for this use case I arrived at something neat

```julia
function handle!(t, x, θ, m, f!, next, event_type, Q)
    i, t′ = peek(Q)
    j = event_type[i]
    if j > 0
        sindex(f!, j, i, t′, t, x, θ, m, event_type, Q)
    end  
    τ, jnext = sfindmin(next, i, t′, t, x, θ, m)
    Q[i] = τ
    event_type[i] = jnext
    (t′, i, x[i], j)
end

```

Getting the hang of it I added `sfindmin` to schedule the next relevant event for each particle.

PS: The scheduler is starting to take shape [https://github.com/mschauer/ZigZagBoomerang.jl/…/src/scheduler.jl](https://github.com/mschauer/ZigZagBoomerang.jl/blob/06f54f7702b09e9c3c9c86ffd2dc03073a14a372/src/scheduler.jl). It looks like something like this might find use in billiard problems too. @Datseris Somehow I just understood that [https://github.com/mschauer/ZigZagBoomerang.jl](https://github.com/mschauer/ZigZagBoomerang.jl) and [https://github.com/JuliaDynamics/DynamicalBilliards.jl](https://github.com/JuliaDynamics/DynamicalBilliards.jl) are somewhat related.

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [April 26, 2021, 9:55pm UTC](https://discourse.julialang.org/t/event-handler/59937/7 "2021-04-26T21:55:46Z")

</div>

Hi, Sorry I don’t see the connection between the two; I’m not familiar with the contents of ZigZagBoomerang.jl by having a look at its page its the first time I see/read any of it.

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [April 27, 2021, 8:39am UTC](https://discourse.julialang.org/t/event-handler/59937/8 "2021-04-27T08:39:23Z")

</div>

Quiz: Is this a DynamicalBilliard or a Zig-Zag sampler of a density defined on the unit square:

 ![billiard](https://global.discourse-cdn.com/julialang/original/3X/2/9/293032cf6ddb24f7f7cb02af921ec7055b991861.png)

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [April 28, 2021, 7:40am UTC](https://discourse.julialang.org/t/event-handler/59937/9 "2021-04-28T07:40:36Z")

</div>

@tisztamo

Absolutely nice:

 ![Screenshot 2021-04-28 at 09.31.59](https://global.discourse-cdn.com/julialang/original/3X/3/9/3956dfa9315c23e16bfd5faa655fa9877b1303d3.png)

with

```julia
  0.814835 seconds (33 allocations: 15.234 KiB

```

for 200000 calls of the event loop computing the random event times and the wall collision times for all 3 “walls” for each of 80 correlated coordinates (hard wall at 1, soft or hard wall at 0 and “sticky” barrier at 0.25).

 ![unbounded2](https://global.discourse-cdn.com/julialang/original/3X/0/2/026d1fa8210ee6d7df3d2ead4a278e50460b17be.jpeg)

Showing phase diagram of two coordinates out of 80.

---

<div class="post-metadata">

**Author:** ![tisztamo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tisztamo/32/16200_2.png) [@tisztamo](https://discourse.julialang.org/u/tisztamo)\
**Post date:** [April 28, 2021, 7:36pm UTC](https://discourse.julialang.org/t/event-handler/59937/10 "2021-04-28T19:36:54Z")

</div>

Great to hear that FunctionWranglers works for you!

I do not really understand what ZigZagBoomerang does, but I see the three large parts on the flame graph and that there is not much extra time between them. If the number of event dispatches is 200\_000 \* 3 \* 80 during this run, then your gain must be very significant to other solutions I think (Not counting compilation).

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [April 28, 2021, 8:52pm UTC](https://discourse.julialang.org/t/event-handler/59937/11 "2021-04-28T20:52:31Z")

</div>

well given that the “trajectory” changes directions in the middle of the square, it isn’t a billiard.

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [April 29, 2021, 12:46am UTC](https://discourse.julialang.org/t/event-handler/59937/12 "2021-04-29T00:46:44Z")

</div>

Well, yes, no,… it’s [ray-splitting](https://juliadynamics.github.io/DynamicalBilliards.jl/dev/ray-splitting/)  
at the contour lines of a density ![](https://global.discourse-cdn.com/julialang/original/3X/e/d/ed06d924eca275e3a6ea60181c6d679d593b9baf.gif)
