forsyde-atom-0.3.0.0: Shallow-embedded DSL for modeling cyber-physical systems
Copyright(c) George Ungureanu 2020
LicenseBSD-style (see the file LICENSE)
Maintainerugeorge@kth.se
Stabilityexperimental
Portabilityportable
Safe HaskellSafe
LanguageHaskell2010

ForSyDe.Atom.MoC.SY.Clocked

Description

This is a small experimental library for modeling multi-clock rate SY systems in the style of Lustre [Halbwachs91]. It is implemented mainly on top of the ForSyDe.Atom.MoC.SY library, re-using it to the full extent, and it represents Lustre language constructs as specific patterns. Instead of developing and representing an inherent clock calculus like Lustre, this library merely propagates "no-ops" as absent (i.e. Abst) events and utilises the algebra of ForSyDe.Atom.ExB to model clock rates.

Internally, a ForSyDe.Atom.MoC.SY.Clocked process constructor represents implicitly a ForSyDe.Atom.MoC.SY MoC layer wrapping a ForSyDe.Atom.ExB.Absent behavior extension layer. Under these asumptions the ForSyDe.Atom.MoC.SY.Clocked models can be interpreted as follows:

  • the host ForSyDe.Atom.MoC.SY processes operate at the basic clock rate. I.e. a signal where all events are present is active in the basic time scale.
  • the wrapped ForSyDe.Atom.ExB behaviors operate on and propagate absent/present events based on the operating clock rate. Abst means that an event "did not occur". Combining a present with an absent event in any regular operation (see comb22) would violate the clock constraints of well-formed systems (see [Halbwachs91]) and would throw a runtime error.
  • Although ForSyDe.Atom.MoC.SY.Clocked is hosted on ForSyDe.Atom.MoC.SY, the Abst "value" has no true meaning in a pure SY reactive system. Therefore to interface between these two SY domains should always be made through a toDE/fromDE interface. OBS: these interfaces are still experimental and higly unsafe especially when considering feedback loops.
Synopsis

Documentation

type Signal a = Stream (SY (AbstExt a)) Source #

Alias showing that in the ForSyDe.Atom.MoC.SY.Clocked domain, a signal is considered a stream of absent-extended SY events.

Lustre constructs

These are process constructors which imitate the behavior of Lustre constructs according to our ForSyDe.Atom.MoC.SY.Clocked definition.

pre :: Signal a -> Signal a Source #

The pre construct in Lustre. OBS: instead of nil, the first value is an Abst. TODO: unclear if this breaks the SY assumption.

>>> let s1 = signal [Prst 1, Prst 2, Prst 3, Prst 4, Prst 5]
>>> pre s1
{⟂,1,2,3,4,5}

(->-) :: Signal a -> Signal a -> Signal a infixl 3 Source #

The -> operator in Lustre.

>>> let s1 = signal [Prst 1, Prst 2, Prst 3, Prst 4, Prst 5]
>>> unit (Prst 10) ->- s1
{10,2,3,4,5}

when Source #

Arguments

:: Signal a

Input signal

-> Signal Bool

Signal of predicates

-> Signal a

Output signal

Determines the existence of events in the (left) signal based on the (right) signal of boolean values (conditions). In Lustre this construct is used to generate other clock rates.

>>> let s1   = (signal . map Prst) [1,2,3,4,5]
>>> let pred = signal [Prst False, Abst, Prst True, Prst False, Prst True]
>>> s1 `when` pred
{⟂,⟂,3,⟂,5}

current Source #

Arguments

:: a

Value to fill with in case there was no previous value

-> Signal a

Input

-> Signal a

Output

Holds the last non-absent value in a signal, like the current construct in Lustre. OBS: instead of nil, the first value is user-defined.

>>> let s1   = signal [Abst, Abst, Prst 1, Prst 2, Abst, Prst 3]
>>> current 0 s1
{0,0,1,2,2,3}

Auxiliary constructs

These are utility process constructors used in combination with the main constructs.

is :: Signal a -> (a -> Bool) -> Signal Bool Source #

Applies a predicate function on a signal of absent-extended events.

>>> let s1   = signal $ map Prst [1,2,3,4,5]
>>> s1 `is` (>3)
{False,False,False,True,True}

It is useful in combination with when.

>>> let s1 = (signal . map Prst) [1,2,3,4,5]
>>> let s2 = (signal . map Prst) [11,22,33,44,55]
>>> s2 `when` (s1 `is` (>3))
{⟂,⟂,⟂,44,55}

whenIs2 :: (a -> Bool) -> Signal a -> Signal b1 -> Signal b2 -> (Signal b1, Signal b2) Source #

Serializes when with is for up to three input signals.

Constructors whenIs[1-3]

>>> let s1 = (signal . map Prst) [1,2,3,4,5]
>>> let s2 = (signal . map Prst) [11,22,33,44,55]
>>> whenIs2 (>3) s1 s1 s2
({⟂,⟂,⟂,4,5},{⟂,⟂,⟂,44,55})

whenPres2 :: Signal b -> Signal b1 -> Signal b2 -> (Signal b1, Signal b2) Source #

Same as whenIs2 but triggering the output events only based on the presence of the first input rather than a boolean.

>>> let s1 = signal $ map Prst [1,2,3,4,5]
>>> let sp = signal [Prst 1, Prst 1, Abst, Prst 1, Abst]
>>> whenPres1 sp s1
{1,2,⟂,4,⟂}

filter Source #

Arguments

:: (a -> Bool)

Predicate function

