Status of Reactive "feedback" (recursive integral, etc)

This has been brought up before, but I'm not sure about the current status our consensus regarding "recursive feedback" in Reactive. In Yampa this is solved by the ArrowLoop instance, and by having two different integral functions: one with a delay and without a delay. If I understood it correctly, it Conal's aim to provide just a single integral function that can handle both the recursive and regular cases? But, is this even possible? A nice example of this is David's "boingee" example: a ball on the screen gets dragged towards the current mouse position. Mathematically, this is vb(t) = s * ( pm(t) - pb(t) ) pb(t) = pb0 + integral [0..t] vb(t) where pb(t) is the position of the ball at time t pb0 is the initial position of the ball at time t=0, pm(t) is the position of the mouse at time t s is some arbitrary scale factor Of course this is not really realistic but it is a simple example of recursive feedback: pb(t) depends on vb(t) and vice versa. Can we make such behaviors with Reactive?

Hi Peter, Thanks for asking about this issue. If I understood it correctly, it Conal's aim to provide just a single
integral function that can handle both the recursive and regular cases?
But, is this even possible?
Yes. The semantics of reactivity, plus the laziness of Haskell and some
careful programming, makes it possible. I did it long ago in Fran.
Currently the implementation of snapshot (which integral uses) is not lazy
enough for recursive snapshots to work. Chuan-kai Lin came up with a
solution, which I think created a space leak. Richard Smith came up with
essentially the same solution (and leak), and has been continuing to pursue
a sufficiently lazy and space-tight. Today, Richard attached his patch to
ticket # 14 on the Reactive tracker (
http://trac.haskell.org/reactive/ticket/14). I'll check it out and
integrate it if I think it will improve things.
In case anyone's curious, the crucial semantic decision is to have reactive
behaviors change immediately after an event occurs. (Really immediately --
not some finite positive delay.) Thus an event can take a snapshot of a
behavior at the moment that the behavior is reacting to that very event.
The behavior and event are defined in terms of each other, in a well-defined
and useful way.
- Conal
2008/12/2 Peter Verswyvelen
This has been brought up before, but I'm not sure about the current status our consensus regarding "recursive feedback" in Reactive. In Yampa this is solved by the ArrowLoop instance, and by having two different integral functions: one with a delay and without a delay.
If I understood it correctly, it Conal's aim to provide just a single integral function that can handle both the recursive and regular cases?
But, is this even possible?
A nice example of this is David's "boingee" example: a ball on the screen gets dragged towards the current mouse position.
Mathematically, this is
vb(t) = s * ( pm(t) - pb(t) ) pb(t) = pb0 + integral [0..t] vb(t)
where pb(t) is the position of the ball at time t pb0 is the initial position of the ball at time t=0, pm(t) is the position of the mouse at time t s is some arbitrary scale factor
Of course this is not really realistic but it is a simple example of recursive feedback: pb(t) depends on vb(t) and vice versa.
Can we make such behaviors with Reactive?
_______________________________________________ Reactive mailing list Reactive@haskell.org http://www.haskell.org/mailman/listinfo/reactive

Okay.
It would be nice to experiment with higher order integration techniques too.
Right now Reactive uses Euler integration but the user should be able to
choose between Euler, Midpoint, Simpson (or whatever other quadrature rule).
However, aren't we actually interested in approximating ordinary
differential equations (or more exactly, initial value problems), instead of
using integral directly? In which case we should choose between 1-th, 2nd,
or 4th order Runge Kutta or something?
I'm not an expert here, but it would be nice to think about this I guess.
On Wed, Dec 3, 2008 at 12:49 AM, Conal Elliott
Hi Peter,
Thanks for asking about this issue.
If I understood it correctly, it Conal's aim to provide just a single
integral function that can handle both the recursive and regular cases?
But, is this even possible?
Yes. The semantics of reactivity, plus the laziness of Haskell and some careful programming, makes it possible. I did it long ago in Fran.
Currently the implementation of snapshot (which integral uses) is not lazy enough for recursive snapshots to work. Chuan-kai Lin came up with a solution, which I think created a space leak. Richard Smith came up with essentially the same solution (and leak), and has been continuing to pursue a sufficiently lazy and space-tight. Today, Richard attached his patch to ticket # 14 on the Reactive tracker ( http://trac.haskell.org/reactive/ticket/14). I'll check it out and integrate it if I think it will improve things.
In case anyone's curious, the crucial semantic decision is to have reactive behaviors change immediately after an event occurs. (Really immediately -- not some finite positive delay.) Thus an event can take a snapshot of a behavior at the moment that the behavior is reacting to that very event. The behavior and event are defined in terms of each other, in a well-defined and useful way.
- Conal
2008/12/2 Peter Verswyvelen
This has been brought up before, but I'm not sure about the current status our consensus regarding "recursive feedback" in Reactive. In Yampa this is solved by the ArrowLoop instance, and by having two different integral functions: one with a delay and without a delay.
If I understood it correctly, it Conal's aim to provide just a single integral function that can handle both the recursive and regular cases?
But, is this even possible?
A nice example of this is David's "boingee" example: a ball on the screen gets dragged towards the current mouse position.
Mathematically, this is
vb(t) = s * ( pm(t) - pb(t) ) pb(t) = pb0 + integral [0..t] vb(t)
where pb(t) is the position of the ball at time t pb0 is the initial position of the ball at time t=0, pm(t) is the position of the mouse at time t s is some arbitrary scale factor
Of course this is not really realistic but it is a simple example of recursive feedback: pb(t) depends on vb(t) and vice versa.
Can we make such behaviors with Reactive?
_______________________________________________ Reactive mailing list Reactive@haskell.org http://www.haskell.org/mailman/listinfo/reactive

