algebraic-graphs-0.2: test/Algebra/Graph/Test/Arbitrary.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
-----------------------------------------------------------------------------
-- |
-- Module : Algebra.Graph.Test.Arbitrary
-- Copyright : (c) Andrey Mokhov 2016-2018
-- License : MIT (see the file LICENSE)
-- Maintainer : andrey.mokhov@gmail.com
-- Stability : experimental
--
-- Generators and orphan Arbitrary instances for various data types.
-----------------------------------------------------------------------------
module Algebra.Graph.Test.Arbitrary (
-- * Generators of arbitrary graph instances
arbitraryGraph, arbitraryRelation, arbitraryAdjacencyMap, arbitraryAdjacencyIntMap
) where
import Prelude ()
import Prelude.Compat
import Control.Monad
import Data.Tree
import Test.QuickCheck
import Algebra.Graph
import Algebra.Graph.AdjacencyMap.Internal
import Algebra.Graph.Export
import Algebra.Graph.Fold (Fold)
import Algebra.Graph.AdjacencyIntMap.Internal
import Algebra.Graph.Relation.Internal
import Algebra.Graph.Relation.InternalDerived
import qualified Algebra.Graph.AdjacencyMap as AdjacencyMap
import qualified Algebra.Graph.Class as C
import qualified Algebra.Graph.AdjacencyIntMap as AdjacencyIntMap
import qualified Algebra.Graph.NonEmpty as NE
import qualified Algebra.Graph.Relation as Relation
-- | Generate an arbitrary 'Graph' value of a specified size.
arbitraryGraph :: (C.Graph g, Arbitrary (C.Vertex g)) => Gen g
arbitraryGraph = sized expr
where
expr 0 = return C.empty
expr 1 = C.vertex <$> arbitrary
expr n = do
left <- choose (0, n)
oneof [ C.overlay <$> expr left <*> expr (n - left)
, C.connect <$> expr left <*> expr (n - left) ]
instance Arbitrary a => Arbitrary (Graph a) where
arbitrary = arbitraryGraph
shrink Empty = []
shrink (Vertex _) = [Empty]
shrink (Overlay x y) = [Empty, x, y]
++ [Overlay x' y' | (x', y') <- shrink (x, y) ]
shrink (Connect x y) = [Empty, x, y, Overlay x y]
++ [Connect x' y' | (x', y') <- shrink (x, y) ]
-- | Generate an arbitrary 'NonEmptyGraph' value of a specified size.
arbitraryNonEmptyGraph :: Arbitrary a => Gen (NE.NonEmptyGraph a)
arbitraryNonEmptyGraph = sized expr
where
expr 0 = NE.vertex <$> arbitrary -- can't generate non-empty graph of size 0
expr 1 = NE.vertex <$> arbitrary
expr n = do
left <- choose (1, n)
oneof [ NE.overlay <$> expr left <*> expr (n - left)
, NE.connect <$> expr left <*> expr (n - left) ]
instance Arbitrary a => Arbitrary (NE.NonEmptyGraph a) where
arbitrary = arbitraryNonEmptyGraph
shrink (NE.Vertex _) = []
shrink (NE.Overlay x y) = [x, y]
++ [NE.Overlay x' y' | (x', y') <- shrink (x, y) ]
shrink (NE.Connect x y) = [x, y, NE.Overlay x y]
++ [NE.Connect x' y' | (x', y') <- shrink (x, y) ]
-- | Generate an arbitrary 'Relation'.
arbitraryRelation :: (Arbitrary a, Ord a) => Gen (Relation a)
arbitraryRelation = Relation.stars <$> arbitrary
-- | Generate an arbitrary 'AdjacencyMap'. It is guaranteed that the
-- resulting adjacency map is 'consistent'.
arbitraryAdjacencyMap :: (Arbitrary a, Ord a) => Gen (AdjacencyMap a)
arbitraryAdjacencyMap = AdjacencyMap.stars <$> arbitrary
-- | Generate an arbitrary 'AdjacencyIntMap'. It is guaranteed that the
-- resulting adjacency map is 'consistent'.
arbitraryAdjacencyIntMap :: Gen AdjacencyIntMap
arbitraryAdjacencyIntMap = AdjacencyIntMap.stars <$> arbitrary
-- TODO: Implement a custom shrink method.
instance (Arbitrary a, Ord a) => Arbitrary (Relation a) where
arbitrary = arbitraryRelation
instance (Arbitrary a, Ord a) => Arbitrary (ReflexiveRelation a) where
arbitrary = ReflexiveRelation <$> arbitraryRelation
instance (Arbitrary a, Ord a) => Arbitrary (SymmetricRelation a) where
arbitrary = SymmetricRelation <$> arbitraryRelation
instance (Arbitrary a, Ord a) => Arbitrary (TransitiveRelation a) where
arbitrary = TransitiveRelation <$> arbitraryRelation
instance (Arbitrary a, Ord a) => Arbitrary (PreorderRelation a) where
arbitrary = PreorderRelation <$> arbitraryRelation
instance (Arbitrary a, Ord a) => Arbitrary (AdjacencyMap a) where
arbitrary = arbitraryAdjacencyMap
instance Arbitrary AdjacencyIntMap where
arbitrary = arbitraryAdjacencyIntMap
instance Arbitrary a => Arbitrary (Fold a) where
arbitrary = arbitraryGraph
instance Arbitrary a => Arbitrary (Tree a) where
arbitrary = sized go
where
go 0 = do
root <- arbitrary
return $ Node root []
go n = do
subTrees <- choose (0, n - 1)
let subSize = (n - 1) `div` subTrees
root <- arbitrary
children <- replicateM subTrees (go subSize)
return $ Node root children
instance Arbitrary s => Arbitrary (Doc s) where
arbitrary = (mconcat . map literal) <$> arbitrary