-> Signal a

Input signal

-> Signal a

Output signal

Filters out values to Abst if they do not fulfill a predicate function, i.e. applies whenIs1 on itself.

>>> let s1   = (signal . map Prst) [1,2,3,4,5]
>>> filter (>3) s1
{⟂,⟂,⟂,4,5}

fill Source #

Arguments

:: a

Value to fill with

-> Signal a

Input

-> Signal a

Output

Fills absent events with a user-defined value.

>>> let s1   = signal [Abst, Abst, Prst 1, Prst 2, Abst, Prst 3]
>>> fill 0 s1
{0,0,1,2,0,3}

Regular constructors

These are the regular process constructors defined as patterns in the ForSyDe.Atom.MoC module, but adapted for the absent-extended behaviors.

delay Source #

Arguments

:: a

initial value

-> Signal a

input signal

-> Signal a

output signal

The delay process "delays" a signal with one event. Serializes a pre and a ->-.

>>> let s = signal [Prst 1,Prst 2,Prst 3,Abst,Prst 5]
>>> delay 0 s
{0,1,2,3,⟂,5}

comb22 Source #

Arguments

:: (a1 -> a2 -> (b1, b2))

function on values

-> Signal a1

first input signal

-> Signal a2

second input signal

-> (Signal b1, Signal b2)

two output signals

comb processes map combinatorial functions on signals on synchronized input signals. It implements the comb pattern (see comb22), and implicitly applies a resolution between absent-extended events (see res22)

Constructors: comb[1-4][1-4].

>>> let s1 = (signal . map Prst) [1..]
>>> let s2 = signal [Prst 1,Prst 1,Abst,Prst 1,Prst 1]
>>> comb11 (+1) s2
{2,2,⟂,2,2}
>>> comb22 (\a b-> (a+b,a-b)) s2 s2
({2,2,⟂,2,2},{0,0,⟂,0,0})

Combining two signals at different clock rates throws a runtime error:

comb22 (\a b-> (a+b,a-b)) s1 s2
({2,3,*** Exception: [ExB.Absent] Illegal occurrence of an absent and present event

stated22 Source #

Arguments

:: (b1 -> b2 -> a1 -> a2 -> (b1, b2))

next stated function

-> (b1, b2)

initial stated values

-> Signal a1

first input signal

-> Signal a2

second input signal

-> (Signal b1, Signal b2)

output signals

stated is a state machine without an output decoder. It implements the stated pattern (see stated22), and operates on degenerated absent-extended values (see ignore22) in order to propagate absent events properly and not raise absent-present resolution errors.

Constructors: stated[1-3][1-3].

>>> let ones = takeS 8 $ SY.constant1 (Prst 1)
>>> let b = (signal . map Prst) [False,True,False,False,True,True,False,True]
>>> ones
{1,1,1,1,1,1,1,1}
>>> b
{False,True,False,False,True,True,False,True}
>>> stated11 (+) 1 ones
{1,2,3,4,5,6,7,8}
>>> stated11 (+) 1 (ones `when` b)
{⟂,1,⟂,⟂,2,3,⟂,4}
>>> stated11 (+) 1 ones `when` b
{⟂,2,⟂,⟂,5,6,⟂,8}

state22 Source #

Arguments

:: (b1 -> b2 -> a1 -> a2 -> (b1, b2))

next state function

-> (b1, b2)

initial state values

-> Signal a1

first input signal

-> Signal a2

second input signal

-> (Signal b1, Signal b2)

output signals

state is a state machine without an output decoder, that reacts instantaneously. It implements the state pattern (see state22), and operates on degenerated absent-extended values (see ignore22) in order to propagate absent events properly and not raise absent-present resolution errors.

Constructors: state[1-3][1-3].

>>> let ones = takeS 8 $ SY.constant1 (Prst 1)
>>> let b = (signal . map Prst) [False,True,False,False,True,True,False,True]
>>> ones
{1,1,1,1,1,1,1,1}
>>> b
{False,True,False,False,True,True,False,True}
>>> state11 (+) 1 ones
{2,3,4,5,6,7,8,9}
>>> state11 (+) 1 (ones `when` b)
{⟂,2,⟂,⟂,3,4,⟂,5}
>>> state11 (+) 1 ones `when` b
{⟂,3,⟂,⟂,6,7,⟂,9}

moore22 Source #

Arguments

:: (st -> a1 -> a2 -> st)

next state function

-> (st -> (b1, b2))

output decoder

-> st

initial state

-> Signal a1 
-> Signal a2 
-> (Signal b1, Signal b2) 

moore processes model Moore state machines. It implements the moore patterns (see moore22), and operates on absent-extended values (see stated22).

Constructors: moore[1-3][1-3].

>>> let s1 = signal [Prst 1,Prst 2,Abst,Abst,Prst 3]
>>> moore11 (+) (+1) 1 s1
{2,3,⟂,⟂,5}

mealy22 Source #

Arguments

:: (st -> a1 -> a2 -> st)

next state function

-> (st -> a1 -> a2 -> (b1, b2))

outpt decoder

-> st

initial state

-> Signal a1 
-> Signal a2 
-> (Signal b1, Signal b2) 

mealy processes model Mealy state machines. It implements the mealy pattern (see mealy22), and operates on absent-extended values (see stated22).

Constructors: mealy[1-3][1-3].

>>> let s1 = signal [Prst 1,Prst 2,Abst,Abst,Prst 3]
>>> mealy11 (+) (+) 1 s1
{2,4,⟂,⟂,7}