2008/12/3 Peter Verswyvelen
Okay. It would be nice to experiment with higher order integration techniques too. Right now Reactive uses Euler integration but the user should be able to choose between Euler, Midpoint, Simpson (or whatever other quadrature rule). However, aren't we actually interested in approximating ordinary differential equations (or more exactly, initial value problems), instead of using integral directly? In which case we should choose between 1-th, 2nd, or 4th order Runge Kutta or something? I'm not an expert here, but it would be nice to think about this I guess.
I think a 4th order Runge Kutta is something we'd want to have, maybe as part of a FRP.Reactive.Physics package?

I'm all for it :) If we manage to make a 4th order Runge Kutta, then all the
others would be easy to make too if they ever would be needed.
On Wed, Dec 3, 2008 at 5:22 PM, Creighton Hogg
2008/12/3 Peter Verswyvelen
: Okay. It would be nice to experiment with higher order integration techniques too. Right now Reactive uses Euler integration but the user should be able to choose between Euler, Midpoint, Simpson (or whatever other quadrature rule). However, aren't we actually interested in approximating ordinary differential equations (or more exactly, initial value problems), instead of using integral directly? In which case we should choose between 1-th, 2nd, or 4th order Runge Kutta or something? I'm not an expert here, but it would be nice to think about this I guess.
I think a 4th order Runge Kutta is something we'd want to have, maybe as part of a FRP.Reactive.Physics package?

So this is a bit of a brainstorming post. I did a little thinking earlier about different simple ODE solving techniques, and tried to translate them fairly directly into Reactive. The result isn't pretty & I'd like to talk about that. The naive definitions, to me, of the Euler, Euler-Cromer, and Midpoint methods should look like the following. Each takes in an Event (), initial positions & velocities, and a Behavior (v -> v -> v) that is the acceleration as a function of time. We want to be general since the acceleration may be an explicit function of time as well as as position & velocity. euler tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) (prev vi) deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = (snapshot_ tau x) vi = (snapshot_ tau v) deltaTs = diffE (tau `snapshot_` time) eulerCromer tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vi deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time) midpoint tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vavg deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time) vavg = fmap (^/2) $ liftA2 (^+^) vi (prev vi) prev :: Event a -> Event a prev = fmap snd . withPrevE this code is fairly verbose, but that's because I'm trying to be very explicit about the ordering of the sampling & how the new values at each time step are created. The problem is that I feel like I'm wrestling very hard against Reactive rather than working with it. I was hoping that I could get some feedback on a way to write these very simple algorithms that is more inline with the spirit of the API.

Nice. I haven't been able yet to test any of these, anyone?
What is your opinion about physics in Reactive? Should we try to make an
adapter to an optimized imperative physics engine, or should we write one in
Haskell?
On Wed, Dec 3, 2008 at 10:38 PM, Creighton Hogg
So this is a bit of a brainstorming post. I did a little thinking earlier about different simple ODE solving techniques, and tried to translate them fairly directly into Reactive. The result isn't pretty & I'd like to talk about that.
The naive definitions, to me, of the Euler, Euler-Cromer, and Midpoint methods should look like the following. Each takes in an Event (), initial positions & velocities, and a Behavior (v -> v -> v) that is the acceleration as a function of time. We want to be general since the acceleration may be an explicit function of time as well as as position & velocity.
euler tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) (prev vi) deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = (snapshot_ tau x) vi = (snapshot_ tau v) deltaTs = diffE (tau `snapshot_` time)
eulerCromer tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vi deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time)
midpoint tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vavg deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time) vavg = fmap (^/2) $ liftA2 (^+^) vi (prev vi)
prev :: Event a -> Event a prev = fmap snd . withPrevE
this code is fairly verbose, but that's because I'm trying to be very explicit about the ordering of the sampling & how the new values at each time step are created. The problem is that I feel like I'm wrestling very hard against Reactive rather than working with it. I was hoping that I could get some feedback on a way to write these very simple algorithms that is more inline with the spirit of the API.

