import ForSyDe.Shallow
import Test.Hspec
-- | Taken from <https://github.com/forsyde/forsyde-shallow-examples>
test_mulacc :: Integer -> Signal Integer
test_mulacc n = sim_run $ mulacc constant1 siggen1
where
sim_run val = zipWithSY (\v _ -> v) val ticks
mulacc a b = result
where addi1 = comb2SY (*) a b -- Multiplier
acci = comb2SY (+) addi1 addi2 -- Adder
addi2 = delaySY 0 acci -- Accumulator
result = acci -- Output of the system
constant1 = sourceSY id 3 :: Signal Integer
siggen1 = sourceSY (+1) 1 :: Signal Integer
ticks = signal [1..n] :: Signal Integer
-- | Taken from <https://github.com/forsyde/forsyde-shallow-examples>
test_fibonacciRabbitsDeath :: Integer -> Signal Integer
test_fibonacciRabbitsDeath months = fibonacciRabbitsDeath $ signal [1..months]
where
fibonacciRabbitsDeath ticks = zipWith4SY fusion n a d ticks
where n = newborns a
a = adults n
d = dead n
fusion x y z ctrl = x + y - z
newborns = delaySY 1
adults = mooreSY nsf out 0
where nsf state input = (state + input)
out state = state
dead = delaynSY 0 4
-- | Taken from <https://github.com/forsyde/forsyde-shallow-examples>
test_adaptiveAmp :: Integer -> Signal Integer
test_adaptiveAmp n = sout
where s1 = p1 s3 sin -- Process p1
sout = p2 s1 -- Process p2
s2 = p3 sout -- Process p3
s3 = p4 s2 -- Process p4
sin = signal [10..n]
p1 = zipUs 1 5
p2 = mapU 1 mult
where mult [([control], signal)] = map (* control) signal
p3 = scanU (\_ -> 5) g 10
where g :: (Ord a, Num a) => a -> [a] -> a
g state signal
| sum signal > 500 = state - 1
| sum signal < 400 = state + 1
| otherwise = state
p4 = initU [10]
-- | Testing feedback loops in in SDF library
test_toySDF :: Signal Double -> Signal Double
test_toySDF s_in = s_out where
s_1 = p_add s_in s_2
s_2 = p_delay s_1
s_out = p_average s_2
-- Process specification
p_add s1 s2 = actor21SDF (1,1) 1 add s1 s2
p_delay s = delaySDF [0] s
p_average s = actor11SDF 3 1 average s
-- Function definition
add [x] [y] = [x + y]
average [x1,x2,x3] = [(x1 + x2 + x3) / 3.0]
s_test = signal [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
-- test1: CSDF graph from the paper Cyclo-Static Dataflow
test_toyCSDF :: Num a => Signal a
test_toyCSDF = s3
where s3 = delayCSDF [1,1] s2
s2 = v2 s1
s1 = v1 s4
s4 = v3 s3
v1 = actor11CSDF [(1, 1, \[a] -> [a]), (1, 0, \_ -> []), (1, 0, \_ -> [])]
v2 = actor11CSDF [(1, 0, \_ -> []), (1, 2, \[a] -> [a, 2*a])]
v3 = actor11CSDF [(1, 3, \[a] -> [a, 2*a, 3*a])]
test_antiWindUpSADF :: (Num a, Ord a) => Signal a -> Signal a
test_antiWindUpSADF input = output
where
output = integrator c1 s1 s3
s3 = delaySADF [0] output
s1 = kernel11SADF c2 input
(c1, c2) = detector s3 input
integrator = kernel21SADF
-- Detector
detector :: (Num a, Ord a) => Signal a -> Signal a
-> (Signal ((Int, Int), Int, [a] -> [a] -> [a]),
Signal (Int, Int, [a] -> [a]))
detector = detector22SADF (1,1) f g 1
-- State transition function for the detector
f :: (Num a, Ord a) => Int -> [a] -> [a] -> Int
f 1 [y] [v] = if (y > 100 && v > 0 || y < (-100) && v < 0)
then 2
else 1
f 2 [y] [v] = if (y > 100 && v > 0 || y < (-100) && v < 0)
then 2
else 1
-- Output function for the detector
g :: Num a => Int -> ((Int, Int), ([((Int, Int), Int, [a] -> [a] -> [a])], [(Int, Int, [a] -> [a])]))
g 1 = ((1,1),
([((1,1), 1, \[a] [b] -> [a+b])],
[(1, 1, \[a] -> [a])]))
g 2 = ((1,1),
([((0,1), 1, \_ [b] -> [b])],
[(1, 0, \[a] -> [])]))
s2_test = signal $ [10..110]
main :: IO ()
main = hspec $ do describe "ForSyDe.Shallow : " $ lab2tests
where
lab2tests = do
it "SY Multiply Accumulator" $ test_mulacc 10
`shouldBe`(read "{3,9,18,30,45,63,84,108,135,165}" :: Signal Integer)
it "SY Fibonacci Reproduction" $ test_fibonacciRabbitsDeath 10
`shouldBe`(read "{1,1,2,3,4,8,12,20,32,52}" :: Signal Integer)
it "U Adaptive Amplifier" $ test_adaptiveAmp 20
`shouldBe`(read "{100,110,120,130,140,135,144,153,162,171}" :: Signal Integer)
it "SDF Feedback Loop" $ test_toySDF s_test
`shouldBe`(read "{1.3333333333333333,10.333333333333334}" :: Signal Double)
it "CSDF Feedback Loop" $ takeS 10 test_toyCSDF
`shouldBe`(read "{1,1,1,2,2,4,4,8,8,16}" :: Signal Integer)
it "SADF Anti Wind-up System" $ takeS 10 (test_antiWindUpSADF s2_test)
`shouldBe`(read "{10,21,33,46,60,75,91,108,108,108}" :: Signal Integer)