forsyde / forsyde-atom

A shallow-embedded DSL for modeling cyber-physical systems
https://forsyde.github.io/forsyde-atom/
BSD 3-Clause "New" or "Revised" License
3 stars 2 forks source link

Feedback from tupled signals bug #7

Closed ugeorge closed 8 years ago

ugeorge commented 8 years ago

There is a bug I've discovered when dealing with tupled output signals when redesigning the multi-output process constructors/patterns. WHY I needed to redesign them is described in this wiki log.

In short, if I want to respect the atom definition (i.e. atoms are completely independent entities, and constructors are just patterns of atoms), the revised implementation deadlocks when feeding back tupled signals into, for example, a multi-signal generator.

ugeorge commented 8 years ago

Attempt 1

The first strategy in dealing with the above-mentioned design issue is to split the outputs and feed them back to the inputs separately. A drawback is that multiple function outputs need to be expressed as tuples, but I have no choice... This means that I need to define some new tuple utility operators (code in private fork):

(<>) :: f -> (a1, a2, ...) -> f -> a1 -> a2 -> ...              -- a currying operator
($$) :: (f1, f2, ...) -> (a1, a2, ...) -> (f1 a1, f2 a2, ...)   -- a function application operator
(-&>>-) = ($$) (delay, delay)                                   -- a tupled delay

scanld12 becomes:

scanld12 :: (b1 -> b2 -> a1 -> (b1, b2)) -> (e (t, b1), e (t, b2)) 
            -> S (e (t, a1)) -> (S (e (t, b1)), S (e (t, b1)))
scanld12 ns i s1 = st 
  where st = i -&>>- (comb32 ns <> st) s1

Great, I have well-formed signals between atoms, everything compiles and it's just dandy! Let's run the tests... wait! This particular process deadlocks! But why?

Digging a bit into how the evaluation is done, it is easy to notice that the self-referential function expects an fully-evaluated kernel to build a recursive structure from. A recursive structure meaning a signal... but we generate a tuple of signals which we then feed to generate the next element... do you see what's wrong here? A tuple of signals needs all its elements fully evaluated to be useful, so it waits for the signals to be evaluated... but the signals wait for the tuple to be evaluated... and so on and so forth.

It first seems that we cannot use tuples of signals to feed back into generators.

ugeorge commented 8 years ago

Attempt 2

It seems that it is not the tupled outputs that are blocking the feedback loop. The simulation seems to stop when evaluating the newly defined tuple operators themselves, more precisely the ($$) operator, for the reason described in Attempt 1. Thus the tupled delay (-&>>-) is malign in this case. By expanding these operators and describing the connections explicitly, the simulation follows its normal course. The following attempt was successful:

gen ns i = (st1, st2)
  where st1 = delay (fst i) (fst $ comb22 ns st1 st2)
        st2 = delay (snd i) (snd $ comb22 ns st1 st2)

and testing it grants the expected results:

λ> let f a b = (a + b, a - b)
λ> let x = gen f (1,2)
λ> takeS 5 $ snd x
{2,-1,4,-2,8}
λ> takeS 5 $ fst x
{1,3,2,6,4}

Not it is a matter of prettyfying the code in order to be readable and to reflect pattern formation.

Update: this looks better:

gen ns (i1, i2) = let (ns1, ns2) = comb22 ns st1 st2
                      (st1, st2) = (i1 -&>- ns1, i2 -&>- ns2)
                  in  (st1, st2)