@@ -69,6 +69,7 @@ import Test.QuickCheck.StateModel.Variables
6969import Control.Concurrent
7070import Control.Monad.Identity
7171import Control.Arrow (first )
72+ import Data.Tree
7273
7374-- | The typeclass users implement to define a model against which to validate some implementation.
7475--
@@ -576,13 +577,6 @@ runActions
576577 => Actions state
577578 -> PropertyM m (Annotated state , Env )
578579runActions (Actions_ rejected (Smart _ actions)) = do
579- let bucket = \ n -> let (a, b) = go n in show a ++ " - " ++ show b
580- where
581- go n
582- | n < 100 = (d * 10 , d * 10 + 9 )
583- | otherwise = let (a, b) = go d in (a * 10 , b * 10 + 9 )
584- where
585- d = div n 10
586580 monitor $ tabulate " # of actions" [show $ bucket $ length actions]
587581 (finalState, env, names, polars) <- runSteps initialAnnotatedState [] actions
588582 monitor $ tabulate " Actions" names
@@ -592,6 +586,14 @@ runActions (Actions_ rejected (Smart _ actions)) = do
592586 tabulate " Actions rejected by precondition" rejected
593587 return (finalState, env)
594588
589+ bucket = \ n -> let (a, b) = go n in show a ++ " - " ++ show b
590+ where
591+ go n
592+ | n < 100 = (d * 10 , d * 10 + 9 )
593+ | otherwise = let (a, b) = go d in (a * 10 , b * 10 + 9 )
594+ where
595+ d = div n 10
596+
595597-- | Core function to execute a sequence of `Step` given some initial `Env`ironment and `Annotated`
596598-- state. Return the list of action names and polarities to work around
597599-- https://github.com/nick8325/quickcheck/issues/416 causing repeated calls to tabulate being slow.
@@ -727,7 +729,7 @@ genParActions = do
727729 -- The ~ works around a bug in ghc (https://gitlab.haskell.org/ghc/ghc/-/issues/22004) (which is not in all ghc versions ?!)
728730 as@ (~ (Actions steps)) <- QC. arbitrary
729731 split <- QC. choose (0 , length steps - 1 )
730- let (common, post) = splitAt split steps
732+ let (common, take 10 -> post) = splitAt split steps
731733 commonCtx = allVariables common
732734 (threadA, threadB) <- go post commonCtx commonCtx [] []
733735 return $ ParallelActions as threadA threadB
@@ -756,6 +758,7 @@ data TraceStep state m where
756758 -> TraceStep state m
757759
758760type Trace state m = [TraceStep state m ]
761+ type TraceTree state m = Tree (TraceStep state m )
759762
760763runTracing :: ( RunModelPar state m
761764 , e ~ Error state m
@@ -800,8 +803,9 @@ runParActions pas = do
800803 monitorTrace env trA
801804 monitor $ counterexample " -- Monitoring thread B"
802805 monitorTrace env trB
803- let ilvs = map (trC ++ ) $ interleavings trA trB
804- assert $ any (checkTrace initialAnnotatedState mempty ) ilvs
806+ let ilvs = interleavings trC trA trB
807+ monitor $ tabulate " TraceTree size" (map (bucket . length ) ilvs)
808+ assert $ null ilvs || any (checkTrace initialAnnotatedState mempty ) ilvs
805809 -- TODO: stats collection and cleanup
806810
807811monitorTrace :: forall state m . (StateModel state , RunModelPar state m )
@@ -814,9 +818,8 @@ monitorTrace env (TraceStep r v step : tr) = do
814818 env' | Right val <- r = (v :== val) : env
815819 | otherwise = env
816820
817- checkTrace :: forall state m . (StateModel state , RunModelPar state m ) => Annotated state -> Env -> Trace state m -> Bool
818- checkTrace _ _ [] = True
819- checkTrace s env (TraceStep r v (ActionWithPolarity a _) : tr) =
821+ checkTrace :: forall state m . (StateModel state , RunModelPar state m ) => Annotated state -> Env -> TraceTree state m -> Bool
822+ checkTrace s env (Node (TraceStep r v (ActionWithPolarity a _)) trs) =
820823 -- NOTE: we need to re-compute the polarity of `a` here because it may be that the failure can be explained,
821824 -- but only by the action failing when it was previous successful
822825 let act = actionWithPolarity s a
@@ -834,14 +837,17 @@ checkTrace s env (TraceStep r v (ActionWithPolarity a _) : tr) =
834837 (polarAction act)
835838 (lookUpVar env')
836839 r
837- in computePrecondition s act && checkPost && checkTrace s' env' tr
838-
839- interleavings :: [a ] -> [a ] -> [[a ]]
840- interleavings [] bs = [bs]
841- interleavings as [] = [as]
842- interleavings (a: as) (b: bs) =
843- map (a: ) (interleavings as (b: bs)) ++
844- map (b: ) (interleavings (a: as) bs)
840+ in computePrecondition s act && checkPost && (null trs || any (checkTrace s' env') trs)
841+
842+ interleavings :: [a ] -> [a ] -> [a ] -> [Tree a ]
843+ interleavings (p: ps) as bs = [Node p (interleavings ps as bs)]
844+ interleavings _ [] bs = spine bs
845+ interleavings _ as [] = spine as
846+ interleavings _ (a: as) (b: bs) = [Node a (interleavings [] as (b: bs)), Node b (interleavings [] (a: as) bs)]
847+
848+ spine :: [a ] -> [Tree a ]
849+ spine [] = []
850+ spine (x: xs) = [Node x (spine xs)]
845851
846852-- TODO:
847853-- - Decide how much of the old QCD interface we can afford to break
0 commit comments