Well, actually testing any of these out seems to eat all the RAM on my
box & I have to kill it...I don't think that I'm 'morally' doing
anything wrong, so I guess I've just been assuming it's related to the
other ticket I filed where the same thing happened. That might not be
a safe assumption though...
As for physics. One person on #haskell (can't remember who...)
suggested making a pure interface to chipmunk similar to FieldTrip's
interface to OpenGL. That seems like a good & pragmatic idea. Being
a bit of a physics nerd, I think it'd be really cool to make an entire
2d or 3d engine to go with Reactive from the ground up. It'd probably
be a lot of fun to work on but it might not be the fastest way to the
finish.
Cheers,
Creighton
On Sat, Dec 6, 2008 at 7:30 AM, Peter Verswyvelen
Nice. I haven't been able yet to test any of these, anyone? What is your opinion about physics in Reactive? Should we try to make an adapter to an optimized imperative physics engine, or should we write one in Haskell?
On Wed, Dec 3, 2008 at 10:38 PM, Creighton Hogg
wrote: So this is a bit of a brainstorming post. I did a little thinking earlier about different simple ODE solving techniques, and tried to translate them fairly directly into Reactive. The result isn't pretty & I'd like to talk about that.
The naive definitions, to me, of the Euler, Euler-Cromer, and Midpoint methods should look like the following. Each takes in an Event (), initial positions & velocities, and a Behavior (v -> v -> v) that is the acceleration as a function of time. We want to be general since the acceleration may be an explicit function of time as well as as position & velocity.
euler tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) (prev vi) deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = (snapshot_ tau x) vi = (snapshot_ tau v) deltaTs = diffE (tau `snapshot_` time)
eulerCromer tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vi deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time)
midpoint tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vavg deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time) vavg = fmap (^/2) $ liftA2 (^+^) vi (prev vi)
prev :: Event a -> Event a prev = fmap snd . withPrevE
this code is fairly verbose, but that's because I'm trying to be very explicit about the ordering of the sampling & how the new values at each time step are created. The problem is that I feel like I'm wrestling very hard against Reactive rather than working with it. I was hoping that I could get some feedback on a way to write these very simple algorithms that is more inline with the spirit of the API.

Well, actually testing any of these out seems to eat all the RAM on my box & I have to kill it...I don't think that I'm 'morally' doing anything wrong, so I guess I've just been assuming it's related to the other ticket I filed where the same thing happened. That might not be a safe assumption though...
I see. IMO in Haskell one can replace 100 lines of C code with just 10 lines of Haskell, but then it takes 10 times as long to fix the space leaks ;) But in the end it's all nicely orthogonal and composable, so it should be worth it :) One thing that I was pondering about: if I recall correctly (it has been a while that I played with this stuff), if one wants to perform a Runge Kutta, then the simulation engine must be able to "peek" ahead in time, temporary moving (and rotating) all rigid bodies a fraction of the time step in the "future", computing the forces and torques at that new time, and then backtrack to the start of the sampling time interval, combining the different forces and torques over the time interval to perform a numerical integration step. So basically if one has a Behavior for the Position of some rigid body, one would need to create a new Position Behavior for sampling these temporary Positions, since the final Position of the rigid body at some time T will be different from the temporary Position at the same T, and since we're dealing with functional programming here, we have referential transparency so the same Behavior cannot have a different value at the same time... I'm not sure how this will work out (and my English seems to be too bad to express what I really mean without a face to face conversation and a piece of paper, sigh)
As for physics. One person on #haskell (can't remember who...) suggested making a pure interface to chipmunk similar to FieldTrip's interface to OpenGL. That seems like a good & pragmatic idea.
Yes, but OpenGL is used as a "backend/actuator"; it just renders stuff. A physics engine would have to generate events and provide behaviors, so it would be "IO in the middle", and I have no idea how that would work out. chipmunk seems to be really cool but it's "just" a 2D physics engine. but anyway a lot of C/C++ physics engine are available. Being a bit of a physics nerd, I think it'd be really cool to make an entire
2d or 3d engine to go with Reactive from the ground up. It'd probably be a lot of fun to work on but it might not be the fastest way to the finish.
Well Reactive isn't exactly the fastest way to finish either, but I guess we all hope it will be the nicest way to finish :) You certainly seem to be the right "nerd" for a "pure" physics engine, so why not give it a shot :) I suspect that the Reactive core might need some architectural changes if one wants to integrate a real physics engine with an good RK4, so I guess it's better to confront Conal with this earlier than later... Personally I'm still struggling to leave my 20 years of imperative hacking skills behind me, so currently I'm just watching and being amazing with all this development ;-) Cheers,
Creighton
participants (3)
-
Conal Elliott
-
Creighton Hogg
-
Peter Verswyvelen