packages feed

PropRatt 0.1.0.0 → 0.2.0.0

raw patch · 10 files changed

+397/−261 lines, 10 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- PropRatt.HList: (%:) :: forall x (xs :: [Type]). x -> HList xs -> HList (x ': xs)
- PropRatt.HList: [HCons] :: forall x (xs :: [Type]). !x -> !HList xs -> HList (x ': xs)
- PropRatt.LTL: [After] :: forall (ts :: [Type]). Int -> Pred ts -> Pred ts
- PropRatt.LTL: [Always] :: forall (ts :: [Type]). Pred ts -> Pred ts
- PropRatt.LTL: [Apply] :: forall (ts :: [Type]) t1 t. Expr ts (t1 -> t) -> Expr ts t1 -> Expr ts t
- PropRatt.LTL: [Contradiction] :: forall (ts :: [Type]). Pred ts
- PropRatt.LTL: [Eighth] :: forall x1 x2 x3 x4 x5 x6 x7 t (x8 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (x6 ': (x7 ': (Value t ': x8)))))))) t
- PropRatt.LTL: [Eventually] :: forall (ts :: [Type]). Pred ts -> Pred ts
- PropRatt.LTL: [Fifth] :: forall x1 x2 x3 x4 t (x5 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (Value t ': x5))))) t
- PropRatt.LTL: [First] :: forall t (x :: [Type]). Lookup (Value t ': x) t
- PropRatt.LTL: [Fourth] :: forall x1 x2 x3 t (x4 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (Value t ': x4)))) t
- PropRatt.LTL: [Implies] :: forall (ts :: [Type]). Pred ts -> Pred ts -> Pred ts
- PropRatt.LTL: [Index] :: forall (ts :: [Type]) t. Lookup ts t -> Expr ts t
- PropRatt.LTL: [Next] :: forall (ts :: [Type]). Pred ts -> Pred ts
- PropRatt.LTL: [Ninth] :: forall x1 x2 x3 x4 x5 x6 x7 x8 t (x9 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (x6 ': (x7 ': (x8 ': (Value t ': x9))))))))) t
- PropRatt.LTL: [Previous] :: forall (ts :: [Type]) t. Lookup ts t -> Lookup ts t
- PropRatt.LTL: [Prior] :: forall (ts :: [Type]) t. Int -> Lookup ts t -> Lookup ts t
- PropRatt.LTL: [Release] :: forall (ts :: [Type]). Pred ts -> Pred ts -> Pred ts
- PropRatt.LTL: [Second] :: forall x1 t (x2 :: [Type]). Lookup (x1 ': (Value t ': x2)) t
- PropRatt.LTL: [Seventh] :: forall x1 x2 x3 x4 x5 x6 t (x7 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (x6 ': (Value t ': x7))))))) t
- PropRatt.LTL: [Sixth] :: forall x1 x2 x3 x4 x5 t (x6 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (Value t ': x6)))))) t
- PropRatt.LTL: [Tautology] :: forall (ts :: [Type]). Pred ts
- PropRatt.LTL: [Third] :: forall x1 x2 t (x3 :: [Type]). Lookup (x1 ': (x2 ': (Value t ': x3))) t
- PropRatt.LTL: [Ticked] :: forall (ts :: [Type]) t1. Lookup ts t1 -> Expr ts Bool
- PropRatt.LTL: [Until] :: forall (ts :: [Type]). Pred ts -> Pred ts -> Pred ts
+ PropRatt.HList: [:%] :: forall x (xs :: [Type]). !x -> !HList xs -> HList (x ': xs)
+ PropRatt.LTL: [:=>] :: forall (ts :: [Type]). Pred ts -> Pred ts -> Pred ts
+ PropRatt.LTL: [App] :: forall (ts :: [Type]) t1 t. Expr ts (t1 -> t) -> Expr ts t1 -> Expr ts t
+ PropRatt.LTL: [FF] :: forall (ts :: [Type]). Pred ts
+ PropRatt.LTL: [F] :: forall (ts :: [Type]). Pred ts -> Pred ts
+ PropRatt.LTL: [G] :: forall (ts :: [Type]). Pred ts -> Pred ts
+ PropRatt.LTL: [PrevN] :: forall (ts :: [Type]) t. Int -> Lookup ts t -> Lookup ts t
+ PropRatt.LTL: [Prev] :: forall (ts :: [Type]) t. Lookup ts t -> Lookup ts t
+ PropRatt.LTL: [R] :: forall (ts :: [Type]). Pred ts -> Pred ts -> Pred ts
+ PropRatt.LTL: [Sig1] :: forall t (x :: [Type]). Lookup (Value t ': x) t
+ PropRatt.LTL: [Sig2] :: forall x1 t (x2 :: [Type]). Lookup (x1 ': (Value t ': x2)) t
+ PropRatt.LTL: [Sig3] :: forall x1 x2 t (x3 :: [Type]). Lookup (x1 ': (x2 ': (Value t ': x3))) t
+ PropRatt.LTL: [Sig4] :: forall x1 x2 x3 t (x4 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (Value t ': x4)))) t
+ PropRatt.LTL: [Sig5] :: forall x1 x2 x3 x4 t (x5 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (Value t ': x5))))) t
+ PropRatt.LTL: [Sig6] :: forall x1 x2 x3 x4 x5 t (x6 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (Value t ': x6)))))) t
+ PropRatt.LTL: [Sig7] :: forall x1 x2 x3 x4 x5 x6 t (x7 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (x6 ': (Value t ': x7))))))) t
+ PropRatt.LTL: [Sig8] :: forall x1 x2 x3 x4 x5 x6 x7 t (x8 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (x6 ': (x7 ': (Value t ': x8)))))))) t
+ PropRatt.LTL: [Sig9] :: forall x1 x2 x3 x4 x5 x6 x7 x8 t (x9 :: [Type]). Lookup (x1 ': (x2 ': (x3 ': (x4 ': (x5 ': (x6 ': (x7 ': (x8 ': (Value t ': x9))))))))) t
+ PropRatt.LTL: [TT] :: forall (ts :: [Type]). Pred ts
+ PropRatt.LTL: [Tick] :: forall (ts :: [Type]) t1. Lookup ts t1 -> Expr ts Bool
+ PropRatt.LTL: [U] :: forall (ts :: [Type]). Pred ts -> Pred ts -> Pred ts
+ PropRatt.LTL: [Val] :: forall (ts :: [Type]) t. Lookup ts t -> Expr ts t
+ PropRatt.LTL: [XN] :: forall (ts :: [Type]). Int -> Pred ts -> Pred ts
+ PropRatt.LTL: [X] :: forall (ts :: [Type]). Pred ts -> Pred ts
+ PropRatt.LTL: prev :: forall (ts :: [Type]) t. Expr ts t -> Expr ts t
+ PropRatt.LTL: prevN :: forall (ts :: [Type]) t. Int -> Expr ts t -> Expr ts t
+ PropRatt.LTL: sig1 :: forall t (ts :: [Type]). Expr (Value t ': ts) t
+ PropRatt.LTL: sig2 :: forall t1 t2 (ts :: [Type]). Expr (t1 ': (Value t2 ': ts)) t2
+ PropRatt.LTL: sig3 :: forall t1 t2 t3 (ts :: [Type]). Expr (t1 ': (t2 ': (Value t3 ': ts))) t3
+ PropRatt.LTL: sig4 :: forall t1 t2 t3 t4 (ts :: [Type]). Expr (t1 ': (t2 ': (t3 ': (Value t4 ': ts)))) t4
+ PropRatt.LTL: tick1 :: forall t (ts :: [Type]). Pred (Value t ': ts)
+ PropRatt.LTL: tick2 :: forall t1 t2 (ts :: [Type]). Pred (t1 ': (Value t2 ': ts))
+ PropRatt.LTL: tick3 :: forall t1 t2 t3 (ts :: [Type]). Pred (t1 ': (t2 ': (Value t3 ': ts)))
+ PropRatt.LTL: tick4 :: forall t1 t2 t3 t4 (ts :: [Type]). Pred (t1 ': (t2 ': (t3 ': (Value t4 ': ts))))
- PropRatt.HList: infixr 5 %:
+ PropRatt.HList: infixr 5 :%
- PropRatt.LTL: (|<=|) :: (Applicative f, Ord t) => f t -> f t -> f Bool
+ PropRatt.LTL: (|<=|) :: forall t (ts :: [Type]). Ord t => Expr ts t -> Expr ts t -> Pred ts
- PropRatt.LTL: (|<|) :: (Applicative f, Ord t) => f t -> f t -> f Bool
+ PropRatt.LTL: (|<|) :: forall t (ts :: [Type]). Ord t => Expr ts t -> Expr ts t -> Pred ts
- PropRatt.LTL: (|==|) :: (Applicative f, Eq t) => f t -> f t -> f Bool
+ PropRatt.LTL: (|==|) :: forall t (ts :: [Type]). Ord t => Expr ts t -> Expr ts t -> Pred ts
- PropRatt.LTL: (|>=|) :: (Applicative f, Ord t) => f t -> f t -> f Bool
+ PropRatt.LTL: (|>=|) :: forall t (ts :: [Type]). Ord t => Expr ts t -> Expr ts t -> Pred ts
- PropRatt.LTL: (|>|) :: (Applicative f, Ord t) => f t -> f t -> f Bool
+ PropRatt.LTL: (|>|) :: forall t (ts :: [Type]). Ord t => Expr ts t -> Expr ts t -> Pred ts

Files

CHANGELOG.md view
@@ -1,11 +1,8 @@-# Changelog for `experiments`--All notable changes to this project will be documented in this file.+# 0.2.0.0 -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),-and this project adheres to the-[Haskell Package Versioning Policy](https://pvp.haskell.org/).+- Revised syntax of specification language.+- Added shorthand syntax. -## Unreleased+# 0.1.0.0 -## 0.1.0.0 - YYYY-MM-DD+Initial release
PropRatt.cabal view
@@ -1,14 +1,22 @@ cabal-version: 2.2 name:           PropRatt-version:        0.1.0.0+version:        0.2.0.0 synopsis:       Property-based testing framework for testing asynchronous FRP programs. category:       testing description:    -                PropRatt is a property-based testing framework for testing Async Rattus programs.+                PropRatt is a property-based testing framework for testing <https://hackage.haskell.org/package/AsyncRattus Async Rattus> programs.                 The key component of PropRatt is its specification language, which extends basic linear temporal logic with                 a means to express properties of several concurrent signals. This                 allows users to express temporal properties that relate data coming from                 different signals at different points in time.+                .+                More details about the specification language can be found in the <https://bahr.io/pubs/files/propratt-paper.pdf accompanying paper>.+                .+                Example specifications written in PropRatt:+                .+                * <https://github.com/pa-ba/PropRatt/blob/main/examples/timer/Timer.hs Specification for a simple GUI application>+                .+                * <https://github.com/pa-ba/PropRatt/blob/main/examples/main/Main.hs Specification for basic signal combinators> (@map@, @zip@, @scan@, etc.) author:         Christian Emil Nielsen, Mathias Faber Kristiansen, Patrick Bahr maintainer:     paba@itu.dk copyright:      2025 Christian Emil Nielsen, Mathias Faber Kristiansen, Patrick Bahr
README.md view
@@ -2,7 +2,23 @@  PropRatt is a Haskell framework for testing AsyncRattus using property-based testing. +# Overview++- The [main example file](examples/main/Main.hs) contains example+  specifications that test signal combinators of the Async Rattus+  library.+- The [timer example file](examples/timer/Timer.hs) contains the timer+  example from the paper.+- The implementation of the specification language can be found in the+  [PropRatt.LTL](src/PropRatt/LTL.hs) module.++ # Running examples +Using `stack`: - `stack run main-example` - `stack run timer-example`++Using `cabal`:+- `cabal run main-example`+- `cabal run timer-example`
examples/main/Main.hs view
@@ -1,5 +1,5 @@ {-# OPTIONS -fplugin=AsyncRattus.Plugin #-}-{-# LANGUAGE TypeApplications, FlexibleInstances #-}+{-# LANGUAGE TypeApplications, FlexibleInstances, TypeOperators #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}@@ -23,6 +23,13 @@  {-# ANN module AllowLazyData #-} +zipWrong :: (Stable a, Stable b) => Sig a -> Sig b -> Sig (a :* b)+zipWrong (a ::: as) (b ::: bs) = (a :* b) ::: delay (+        case select as bs of+        Fst (a' ::: as') bs' -> zipWrong (a' ::: as') (b ::: bs')+        Snd as' (b' ::: bs') -> zipWrong (a ::: as') (b ::: bs')+        Both as' bs' -> zipWrong as' bs')+ filterM :: Box (a -> Bool) -> Sig a -> Sig (Maybe' a) filterM f (x ::: xs) = if unbox f x   then Just' x ::: delay (filterM f (adv xs))@@ -47,11 +54,11 @@ prop_interleave = forAll (generateSignals @[Int, Int]) $ \intSignals ->     let interleaved     = interleave (box (+)) (future $ first intSignals) (future $ second intSignals)         state           = prependLater interleaved $ flatten intSignals-        predicate       = Next $ Always $ ((Now ((Index First) |==| (Index Second)))+        predicate       = X $ G $ ((sig1 |==| sig2)                                         `Or`-                                        (Now ((Index First) |==| (Index Third))))+                                        (sig1 |==| sig3))                                         `Or`-                                        (Now (((Index Second) + (Index Third)) |==| (Index First)))+                                        ((sig2 + sig3) |==| sig1)         result          = evaluate predicate state     in result @@ -61,10 +68,7 @@    let  jumpFunc    = box (\n -> if n > 10 then Just' (const 1) else Nothing')         jumpSig     = jump jumpFunc (first intSignals)         state       = prepend jumpSig $ flatten intSignals-        predicate   = Always $-                        Now ((Index First) |==| (Index Second))-                        `Or`-                        Now ((Index First) |==| (Pure 1)) --+        predicate   = G $ (sig1 |==| sig2) `Or` (sig1 |==| pure 1)         result      = evaluate predicate state     in result @@ -73,7 +77,7 @@ prop_scan_failing =  forAllShrink (generateSignals @Int) shrinkHls $ \intSignals ->     let prefixSum   = scan (box (+)) 0 (first intSignals)         state       = prepend prefixSum $ flatten intSignals-        predicate   = Next $ Always $ Now $ Index (Previous First) |<| (Index First)+        predicate   = X $ G $ prev sig1 |<| sig1         result      = evaluate predicate state     in counterexample ("Must be natural numbers.") result @@ -83,7 +87,7 @@     let absSig      = map (box (\x -> (abs x + 1))) (first intSignals)         prefixSum   = scan (box (+)) 0 absSig         state       = prepend prefixSum $ flatten intSignals-        predicate   = Next $ Always $ Now $ Index (Previous First) |<| (Index First)+        predicate   = X $ G $ prev sig1 |<| sig1         result      = evaluate predicate state     in result @@ -92,7 +96,7 @@ prop_switchedSignal = forAll (generateSignals @[Int, Int]) $ \intSignals ->     let switched    = switch (first intSignals) (future (second intSignals))         state       = prepend switched $ flatten intSignals-        predicate   = Until (Now ((Index First) |==| (Index Second))) (Now ((Index First) |==| (Index Third)))+        predicate   = (sig1 |==| sig2) `U` (tick3 `And` G(sig1 |==| sig3))         result      = evaluate predicate state     in result @@ -101,7 +105,7 @@ prop_buffer = forAll (generateSignals @Int) $ \intSignals ->     let bufferedSig = buffer 10 (first intSignals)         state       = prepend bufferedSig $ flatten intSignals-        predicate   = Next $ Always $ Now $ (Index First) |==| Index (Previous Second)+        predicate   = X $ G $ sig1 |==| prev sig2         result      = evaluate predicate state     in result @@ -110,7 +114,7 @@ prop_stop = forAll (generateSignals @Int) $ \intSignals ->     let stopped     = stop (box (>100)) (first intSignals)         state       = prepend stopped $ flatten intSignals-        predicate   = Always $ Implies (Now ((Index First) |>| (Pure 100))) (Always $ Next (Now (Index (Previous First) |==| (Index First))))+        predicate   = G ((sig1 |>| pure 100) :=> (G $ X (prev sig1 |==| sig1)))         result      = evaluate predicate state     in result @@ -119,18 +123,26 @@ prop_zip = forAll (generateSignals @[Int, Int]) $ \intSignals ->     let s1          = zip (first intSignals) (second intSignals)         state       = prepend s1 $ flatten intSignals-        predicate   = Always $ Now ((fst' <$> (Index First)) |==| (Index Second)) `And` (Now ((snd' <$> (Index First)) |==| (Index Third)))+        predicate   = G $ ((fst' <$> sig1) |==| sig2) `And` ((snd' <$> sig1) |==| sig3)         result      = evaluate predicate state     in result +prop_zipWrong :: Property+prop_zipWrong = forAllShrink (generateSignals @[Int, Int]) shrinkHls $ \intSignals ->+    let s1          = zipWrong (first intSignals) (second intSignals)+        state       = prepend s1 $ flatten intSignals+        predicate   = G (tick3 :=> (sig3 |==| (snd' <$> sig1)))+        result      = evaluate predicate state+    in counterexample (show state) result+ prop_filter :: Property prop_filter = forAll (generateSignals @Int) $ \intSignals ->   let filtered      = filterM (box (>= 10)) (first intSignals)       state         = prepend filtered $ flatten intSignals-      predicate     = Always $ -            Implies (Now ((Index Second) |>=| Pure (10))) (Now ((Index First) |>=| (Pure (Just' 10))))+      predicate     = G $+            ((sig2 |>=| pure 10) :=> (sig1 |>=| pure (Just' 10)))             `And`-            Implies (Now ((Index Second) |<| Pure (10))) (Now ((Index First) |==| (Pure Nothing')))+            (sig2 |<| pure 10) :=> (sig1 |==| pure Nothing')       result        = evaluate predicate state   in result @@ -138,8 +150,9 @@ prop_triggerM = forAll (generateSignals @[Int, Int]) $ \intSignals ->   let triggered     = triggerM (box (*)) (first intSignals) (second intSignals)       state         = prepend triggered $ flatten intSignals-      predicate     = Always $ -            Implies (Now ((Ticked Second) |==| (Pure True))) ((Now ((Ticked First) |==| (Pure True))) `And` (Now ((fromMaybe' 0 <$> (Index First)) |==| ((Index Second) * (Index Third)))))+      predicate     = G +            tick2 :=> +            (tick1 `And` ((fromMaybe' 0 <$> sig1) |==| (sig2 * sig3)))       result        = evaluate predicate state   in result @@ -147,10 +160,7 @@ prop_parallel = forAllShrink (generateSignals @[Int, Int]) shrinkHls $ \intSignals ->     let paralleled  = parallel (first intSignals) (second intSignals)         state       = prepend paralleled $ flatten intSignals-        predicate   = Always $-            Implies (Now (Ticked Third)) (Now (Ticked First))-            `And`-            Implies (Now (Ticked Second)) (Now (Ticked First))+        predicate   = G $ (tick3 :=> tick1) `And`(tick2 :=> tick1)         result      = evaluate predicate state     in result @@ -158,10 +168,10 @@ prop_isStuttering = forAll (generateSignals @[Int, Int]) $ \intSignals ->     let stuttered   = stutter (first intSignals) (second intSignals)         state       = prepend stuttered $ flatten intSignals-        predicate   = Always $-            Implies (Now (Ticked First)) (Now (Index First |==| Index Second))+        predicate   = G $+            (tick1 :=> (sig1 |==| sig2))             `And`-            Next (Implies (And (Now (Ticked Third)) (Not (Now (Ticked Second)))) (Now (Index (Previous First) |==| Index First)))+            X ((tick3 `And` Not (tick2)) :=> (prev sig1 |==| sig1))         result      = evaluate predicate state     in result @@ -169,14 +179,14 @@ prop_functionIsMonotonic = forAll (generateSignals @Int) $ \intSignals ->     let mono        = monotonic (first intSignals)         state       = singletonH mono-        predicate   = Always $ Next (Now ((Index First) |>=| (Index (Previous First))))+        predicate   = G $ X (sig1 |>=| prev sig1)         result      = evaluate predicate state     in result  prop_singleSignalAlwaysTicks :: Property prop_singleSignalAlwaysTicks = forAllShrink (arbitrary :: Gen (Sig Int)) shrink $ \sig ->     let state       = singletonH sig-        predicate   = Always $ Now ((Ticked First) |==| (Pure True))+        predicate   = G tick1         result      = evaluate predicate state     in result @@ -187,14 +197,11 @@         (_ ::: ys)          = (scan (box (\n _ -> n + 1)) 0 (takeN (sigLength xs) mkSigZero)) :: Sig Int         zs                  = switchR xs (mapAwait (box (\b _ -> const b)) ys)         state               = prepend zs $ prependLater ys $ flatten intSignals-        predicate           = (Now ((Index First) |==| (Index Third)))-                                `Until`-                                (Now ((Ticked Second) |==| (Pure True)))+        predicate           = ((sig1 |==| sig3) `U`tick2)                                 `And` -                                ((Always $ Next -                                    (((Implies  (Not (Now (Ticked Second))) (Now ((Index (Previous First)) |==| (Index First))))))))-                                `Until`-                               (Next $ (Implies (Now (Ticked Second)) (Not (Now ((Index (Previous First)) |==| (Index First))))))+                                (G $ X (Not tick2 :=> (prev sig1 |==| sig1)))+                                `U`+                                 (X (tick2 :=> Not (prev sig1 |==| sig1)))         result              = evaluate predicate state     in counterexample (show state) result @@ -205,21 +212,19 @@         ggg                 = Delay (IntSet.fromList [1,2,3]) (\_ a -> const a)         zs                  = switchS xs ggg         state               = prepend zs $ prependLater ys $ flatten intSignals-        predicate           =(Now ((Index First) |==| (Index Third)))-                                `Until`-                                (Now ((Ticked Second) |==| (Pure True)))+        predicate           =(sig1 |==| sig3)+                                `U`+                                tick2                                 `And` -                                ((Always $ Next -                                    (((Implies  (Not (Now (Ticked Second))) (Now ((Index (Previous First)) |==| (Index First))))))))-                                `Until`-                               (Next $ (Implies (Now (Ticked Second)) (Not (Now ((Index (Previous First)) |==| (Index First))))))+                                (G $ X (Not tick2 :=> (prev sig1 |==| sig1)))+                                `U`(X (tick2 :=> Not (prev sig1 |==| sig1)))         result              = evaluate predicate state     in counterexample (show gg ++ show zs ++ show xs) result  prop_sigLength :: Property prop_sigLength = forAllShrink (arbitrary :: Gen (Sig Int)) shrink $ \(sig :: Sig Int) ->         let state       = singletonH (sig :: Sig Int)-            predicate   = Always $ (Now ((Index First) |<| (Pure 50)))+            predicate   = G (sig1 |<| pure 50)             result      = evaluate predicate state         in result @@ -227,14 +232,14 @@ prop_sigIsPositive = forAll (generateSignals @Int) $ \sig ->         let mapped      = map (box (abs)) (first sig)             state       = singletonH mapped-            predicate   = Next $ Always $ Now ((Index (Prior 1 First)) |>=| (Pure 0))+            predicate   = X $ G (prevN 1 sig1 |>=| pure 0)             result      = evaluate predicate state          in result  prop_catchsubtle :: Property prop_catchsubtle = forAllShrink (arbitrary :: Gen (Sig Int)) shrink $ \(sig :: Sig Int) ->         let state       = singletonH (sig :: Sig Int)-            predicate   = Always $ Implies (Now ((Index First) |>| (Pure 80))) (Next $ (Now ((Index First) |<| (Index (Previous First)))))+            predicate   = G ((sig1 |>| pure 80) :=> X (sig1 |<| (prev sig1)))             result      = evaluate predicate state         in result @@ -242,7 +247,7 @@ prop_predLengthOutsideDefault =  forAllShrink (generateSignals @Int) shrinkHls $ \intSignals ->     let prefixSum   = scan (box (+)) 0 (first intSignals)         state       = prepend prefixSum $ flatten intSignals-        predicate   = After 100 $ Always $ Now $ Index (Previous First) |<| (Index First)+        predicate   = XN 100 $ G (prev sig1 |<| sig1)         result      = evaluate predicate state     in result @@ -274,3 +279,5 @@     quickCheck (withMaxSuccess 1000 prop_catchsubtle)     putStrLn "====================="     quickCheck prop_predLengthOutsideDefault+    putStrLn "====================="+    quickCheck prop_zipWrong
examples/timer/Timer.hs view
@@ -17,10 +17,15 @@  {-# ANN module AllowLazyData #-} -{-# ANN everySecondSig AllowRecursion #-}-everySecondSig :: O (Sig ())-everySecondSig = Delay (IntSet.fromList [2]) (\_ -> () ::: everySecondSig)+{-# ANN everySig2Sig' AllowRecursion #-}+everySig2Sig' :: Int -> O (Sig ())+everySig2Sig' 0 = never+everySig2Sig' n = Delay (IntSet.fromList [2]) (\_ -> () ::: everySig2Sig' (n-1)) +everySig2Sig :: O (Sig ())+everySig2Sig = everySig2Sig' 100++ nats :: O (Sig ()) -> (Int :* Int) -> Sig (Int :* Int) nats later (n :* max) = stop     (box (\ (n' :* max') -> n' >= max'))@@ -38,15 +43,15 @@             currentMax  = current sliderSig             setMaxSig   = mapAwait (box setMax) ss             inputSig    = interleave (box (.)) resetSig setMaxSig-            inputSig'   = mapAwait (box ((nats everySecondSig) .)) inputSig-            counterSig  = switchR ((nats everySecondSig) (0 :* currentMax)) inputSig'+            inputSig'   = mapAwait (box ((nats everySig2Sig) .)) inputSig+            counterSig  = switchR ((nats everySig2Sig) (0 :* currentMax)) inputSig'     in counterSig  prop_counterSigAlwaysLessThanMax :: Property prop_counterSigAlwaysLessThanMax = forAll genDouble $ \(reset, slider) ->         let counterSig  = timerState reset slider             state       = prepend counterSig $ prepend reset $ singletonH slider-            predicate   = Always $ Now ((fst' <$> Index First) |<=| (snd' <$> Index First))+            predicate   = G ((fst' <$> sig1) |<=| (snd' <$> sig1))             result      = evaluate predicate state         in counterexample (show state) result   where@@ -59,7 +64,7 @@ prop_maxAlwaysEqualsMax = forAll genDouble $ \(reset, slider) ->         let counterSig  = timerState reset slider             state       = prepend counterSig $ prepend reset $ singletonH slider-            predicate   = Always $ Now ((Index Third) |==| (snd' <$> Index First))+            predicate   = G (sig3 |==| (snd' <$> sig1))             result      = evaluate predicate state         in counterexample (show state) result   where@@ -73,11 +78,11 @@ prop_concurrentResetAndSlider = forAll genDouble $ \(reset, slider) ->         let counterSig  = timerState reset slider             state       = prepend counterSig $ prepend reset $ singletonH slider-            predicate   = Always $ Implies-                (And (Now ((Ticked Second))) (Now ((Ticked Third))))-                ((Now (((Index Third)) |==| (snd' <$> Index First)))+            predicate   = G $ +                ((tick2 `And` tick3) :=>+                ((sig3 |==| (snd' <$> sig1))                 `And`-                (Now ((Pure 0) |==| (fst' <$> Index First))))+                (pure 0 |==| (fst' <$> sig1))))             result      = evaluate predicate state         in counterexample (show state) result   where@@ -86,14 +91,41 @@       reset <- (arbitrarySigWeighted 100 :: Gen (Sig (())))       return (reset, slider) +++prop_reset :: Property+prop_reset = forAll genDouble $ \(reset, slider) ->+        let counterSig  = timerState reset slider+            state       = prepend counterSig $ prepend reset $ singletonH slider+            predicate   = G (tick2 :=> (pure 0 |==| (fst' <$> sig1)))+            result      = evaluate predicate state+        in counterexample (show state) result+  where+    genDouble = do+      slider <- (arbitrarySigWith 100 (chooseInt (0, 100)) :: Gen (Sig Int))+      reset <- (arbitrarySigWeighted 100 :: Gen (Sig (())))+      return (reset, slider)++prop_max :: Property+prop_max = forAll genDouble $ \(reset, slider) ->+        let counterSig  = timerState reset slider+            state       = prepend counterSig $ prepend reset $ singletonH slider+            predicate   = G (sig3 |==| (snd' <$> sig1))+            result      = evaluate predicate state+        in counterexample (show state) result+  where+    genDouble = do+      slider <- (arbitrarySigWith 100 (chooseInt (0, 100)) :: Gen (Sig Int))+      reset <- (arbitrarySigWeighted 100 :: Gen (Sig (())))+      return (reset, slider)+ prop_timerIsStrictlyMonotonicallyIncreasing :: Property prop_timerIsStrictlyMonotonicallyIncreasing = forAll genDouble $ \(reset, slider) ->         let counterSig  = timerState reset slider             state       = prepend counterSig $ prepend reset $ singletonH slider-            predicate   = Always $ Next $-                Implies-                ((Now (Ticked First)) `And` ((Not (Now (Ticked Second)) `And` (Not (Now (Ticked Third))))))-                (Now (((fst' <$> (Index First)) |>| (fst' <$> (Index (Previous First))))))+            predicate   = G $ X+                ((tick1 `And` (Not tick2 `And` Not tick3)) :=>+                ((fst' <$> sig1) |>| (fst' <$> prev sig1)))             result      = evaluate predicate state         in counterexample (show state) result   where@@ -107,7 +139,7 @@ prop_init = forAll genDouble $ \(reset, slider) ->         let counterSig  = timerState reset slider             state       = prepend counterSig $ prepend reset $ singletonH slider-            predicate   = Now ((fst' <$> (Index First)) |==| (Pure 0)) `And` (Now ((snd' <$> (Index First)) |==| (Index Third)))+            predicate   = ((fst' <$> sig1) |==| pure 0) `And` ((snd' <$> sig1) |==| sig3)             result      = evaluate predicate state         in counterexample (show state) result   where@@ -121,12 +153,11 @@ prop_counterSigStaysAtMaxValue = forAllShrink genDouble shrink $ \(reset, slider) ->         let counterSig  = timerState reset slider             state       = prepend counterSig $ prepend reset $ singletonH slider-            predicate   = Always $-                Implies-                    (Now ((fst' <$> (Index First)) |==| (snd' <$> (Index First))))-                    (Next $ (Now ((fst' <$> (Index First)) |==| (fst' <$> (Index (Previous First))))-                    `Until`-                    ((Now (Ticked Second)) `Or` (Now (Ticked Third)))))+            predicate   = G $+                    (((fst' <$> sig1) |==| (snd' <$> sig1)) :=>+                    (X $ ((fst' <$> sig1) |==| (fst' <$> prev sig1))+                    `U`+                    (tick2 `Or` tick3)))             result      = evaluate predicate state         in counterexample (show state) result   where@@ -139,7 +170,7 @@ prop_counterSigAlwaysTicks = forAll genDouble $ \(reset, slider) ->         let counterSig  = timerState reset slider             state       = prepend counterSig $ prepend reset $ singletonH slider-            predicate   = Always $ Now (Ticked First) `And` (Next $ Now (Ticked First))+            predicate   = G (tick1 `And` X tick1)             result      = evaluate predicate state         in counterexample (show state) result   where@@ -148,6 +179,38 @@       reset <- (arbitrarySigWeighted 100 :: Gen (Sig (())))       return (reset, slider) +++-- the timer is constant unless a second passes or reset is pressed+prop_timerConst :: Property+prop_timerConst = forAllShrink genDouble shrink $ \(reset, slider) ->+        let counterSig  = timerState reset slider+            state       = prepend counterSig $ prepend reset $ prepend slider $ singletonH (() ::: everySig2Sig)+            predicate   = G (X ((Not tick2 `And` Not tick4) :=> ((fst' <$> prev sig1) |==| (fst' <$> sig1))))+            result      = evaluate predicate state+        in counterexample (show state) result+  where+    genDouble = do+      slider <- (arbitrarySigWith 100 (chooseInt (0, 100)) :: Gen (Sig Int))+      reset <- (arbitrarySigWeighted 100 :: Gen (Sig ()))+      return (reset, slider)++++-- the timer ticks unless it reached its maximum+prop_timerTicks :: Property+prop_timerTicks = forAllShrink genDouble shrink $ \(reset, slider) ->+        let counterSig  = timerState reset slider+            state       = prepend counterSig $ prepend reset $ prepend slider $ singletonH (() ::: everySig2Sig)+            predicate   = G ( ((snd' <$> sig1) |<| sig3 `And` X tick4)  :=> X ((snd' <$> sig1) |==| ((+1) . snd' <$> prev sig1)))+            result      = evaluate predicate state+        in counterexample (show state) result+  where+    genDouble = do+      slider <- (arbitrarySigWith 100 (chooseInt (0, 100)) :: Gen (Sig Int))+      reset <- (arbitrarySigWeighted 100 :: Gen (Sig ()))+      return (reset, slider)+ main :: IO () main = do     quickCheck prop_counterSigAlwaysLessThanMax@@ -157,3 +220,7 @@     quickCheck prop_init     quickCheck prop_counterSigStaysAtMaxValue     quickCheck prop_counterSigAlwaysTicks+    quickCheck prop_reset+    quickCheck prop_max+    quickCheck prop_timerConst+    quickCheck prop_timerTicks
src/PropRatt/Arbitrary.hs view
@@ -103,14 +103,17 @@ genClockChannelWeighted :: Gen Int genClockChannelWeighted = frequency [(1, pure 1), (1, pure 2), (50, pure 3)] -genClock :: Int -> Gen Clock-genClock n = case n of++genClock :: Gen Clock+genClock = do+  n <- chooseInt (1, 3)+  case n of     1 -> do       x <- chooseInt (1,3)       return (IntSet.fromList [x])-    2 -> frequency [(1, return (IntSet.fromList [1,2])),(1, return (IntSet.fromList [2,3])),(1, return (IntSet.fromList [1,3]))]+    2 -> elements $ map IntSet.fromList [[1,2], [2,3], [1,3]]     3 -> return (IntSet.fromList [1,2,3])-    _ -> error "Partial function doesnt support n > 3"+    _ -> error "genClock: impossible!"  genClockListWeighted :: Gen [Int] genClockListWeighted = vectorOf 1 genClockChannelWeighted@@ -128,8 +131,7 @@           return (x ::: never)         go m = do           x <- arbitrary-          len <- chooseInt (1, 3)-          cl <- genClock len+          cl <- genClock           xs <- go (m - 1)           let later = Delay cl (\_ -> xs)           return (x ::: later)@@ -147,8 +149,7 @@           return (x ::: never)         go m = do           x <- gen-          len <- chooseInt (1, 3)-          cl <- genClock len+          cl <- genClock           xs <- go (m - 1)           let later = Delay cl (\_ -> xs)           return (x ::: later)@@ -190,7 +191,7 @@   generateHList = do     x <- arbitrary     xs <- generateHList @ts-    return (x %: xs)+    return (x :% xs)  generateSignals :: forall a. HListGen (ToList a) => Gen (HList (Map Sig (ToList a))) generateSignals = generateHList @(ToList a)@@ -202,7 +203,7 @@   shrinkHls _ = []  instance (Arbitrary a, ShrinkHList as) => ShrinkHList (a ': as) where-  shrinkHls (HCons x xs) =-    [ HCons x' xs | x'  <- shrink x ] ++-    [ HCons x xs' | xs' <- shrinkHls xs ] ++-    [ HCons x' xs' | x'  <- shrink x, xs' <- shrinkHls xs ]+  shrinkHls (x :% xs) =+    [ x' :% xs | x'  <- shrink x ] +++    [ x :% xs' | xs' <- shrinkHls xs ] +++    [ x' :% xs' | x'  <- shrink x, xs' <- shrinkHls xs ]
src/PropRatt/Core.hs view
@@ -40,7 +40,7 @@  instance (Stable a, Stable (Value a), Flatten as bs, Falsify bs) => Flatten (Sig a ': as) (Value a ': bs) where   flatten :: HList (Sig a : as) -> Sig (HList (Value a : bs))-  flatten (HCons h t) = prepend h (flatten t)+  flatten (h :% t) = prepend h (flatten t)  class Falsify ts where   toFalse :: HList ts -> HList ts@@ -51,24 +51,24 @@  instance (Falsify ts) => Falsify (Value t ': ts) where   toFalse :: HList (Value t : ts) -> HList (Value t : ts)-  toFalse (HCons (Current _ x) t) = Current (HasTicked False) x %: toFalse t+  toFalse (Current _ x :% t) = Current (HasTick False) x :% toFalse t  -- | Like 'prepend', but the new head is delayed by one tick. --   This emits a dummy value at the head on the first tick, then behaves like 'prepend' on subsequent ticks. prependLater :: (Stable t, Stable (HList ts), Falsify ts) => O (Sig t) -> Sig (HList ts) -> Sig (HList (Value t ': ts)) prependLater xs (y ::: ys) =-  HCons (Current (HasTicked False) Nil) y ::: prependAwait Nil xs y ys+  (Current (HasTick False) Nil :% y) ::: prependAwait Nil xs y ys  prepend :: (Stable t, Stable (HList ts), Falsify ts) => Sig t -> Sig (HList ts) -> Sig (HList (Value t ': ts)) prepend (x ::: xs) (y ::: ys) =-  HCons (Current (HasTicked True) (x :! Nil)) y ::: prependAwait (x :! Nil) xs y ys+  (Current (HasTick True) (x :! Nil) :% y) ::: prependAwait (x :! Nil) xs y ys  prependAwait :: (Stable t, Stable hls, hls ~ HList ts, Falsify ts) => List t -> O (Sig t) -> hls -> O (Sig hls) -> O (Sig (HList (Value t ': ts))) prependAwait x xs y ys  = delay (   case select xs ys of-     Fst (x' ::: xs')   ys'         -> (Current (HasTicked True) (x' :! x) %: toFalse y)  ::: prependAwait (x' :! x) xs' y ys'-     Snd xs' (y' ::: ys')           -> (Current (HasTicked False) x %: y')                ::: prependAwait x xs' y' ys'-     Both (x' ::: xs') (y' ::: ys') -> (Current (HasTicked True) (x' :! x) %: y')         ::: prependAwait (x' :! x) xs' y' ys')+     Fst (x' ::: xs')   ys'         -> (Current (HasTick True) (x' :! x) :% toFalse y)  ::: prependAwait (x' :! x) xs' y ys'+     Snd xs' (y' ::: ys')           -> (Current (HasTick False) x :% y')                ::: prependAwait x xs' y' ys'+     Both (x' ::: xs') (y' ::: ys') -> (Current (HasTick True) (x' :! x) :% y')         ::: prependAwait (x' :! x) xs' y' ys')  singletonH :: (Stable t) => Sig t -> Sig (HList '[Value t])-singletonH sig = flatten (sig %: HNil)+singletonH sig = flatten (sig :% HNil)
src/PropRatt/HList.hs view
@@ -13,57 +13,55 @@ {-# OPTIONS_GHC -Wno-partial-type-signatures #-} {-# OPTIONS_GHC -Wno-redundant-constraints #-} -module PropRatt.HList (HList(..), (%:), first,second,third,fourth,fifth,sixth,seventh,eighth,ninth,lengthH) where       +module PropRatt.HList (HList(..), first,second,third,fourth,fifth,sixth,seventh,eighth,ninth,lengthH) where        import AsyncRattus.InternalPrimitives ( Stable ) import Data.Kind (Type)  data HList :: [Type] -> Type where   HNil :: HList '[]-  HCons :: !x -> !(HList xs) -> HList (x ': xs)+  (:%) :: !x -> !(HList xs) -> HList (x ': xs) -infixr 5 %:-(%:) :: x -> HList xs -> HList (x ': xs)-(%:) = HCons+infixr 5 :%  instance Show (HList '[]) where   show :: HList '[] -> String-  show HNil = "HNil"+  show HNil = "\n"  instance (Show x, (Show (HList xs))) => Show (HList (x ': xs)) where   show :: (Show x, Show (HList xs)) => HList (x : xs) -> String-  show (HCons x xs) = show x ++ " %: " ++ show xs+  show (x :% xs) = show x ++ "; " ++ show xs  instance Stable (HList '[]) where instance (Stable a, Stable (HList as)) => Stable (HList (a ': as)) where  first :: HList (a ': _) -> a-first (HCons h _) = h+first (v :% _) = v  second :: HList (_ ': a ': _) -> a-second (HCons _ (HCons h2 _)) = h2+second (_ :% v :% _) = v  third :: HList (_ ': _ ': a ': _) -> a-third (HCons _ (HCons _ (HCons h3 _))) = h3+third (_ :% _ :% v :% _) = v  fourth :: HList (_ ': _ ': _ ': a ': _) -> a-fourth (HCons _ (HCons _ (HCons _ (HCons h4 _)))) = h4+fourth (_ :% _ :% _ :% v :% _) = v  fifth :: HList (_ ': _ ': _ ': _ ': a ': _) -> a-fifth (HCons _ (HCons _ (HCons _ (HCons _ (HCons h5 _))))) = h5+fifth (_ :% _ :% _ :% _ :% v :% _) = v  sixth :: HList (_ ': _ ': _ ': _ ': _ ': a ': _) -> a-sixth (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons h6 _)))))) = h6+sixth (_ :% _ :% _ :% _ :% _ :% v :% _) = v  seventh :: HList (_ ':_ ': _ ': _ ': _ ': _ ': a ': _) -> a-seventh (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons h7 _))))))) = h7+seventh (_ :% _ :% _ :% _ :% _ :% _ :% v :% _) = v  eighth :: HList (_ ': _ ': _ ': _ ': _ ': _ ': _ ': a ': _) -> a-eighth (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons h8 _)))))))) = h8+eighth (_ :% _ :% _ :% _ :% _ :% _ :% _ :% v :% _) = v  ninth :: HList (_ ': _ ': _ ': _ ': _ ': _ ': _ ': _ ': a ': _) -> a-ninth (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons _ (HCons h9 _))))))))) = h9+ninth (_ :% _ :% _ :% _ :% _ :% _ :% _ :% _ :% v :% _) = v   lengthH :: HList ts -> Int -> Int lengthH HNil n = n-lengthH (HCons _ as) n = lengthH as (n+1)+lengthH (_ :% as) n = lengthH as (n+1)
src/PropRatt/LTL.hs view
@@ -19,6 +19,9 @@     (|>|),     (|>=|),     (|==|),+    tick1,tick2,tick3,tick4,+    sig1,sig2,sig3,sig4,+    prev, prevN   ) where @@ -32,53 +35,52 @@ import PropRatt.Utils  data Pred (ts :: [Type]) where-  Tautology     :: Pred ts-  Contradiction :: Pred ts-  Now           :: Expr ts Bool -> Pred ts-  Not           :: Pred ts -> Pred ts-  And           :: Pred ts -> Pred ts -> Pred ts-  Or            :: Pred ts -> Pred ts -> Pred ts-  Until         :: Pred ts -> Pred ts -> Pred ts-  Next          :: Pred ts -> Pred ts-  Implies       :: Pred ts -> Pred ts -> Pred ts-  Always        :: Pred ts -> Pred ts-  Eventually    :: Pred ts -> Pred ts-  After         :: Int -> Pred ts-> Pred ts-  Release       :: Pred ts -> Pred ts -> Pred ts+  TT    :: Pred ts+  FF    :: Pred ts+  Now   :: Expr ts Bool -> Pred ts+  Not   :: Pred ts -> Pred ts+  And   :: Pred ts -> Pred ts -> Pred ts+  Or    :: Pred ts -> Pred ts -> Pred ts+  U     :: Pred ts -> Pred ts -> Pred ts+  X     :: Pred ts -> Pred ts+  (:=>) :: Pred ts -> Pred ts -> Pred ts+  G     :: Pred ts -> Pred ts+  F     :: Pred ts -> Pred ts+  XN    :: Int -> Pred ts-> Pred ts+  R     :: Pred ts -> Pred ts -> Pred ts  data Expr (ts :: [Type]) (t :: Type) where-  Pure    :: t -> Expr ts t-  Apply   :: Expr ts (t -> r) -> Expr ts t -> Expr ts r-  Index   :: Lookup ts t -> Expr ts t-  Ticked  :: Lookup ts t -> Expr ts Bool+  Pure  :: t -> Expr ts t+  App   :: Expr ts (t -> r) -> Expr ts t -> Expr ts r+  Val   :: Lookup ts t -> Expr ts t+  Tick  :: Lookup ts t -> Expr ts Bool  data Lookup (ts :: [Type]) (t :: Type) where-  Previous  :: Lookup ts t -> Lookup ts t-  Prior     :: Int -> Lookup ts t -> Lookup ts t-  First     :: Lookup (Value t ': x) t-  Second    :: Lookup (x1 ': Value t ': x2) t-  Third     :: Lookup (x1 ': x2 ': Value t ': x3) t-  Fourth    :: Lookup (x1 ': x2 ': x3 ': Value t ': x4) t-  Fifth     :: Lookup (x1 ': x2 ': x3 ': x4 ': Value t ': x5) t-  Sixth     :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': Value t ': x6) t-  Seventh   :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': x6 ': Value t ': x7) t-  Eighth    :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': x6 ': x7 ': Value t ': x8) t-  Ninth     :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': x6 ': x7 ': x8 ': Value t ': x9) t+  Prev   :: Lookup ts t -> Lookup ts t+  PrevN  :: Int -> Lookup ts t -> Lookup ts t+  Sig1   :: Lookup (Value t ': x) t+  Sig2   :: Lookup (x1 ': Value t ': x2) t+  Sig3   :: Lookup (x1 ': x2 ': Value t ': x3) t+  Sig4   :: Lookup (x1 ': x2 ': x3 ': Value t ': x4) t+  Sig5   :: Lookup (x1 ': x2 ': x3 ': x4 ': Value t ': x5) t+  Sig6   :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': Value t ': x6) t+  Sig7   :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': x6 ': Value t ': x7) t+  Sig8   :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': x6 ': x7 ': Value t ': x8) t+  Sig9   :: Lookup (x1 ': x2 ': x3 ': x4 ': x5 ': x6 ': x7 ': x8 ': Value t ': x9) t  instance Functor (Expr ts) where   fmap :: (t -> r) -> Expr ts t -> Expr ts r   fmap f (Pure x)     = Pure (f x)-  fmap f (Apply g x)  = Apply (fmap (f .) g) x-  fmap f (Index lu)   = Apply (Pure f) (Index lu)-  fmap f (Ticked lu)  = Apply (Pure f) (Ticked lu)+  fmap f (App g x)  = App (fmap (f .) g) x+  fmap f (Val lu)   = App (Pure f) (Val lu)+  fmap f (Tick lu)  = App (Pure f) (Tick lu)  instance Applicative (Expr ts) where     pure :: t -> Expr ts t     pure = Pure     (<*>) :: Expr ts (t -> r) -> Expr ts t -> Expr ts r     Pure f <*> x = fmap f x-    Apply f g <*> x = Apply (Apply f g) x-    (<*>) _ _ = error "Expr: unsupported constructor for applicative application."+    f <*> x = App f x  instance Num t => Num (Expr ts t) where   (+) :: Expr ts t -> Expr ts t -> Expr ts t@@ -96,41 +98,78 @@   fromInteger :: Integer -> Expr ts t   fromInteger n = pure (fromInteger n) -(|<|) :: (Applicative f, Ord t) => f t -> f t -> f Bool-x |<| y = (<) <$> x <*> y-(|<=|) :: (Applicative f, Ord t) => f t -> f t -> f Bool-x |<=| y = (<=) <$> x <*> y-(|>|) :: (Applicative f, Ord t) => f t -> f t -> f Bool-x |>| y = (>) <$> x <*> y-(|>=|) :: (Applicative f, Ord t) => f t -> f t -> f Bool-x |>=| y = (>=) <$> x <*> y-(|==|) :: (Applicative f, Eq t) => f t -> f t -> f Bool-x |==| y = (==) <$> x <*> y+(|<|) :: Ord t => Expr ts t -> Expr ts t -> Pred ts+x |<| y = Now ((<) <$> x <*> y)+(|<=|) :: Ord t => Expr ts t -> Expr ts t -> Pred ts+x |<=| y = Now ((<=) <$> x <*> y)+(|>|) :: Ord t => Expr ts t -> Expr ts t -> Pred ts+x |>| y = Now ((>) <$> x <*> y)+(|>=|) :: Ord t => Expr ts t -> Expr ts t -> Pred ts+x |>=| y = Now ((>=) <$> x <*> y)+(|==|) :: Ord t => Expr ts t -> Expr ts t -> Pred ts+x |==| y = Now ((==) <$> x <*> y) --- | Checks whether the instances of "previous" is within scope of t "next" operator.+tick1 :: Pred (Value t ': ts)+tick1 = Now (Tick Sig1)++tick2 :: Pred (t1 ': Value t2 ': ts)+tick2 = Now (Tick Sig2)++tick3 :: Pred (t1 ': t2 ': Value t3 ': ts)+tick3 = Now (Tick Sig3)++tick4 :: Pred (t1 ': t2 ': t3 ': Value t4 ': ts)+tick4 = Now (Tick Sig4)+++sig1 :: Expr (Value t ': ts) t+sig1 = Val Sig1++sig2 :: Expr (t1 ': Value t2 ': ts) t2+sig2 = Val Sig2++sig3 :: Expr (t1 ': t2 ': Value t3 ': ts) t3+sig3 = Val Sig3++sig4 :: Expr (t1 ': t2 ': t3 ': Value t4 ': ts) t4+sig4 = Val Sig4++prev :: Expr ts t -> Expr ts t+prev (Pure x)   = Pure x+prev (App f x)  = App (prev f) (prev x)+prev (Val lu)   = Val (Prev lu)+prev (Tick lu)  = Tick (Prev lu)++prevN :: Int -> Expr ts t -> Expr ts t+prevN _ (Pure x)   = Pure x+prevN n (App f x)  = App (prevN n f) (prevN n x)+prevN n (Val lu)   = Val (PrevN n lu)+prevN n (Tick lu)  = Tick (PrevN n lu)++-- | Checks whether the instances of "previous" is within scope of t "X" operator. -- This prevents the evaluation from looking too far back in time. checkScope :: Pred ts -> Bool checkScope p = checkPred p 0  -- | Traverses the predicate supplied and exits early if it finds a subtree where the scope is negative.--- The scope is incremented for each next constructor, and decremented for each previous or prior constructor.+-- The scope is incremented for each X constructor, and decremented for each previous or prior constructor. checkPred :: Pred ts -> Int -> Bool checkPred predicate scope =   valid scope &&   case predicate of-    Tautology       -> valid scope-    Contradiction   -> valid scope-    Now expr        -> valid (checkExpr expr scope)-    Not p           -> checkPred p scope-    And p1 p2       -> checkPred p1 scope && checkPred p2 scope-    Or p1 p2        -> checkPred p1 scope || checkPred p2 scope-    Until p1 p2     -> checkPred p1 scope && checkPred p2 scope-    Next p          -> checkPred p (scope + 1)-    Implies p1 p2   -> checkPred p1 scope && checkPred p2 scope-    Release p1 p2   -> checkPred p1 scope && checkPred p2 scope-    Always p        -> checkPred p scope-    Eventually p    -> checkPred p scope-    After n p       -> checkPred p (scope + n)+    TT        -> valid scope+    FF        -> valid scope+    Now expr  -> valid (checkExpr expr scope)+    Not p     -> checkPred p scope+    And p1 p2 -> checkPred p1 scope && checkPred p2 scope+    Or p1 p2  -> checkPred p1 scope || checkPred p2 scope+    U p1 p2   -> checkPred p1 scope && checkPred p2 scope+    X p       -> checkPred p (scope + 1)+    p1 :=> p2 -> checkPred p1 scope && checkPred p2 scope+    R p1 p2   -> checkPred p1 scope && checkPred p2 scope+    G p       -> checkPred p scope+    F p       -> checkPred p scope+    XN n p    -> checkPred p (scope + n)   where     valid s = s >= 0 @@ -138,111 +177,111 @@ checkExpr :: Expr ts t -> Int -> Int checkExpr expr scope =   case expr of-    Pure _        -> scope-    Apply fun arg -> min (checkExpr fun scope) (checkExpr arg scope)-    Index lu      -> checkLookup lu scope-    Ticked lu     -> checkLookup lu scope+    Pure _      -> scope+    App fun arg -> min (checkExpr fun scope) (checkExpr arg scope)+    Val lu      -> checkLookup lu scope+    Tick lu     -> checkLookup lu scope  checkLookup :: Lookup ts t -> Int -> Int checkLookup lu scope =   case lu of-    Previous lu'  -> checkLookup lu' (scope - 1)-    Prior n lu'   -> checkLookup lu' (scope - n)-    _             -> scope+    Prev lu'    -> checkLookup lu' (scope - 1)+    PrevN n lu' -> checkLookup lu' (scope - n)+    _           -> scope  -- Returns the amount of signal elements needed to evaluate the predicate. minSigLengthForPred :: Pred ts -> Int -> Int minSigLengthForPred predicate acc =     case predicate of-      Not p           -> minSigLengthForPred p acc-      And p1 p2       -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc-      Or p1 p2        -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc-      Until p1 p2     -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc-      Next p          -> minSigLengthForPred p (acc + 1)-      Implies p1 p2   -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc-      Release p1 p2   -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc-      Always p        -> minSigLengthForPred p acc-      Eventually p    -> minSigLengthForPred p acc-      After n p       -> minSigLengthForPred p (acc + n)-      _               -> acc+      Not p     -> minSigLengthForPred p acc+      And p1 p2 -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc+      Or p1 p2  -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc+      U p1 p2   -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc+      X p       -> minSigLengthForPred p (acc + 1)+      p1 :=> p2 -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc+      R p1 p2   -> minSigLengthForPred p1 acc `max` minSigLengthForPred p2 acc+      G p       -> minSigLengthForPred p acc+      F p       -> minSigLengthForPred p acc+      XN n p    -> minSigLengthForPred p (acc + n)+      _         -> acc -nthPrevious :: Int -> Value t -> Maybe' (Value t)-nthPrevious n curr@(Current b history)+nthPrev :: Int -> Value t -> Maybe' (Value t)+nthPrev n curr@(Current b history)   | n <= 0    = Just' curr   | otherwise =       case history of-        _ :! xs -> nthPrevious (n - 1) (Current b xs)+        _ :! xs -> nthPrev (n - 1) (Current b xs)         Nil     -> Nothing' -evalTicked :: Lookup ts t -> HList ts -> Bool-evalTicked lu hls = case lu of-  Previous _ -> errorTickedPast-  Prior _ _  -> errorTickedPast-  First      -> extract $ first hls-  Second     -> extract $ second hls-  Third      -> extract $ third hls-  Fourth     -> extract $ fourth hls-  Fifth      -> extract $ fifth hls-  Sixth      -> extract $ sixth hls-  Seventh    -> extract $ seventh hls-  Eighth     -> extract $ eighth hls-  Ninth      -> extract $ ninth hls+evalTick :: Lookup ts t -> HList ts -> Bool+evalTick lu hls = case lu of+  Prev _    -> errorTickPast+  PrevN _ _ -> errorTickPast+  Sig1      -> extract $ first hls+  Sig2      -> extract $ second hls+  Sig3      -> extract $ third hls+  Sig4      -> extract $ fourth hls+  Sig5      -> extract $ fifth hls+  Sig6      -> extract $ sixth hls+  Sig7      -> extract $ seventh hls+  Sig8      -> extract $ eighth hls+  Sig9      -> extract $ ninth hls   where-    errorTickedPast                   = error "Cannot check if signal has ticked in the past."-    extract (Current (HasTicked b) _) = b+    errorTickPast                   = error "Cannot check if signal has ticked in the past."+    extract (Current (HasTick b) _) = b  evalExpr :: Expr ts t -> HList ts -> Expr ts t evalExpr (Pure x) _      = pure x-evalExpr (Apply f x) hls = (($) <$> evalExpr f hls) <*> evalExpr x hls-evalExpr (Index lu) hls  =+evalExpr (App f x) hls = (($) <$> evalExpr f hls) <*> evalExpr x hls+evalExpr (Val lu) hls  =   case evalLookup lu hls of     Just' (Current _ (h :! _)) -> pure h     Just' (Current _ Nil)      -> error "History not found for signal."     Nothing'                   -> error "Signal not found."-evalExpr (Ticked lu) hls = pure (evalTicked lu hls)+evalExpr (Tick lu) hls = pure (evalTick lu hls)  evalLookup :: Lookup ts t -> HList ts -> Maybe' (Value t) evalLookup lu hls = case lu of-  Previous lu' ->+  Prev lu' ->     case evalLookup lu' hls of       Just' (Current b history) ->         case history of           _ :! xs -> Just' (Current b xs)           Nil     -> Nothing'       Nothing' -> Nothing'-  Prior n lu'  -> case evalLookup lu' hls of-    Just' v  -> nthPrevious n v+  PrevN n lu'  -> case evalLookup lu' hls of+    Just' v  -> nthPrev n v     Nothing' -> Nothing'-  First         -> Just' (first hls)-  Second        -> Just' (second hls)-  Third         -> Just' (third hls)-  Fourth        -> Just' (fourth hls)-  Fifth         -> Just' (fifth hls)-  Sixth         -> Just' (sixth hls)-  Seventh       -> Just' (seventh hls)-  Eighth        -> Just' (eighth hls)-  Ninth         -> Just' (ninth hls)+  Sig1 -> Just' (first hls)+  Sig2 -> Just' (second hls)+  Sig3 -> Just' (third hls)+  Sig4 -> Just' (fourth hls)+  Sig5 -> Just' (fifth hls)+  Sig6 -> Just' (sixth hls)+  Sig7 -> Just' (seventh hls)+  Sig8 -> Just' (eighth hls)+  Sig9 -> Just' (ninth hls)  -- Evaluate a single timestep. Used exclusively for shrink cases. evaluateSingle  :: Int -> Pred ts -> Sig (HList ts) -> Bool evaluateSingle timestepsLeft formulae sig@(x ::: _) =   timestepsLeft <= 0 || case formulae of-            Tautology       -> True-            Contradiction   -> False+            TT -> True+            FF -> False             Now expr        ->               case evalExpr expr x of                 Pure b -> b                 _ -> error "Unexpected error during evaluation."-            Not phi         -> not (eval phi sig)-            And phi psi     -> eval phi sig && eval psi sig-            Or phi psi      -> eval phi sig || eval psi sig-            Until phi psi   -> eval psi sig || eval phi sig-            Next _          -> True-            Implies phi psi -> not (eval phi sig && not (eval psi sig))-            Always phi      -> eval phi sig-            Eventually phi  -> eval phi sig -            Release _ _     -> True -            After _ _       -> True+            Not phi     -> not (eval phi sig)+            And phi psi -> eval phi sig && eval psi sig+            Or phi psi  -> eval phi sig || eval psi sig+            U phi psi   -> eval psi sig || eval phi sig+            X _         -> True+            phi :=> psi -> not (eval phi sig && not (eval psi sig))+            G phi       -> eval phi sig+            F phi       -> eval phi sig +            R _ _       -> True +            XN _ _      -> True         where           eval = evaluateSingle timestepsLeft @@ -251,27 +290,27 @@   if IntSet.null cl     then evaluateSingle timestepsLeft formulae sig     else timestepsLeft <= 0 || case formulae of-            Tautology       -> True-            Contradiction   -> False-            Now expr        ->+            TT   -> True+            FF   -> False+            Now expr ->               case evalExpr expr x of                 Pure b -> b                 _ -> error "Unexpected error during evaluation."-            Not phi         -> not (eval phi sig)-            And phi psi     -> eval phi sig && eval psi sig-            Or phi psi      -> eval phi sig || eval psi sig-            Until phi psi   -> eval psi sig-                              || (eval phi sig && evaluateNext (phi `Until` psi) advance)-            Next phi        -> evaluateNext phi advance-            Implies phi psi -> not (eval phi sig && not (eval psi sig))-            Always phi      -> eval phi sig && evaluateNext (Always phi) advance-            Eventually phi  -> (eval phi sig || evaluateNext (Eventually phi) advance)+            Not phi     -> not (eval phi sig)+            And phi psi -> eval phi sig && eval psi sig+            Or phi psi  -> eval phi sig || eval psi sig+            U phi psi   -> eval psi sig+                              || (eval phi sig && evaluateX (phi `U` psi) advance)+            X phi       -> evaluateX phi advance+            phi :=> psi -> not (eval phi sig && not (eval psi sig))+            G phi       -> eval phi sig && evaluateX (G phi) advance+            F phi       -> (eval phi sig || evaluateX (F phi) advance)                                 && not (timestepsLeft == 1 && not (eval phi sig))-            Release phi psi -> (eval psi sig && eval phi sig)-                                || (eval psi sig && evaluateNext (phi `Until` psi) advance)-            After n phi     -> if n <= 0 then eval phi sig else evaluateNext (After (n - 1) phi) sig+            R phi psi   -> (eval psi sig && eval phi sig)+                                || (eval psi sig && evaluateX (phi `U` psi) advance)+            XN n phi    -> if n <= 0 then eval phi sig else evaluateX (XN (n - 1) phi) sig       where-        evaluateNext = evaluate' (timestepsLeft - 1)+        evaluateX = evaluate' (timestepsLeft - 1)         eval = evaluate' timestepsLeft         advance = f (InputValue (IntSet.findMin cl) ()) @@ -288,7 +327,7 @@       scopeOk   = checkScope p   in      if not scopeOk-      then error "Previous must be in scope of next" +      then error "Prev must be in scope of X"      else if min' > defaultTimeStepsToCheck       then error ("Cannot evaluate more than " ++ show defaultTimeStepsToCheck ++ " values.\n" ++ "Predicate requires " ++ show min' ++ " timesteps. Consider using evaluateWith (>= " ++ show min' ++ ")")     else
src/PropRatt/Value.hs view
@@ -6,16 +6,20 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ScopedTypeVariables, UndecidableInstances #-} -module PropRatt.Value (Value(..),pureVal,current, HasTicked(..)) where+module PropRatt.Value (Value(..),pureVal,current, HasTick(..)) where import AsyncRattus.Strict import AsyncRattus.Signal hiding (current) import PropRatt.Utils import AsyncRattus -newtype HasTicked = HasTicked Bool deriving Show+newtype HasTick = HasTick Bool +instance Show HasTick where+  show (HasTick True) = "!"+  show (HasTick False) = "_"+ data Value a where-  Current :: !HasTicked -> !(List a) -> Value a+  Current :: !HasTick -> !(List a) -> Value a  instance Stable (Value a) where  instance Num a => Num (Value a) where@@ -29,8 +33,7 @@  instance Show a => Show (Value a) where   show (Current t Nil) = show t-  show (Current _ (h :! Nil)) = show h-  show (Current _ (h :! h2 :! _)) =  show h ++ " " ++ show h2+  show (Current t (h :! _)) = show t ++ show h  instance Show a => Show (Sig [Value a]) where   show sig = "Sig [Value a]: " ++ show (toListOfLength 100 sig) ++ "..."@@ -42,7 +45,7 @@   v1 == v2 = current v1 == current v2  pureVal :: a -> Value a-pureVal x = Current (HasTicked False) (x :! Nil)+pureVal x = Current (HasTick False) (x :! Nil)  current :: Value a -> a current (Current _ (h :! _)) = h