packages feed

algebraic-graphs 0.2 → 0.3

raw patch · 47 files changed

+7626/−2450 lines, 47 filesdep +inspection-testingdep ~QuickCheckPVP ok

version bump matches the API change (PVP)

Dependencies added: inspection-testing

Dependency ranges changed: QuickCheck

API changes (from Hackage documentation)

- Algebra.Graph: adjacencyIntMap :: Graph Int -> IntMap IntSet
- Algebra.Graph: adjacencyMap :: Ord a => Graph a -> Map a (Set a)
- Algebra.Graph: instance Data.Foldable.Foldable Algebra.Graph.Graph
- Algebra.Graph: instance Data.Traversable.Traversable Algebra.Graph.Graph
- Algebra.Graph: vertexIntSet :: Graph Int -> IntSet
- Algebra.Graph.AdjacencyIntMap: dfs :: [Int] -> AdjacencyIntMap -> [Int]
- Algebra.Graph.AdjacencyIntMap: dfsForest :: AdjacencyIntMap -> Forest Int
- Algebra.Graph.AdjacencyIntMap: dfsForestFrom :: [Int] -> AdjacencyIntMap -> Forest Int
- Algebra.Graph.AdjacencyIntMap: isAcyclic :: AdjacencyIntMap -> Bool
- Algebra.Graph.AdjacencyIntMap: isDfsForestOf :: Forest Int -> AdjacencyIntMap -> Bool
- Algebra.Graph.AdjacencyIntMap: isTopSortOf :: [Int] -> AdjacencyIntMap -> Bool
- Algebra.Graph.AdjacencyIntMap: reachable :: Int -> AdjacencyIntMap -> [Int]
- Algebra.Graph.AdjacencyIntMap: topSort :: AdjacencyIntMap -> Maybe [Int]
- Algebra.Graph.AdjacencyIntMap.Internal: connect :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap
- Algebra.Graph.AdjacencyIntMap.Internal: empty :: AdjacencyIntMap
- Algebra.Graph.AdjacencyIntMap.Internal: fromAdjacencyIntSets :: [(Int, IntSet)] -> AdjacencyIntMap
- Algebra.Graph.AdjacencyIntMap.Internal: overlay :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap
- Algebra.Graph.AdjacencyIntMap.Internal: vertex :: Int -> AdjacencyIntMap
- Algebra.Graph.AdjacencyMap: dfs :: Ord a => [a] -> AdjacencyMap a -> [a]
- Algebra.Graph.AdjacencyMap: dfsForest :: Ord a => AdjacencyMap a -> Forest a
- Algebra.Graph.AdjacencyMap: dfsForestFrom :: Ord a => [a] -> AdjacencyMap a -> Forest a
- Algebra.Graph.AdjacencyMap: isAcyclic :: Ord a => AdjacencyMap a -> Bool
- Algebra.Graph.AdjacencyMap: isDfsForestOf :: Ord a => Forest a -> AdjacencyMap a -> Bool
- Algebra.Graph.AdjacencyMap: isTopSortOf :: Ord a => [a] -> AdjacencyMap a -> Bool
- Algebra.Graph.AdjacencyMap: reachable :: Ord a => a -> AdjacencyMap a -> [a]
- Algebra.Graph.AdjacencyMap: scc :: Ord a => AdjacencyMap a -> AdjacencyMap (Set a)
- Algebra.Graph.AdjacencyMap: topSort :: Ord a => AdjacencyMap a -> Maybe [a]
- Algebra.Graph.AdjacencyMap: vertexIntSet :: AdjacencyMap Int -> IntSet
- Algebra.Graph.AdjacencyMap.Internal: connect :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a
- Algebra.Graph.AdjacencyMap.Internal: empty :: AdjacencyMap a
- Algebra.Graph.AdjacencyMap.Internal: fromAdjacencySets :: Ord a => [(a, Set a)] -> AdjacencyMap a
- Algebra.Graph.AdjacencyMap.Internal: overlay :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a
- Algebra.Graph.AdjacencyMap.Internal: vertex :: a -> AdjacencyMap a
- Algebra.Graph.Class: instance Algebra.Graph.Class.Graph g => Algebra.Graph.Class.Graph (GHC.Base.Maybe g)
- Algebra.Graph.Class: instance Algebra.Graph.Class.Preorder g => Algebra.Graph.Class.Preorder (GHC.Base.Maybe g)
- Algebra.Graph.Class: instance Algebra.Graph.Class.Reflexive g => Algebra.Graph.Class.Reflexive (GHC.Base.Maybe g)
- Algebra.Graph.Class: instance Algebra.Graph.Class.Transitive g => Algebra.Graph.Class.Transitive (GHC.Base.Maybe g)
- Algebra.Graph.Class: instance Algebra.Graph.Class.Undirected g => Algebra.Graph.Class.Undirected (GHC.Base.Maybe g)
- Algebra.Graph.Class: starTranspose :: Graph g => Vertex g -> [Vertex g] -> g
- Algebra.Graph.Fold: instance Data.Foldable.Foldable Algebra.Graph.Fold.Fold
- Algebra.Graph.Fold: instance Data.Traversable.Traversable Algebra.Graph.Fold.Fold
- Algebra.Graph.Fold: vertexIntSet :: Fold Int -> IntSet
- Algebra.Graph.HigherKinded.Class: box :: Graph g => g a -> g b -> g (a, b)
- Algebra.Graph.HigherKinded.Class: hasVertex :: (Eq a, Graph g) => a -> g a -> Bool
- Algebra.Graph.HigherKinded.Class: isEmpty :: Graph g => g a -> Bool
- Algebra.Graph.HigherKinded.Class: starTranspose :: Graph g => a -> [a] -> g a
- Algebra.Graph.HigherKinded.Class: vertexCount :: (Ord a, Graph g) => g a -> Int
- Algebra.Graph.HigherKinded.Class: vertexIntSet :: Graph g => g Int -> IntSet
- Algebra.Graph.HigherKinded.Class: vertexList :: (Ord a, Graph g) => g a -> [a]
- Algebra.Graph.HigherKinded.Class: vertexSet :: (Ord a, Graph g) => g a -> Set a
- Algebra.Graph.Label: (/\) :: Dioid a => a -> a -> a
- Algebra.Graph.Label: (\/) :: Semilattice a => a -> a -> a
- Algebra.Graph.Label: Finite :: a -> Distance a
- Algebra.Graph.Label: Infinite :: Distance a
- Algebra.Graph.Label: class Semilattice a
- Algebra.Graph.Label: instance (GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Num.Num (Algebra.Graph.Label.Distance a)
- Algebra.Graph.Label: instance Algebra.Graph.Label.Dioid GHC.Types.Bool
- Algebra.Graph.Label: instance Algebra.Graph.Label.Semilattice GHC.Types.Bool
- Algebra.Graph.Label: instance GHC.Classes.Ord a => Algebra.Graph.Label.Semilattice (Algebra.Graph.Label.Distance a)
- Algebra.Graph.Label: instance GHC.Classes.Ord a => Algebra.Graph.Label.Semilattice (Data.Set.Internal.Set a)
- Algebra.Graph.Labelled: connectBy :: e -> Graph e a -> Graph e a -> Graph e a
- Algebra.Graph.Labelled: instance Algebra.Graph.Label.Dioid e => Algebra.Graph.Class.Graph (Algebra.Graph.Labelled.Graph e a)
- Algebra.Graph.Labelled: instance Data.Foldable.Foldable (Algebra.Graph.Labelled.Graph e)
- Algebra.Graph.Labelled: instance Data.Traversable.Traversable (Algebra.Graph.Labelled.Graph e)
- Algebra.Graph.NonEmpty: data NonEmptyGraph a
- Algebra.Graph.NonEmpty: instance Algebra.Graph.ToGraph.ToGraph (Algebra.Graph.NonEmpty.NonEmptyGraph a)
- Algebra.Graph.NonEmpty: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Algebra.Graph.NonEmpty.NonEmptyGraph a)
- Algebra.Graph.NonEmpty: instance Data.Foldable.Foldable Algebra.Graph.NonEmpty.NonEmptyGraph
- Algebra.Graph.NonEmpty: instance Data.Traversable.Traversable Algebra.Graph.NonEmpty.NonEmptyGraph
- Algebra.Graph.NonEmpty: instance GHC.Base.Applicative Algebra.Graph.NonEmpty.NonEmptyGraph
- Algebra.Graph.NonEmpty: instance GHC.Base.Functor Algebra.Graph.NonEmpty.NonEmptyGraph
- Algebra.Graph.NonEmpty: instance GHC.Base.Monad Algebra.Graph.NonEmpty.NonEmptyGraph
- Algebra.Graph.NonEmpty: instance GHC.Classes.Ord a => GHC.Classes.Eq (Algebra.Graph.NonEmpty.NonEmptyGraph a)
- Algebra.Graph.NonEmpty: instance GHC.Num.Num a => GHC.Num.Num (Algebra.Graph.NonEmpty.NonEmptyGraph a)
- Algebra.Graph.NonEmpty: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.NonEmpty.NonEmptyGraph a)
- Algebra.Graph.NonEmpty: toNonEmptyGraph :: Graph a -> Maybe (NonEmptyGraph a)
- Algebra.Graph.NonEmpty: vertexIntSet :: NonEmptyGraph Int -> IntSet
- Algebra.Graph.Relation: preorderClosure :: Ord a => Relation a -> Relation a
- Algebra.Graph.Relation: vertexIntSet :: Relation Int -> IntSet
+ Algebra.Graph: compose :: Ord a => Graph a -> Graph a -> Graph a
+ Algebra.Graph: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Context a)
+ Algebra.Graph: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Graph a)
+ Algebra.Graph: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.Context a)
+ Algebra.Graph.AdjacencyIntMap: closure :: AdjacencyIntMap -> AdjacencyIntMap
+ Algebra.Graph.AdjacencyIntMap: compose :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap
+ Algebra.Graph.AdjacencyIntMap: fromAdjacencyIntSets :: [(Int, IntSet)] -> AdjacencyIntMap
+ Algebra.Graph.AdjacencyIntMap: reflexiveClosure :: AdjacencyIntMap -> AdjacencyIntMap
+ Algebra.Graph.AdjacencyIntMap: symmetricClosure :: AdjacencyIntMap -> AdjacencyIntMap
+ Algebra.Graph.AdjacencyIntMap: transitiveClosure :: AdjacencyIntMap -> AdjacencyIntMap
+ Algebra.Graph.AdjacencyIntMap.Algorithm: dfs :: [Int] -> AdjacencyIntMap -> [Int]
+ Algebra.Graph.AdjacencyIntMap.Algorithm: dfsForest :: AdjacencyIntMap -> Forest Int
+ Algebra.Graph.AdjacencyIntMap.Algorithm: dfsForestFrom :: [Int] -> AdjacencyIntMap -> Forest Int
+ Algebra.Graph.AdjacencyIntMap.Algorithm: isAcyclic :: AdjacencyIntMap -> Bool
+ Algebra.Graph.AdjacencyIntMap.Algorithm: isDfsForestOf :: Forest Int -> AdjacencyIntMap -> Bool
+ Algebra.Graph.AdjacencyIntMap.Algorithm: isTopSortOf :: [Int] -> AdjacencyIntMap -> Bool
+ Algebra.Graph.AdjacencyIntMap.Algorithm: reachable :: Int -> AdjacencyIntMap -> [Int]
+ Algebra.Graph.AdjacencyIntMap.Algorithm: topSort :: AdjacencyIntMap -> Maybe [Int]
+ Algebra.Graph.AdjacencyIntMap.Internal: instance GHC.Classes.Ord Algebra.Graph.AdjacencyIntMap.Internal.AdjacencyIntMap
+ Algebra.Graph.AdjacencyMap: closure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.AdjacencyMap: compose :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.AdjacencyMap: fromAdjacencySets :: Ord a => [(a, Set a)] -> AdjacencyMap a
+ Algebra.Graph.AdjacencyMap: reflexiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.AdjacencyMap: symmetricClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.AdjacencyMap: transitiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.AdjacencyMap.Algorithm: dfs :: Ord a => [a] -> AdjacencyMap a -> [a]
+ Algebra.Graph.AdjacencyMap.Algorithm: dfsForest :: Ord a => AdjacencyMap a -> Forest a
+ Algebra.Graph.AdjacencyMap.Algorithm: dfsForestFrom :: Ord a => [a] -> AdjacencyMap a -> Forest a
+ Algebra.Graph.AdjacencyMap.Algorithm: isAcyclic :: Ord a => AdjacencyMap a -> Bool
+ Algebra.Graph.AdjacencyMap.Algorithm: isDfsForestOf :: Ord a => Forest a -> AdjacencyMap a -> Bool
+ Algebra.Graph.AdjacencyMap.Algorithm: isTopSortOf :: Ord a => [a] -> AdjacencyMap a -> Bool
+ Algebra.Graph.AdjacencyMap.Algorithm: reachable :: Ord a => a -> AdjacencyMap a -> [a]
+ Algebra.Graph.AdjacencyMap.Algorithm: scc :: Ord a => AdjacencyMap a -> AdjacencyMap (AdjacencyMap a)
+ Algebra.Graph.AdjacencyMap.Algorithm: topSort :: Ord a => AdjacencyMap a -> Maybe [a]
+ Algebra.Graph.AdjacencyMap.Internal: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.AdjacencyMap.Internal.AdjacencyMap a)
+ Algebra.Graph.AdjacencyMap.Internal: internalEdgeList :: Map a (Set a) -> [(a, a)]
+ Algebra.Graph.AdjacencyMap.Internal: referredToVertexSet :: Ord a => Map a (Set a) -> Set a
+ Algebra.Graph.Class: -- | The type of graph vertices.
+ Algebra.Graph.Class: instance (Algebra.Graph.Label.Dioid e, GHC.Classes.Eq e, GHC.Classes.Ord a) => Algebra.Graph.Class.Graph (Algebra.Graph.Labelled.AdjacencyMap.Internal.AdjacencyMap e a)
+ Algebra.Graph.Class: instance Algebra.Graph.Class.Graph g => Algebra.Graph.Class.Graph (GHC.Maybe.Maybe g)
+ Algebra.Graph.Class: instance Algebra.Graph.Class.Preorder g => Algebra.Graph.Class.Preorder (GHC.Maybe.Maybe g)
+ Algebra.Graph.Class: instance Algebra.Graph.Class.Reflexive g => Algebra.Graph.Class.Reflexive (GHC.Maybe.Maybe g)
+ Algebra.Graph.Class: instance Algebra.Graph.Class.Transitive g => Algebra.Graph.Class.Transitive (GHC.Maybe.Maybe g)
+ Algebra.Graph.Class: instance Algebra.Graph.Class.Undirected g => Algebra.Graph.Class.Undirected (GHC.Maybe.Maybe g)
+ Algebra.Graph.Class: instance Algebra.Graph.Label.Dioid e => Algebra.Graph.Class.Graph (Algebra.Graph.Labelled.Graph e a)
+ Algebra.Graph.Export: isEmpty :: Doc s -> Bool
+ Algebra.Graph.Fold: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Fold.Fold a)
+ Algebra.Graph.HigherKinded.Class: stars :: Graph g => [(a, [a])] -> g a
+ Algebra.Graph.Internal: maybeF :: (a -> b -> a) -> a -> Maybe b -> Maybe a
+ Algebra.Graph.Internal: setProduct :: Set a -> Set b -> Set (a, b)
+ Algebra.Graph.Internal: setProductWith :: Ord c => (a -> b -> c) -> Set a -> Set b -> Set c
+ Algebra.Graph.Label: (<+>) :: Semigroup a => a -> a -> a
+ Algebra.Graph.Label: (<.>) :: Semiring a => a -> a -> a
+ Algebra.Graph.Label: Optimum :: o -> a -> Optimum o a
+ Algebra.Graph.Label: PowerSet :: Set a -> PowerSet a
+ Algebra.Graph.Label: [getArgument] :: Optimum o a -> a
+ Algebra.Graph.Label: [getOptimum] :: Optimum o a -> o
+ Algebra.Graph.Label: [getPowerSet] :: PowerSet a -> Set a
+ Algebra.Graph.Label: capacity :: NonNegative a -> Capacity a
+ Algebra.Graph.Label: class (Monoid a, Semigroup a) => Semiring a
+ Algebra.Graph.Label: class Semiring a => StarSemiring a
+ Algebra.Graph.Label: count :: NonNegative a -> Count a
+ Algebra.Graph.Label: data Capacity a
+ Algebra.Graph.Label: data Count a
+ Algebra.Graph.Label: data Label a
+ Algebra.Graph.Label: data Minimum a
+ Algebra.Graph.Label: data NonNegative a
+ Algebra.Graph.Label: data Optimum o a
+ Algebra.Graph.Label: distance :: NonNegative a -> Distance a
+ Algebra.Graph.Label: finite :: (Num a, Ord a) => a -> Maybe (NonNegative a)
+ Algebra.Graph.Label: finiteWord :: Word -> NonNegative Word
+ Algebra.Graph.Label: getCapacity :: Capacity a -> NonNegative a
+ Algebra.Graph.Label: getCount :: Count a -> NonNegative a
+ Algebra.Graph.Label: getDistance :: Distance a -> NonNegative a
+ Algebra.Graph.Label: getFinite :: NonNegative a -> Maybe a
+ Algebra.Graph.Label: getMinimum :: Minimum a -> Maybe a
+ Algebra.Graph.Label: infinite :: NonNegative a
+ Algebra.Graph.Label: infixr 6 <+>
+ Algebra.Graph.Label: infixr 7 <.>
+ Algebra.Graph.Label: instance (GHC.Base.Monoid a, GHC.Classes.Ord a) => Algebra.Graph.Label.Dioid (Algebra.Graph.Label.PowerSet a)
+ Algebra.Graph.Label: instance (GHC.Base.Monoid a, GHC.Classes.Ord a) => Algebra.Graph.Label.Semiring (Algebra.Graph.Label.PowerSet a)
+ Algebra.Graph.Label: instance (GHC.Base.Monoid a, GHC.Classes.Ord a) => Algebra.Graph.Label.StarSemiring (Algebra.Graph.Label.PowerSet a)
+ Algebra.Graph.Label: instance (GHC.Classes.Eq o, Algebra.Graph.Label.Dioid a, Algebra.Graph.Label.Dioid o) => Algebra.Graph.Label.Dioid (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance (GHC.Classes.Eq o, Algebra.Graph.Label.Semiring a, Algebra.Graph.Label.Semiring o) => Algebra.Graph.Label.Semiring (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance (GHC.Classes.Eq o, Algebra.Graph.Label.StarSemiring a, Algebra.Graph.Label.StarSemiring o) => Algebra.Graph.Label.StarSemiring (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance (GHC.Classes.Eq o, GHC.Base.Monoid a, GHC.Base.Monoid o) => GHC.Base.Monoid (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance (GHC.Classes.Eq o, GHC.Base.Monoid a, GHC.Base.Monoid o) => GHC.Base.Semigroup (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance (GHC.Classes.Eq o, GHC.Classes.Eq a) => GHC.Classes.Eq (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance (GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Base.Monoid (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance (GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Base.Monoid (Algebra.Graph.Label.Distance a)
+ Algebra.Graph.Label: instance (GHC.Classes.Ord o, GHC.Classes.Ord a) => GHC.Classes.Ord (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Algebra.Graph.Label.Dioid (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Algebra.Graph.Label.Semiring (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Algebra.Graph.Label.Semiring (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Algebra.Graph.Label.Semiring (Algebra.Graph.Label.Distance a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Algebra.Graph.Label.StarSemiring (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Algebra.Graph.Label.StarSemiring (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => Algebra.Graph.Label.StarSemiring (Algebra.Graph.Label.Distance a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Base.Monoid (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Base.Semigroup (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Num.Num (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Num.Num (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Num.Num (Algebra.Graph.Label.Distance a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Num.Num (Algebra.Graph.Label.NonNegative a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Show.Show a) => GHC.Show.Show (Algebra.Graph.Label.Minimum a)
+ Algebra.Graph.Label: instance (GHC.Num.Num a, GHC.Show.Show a) => GHC.Show.Show (Algebra.Graph.Label.NonNegative a)
+ Algebra.Graph.Label: instance (GHC.Show.Show o, GHC.Show.Show a) => GHC.Show.Show (Algebra.Graph.Label.Optimum o a)
+ Algebra.Graph.Label: instance Algebra.Graph.Label.Dioid Data.Semigroup.Internal.Any
+ Algebra.Graph.Label: instance Algebra.Graph.Label.Semiring (Algebra.Graph.Label.Label a)
+ Algebra.Graph.Label: instance Algebra.Graph.Label.Semiring Data.Semigroup.Internal.Any
+ Algebra.Graph.Label: instance Algebra.Graph.Label.StarSemiring (Algebra.Graph.Label.Label a)
+ Algebra.Graph.Label: instance Algebra.Graph.Label.StarSemiring Data.Semigroup.Internal.Any
+ Algebra.Graph.Label: instance GHC.Base.Applicative Algebra.Graph.Label.Extended
+ Algebra.Graph.Label: instance GHC.Base.Applicative Algebra.Graph.Label.Minimum
+ Algebra.Graph.Label: instance GHC.Base.Applicative Algebra.Graph.Label.NonNegative
+ Algebra.Graph.Label: instance GHC.Base.Functor Algebra.Graph.Label.Extended
+ Algebra.Graph.Label: instance GHC.Base.Functor Algebra.Graph.Label.Label
+ Algebra.Graph.Label: instance GHC.Base.Functor Algebra.Graph.Label.Minimum
+ Algebra.Graph.Label: instance GHC.Base.Functor Algebra.Graph.Label.NonNegative
+ Algebra.Graph.Label: instance GHC.Base.Monad Algebra.Graph.Label.Extended
+ Algebra.Graph.Label: instance GHC.Base.Monad Algebra.Graph.Label.Minimum
+ Algebra.Graph.Label: instance GHC.Base.Monad Algebra.Graph.Label.NonNegative
+ Algebra.Graph.Label: instance GHC.Base.Monoid (Algebra.Graph.Label.Label a)
+ Algebra.Graph.Label: instance GHC.Base.Semigroup (Algebra.Graph.Label.Label a)
+ Algebra.Graph.Label: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Label.Extended a)
+ Algebra.Graph.Label: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Label.Minimum a)
+ Algebra.Graph.Label: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Label.NonNegative a)
+ Algebra.Graph.Label: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Label.PowerSet a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Base.Monoid (Algebra.Graph.Label.PowerSet a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Base.Semigroup (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Base.Semigroup (Algebra.Graph.Label.Distance a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Base.Semigroup (Algebra.Graph.Label.PowerSet a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Label.Extended a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Label.Minimum a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Label.NonNegative a)
+ Algebra.Graph.Label: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Label.PowerSet a)
+ Algebra.Graph.Label: instance GHC.Exts.IsList (Algebra.Graph.Label.Label a)
+ Algebra.Graph.Label: instance GHC.Exts.IsList a => GHC.Exts.IsList (Algebra.Graph.Label.Minimum a)
+ Algebra.Graph.Label: instance GHC.Num.Num a => GHC.Enum.Bounded (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance GHC.Num.Num a => GHC.Enum.Bounded (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance GHC.Num.Num a => GHC.Enum.Bounded (Algebra.Graph.Label.Distance a)
+ Algebra.Graph.Label: instance GHC.Num.Num a => GHC.Enum.Bounded (Algebra.Graph.Label.NonNegative a)
+ Algebra.Graph.Label: instance GHC.Num.Num a => GHC.Num.Num (Algebra.Graph.Label.Extended a)
+ Algebra.Graph.Label: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.Label.Capacity a)
+ Algebra.Graph.Label: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.Label.Count a)
+ Algebra.Graph.Label: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.Label.Extended a)
+ Algebra.Graph.Label: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.Label.Label a)
+ Algebra.Graph.Label: isZero :: Label a -> Bool
+ Algebra.Graph.Label: newtype PowerSet a
+ Algebra.Graph.Label: noMinimum :: Minimum a
+ Algebra.Graph.Label: star :: StarSemiring a => a -> a
+ Algebra.Graph.Label: type AllShortestPaths e a = Optimum (Distance e) (PowerSet (Path a))
+ Algebra.Graph.Label: type CountShortestPaths e a = Optimum (Distance e) (Count Integer)
+ Algebra.Graph.Label: type Path a = [(a, a)]
+ Algebra.Graph.Label: type RegularExpression a = Label a
+ Algebra.Graph.Label: type ShortestPath e a = Optimum (Distance e) (Minimum (Path a))
+ Algebra.Graph.Label: type WidestPath e a = Optimum (Capacity e) (Minimum (Path a))
+ Algebra.Graph.Label: unsafeFinite :: a -> NonNegative a
+ Algebra.Graph.Labelled: Context :: [(e, a)] -> [(e, a)] -> Context e a
+ Algebra.Graph.Labelled: [inputs] :: Context e a -> [(e, a)]
+ Algebra.Graph.Labelled: [outputs] :: Context e a -> [(e, a)]
+ Algebra.Graph.Labelled: closure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a
+ Algebra.Graph.Labelled: context :: (Eq e, Monoid e) => (a -> Bool) -> Graph e a -> Maybe (Context e a)
+ Algebra.Graph.Labelled: data Context e a
+ Algebra.Graph.Labelled: edgeList :: (Eq e, Monoid e, Ord a) => Graph e a -> [(e, a, a)]
+ Algebra.Graph.Labelled: edgeSet :: (Eq e, Monoid e, Ord a) => Graph e a -> Set (e, a, a)
+ Algebra.Graph.Labelled: edges :: Monoid e => [(e, a, a)] -> Graph e a
+ Algebra.Graph.Labelled: emap :: (e -> f) -> Graph e a -> Graph f a
+ Algebra.Graph.Labelled: foldg :: b -> (a -> b) -> (e -> b -> b -> b) -> Graph e a -> b
+ Algebra.Graph.Labelled: hasEdge :: (Eq e, Monoid e, Ord a) => a -> a -> Graph e a -> Bool
+ Algebra.Graph.Labelled: hasVertex :: Eq a => a -> Graph e a -> Bool
+ Algebra.Graph.Labelled: induce :: (a -> Bool) -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: instance (GHC.Classes.Eq e, GHC.Base.Monoid e, GHC.Classes.Ord a) => GHC.Classes.Eq (Algebra.Graph.Labelled.Graph e a)
+ Algebra.Graph.Labelled: instance (GHC.Classes.Eq e, GHC.Base.Monoid e, GHC.Classes.Ord a, GHC.Classes.Ord e) => GHC.Classes.Ord (Algebra.Graph.Labelled.Graph e a)
+ Algebra.Graph.Labelled: instance (GHC.Classes.Eq e, GHC.Classes.Eq a) => GHC.Classes.Eq (Algebra.Graph.Labelled.Context e a)
+ Algebra.Graph.Labelled: instance (GHC.Classes.Ord a, GHC.Num.Num a, Algebra.Graph.Label.Dioid e) => GHC.Num.Num (Algebra.Graph.Labelled.Graph e a)
+ Algebra.Graph.Labelled: instance (GHC.Show.Show e, GHC.Show.Show a) => GHC.Show.Show (Algebra.Graph.Labelled.Context e a)
+ Algebra.Graph.Labelled: isEmpty :: Graph e a -> Bool
+ Algebra.Graph.Labelled: isSubgraphOf :: (Eq e, Monoid e, Ord a) => Graph e a -> Graph e a -> Bool
+ Algebra.Graph.Labelled: overlays :: Monoid e => [Graph e a] -> Graph e a
+ Algebra.Graph.Labelled: reflexiveClosure :: (Ord a, Semiring e) => Graph e a -> Graph e a
+ Algebra.Graph.Labelled: removeEdge :: (Eq a, Eq e, Monoid e) => a -> a -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: removeVertex :: Eq a => a -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: replaceEdge :: (Eq e, Monoid e, Ord a) => e -> a -> a -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: replaceVertex :: Eq a => a -> a -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: size :: Graph e a -> Int
+ Algebra.Graph.Labelled: symmetricClosure :: Monoid e => Graph e a -> Graph e a
+ Algebra.Graph.Labelled: transitiveClosure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a
+ Algebra.Graph.Labelled: transpose :: Graph e a -> Graph e a
+ Algebra.Graph.Labelled: type Automaton a s = Graph (RegularExpression a) s
+ Algebra.Graph.Labelled: type Network e a = Graph (Distance e) a
+ Algebra.Graph.Labelled: vertexList :: Ord a => Graph e a -> [a]
+ Algebra.Graph.Labelled: vertexSet :: Ord a => Graph e a -> Set a
+ Algebra.Graph.Labelled: vertices :: Monoid e => [a] -> Graph e a
+ Algebra.Graph.Labelled.AdjacencyMap: (-<) :: a -> e -> (a, e)
+ Algebra.Graph.Labelled.AdjacencyMap: (>-) :: (Eq e, Monoid e, Ord a) => (a, e) -> a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: adjacencyMap :: AdjacencyMap e a -> Map a (Map a e)
+ Algebra.Graph.Labelled.AdjacencyMap: closure :: (Eq e, Ord a, StarSemiring e) => AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: connect :: (Eq e, Monoid e, Ord a) => e -> AdjacencyMap e a -> AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: data AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: edge :: (Eq e, Monoid e, Ord a) => e -> a -> a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: edgeCount :: AdjacencyMap e a -> Int
+ Algebra.Graph.Labelled.AdjacencyMap: edgeLabel :: (Monoid e, Ord a) => a -> a -> AdjacencyMap e a -> e
+ Algebra.Graph.Labelled.AdjacencyMap: edgeList :: AdjacencyMap e a -> [(e, a, a)]
+ Algebra.Graph.Labelled.AdjacencyMap: edgeSet :: (Eq a, Eq e) => AdjacencyMap e a -> Set (e, a, a)
+ Algebra.Graph.Labelled.AdjacencyMap: edges :: (Eq e, Monoid e, Ord a) => [(e, a, a)] -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: emap :: (Eq f, Monoid f) => (e -> f) -> AdjacencyMap e a -> AdjacencyMap f a
+ Algebra.Graph.Labelled.AdjacencyMap: empty :: AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: fromAdjacencyMaps :: (Eq e, Monoid e, Ord a) => [(a, Map a e)] -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: gmap :: (Eq e, Monoid e, Ord a, Ord b) => (a -> b) -> AdjacencyMap e a -> AdjacencyMap e b
+ Algebra.Graph.Labelled.AdjacencyMap: hasEdge :: Ord a => a -> a -> AdjacencyMap e a -> Bool
+ Algebra.Graph.Labelled.AdjacencyMap: hasVertex :: Ord a => a -> AdjacencyMap e a -> Bool
+ Algebra.Graph.Labelled.AdjacencyMap: induce :: (a -> Bool) -> AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: infixl 5 >-
+ Algebra.Graph.Labelled.AdjacencyMap: isEmpty :: AdjacencyMap e a -> Bool
+ Algebra.Graph.Labelled.AdjacencyMap: isSubgraphOf :: (Eq e, Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a -> Bool
+ Algebra.Graph.Labelled.AdjacencyMap: overlay :: (Eq e, Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: overlays :: (Eq e, Monoid e, Ord a) => [AdjacencyMap e a] -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: postSet :: Ord a => a -> AdjacencyMap e a -> Set a
+ Algebra.Graph.Labelled.AdjacencyMap: preSet :: Ord a => a -> AdjacencyMap e a -> Set a
+ Algebra.Graph.Labelled.AdjacencyMap: reflexiveClosure :: (Ord a, Semiring e) => AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: removeEdge :: Ord a => a -> a -> AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: removeVertex :: Ord a => a -> AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: replaceEdge :: (Eq e, Monoid e, Ord a) => e -> a -> a -> AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: replaceVertex :: (Eq e, Monoid e, Ord a) => a -> a -> AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: skeleton :: AdjacencyMap e a -> AdjacencyMap a
+ Algebra.Graph.Labelled.AdjacencyMap: symmetricClosure :: (Eq e, Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: transitiveClosure :: (Eq e, Ord a, StarSemiring e) => AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: transpose :: (Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: vertex :: a -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap: vertexCount :: AdjacencyMap e a -> Int
+ Algebra.Graph.Labelled.AdjacencyMap: vertexList :: AdjacencyMap e a -> [a]
+ Algebra.Graph.Labelled.AdjacencyMap: vertexSet :: AdjacencyMap e a -> Set a
+ Algebra.Graph.Labelled.AdjacencyMap: vertices :: Ord a => [a] -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: AM :: Map a (Map a e) -> AdjacencyMap e a
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: [adjacencyMap] :: AdjacencyMap e a -> Map a (Map a e)
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: consistent :: (Ord a, Eq e, Monoid e) => AdjacencyMap e a -> Bool
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: instance (Control.DeepSeq.NFData a, Control.DeepSeq.NFData e) => Control.DeepSeq.NFData (Algebra.Graph.Labelled.AdjacencyMap.Internal.AdjacencyMap e a)
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: instance (GHC.Classes.Eq a, GHC.Classes.Eq e) => GHC.Classes.Eq (Algebra.Graph.Labelled.AdjacencyMap.Internal.AdjacencyMap e a)
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: instance (GHC.Classes.Eq e, Algebra.Graph.Label.Dioid e, GHC.Num.Num a, GHC.Classes.Ord a) => GHC.Num.Num (Algebra.Graph.Labelled.AdjacencyMap.Internal.AdjacencyMap e a)
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: instance (GHC.Classes.Ord a, GHC.Show.Show a, GHC.Classes.Ord e, GHC.Show.Show e) => GHC.Show.Show (Algebra.Graph.Labelled.AdjacencyMap.Internal.AdjacencyMap e a)
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: instance (GHC.Classes.Ord e, GHC.Base.Monoid e, GHC.Classes.Ord a) => GHC.Classes.Ord (Algebra.Graph.Labelled.AdjacencyMap.Internal.AdjacencyMap e a)
+ Algebra.Graph.Labelled.AdjacencyMap.Internal: newtype AdjacencyMap e a
+ Algebra.Graph.Labelled.Example.Automaton: Cancel :: Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: Choice :: State
+ Algebra.Graph.Labelled.Example.Automaton: Coffee :: Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: Complete :: State
+ Algebra.Graph.Labelled.Example.Automaton: Pay :: Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: Payment :: State
+ Algebra.Graph.Labelled.Example.Automaton: Tea :: Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: coffeeTeaAutomaton :: Automaton Alphabet State
+ Algebra.Graph.Labelled.Example.Automaton: data Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: data State
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Classes.Eq Algebra.Graph.Labelled.Example.Automaton.Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Classes.Eq Algebra.Graph.Labelled.Example.Automaton.State
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Classes.Ord Algebra.Graph.Labelled.Example.Automaton.Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Classes.Ord Algebra.Graph.Labelled.Example.Automaton.State
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Enum.Bounded Algebra.Graph.Labelled.Example.Automaton.Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Enum.Bounded Algebra.Graph.Labelled.Example.Automaton.State
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Enum.Enum Algebra.Graph.Labelled.Example.Automaton.Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Enum.Enum Algebra.Graph.Labelled.Example.Automaton.State
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Show.Show Algebra.Graph.Labelled.Example.Automaton.Alphabet
+ Algebra.Graph.Labelled.Example.Automaton: instance GHC.Show.Show Algebra.Graph.Labelled.Example.Automaton.State
+ Algebra.Graph.Labelled.Example.Automaton: reachability :: Map State [State]
+ Algebra.Graph.Labelled.Example.Network: Aberdeen :: City
+ Algebra.Graph.Labelled.Example.Network: Edinburgh :: City
+ Algebra.Graph.Labelled.Example.Network: Glasgow :: City
+ Algebra.Graph.Labelled.Example.Network: London :: City
+ Algebra.Graph.Labelled.Example.Network: Newcastle :: City
+ Algebra.Graph.Labelled.Example.Network: data City
+ Algebra.Graph.Labelled.Example.Network: eastCoast :: Network JourneyTime City
+ Algebra.Graph.Labelled.Example.Network: instance GHC.Classes.Eq Algebra.Graph.Labelled.Example.Network.City
+ Algebra.Graph.Labelled.Example.Network: instance GHC.Classes.Ord Algebra.Graph.Labelled.Example.Network.City
+ Algebra.Graph.Labelled.Example.Network: instance GHC.Enum.Bounded Algebra.Graph.Labelled.Example.Network.City
+ Algebra.Graph.Labelled.Example.Network: instance GHC.Enum.Enum Algebra.Graph.Labelled.Example.Network.City
+ Algebra.Graph.Labelled.Example.Network: instance GHC.Show.Show Algebra.Graph.Labelled.Example.Network.City
+ Algebra.Graph.Labelled.Example.Network: network :: Network JourneyTime City
+ Algebra.Graph.Labelled.Example.Network: scotRail :: Network JourneyTime City
+ Algebra.Graph.Labelled.Example.Network: type JourneyTime = Int
+ Algebra.Graph.NonEmpty: data Graph a
+ Algebra.Graph.NonEmpty: instance Algebra.Graph.ToGraph.ToGraph (Algebra.Graph.NonEmpty.Graph a)
+ Algebra.Graph.NonEmpty: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Algebra.Graph.NonEmpty.Graph a)
+ Algebra.Graph.NonEmpty: instance GHC.Base.Applicative Algebra.Graph.NonEmpty.Graph
+ Algebra.Graph.NonEmpty: instance GHC.Base.Functor Algebra.Graph.NonEmpty.Graph
+ Algebra.Graph.NonEmpty: instance GHC.Base.Monad Algebra.Graph.NonEmpty.Graph
+ Algebra.Graph.NonEmpty: instance GHC.Classes.Ord a => GHC.Classes.Eq (Algebra.Graph.NonEmpty.Graph a)
+ Algebra.Graph.NonEmpty: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.NonEmpty.Graph a)
+ Algebra.Graph.NonEmpty: instance GHC.Num.Num a => GHC.Num.Num (Algebra.Graph.NonEmpty.Graph a)
+ Algebra.Graph.NonEmpty: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.NonEmpty.Graph a)
+ Algebra.Graph.NonEmpty: toNonEmpty :: Graph a -> Maybe (Graph a)
+ Algebra.Graph.NonEmpty.AdjacencyMap: biclique1 :: Ord a => NonEmpty a -> NonEmpty a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: circuit1 :: Ord a => NonEmpty a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: clique1 :: Ord a => NonEmpty a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: closure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: connect :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: connects1 :: Ord a => NonEmpty (AdjacencyMap a) -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: data AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: edge :: Ord a => a -> a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: edgeCount :: AdjacencyMap a -> Int
+ Algebra.Graph.NonEmpty.AdjacencyMap: edgeList :: AdjacencyMap a -> [(a, a)]
+ Algebra.Graph.NonEmpty.AdjacencyMap: edgeSet :: Ord a => AdjacencyMap a -> Set (a, a)
+ Algebra.Graph.NonEmpty.AdjacencyMap: edges1 :: Ord a => NonEmpty (a, a) -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: gmap :: (Ord a, Ord b) => (a -> b) -> AdjacencyMap a -> AdjacencyMap b
+ Algebra.Graph.NonEmpty.AdjacencyMap: hasEdge :: Ord a => a -> a -> AdjacencyMap a -> Bool
+ Algebra.Graph.NonEmpty.AdjacencyMap: hasVertex :: Ord a => a -> AdjacencyMap a -> Bool
+ Algebra.Graph.NonEmpty.AdjacencyMap: induce1 :: (a -> Bool) -> AdjacencyMap a -> Maybe (AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap: isSubgraphOf :: Ord a => AdjacencyMap a -> AdjacencyMap a -> Bool
+ Algebra.Graph.NonEmpty.AdjacencyMap: mergeVertices :: Ord a => (a -> Bool) -> a -> AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: overlay :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: overlays1 :: Ord a => NonEmpty (AdjacencyMap a) -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: path1 :: Ord a => NonEmpty a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: postSet :: Ord a => a -> AdjacencyMap a -> Set a
+ Algebra.Graph.NonEmpty.AdjacencyMap: preSet :: Ord a => a -> AdjacencyMap a -> Set a
+ Algebra.Graph.NonEmpty.AdjacencyMap: reflexiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: removeEdge :: Ord a => a -> a -> AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: removeVertex1 :: Ord a => a -> AdjacencyMap a -> Maybe (AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap: replaceVertex :: Ord a => a -> a -> AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: star :: Ord a => a -> [a] -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: stars1 :: Ord a => NonEmpty (a, [a]) -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: symmetricClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: toNonEmpty :: AdjacencyMap a -> Maybe (AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap: transitiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: transpose :: Ord a => AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: tree :: Ord a => Tree a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: vertex :: a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap: vertexCount :: AdjacencyMap a -> Int
+ Algebra.Graph.NonEmpty.AdjacencyMap: vertexList1 :: AdjacencyMap a -> NonEmpty a
+ Algebra.Graph.NonEmpty.AdjacencyMap: vertexSet :: AdjacencyMap a -> Set a
+ Algebra.Graph.NonEmpty.AdjacencyMap: vertices1 :: Ord a => NonEmpty a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: NAM :: AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: [am] :: AdjacencyMap a -> AdjacencyMap a
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: consistent :: Ord a => AdjacencyMap a -> Bool
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: instance (GHC.Classes.Ord a, GHC.Num.Num a) => GHC.Num.Num (Algebra.Graph.NonEmpty.AdjacencyMap.Internal.AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: instance (GHC.Classes.Ord a, GHC.Show.Show a) => GHC.Show.Show (Algebra.Graph.NonEmpty.AdjacencyMap.Internal.AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Algebra.Graph.NonEmpty.AdjacencyMap.Internal.AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.NonEmpty.AdjacencyMap.Internal.AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.NonEmpty.AdjacencyMap.Internal.AdjacencyMap a)
+ Algebra.Graph.NonEmpty.AdjacencyMap.Internal: newtype AdjacencyMap a
+ Algebra.Graph.Relation: closure :: Ord a => Relation a -> Relation a
+ Algebra.Graph.Relation.Internal: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Relation.Internal.Relation a)
+ Algebra.Graph.ToGraph: -- | The type of vertices of the resulting graph.
+ Algebra.Graph.ToGraph: instance (GHC.Classes.Eq e, GHC.Base.Monoid e, GHC.Classes.Ord a) => Algebra.Graph.ToGraph.ToGraph (Algebra.Graph.Labelled.AdjacencyMap.Internal.AdjacencyMap e a)
+ Algebra.Graph.ToGraph: instance (GHC.Classes.Eq e, GHC.Base.Monoid e, GHC.Classes.Ord a) => Algebra.Graph.ToGraph.ToGraph (Algebra.Graph.Labelled.Graph e a)
+ Algebra.Graph.ToGraph: instance GHC.Classes.Ord a => Algebra.Graph.ToGraph.ToGraph (Algebra.Graph.NonEmpty.AdjacencyMap.Internal.AdjacencyMap a)
- Algebra.Graph: Connect :: (Graph a) -> (Graph a) -> Graph a
+ Algebra.Graph: Connect :: Graph a -> Graph a -> Graph a
- Algebra.Graph: Overlay :: (Graph a) -> (Graph a) -> Graph a
+ Algebra.Graph: Overlay :: Graph a -> Graph a -> Graph a
- Algebra.Graph.AdjacencyMap: edgeSet :: Ord a => AdjacencyMap a -> Set (a, a)
+ Algebra.Graph.AdjacencyMap: edgeSet :: Eq a => AdjacencyMap a -> Set (a, a)
- Algebra.Graph.Export: (<+>) :: (Eq s, IsString s, Monoid s) => Doc s -> Doc s -> Doc s
+ Algebra.Graph.Export: (<+>) :: IsString s => Doc s -> Doc s -> Doc s
- Algebra.Graph.Export.Dot: Style :: s -> s -> [Attribute s] -> [Attribute s] -> [Attribute s] -> a -> s -> a -> [Attribute s] -> a -> a -> [Attribute s] -> Style a s
+ Algebra.Graph.Export.Dot: Style :: s -> [s] -> [Attribute s] -> [Attribute s] -> [Attribute s] -> (a -> s) -> (a -> [Attribute s]) -> (a -> a -> [Attribute s]) -> Style a s
- Algebra.Graph.Export.Dot: [preamble] :: Style a s -> s
+ Algebra.Graph.Export.Dot: [preamble] :: Style a s -> [s]
- Algebra.Graph.Export.Dot: export :: (IsString s, Monoid s, Eq s, Ord a, ToGraph g, ToVertex g ~ a) => Style a s -> g -> s
+ Algebra.Graph.Export.Dot: export :: (IsString s, Monoid s, Ord a, ToGraph g, ToVertex g ~ a) => Style a s -> g -> s
- Algebra.Graph.Export.Dot: exportAsIs :: (IsString s, Monoid s, Ord s, ToGraph g, ToVertex g ~ s) => g -> s
+ Algebra.Graph.Export.Dot: exportAsIs :: (IsString s, Monoid s, Ord (ToVertex g), ToGraph g, ToVertex g ~ s) => g -> s
- Algebra.Graph.Export.Dot: exportViaShow :: (IsString s, Monoid s, Eq s, ToGraph g, Ord (ToVertex g), Show (ToVertex g)) => g -> s
+ Algebra.Graph.Export.Dot: exportViaShow :: (IsString s, Monoid s, Ord (ToVertex g), Show (ToVertex g), ToGraph g) => g -> s
- Algebra.Graph.HigherKinded.Class: class (Traversable g, MonadPlus g) => Graph g
+ Algebra.Graph.HigherKinded.Class: class (MonadPlus g) => Graph g
- Algebra.Graph.Internal: List :: (Endo [a]) -> List a
+ Algebra.Graph.Internal: List :: Endo [a] -> List a
- Algebra.Graph.Label: class Semilattice a => Dioid a
+ Algebra.Graph.Label: class Semiring a => Dioid a
- Algebra.Graph.Label: one :: Dioid a => a
+ Algebra.Graph.Label: one :: Semiring a => a
- Algebra.Graph.Label: zero :: Semilattice a => a
+ Algebra.Graph.Label: zero :: Monoid a => a
- Algebra.Graph.Labelled: (-<) :: Graph e a -> e -> (Graph e a, e)
+ Algebra.Graph.Labelled: (-<) :: a -> e -> (a, e)
- Algebra.Graph.Labelled: (>-) :: (Graph e a, e) -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: (>-) :: (a, e) -> a -> Graph e a
- Algebra.Graph.Labelled: Connect :: e -> (Graph e a) -> (Graph e a) -> Graph e a
+ Algebra.Graph.Labelled: Connect :: e -> Graph e a -> Graph e a -> Graph e a
- Algebra.Graph.Labelled: connect :: Dioid e => Graph e a -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: connect :: e -> Graph e a -> Graph e a -> Graph e a
- Algebra.Graph.Labelled: edge :: Dioid e => a -> a -> Graph e a
+ Algebra.Graph.Labelled: edge :: e -> a -> a -> Graph e a
- Algebra.Graph.Labelled: edgeLabel :: (Eq a, Semilattice e) => a -> a -> Graph e a -> e
+ Algebra.Graph.Labelled: edgeLabel :: (Eq a, Monoid e) => a -> a -> Graph e a -> e
- Algebra.Graph.Labelled: overlay :: Semilattice e => Graph e a -> Graph e a -> Graph e a
+ Algebra.Graph.Labelled: overlay :: Monoid e => Graph e a -> Graph e a -> Graph e a
- Algebra.Graph.Labelled: type UnlabelledGraph a = Graph Bool a
+ Algebra.Graph.Labelled: type UnlabelledGraph a = Graph Any a
- Algebra.Graph.NonEmpty: (===) :: Eq a => NonEmptyGraph a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: (===) :: Eq a => Graph a -> Graph a -> Bool
- Algebra.Graph.NonEmpty: Connect :: (NonEmptyGraph a) -> (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: Connect :: Graph a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: Overlay :: (NonEmptyGraph a) -> (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: Overlay :: Graph a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: Vertex :: a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: Vertex :: a -> Graph a
- Algebra.Graph.NonEmpty: biclique1 :: NonEmpty a -> NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: biclique1 :: NonEmpty a -> NonEmpty a -> Graph a
- Algebra.Graph.NonEmpty: box :: NonEmptyGraph a -> NonEmptyGraph b -> NonEmptyGraph (a, b)
+ Algebra.Graph.NonEmpty: box :: Graph a -> Graph b -> Graph (a, b)
- Algebra.Graph.NonEmpty: circuit1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: circuit1 :: NonEmpty a -> Graph a
- Algebra.Graph.NonEmpty: clique1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: clique1 :: NonEmpty a -> Graph a
- Algebra.Graph.NonEmpty: connect :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: connect :: Graph a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: connects1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: connects1 :: NonEmpty (Graph a) -> Graph a
- Algebra.Graph.NonEmpty: edge :: a -> a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: edge :: a -> a -> Graph a
- Algebra.Graph.NonEmpty: edgeCount :: Ord a => NonEmptyGraph a -> Int
+ Algebra.Graph.NonEmpty: edgeCount :: Ord a => Graph a -> Int
- Algebra.Graph.NonEmpty: edgeList :: Ord a => NonEmptyGraph a -> [(a, a)]
+ Algebra.Graph.NonEmpty: edgeList :: Ord a => Graph a -> [(a, a)]
- Algebra.Graph.NonEmpty: edgeSet :: Ord a => NonEmptyGraph a -> Set (a, a)
+ Algebra.Graph.NonEmpty: edgeSet :: Ord a => Graph a -> Set (a, a)
- Algebra.Graph.NonEmpty: edges1 :: NonEmpty (a, a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: edges1 :: NonEmpty (a, a) -> Graph a
- Algebra.Graph.NonEmpty: foldg1 :: (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> NonEmptyGraph a -> b
+ Algebra.Graph.NonEmpty: foldg1 :: (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> b
- Algebra.Graph.NonEmpty: hasEdge :: Eq a => a -> a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: hasEdge :: Eq a => a -> a -> Graph a -> Bool
- Algebra.Graph.NonEmpty: hasVertex :: Eq a => a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: hasVertex :: Eq a => a -> Graph a -> Bool
- Algebra.Graph.NonEmpty: induce1 :: (a -> Bool) -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)
+ Algebra.Graph.NonEmpty: induce1 :: (a -> Bool) -> Graph a -> Maybe (Graph a)
- Algebra.Graph.NonEmpty: isSubgraphOf :: Ord a => NonEmptyGraph a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: isSubgraphOf :: Ord a => Graph a -> Graph a -> Bool
- Algebra.Graph.NonEmpty: mergeVertices :: (a -> Bool) -> a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: mergeVertices :: (a -> Bool) -> a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: mesh1 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)
+ Algebra.Graph.NonEmpty: mesh1 :: NonEmpty a -> NonEmpty b -> Graph (a, b)
- Algebra.Graph.NonEmpty: overlay :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: overlay :: Graph a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: overlay1 :: Graph a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: overlay1 :: Graph a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: overlays1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: overlays1 :: NonEmpty (Graph a) -> Graph a
- Algebra.Graph.NonEmpty: path1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: path1 :: NonEmpty a -> Graph a
- Algebra.Graph.NonEmpty: removeEdge :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: removeEdge :: Eq a => a -> a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: removeVertex1 :: Eq a => a -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)
+ Algebra.Graph.NonEmpty: removeVertex1 :: Eq a => a -> Graph a -> Maybe (Graph a)
- Algebra.Graph.NonEmpty: replaceVertex :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: replaceVertex :: Eq a => a -> a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: simplify :: Ord a => NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: simplify :: Ord a => Graph a -> Graph a
- Algebra.Graph.NonEmpty: size :: NonEmptyGraph a -> Int
+ Algebra.Graph.NonEmpty: size :: Graph a -> Int
- Algebra.Graph.NonEmpty: sparsify :: NonEmptyGraph a -> NonEmptyGraph (Either Int a)
+ Algebra.Graph.NonEmpty: sparsify :: Graph a -> Graph (Either Int a)
- Algebra.Graph.NonEmpty: splitVertex1 :: Eq a => a -> NonEmpty a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: splitVertex1 :: Eq a => a -> NonEmpty a -> Graph a -> Graph a
- Algebra.Graph.NonEmpty: star :: a -> [a] -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: star :: a -> [a] -> Graph a
- Algebra.Graph.NonEmpty: stars1 :: NonEmpty (a, [a]) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: stars1 :: NonEmpty (a, [a]) -> Graph a
- Algebra.Graph.NonEmpty: torus1 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)
+ Algebra.Graph.NonEmpty: torus1 :: NonEmpty a -> NonEmpty b -> Graph (a, b)
- Algebra.Graph.NonEmpty: transpose :: NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: transpose :: Graph a -> Graph a
- Algebra.Graph.NonEmpty: tree :: Tree a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: tree :: Tree a -> Graph a
- Algebra.Graph.NonEmpty: vertex :: a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: vertex :: a -> Graph a
- Algebra.Graph.NonEmpty: vertexCount :: Ord a => NonEmptyGraph a -> Int
+ Algebra.Graph.NonEmpty: vertexCount :: Ord a => Graph a -> Int
- Algebra.Graph.NonEmpty: vertexList1 :: Ord a => NonEmptyGraph a -> NonEmpty a
+ Algebra.Graph.NonEmpty: vertexList1 :: Ord a => Graph a -> NonEmpty a
- Algebra.Graph.NonEmpty: vertexSet :: Ord a => NonEmptyGraph a -> Set a
+ Algebra.Graph.NonEmpty: vertexSet :: Ord a => Graph a -> Set a
- Algebra.Graph.NonEmpty: vertices1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: vertices1 :: NonEmpty a -> Graph a
- Data.Graph.Typed: GraphKL :: Graph -> Vertex -> a -> a -> Maybe Vertex -> GraphKL a
+ Data.Graph.Typed: GraphKL :: Graph -> (Vertex -> a) -> (a -> Maybe Vertex) -> GraphKL a

Files

CHANGES.md view
@@ -1,5 +1,28 @@ # Change log
 
+## 0.3
+
+* #129: Add a testsuite for rewrite rules based on the `inspection-testing` library.
+* #63, #148: Add relational composition of algebraic graphs.
+* #139, #146: Add relational operations to adjacency maps.
+* #146: Rename `preorderClosure` to `closure`.
+* #146: Switch to left-to-right composition in `Relation.compose`.
+* #143: Allow newer QuickCheck.
+* #140, #142: Fix `Show` instances.
+* #128, #130: Modify the SCC algorithm to return non-empty graph components.
+* #130: Move adjacency map algorithms to separate modules.
+* #130: Export `fromAdjacencySets` and `fromAdjacencyIntSets`.
+* #138: Do not require `Eq` instance on the string type when exporting graphs.
+* #136: Rename `Algebra.Graph.NonEmpty.NonEmptyGraph` to `Algebra.Graph.NonEmpty.Graph`.
+* #136: Add `Algebra.Graph.NonEmpty.AdjacencyMap`.
+* #136: Remove `vertexIntSet` from the API of basic graph data types. Also
+        remove `Algebra.Graph.adjacencyMap` and `Algebra.Graph.adjacencyIntMap`.
+        This functionality is still available from the type class `ToGraph`.
+* #126, #131: Implement custom `Ord` instance.
+* #17, #122, #125, #149: Add labelled algebraic graphs.
+* #121: Drop `Foldable` and `Traversable` instances.
+* #113: Add `Labelled.AdjacencyMap`.
+
 ## 0.2
 
 * #117: Add `sparsify`.
README.md view
@@ -54,6 +54,18 @@ To represent *non-empty graphs*, we can drop the `Empty` constructor -- see module [Algebra.Graph.NonEmpty](http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-NonEmpty.html). +To represent *edge-labelled graphs*, we can switch to the following data type, as+explained in my [Haskell eXchange 2018 talk](https://skillsmatter.com/skillscasts/12361-labelled-algebraic-graphs):++```haskell+data Graph e a = Empty+               | Vertex a+               | Connect e (Graph e a) (Graph e a)+```++Here `e` is the type of edge labels. If `e` is a monoid `(<+>, zero)` then graph overlay can be recovered+as `Connect zero`, and `<+>` corresponds to *parallel composition* of edge labels.+ ## How fast is the library?  Alga can handle graphs comprising millions of vertices and billions of edges in a matter of seconds, which is fast@@ -69,3 +81,8 @@ * A few different flavours of the algebra: https://blogs.ncl.ac.uk/andreymokhov/graphs-a-la-carte/ * Graphs in disguise or How to plan you holiday using Haskell: https://blogs.ncl.ac.uk/andreymokhov/graphs-in-disguise/ * Old graphs from new types: https://blogs.ncl.ac.uk/andreymokhov/old-graphs-from-new-types/++## Algebraic graphs in other languages++See draft implementations in [Agda](http://github.com/algebraic-graphs/agda)+and [Scala](http://github.com/algebraic-graphs/scala).
algebraic-graphs.cabal view
@@ -1,5 +1,5 @@ name:          algebraic-graphs-version:       0.2+version:       0.3 synopsis:      A library for algebraic graph construction and transformation license:       MIT license-file:  LICENSE@@ -25,24 +25,34 @@     .     The top-level module     <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph.html Algebra.Graph>-    defines the core data type+    defines the main data type for /algebraic graphs/     <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph.html#t:Graph Graph>,-    which is a deep embedding of four graph construction primitives /empty/,-    /vertex/, /overlay/ and /connect/. To represent non-empty graphs, see+    as well as associated algorithms. For type-safe representation and+    manipulation of /non-empty algebraic graphs/, see     <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-NonEmpty.html Algebra.Graph.NonEmpty>.-    More conventional graph representations can be found in+    Furthermore, /algebraic graphs with edge labels/ are implemented in+    <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-Labelled.html Algebra.Graph.Labelled>.+    .+    The library also provides conventional graph data structures, such as     <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-AdjacencyMap.html Algebra.Graph.AdjacencyMap>-    and-    <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-Relation.html Algebra.Graph.Relation>.+    along with its various flavours: adjacency maps specialised to graphs with+    vertices of type 'Int'+    (<http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-AdjacencyIntMap.html Algebra.Graph.AdjacencyIntMap>),+    non-empty adjacency maps+    (<http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-NonEmpty-AdjacencyMap.html Algebra.Graph.NonEmpty.AdjacencyMap>),+    and adjacency maps with edge labels+    (<http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-Labelled-AdjacencyMap.html Algebra.Graph.Labelled.AdjacencyMap>).+    A large part of the API of algebraic graphs and adjacency maps is available+    through the 'Foldable'-like type class+    <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-ToGraph.html Algebra.Graph.ToGraph>.     .     The type classes defined in     <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-Class.html Algebra.Graph.Class>     and     <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-HigherKinded-Class.html Algebra.Graph.HigherKinded.Class>-    can be used for polymorphic graph construction and manipulation. Also see+    can be used for polymorphic construction and manipulation of graphs. Also see     <http://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-Fold.html Algebra.Graph.Fold>-    that defines the Boehm-Berarducci encoding of algebraic graphs and provides additional-    flexibility for polymorphic graph manipulation.+    that defines the Boehm-Berarducci encoding of algebraic graphs.     .     This is an experimental library and the API is expected to remain unstable until version 1.0.0.     Please consider contributing to the on-going@@ -59,19 +69,27 @@ library     hs-source-dirs:     src     exposed-modules:    Algebra.Graph,+                        Algebra.Graph.AdjacencyIntMap,+                        Algebra.Graph.AdjacencyIntMap.Algorithm,+                        Algebra.Graph.AdjacencyIntMap.Internal,                         Algebra.Graph.AdjacencyMap,+                        Algebra.Graph.AdjacencyMap.Algorithm,                         Algebra.Graph.AdjacencyMap.Internal,                         Algebra.Graph.Class,                         Algebra.Graph.Export,                         Algebra.Graph.Export.Dot,                         Algebra.Graph.Fold,                         Algebra.Graph.HigherKinded.Class,-                        Algebra.Graph.AdjacencyIntMap,-                        Algebra.Graph.AdjacencyIntMap.Internal,                         Algebra.Graph.Internal,                         Algebra.Graph.Label,                         Algebra.Graph.Labelled,+                        Algebra.Graph.Labelled.AdjacencyMap,+                        Algebra.Graph.Labelled.AdjacencyMap.Internal,+                        Algebra.Graph.Labelled.Example.Automaton,+                        Algebra.Graph.Labelled.Example.Network,                         Algebra.Graph.NonEmpty,+                        Algebra.Graph.NonEmpty.AdjacencyMap,+                        Algebra.Graph.NonEmpty.AdjacencyMap.Internal,                         Algebra.Graph.Relation,                         Algebra.Graph.Relation.Internal,                         Algebra.Graph.Relation.InternalDerived,@@ -91,18 +109,18 @@         build-depends:  semigroups  >= 0.18.3  && < 0.18.4     default-language:   Haskell2010     default-extensions: FlexibleContexts+                        FlexibleInstances                         GeneralizedNewtypeDeriving                         ScopedTypeVariables                         TupleSections                         TypeFamilies     other-extensions:   CPP-                        DeriveFoldable                         DeriveFunctor-                        DeriveTraversable                         OverloadedStrings                         RecordWildCards     GHC-options:        -Wall                         -fno-warn-name-shadowing+                        -fspec-constr     if impl(ghc >= 8.0)         GHC-options:    -Wcompat                         -Wincomplete-record-updates@@ -115,17 +133,22 @@     main-is:            Main.hs     other-modules:      Algebra.Graph.Test,                         Algebra.Graph.Test.API,+                        Algebra.Graph.Test.AdjacencyIntMap,                         Algebra.Graph.Test.AdjacencyMap,                         Algebra.Graph.Test.Arbitrary,                         Algebra.Graph.Test.Export,                         Algebra.Graph.Test.Fold,                         Algebra.Graph.Test.Generic,                         Algebra.Graph.Test.Graph,-                        Algebra.Graph.Test.AdjacencyIntMap,                         Algebra.Graph.Test.Internal,-                        Algebra.Graph.Test.NonEmptyGraph,+                        Algebra.Graph.Test.Labelled.AdjacencyMap,+                        Algebra.Graph.Test.Labelled.Graph,+                        Algebra.Graph.Test.NonEmpty.AdjacencyMap,+                        Algebra.Graph.Test.NonEmpty.Graph,                         Algebra.Graph.Test.Relation,                         Data.Graph.Test.Typed+    if impl(ghc >= 8.0.2)+        other-modules:  Algebra.Graph.Test.RewriteRules     build-depends:      algebraic-graphs,                         array        >= 0.4     && < 0.6,                         base         >= 4.7     && < 5,@@ -133,21 +156,27 @@                         base-orphans >= 0.5.4   && < 0.9,                         containers   >= 0.5.5.1 && < 0.8,                         extra        >= 1.5     && < 2,-                        QuickCheck   >= 2.9     && < 2.12+                        QuickCheck   >= 2.9     && < 2.13     if !impl(ghc >= 8.0)         build-depends:  semigroups   >= 0.18.3  && < 0.18.4+    if impl(ghc >= 8.0.2)+        build-depends:  inspection-testing >= 0.4 && < 0.5+     default-language:   Haskell2010     GHC-options:        -Wall                         -fno-warn-name-shadowing+                        -fspec-constr     if impl(ghc >= 8.0)         GHC-options:    -Wcompat                         -Wincomplete-record-updates                         -Wincomplete-uni-patterns                         -Wredundant-constraints     default-extensions: FlexibleContexts+                        FlexibleInstances                         GeneralizedNewtypeDeriving-                        TypeFamilies                         ScopedTypeVariables+                        TupleSections+                        TypeFamilies     other-extensions:   ConstrainedClassMethods                         ConstraintKinds                         RankNTypes
src/Algebra/Graph.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+{-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph@@ -33,8 +33,7 @@      -- * Graph properties     isEmpty, size, hasVertex, hasEdge, vertexCount, edgeCount, vertexList,-    edgeList, vertexSet, vertexIntSet, edgeSet, adjacencyList, adjacencyMap,-    adjacencyIntMap,+    edgeList, vertexSet, edgeSet, adjacencyList,      -- * Standard families of graphs     path, circuit, clique, biclique, star, stars, tree, forest, mesh, torus,@@ -45,14 +44,14 @@     transpose, induce, simplify, sparsify,      -- * Graph composition-    box,+    compose, box,      -- * Context     Context (..), context-  ) where+    ) where  import Prelude ()-import Prelude.Compat+import Prelude.Compat hiding ((<>))  import Control.Applicative (Alternative) import Control.DeepSeq (NFData (..))@@ -60,15 +59,11 @@ import Control.Monad.State (runState, get, put) import Data.Foldable (toList) import Data.Maybe (fromMaybe)+import Data.Monoid ((<>)) import Data.Tree  import Algebra.Graph.Internal -import Data.IntMap (IntMap)-import Data.IntSet (IntSet)-import Data.Map    (Map)-import Data.Set    (Set)- import qualified Algebra.Graph.AdjacencyMap    as AM import qualified Algebra.Graph.AdjacencyIntMap as AIM import qualified Control.Applicative           as Ap@@ -86,6 +81,14 @@     > 1 + 2 * 3   == Overlay (Vertex 1) (Connect (Vertex 2) (Vertex 3))     > 1 * (2 + 3) == Connect (Vertex 1) (Overlay (Vertex 2) (Vertex 3)) +__Note:__ the 'Num' instance does not satisfy several "customary laws" of 'Num',+which dictate that 'fromInteger' @0@ and 'fromInteger' @1@ should act as+additive and multiplicative identities, and 'negate' as additive inverse.+Nevertheless, overloading 'fromInteger', '+' and '*' is very convenient when+working with algebraic graphs; we hope that in future Haskell's Prelude will+provide a more fine-grained class hierarchy for algebraic structures, which we+would be able to utilise without violating any laws.+ The 'Eq' instance is currently implemented using the 'AM.AdjacencyMap' as the /canonical graph representation/ and satisfies all axioms of algebraic graphs: @@ -132,37 +135,96 @@ m == 'edgeCount' g s == 'size' g@ -Note that 'size' is slightly different from the 'length' method of the-'Foldable' type class, as the latter does not count 'empty' leaves of the-expression:--@'length' 'empty'           == 0-'size'   'empty'           == 1-'length' ('vertex' x)      == 1-'size'   ('vertex' x)      == 1-'length' ('empty' + 'empty') == 0-'size'   ('empty' + 'empty') == 2@+Note that 'size' counts all leaves of the expression: -The 'size' of any graph is positive, and the difference @('size' g - 'length' g)@-corresponds to the number of occurrences of 'empty' in an expression @g@.+@'vertexCount' 'empty'           == 0+'size'        'empty'           == 1+'vertexCount' ('vertex' x)      == 1+'size'        ('vertex' x)      == 1+'vertexCount' ('empty' + 'empty') == 0+'size'        ('empty' + 'empty') == 2@  Converting a 'Graph' to the corresponding 'AM.AdjacencyMap' takes /O(s + m * log(m))/-time and /O(s + m)/ memory. This is also the complexity of the graph equality test,-because it is currently implemented by converting graph expressions to canonical-representations based on adjacency maps.+time and /O(s + m)/ memory. This is also the complexity of the graph equality+test, because it is currently implemented by converting graph expressions to+canonical representations based on adjacency maps.++The total order on graphs is defined using /size-lexicographic/ comparison:++* Compare the number of vertices. In case of a tie, continue.+* Compare the sets of vertices. In case of a tie, continue.+* Compare the number of edges. In case of a tie, continue.+* Compare the sets of edges.++Here are a few examples:++@'vertex' 1 < 'vertex' 2+'vertex' 3 < 'edge' 1 2+'vertex' 1 < 'edge' 1 1+'edge' 1 1 < 'edge' 1 2+'edge' 1 2 < 'edge' 1 1 + 'edge' 2 2+'edge' 1 2 < 'edge' 1 3@++Note that the resulting order refines the 'isSubgraphOf' relation and is+compatible with 'overlay' and 'connect' operations:++@'isSubgraphOf' x y ==> x <= y@++@'empty' <= x+x     <= x + y+x + y <= x * y@ -} data Graph a = Empty              | Vertex a              | Overlay (Graph a) (Graph a)              | Connect (Graph a) (Graph a)-             deriving (Foldable, Functor, Show, Traversable)+             deriving (Show) +{- Note [Functions for rewrite rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++This module contains several functions whose only purpose is to guide GHC+rewrite rules. The names of all such functions are suffixed with "R" so that it+is easier to distinguish them from others.++Why do we need them?++These functions are annotated with carefully chosen GHC pragmas that control+inlining, which would be impossible or unreliable if we used standard functions+instead. For example, the function 'eqR' has the following annotations:++    NOINLINE [1] eqR+    RULES "eqIntR" eqR = eqIntR++This tells GHC to rewrite 'eqR' to faster 'eqIntR' if possible (if the types+match), and -- importantly -- not to inline 'eqR' too early, before the rewrite+rule had a chance to fire.++We could have written the following rule instead:++    RULES "eqIntR" (==) = eqIntR++But that would have to rely on appropriate inlining behaviour of (==) which is+not under our control. We therefore choose the safe and more explicit path of+creating our own intermediate functions for guiding rewrite rules when needed.+-}++instance Functor Graph where+    fmap = fmapR++-- This is a usual implementation of 'fmap', but with custom rewrite rules.+fmapR :: (a -> b) -> Graph a -> Graph b+fmapR f = foldg empty (vertex . f) overlay connect+{-# INLINE [0] fmapR #-}+ instance NFData a => NFData (Graph a) where     rnf Empty         = ()     rnf (Vertex  x  ) = rnf x     rnf (Overlay x y) = rnf x `seq` rnf y     rnf (Connect x y) = rnf x `seq` rnf y +-- | __Note:__ this does not satisfy the usual ring laws; see 'Graph' for more+-- details. instance Num a => Num (Graph a) where     fromInteger = Vertex . fromInteger     (+)         = Overlay@@ -172,19 +234,33 @@     negate      = id  instance Ord a => Eq (Graph a) where-    (==) = equals+    (==) = eqR +instance Ord a => Ord (Graph a) where+    compare = ordR+ -- TODO: Find a more efficient equality check.--- | Compare two graphs by converting them to their adjacency maps.-{-# NOINLINE [1] equals #-}-{-# RULES "equalsInt" equals = equalsInt #-}-equals :: Ord a => Graph a -> Graph a -> Bool-equals x y = adjacencyMap x == adjacencyMap y+-- Check if two graphs are equal by converting them to their adjacency maps.+eqR :: Ord a => Graph a -> Graph a -> Bool+eqR x y = toAdjacencyMap x == toAdjacencyMap y+{-# NOINLINE [1] eqR #-}+{-# RULES "eqR/Int" eqR = eqIntR #-} --- | Like @equals@ but specialised for graphs with vertices of type 'Int'.-equalsInt :: Graph Int -> Graph Int -> Bool-equalsInt x y = adjacencyIntMap x == adjacencyIntMap y+-- Like 'eqR' but specialised for graphs with vertices of type 'Int'.+eqIntR :: Graph Int -> Graph Int -> Bool+eqIntR x y = toAdjacencyIntMap x == toAdjacencyIntMap y +-- TODO: Find a more efficient comparison.+-- Compare two graphs by converting them to their adjacency maps.+ordR :: Ord a => Graph a -> Graph a -> Ordering+ordR x y = compare (toAdjacencyMap x) (toAdjacencyMap y)+{-# NOINLINE [1] ordR #-}+{-# RULES "ordR/Int" ordR = ordIntR #-}++-- Like 'ordR' but specialised for graphs with vertices of type 'Int'.+ordIntR :: Graph Int -> Graph Int -> Ordering+ordIntR x y = compare (toAdjacencyIntMap x) (toAdjacencyIntMap y)+ instance Applicative Graph where     pure  = Vertex     (<*>) = ap@@ -299,7 +375,7 @@ -- @ vertices :: [a] -> Graph a vertices = overlays . map vertex-{-# NOINLINE [1] vertices #-}+{-# INLINE vertices #-}  -- | Construct the graph from a list of edges. -- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the@@ -325,8 +401,8 @@ -- 'isEmpty' . overlays == 'all' 'isEmpty' -- @ overlays :: [Graph a] -> Graph a-overlays = concatg overlay-{-# INLINE [2] overlays #-}+overlays = fromMaybe empty . foldr1Safe overlay+{-# INLINE [1] overlays #-}  -- | Connect a given list of graphs. -- Complexity: /O(L)/ time and memory, and /O(S)/ size, where /L/ is the length@@ -340,12 +416,8 @@ -- 'isEmpty' . connects == 'all' 'isEmpty' -- @ connects :: [Graph a] -> Graph a-connects = concatg connect-{-# INLINE [2] connects #-}---- | Auxiliary function, similar to 'mconcat'.-concatg :: (Graph a -> Graph a -> Graph a) -> [Graph a] -> Graph a-concatg combine = fromMaybe empty . foldr1Safe combine+connects = fromMaybe empty . foldr1Safe connect+{-# INLINE [1] connects #-}  -- | Generalised 'Graph' folding: recursively collapse a 'Graph' by applying -- the provided functions to the leaves and internal nodes of the expression.@@ -355,11 +427,10 @@ -- -- @ -- foldg 'empty' 'vertex'        'overlay' 'connect'        == id--- foldg 'empty' 'vertex'        'overlay' (flip 'connect') == 'transpose'--- foldg []    return        (++)    (++)           == 'Data.Foldable.toList'--- foldg 0     (const 1)     (+)     (+)            == 'Data.Foldable.length'--- foldg 1     (const 1)     (+)     (+)            == 'size'--- foldg True  (const False) (&&)    (&&)           == 'isEmpty'+-- foldg 'empty' 'vertex'        'overlay' ('flip' 'connect') == 'transpose'+-- foldg 1     ('const' 1)     (+)     (+)            == 'size'+-- foldg True  ('const' False) (&&)    (&&)           == 'isEmpty'+-- foldg False (== x)        (||)    (||)           == 'hasVertex' x -- @ foldg :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> b foldg e v o c = go@@ -368,22 +439,40 @@     go (Vertex  x  ) = v x     go (Overlay x y) = o (go x) (go y)     go (Connect x y) = c (go x) (go y)+{-# INLINE [0] foldg #-} +{-# RULES+"foldg/Empty"   forall e v o c.+    foldg e v o c Empty = e+"foldg/Vertex"  forall e v o c x.+    foldg e v o c (Vertex x) = v x+"foldg/Overlay" forall e v o c x y.+    foldg e v o c (Overlay x y) = o (foldg e v o c x) (foldg e v o c y)+"foldg/Connect" forall e v o c x y.+    foldg e v o c (Connect x y) = c (foldg e v o c x) (foldg e v o c y)++"foldg/overlays" forall e v o c xs.+    foldg e v o c (overlays xs) = fromMaybe e (foldr (maybeF o . foldg e v o c) Nothing xs)+"foldg/connects" forall e v o c xs.+    foldg e v o c (connects xs) = fromMaybe e (foldr (maybeF c . foldg e v o c) Nothing xs)+ #-}+ -- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the -- first graph is a /subgraph/ of the second. -- Complexity: /O(s + m * log(m))/ time. Note that the number of edges /m/ of a -- graph can be quadratic with respect to the expression size /s/. -- -- @--- isSubgraphOf 'empty'         x             == True--- isSubgraphOf ('vertex' x)    'empty'         == False--- isSubgraphOf x             ('overlay' x y) == True--- isSubgraphOf ('overlay' x y) ('connect' x y) == True--- isSubgraphOf ('path' xs)     ('circuit' xs)  == True+-- isSubgraphOf 'empty'         x             ==  True+-- isSubgraphOf ('vertex' x)    'empty'         ==  False+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf ('path' xs)     ('circuit' xs)  ==  True+-- isSubgraphOf x y                         ==> x <= y -- @-{-# SPECIALISE isSubgraphOf :: Graph Int -> Graph Int -> Bool #-} isSubgraphOf :: Ord a => Graph a -> Graph a -> Bool isSubgraphOf x y = overlay x y == y+{-# SPECIALISE isSubgraphOf :: Graph Int -> Graph Int -> Bool #-}  -- | Structural equality on graph expressions. -- Complexity: /O(s)/ time.@@ -395,13 +484,13 @@ -- 1 + 2 === 2 + 1     == False -- x + y === x * y     == False -- @-{-# SPECIALISE (===) :: Graph Int -> Graph Int -> Bool #-} (===) :: Eq a => Graph a -> Graph a -> Bool Empty           === Empty           = True (Vertex  x1   ) === (Vertex  x2   ) = x1 ==  x2 (Overlay x1 y1) === (Overlay x2 y2) = x1 === x2 && y1 === y2 (Connect x1 y1) === (Connect x2 y2) = x1 === x2 && y1 === y2 _               === _               = False+{-# SPECIALISE (===) :: Graph Int -> Graph Int -> Bool #-}  infix 4 === @@ -433,18 +522,18 @@ size :: Graph a -> Int size = foldg 1 (const 1) (+) (+) --- | Check if a graph contains a given vertex. A convenient alias for `elem`.+-- | Check if a graph contains a given vertex. -- Complexity: /O(s)/ time. -- -- @ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True -- hasVertex 1 ('vertex' 2)       == False--- hasVertex x . 'removeVertex' x == const False+-- hasVertex x . 'removeVertex' x == 'const' False -- @-{-# SPECIALISE hasVertex :: Int -> Graph Int -> Bool #-} hasVertex :: Eq a => a -> Graph a -> Bool hasVertex x = foldg False (==x) (||) (||)+{-# SPECIALISE hasVertex :: Int -> Graph Int -> Bool #-}  -- | Check if a graph contains a given edge. -- Complexity: /O(s)/ time.@@ -453,10 +542,9 @@ -- hasEdge x y 'empty'            == False -- hasEdge x y ('vertex' z)       == False -- hasEdge x y ('edge' x y)       == True--- hasEdge x y . 'removeEdge' x y == const False+-- hasEdge x y . 'removeEdge' x y == 'const' False -- hasEdge x y                  == 'elem' (x,y) . 'edgeList' -- @-{-# SPECIALISE hasEdge :: Int -> Int -> Graph Int -> Bool #-} hasEdge :: Eq a => a -> a -> Graph a -> Bool hasEdge s t g = hit g == Edge   where@@ -470,23 +558,25 @@         Miss -> hit y         Tail -> if hasVertex t y then Edge else Tail         Edge -> Edge+{-# SPECIALISE hasEdge :: Int -> Int -> Graph Int -> Bool #-}  -- | The number of vertices in a graph. -- Complexity: /O(s * log(n))/ time. -- -- @--- vertexCount 'empty'      == 0--- vertexCount ('vertex' x) == 1--- vertexCount            == 'length' . 'vertexList'+-- vertexCount 'empty'             ==  0+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y -- @-{-# INLINE [1] vertexCount #-}-{-# RULES "vertexCount/Int" vertexCount = vertexIntCount #-} vertexCount :: Ord a => Graph a -> Int vertexCount = Set.size . vertexSet+{-# INLINE [1] vertexCount #-}+{-# RULES "vertexCount/Int" vertexCount = vertexIntCountR #-} --- | Like 'vertexCount' but specialised for graphs with vertices of type 'Int'.-vertexIntCount :: Graph Int -> Int-vertexIntCount = IntSet.size . vertexIntSet+-- Like 'vertexCount' but specialised for graphs with vertices of type 'Int'.+vertexIntCountR :: Graph Int -> Int+vertexIntCountR = IntSet.size . vertexIntSetR  -- | The number of edges in a graph. -- Complexity: /O(s + m * log(m))/ time. Note that the number of edges /m/ of a@@ -498,14 +588,14 @@ -- edgeCount ('edge' x y) == 1 -- edgeCount            == 'length' . 'edgeList' -- @-{-# INLINE [1] edgeCount #-}-{-# RULES "edgeCount/Int" edgeCount = edgeCountInt #-} edgeCount :: Ord a => Graph a -> Int edgeCount = AM.edgeCount . toAdjacencyMap+{-# INLINE [1] edgeCount #-}+{-# RULES "edgeCount/Int" edgeCount = edgeCountIntR #-} --- | Like 'edgeCount' but specialised for graphs with vertices of type 'Int'.-edgeCountInt :: Graph Int -> Int-edgeCountInt = AIM.edgeCount . toAdjacencyIntMap+-- Like 'edgeCount' but specialised for graphs with vertices of type 'Int'.+edgeCountIntR :: Graph Int -> Int+edgeCountIntR = AIM.edgeCount . toAdjacencyIntMap  -- | The sorted list of vertices of a given graph. -- Complexity: /O(s * log(n))/ time and /O(n)/ memory.@@ -515,14 +605,14 @@ -- vertexList ('vertex' x) == [x] -- vertexList . 'vertices' == 'Data.List.nub' . 'Data.List.sort' -- @-{-# INLINE [1] vertexList #-}-{-# RULES "vertexList/Int" vertexList = vertexIntList #-} vertexList :: Ord a => Graph a -> [a] vertexList = Set.toAscList . vertexSet+{-# INLINE [1] vertexList #-}+{-# RULES "vertexList/Int" vertexList = vertexIntListR #-} --- | Like 'vertexList' but specialised for graphs with vertices of type 'Int'.-vertexIntList :: Graph Int -> [Int]-vertexIntList = IntSet.toList . vertexIntSet+-- Like 'vertexList' but specialised for graphs with vertices of type 'Int'.+vertexIntListR :: Graph Int -> [Int]+vertexIntListR = IntSet.toList . vertexIntSetR  -- | The sorted list of edges of a graph. -- Complexity: /O(s + m * log(m))/ time and /O(m)/ memory. Note that the number of@@ -534,16 +624,16 @@ -- edgeList ('edge' x y)     == [(x,y)] -- edgeList ('star' 2 [3,1]) == [(2,1), (2,3)] -- edgeList . 'edges'        == 'Data.List.nub' . 'Data.List.sort'--- edgeList . 'transpose'    == 'Data.List.sort' . map 'Data.Tuple.swap' . edgeList+-- edgeList . 'transpose'    == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . edgeList -- @-{-# INLINE [1] edgeList #-}-{-# RULES "edgeList/Int" edgeList = edgeIntList #-} edgeList :: Ord a => Graph a -> [(a, a)] edgeList = AM.edgeList . toAdjacencyMap+{-# INLINE [1] edgeList #-}+{-# RULES "edgeList/Int" edgeList = edgeIntListR #-} --- | Like 'edgeList' but specialised for graphs with vertices of type 'Int'.-edgeIntList :: Graph Int -> [(Int, Int)]-edgeIntList = AIM.edgeList . toAdjacencyIntMap+-- Like 'edgeList' but specialised for graphs with vertices of type 'Int'.+edgeIntListR :: Graph Int -> [(Int, Int)]+edgeIntListR = AIM.edgeList . toAdjacencyIntMap  -- | The set of vertices of a given graph. -- Complexity: /O(s * log(n))/ time and /O(n)/ memory.@@ -552,23 +642,13 @@ -- vertexSet 'empty'      == Set.'Set.empty' -- vertexSet . 'vertex'   == Set.'Set.singleton' -- vertexSet . 'vertices' == Set.'Set.fromList'--- vertexSet . 'clique'   == Set.'Set.fromList' -- @ vertexSet :: Ord a => Graph a -> Set.Set a vertexSet = foldg Set.empty Set.singleton Set.union Set.union --- | The set of vertices of a given graph. Like 'vertexSet' but specialised for--- graphs with vertices of type 'Int'.--- Complexity: /O(s * log(n))/ time and /O(n)/ memory.------ @--- vertexIntSet 'empty'      == IntSet.'IntSet.empty'--- vertexIntSet . 'vertex'   == IntSet.'IntSet.singleton'--- vertexIntSet . 'vertices' == IntSet.'IntSet.fromList'--- vertexIntSet . 'clique'   == IntSet.'IntSet.fromList'--- @-vertexIntSet :: Graph Int -> IntSet.IntSet-vertexIntSet = foldg IntSet.empty IntSet.singleton IntSet.union IntSet.union+-- Like 'vertexSet' but specialised for graphs with vertices of type 'Int'.+vertexIntSetR :: Graph Int -> IntSet.IntSet+vertexIntSetR = foldg IntSet.empty IntSet.singleton IntSet.union IntSet.union  -- | The set of edges of a given graph. -- Complexity: /O(s * log(m))/ time and /O(m)/ memory.@@ -582,11 +662,11 @@ edgeSet :: Ord a => Graph a -> Set.Set (a, a) edgeSet = AM.edgeSet . toAdjacencyMap {-# INLINE [1] edgeSet #-}-{-# RULES "edgeSet/Int" edgeSet = edgeIntSet #-}+{-# RULES "edgeSet/Int" edgeSet = edgeIntSetR #-} --- | Like 'edgeSet' but specialised for graphs with vertices of type 'Int'.-edgeIntSet :: Graph Int -> Set.Set (Int,Int)-edgeIntSet = AIM.edgeSet . toAdjacencyIntMap+-- Like 'edgeSet' but specialised for graphs with vertices of type 'Int'.+edgeIntSetR :: Graph Int -> Set.Set (Int,Int)+edgeIntSetR = AIM.edgeSet . toAdjacencyIntMap  -- | The sorted /adjacency list/ of a graph. -- Complexity: /O(n + m)/ time and /O(m)/ memory.@@ -598,29 +678,18 @@ -- adjacencyList ('star' 2 [3,1]) == [(1, []), (2, [1,3]), (3, [])] -- 'stars' . adjacencyList        == id -- @-{-# SPECIALISE adjacencyList :: Graph Int -> [(Int, [Int])] #-} adjacencyList :: Ord a => Graph a -> [(a, [a])] adjacencyList = AM.adjacencyList . toAdjacencyMap---- | The /adjacency map/ of a graph: each vertex is associated with a set of its--- direct successors.--- Complexity: /O(s + m * log(m))/ time. Note that the number of edges /m/ of a--- graph can be quadratic with respect to the expression size /s/.-adjacencyMap :: Ord a => Graph a -> Map a (Set a)-adjacencyMap = AM.adjacencyMap . toAdjacencyMap+{-# SPECIALISE adjacencyList :: Graph Int -> [(Int, [Int])] #-}  -- TODO: This is a very inefficient implementation. Find a way to construct an -- adjacency map directly, without building intermediate representations for all -- subgraphs.--- | Convert a graph to 'AM.AdjacencyMap'.+-- Convert a graph to 'AM.AdjacencyMap'. toAdjacencyMap :: Ord a => Graph a -> AM.AdjacencyMap a toAdjacencyMap = foldg AM.empty AM.vertex AM.overlay AM.connect --- | Like 'adjacencyMap' but specialised for graphs with vertices of type 'Int'.-adjacencyIntMap :: Graph Int -> IntMap IntSet-adjacencyIntMap = AIM.adjacencyIntMap . toAdjacencyIntMap---- | Like @toAdjacencyMap@ but specialised for graphs with vertices of type 'Int'.+-- Like @toAdjacencyMap@ but specialised for graphs with vertices of type 'Int'. toAdjacencyIntMap :: Graph Int -> AIM.AdjacencyIntMap toAdjacencyIntMap = foldg AIM.empty AIM.vertex AIM.overlay AIM.connect @@ -667,7 +736,7 @@ -- @ clique :: [a] -> Graph a clique = connects . map vertex-{-# NOINLINE [1] clique #-}+{-# INLINE [1] clique #-}  -- | The /biclique/ on two lists of vertices. -- Complexity: /O(L1 + L2)/ time, memory and size, where /L1/ and /L2/ are the@@ -710,7 +779,7 @@ -- stars [(x, [])]               == 'vertex' x -- stars [(x, [y])]              == 'edge' x y -- stars [(x, ys)]               == 'star' x ys--- stars                         == 'overlays' . map (uncurry 'star')+-- stars                         == 'overlays' . 'map' ('uncurry' 'star') -- stars . 'adjacencyList'         == id -- 'overlay' (stars xs) (stars ys) == stars (xs ++ ys) -- @@@ -741,7 +810,7 @@ -- forest []                                                  == 'empty' -- forest [x]                                                 == 'tree' x -- forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == 'edges' [(1,2), (1,3), (4,5)]--- forest                                                     == 'overlays' . map 'tree'+-- forest                                                     == 'overlays' . 'map' 'tree' -- @ forest :: Tree.Forest a -> Graph a forest = overlays . map tree@@ -825,9 +894,9 @@ -- removeVertex 1 ('edge' 1 2)       == 'vertex' 2 -- removeVertex x . removeVertex x == removeVertex x -- @-{-# SPECIALISE removeVertex :: Int -> Graph Int -> Graph Int #-} removeVertex :: Eq a => a -> Graph a -> Graph a removeVertex v = induce (/= v)+{-# SPECIALISE removeVertex :: Int -> Graph Int -> Graph Int #-}  -- | Remove an edge from a given graph. -- Complexity: /O(s)/ time, memory and size.@@ -840,19 +909,18 @@ -- removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2 -- 'size' (removeEdge x y z)         <= 3 * 'size' z -- @-{-# SPECIALISE removeEdge :: Int -> Int -> Graph Int -> Graph Int #-} removeEdge :: Eq a => a -> a -> Graph a -> Graph a removeEdge s t = filterContext s (/=s) (/=t)-+{-# SPECIALISE removeEdge :: Int -> Int -> Graph Int -> Graph Int #-}  -- TODO: Export--- | Filter vertices in a subgraph context.-{-# SPECIALISE filterContext :: Int -> (Int -> Bool) -> (Int -> Bool) -> Graph Int -> Graph Int #-}+-- Filter vertices in a subgraph context. filterContext :: Eq a => a -> (a -> Bool) -> (a -> Bool) -> Graph a -> Graph a filterContext s i o g = maybe g go $ context (==s) g   where     go (Context is os) = induce (/=s) g `overlay` transpose (star s (filter i is))-                                        `overlay` star          s (filter o os)+                                        `overlay` star            s (filter o os)+{-# SPECIALISE filterContext :: Int -> (Int -> Bool) -> (Int -> Bool) -> Graph Int -> Graph Int #-}  -- | The function @'replaceVertex' x y@ replaces vertex @x@ with vertex @y@ in a -- given 'Graph'. If @y@ already exists, @x@ and @y@ will be merged.@@ -863,20 +931,19 @@ -- replaceVertex x y ('vertex' x) == 'vertex' y -- replaceVertex x y            == 'mergeVertices' (== x) y -- @-{-# SPECIALISE replaceVertex :: Int -> Int -> Graph Int -> Graph Int #-} replaceVertex :: Eq a => a -> a -> Graph a -> Graph a replaceVertex u v = fmap $ \w -> if w == u then v else w-+{-# SPECIALISE replaceVertex :: Int -> Int -> Graph Int -> Graph Int #-}  -- | Merge vertices satisfying a given predicate into a given vertex. -- Complexity: /O(s)/ time, memory and size, assuming that the predicate takes -- /O(1)/ to be evaluated. -- -- @--- mergeVertices (const False) x    == id+-- mergeVertices ('const' False) x    == id -- mergeVertices (== x) y           == 'replaceVertex' x y--- mergeVertices even 1 (0 * 2)     == 1 * 1--- mergeVertices odd  1 (3 + 4 * 5) == 4 * 1+-- mergeVertices 'even' 1 (0 * 2)     == 1 * 1+-- mergeVertices 'odd'  1 (3 + 4 * 5) == 4 * 1 -- @ mergeVertices :: (a -> Bool) -> a -> Graph a -> Graph a mergeVertices p v = fmap $ \w -> if p w then v else w@@ -892,9 +959,9 @@ -- splitVertex x [y]                 == 'replaceVertex' x y -- splitVertex 1 [0,1] $ 1 * (2 + 3) == (0 + 1) * (2 + 3) -- @-{-# SPECIALISE splitVertex :: Int -> [Int] -> Graph Int -> Graph Int #-} splitVertex :: Eq a => a -> [a] -> Graph a -> Graph a splitVertex v us g = g >>= \w -> if w == v then vertices us else vertex w+{-# SPECIALISE splitVertex :: Int -> [Int] -> Graph Int -> Graph Int #-}  -- | Transpose a given graph. -- Complexity: /O(s)/ time, memory and size.@@ -905,24 +972,11 @@ -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id -- transpose ('box' x y)   == 'box' (transpose x) (transpose y)--- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList'+-- 'edgeList' . transpose  == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: Graph a -> Graph a transpose = foldg Empty Vertex Overlay (flip Connect)-{-# NOINLINE [1] transpose #-}--{-# RULES-"transpose/Empty"    transpose Empty = Empty-"transpose/Vertex"   forall x. transpose (Vertex x) = Vertex x-"transpose/Overlay"  forall g1 g2. transpose (Overlay g1 g2) = Overlay (transpose g1) (transpose g2)-"transpose/Connect"  forall g1 g2. transpose (Connect g1 g2) = Connect (transpose g2) (transpose g1)--"transpose/overlays" forall xs. transpose (overlays xs) = overlays (map transpose xs)-"transpose/connects" forall xs. transpose (connects xs) = connects (reverse (map transpose xs))--"transpose/vertices" forall xs. transpose (vertices xs) = vertices xs-"transpose/clique"   forall xs. transpose (clique xs)   = clique (reverse xs)- #-}+{-# INLINE transpose #-}  -- | Construct the /induced subgraph/ of a given graph by removing the -- vertices that do not satisfy a given predicate.@@ -930,8 +984,8 @@ -- /O(1)/ to be evaluated. -- -- @--- induce (const True ) x      == x--- induce (const False) x      == 'empty'+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x) -- 'isSubgraphOf' (induce p x) x == True@@ -942,6 +996,7 @@     k _ x     Empty = x -- Constant folding to get rid of Empty leaves     k _ Empty y     = y     k f x     y     = f x y+{-# INLINE [1] induce #-}  -- | Simplify a graph expression. Semantically, this is the identity function, -- but it simplifies a given expression according to the laws of the algebra.@@ -959,11 +1014,10 @@ -- simplify (1 + 2 + 1) '===' 1 + 2 -- simplify (1 * 1 * 1) '===' 1 * 1 -- @-{-# SPECIALISE simplify :: Graph Int -> Graph Int #-} simplify :: Ord a => Graph a -> Graph a simplify = foldg Empty Vertex (simple Overlay) (simple Connect)+{-# SPECIALISE simplify :: Graph Int -> Graph Int #-} -{-# SPECIALISE simple :: (Int -> Int -> Int) -> Int -> Int -> Int #-} simple :: Eq g => (g -> g -> g) -> g -> g -> g simple op x y     | x == z    = x@@ -971,7 +1025,44 @@     | otherwise = z   where     z = op x y+{-# SPECIALISE simple :: (Int -> Int -> Int) -> Int -> Int -> Int #-} +-- | Left-to-right /relational composition/ of graphs: vertices @x@ and @z@ are+-- connected in the resulting graph if there is a vertex @y@, such that @x@ is+-- connected to @y@ in the first graph, and @y@ is connected to @z@ in the+-- second graph. There are no isolated vertices in the result. This operation is+-- associative, has 'empty' and single-'vertex' graphs as /annihilating zeroes/,+-- and distributes over 'overlay'.+-- Complexity: /O(n * m * log(n))/ time, /O(n + m)/ memory, and /O(m1 + m2)/+-- size, where /n/ and /m/ stand for the number of vertices and edges in the+-- resulting graph, while /m1/ and /m2/ are the number of edges in the original+-- graphs. Note that the number of edges in the resulting graph may be+-- quadratic, i.e. /m = O(m1 * m2)/, but the algebraic representation requires+-- only /O(m1 + m2)/ operations to list them.+--+-- @+-- compose 'empty'            x                == 'empty'+-- compose x                'empty'            == 'empty'+-- compose ('vertex' x)       y                == 'empty'+-- compose x                ('vertex' y)       == 'empty'+-- compose x                (compose y z)    == compose (compose x y) z+-- compose x                ('overlay' y z)    == 'overlay' (compose x y) (compose x z)+-- compose ('overlay' x y)    z                == 'overlay' (compose x z) (compose y z)+-- compose ('edge' x y)       ('edge' y z)       == 'edge' x z+-- compose ('path'    [1..5]) ('path'    [1..5]) == 'edges' [(1,3), (2,4), (3,5)]+-- compose ('circuit' [1..5]) ('circuit' [1..5]) == 'circuit' [1,3,5,2,4]+-- 'size' (compose x y)                        <= 'edgeCount' x + 'edgeCount' y + 1+-- @+compose :: Ord a => Graph a -> Graph a -> Graph a+compose x y = overlays+    [ biclique xs ys+    | v <- Set.toList (AM.vertexSet mx `Set.union` AM.vertexSet my)+    , let xs = Set.toList (AM.postSet v mx), not (null xs)+    , let ys = Set.toList (AM.postSet v my), not (null ys) ]+  where+    mx = toAdjacencyMap (transpose x)+    my = toAdjacencyMap y+ -- | Compute the /Cartesian product/ of graphs. -- Complexity: /O(s1 * s2)/ time, memory and size, where /s1/ and /s2/ are the -- sizes of the given graphs.@@ -1000,24 +1091,10 @@ box :: Graph a -> Graph b -> Graph (a, b) box x y = overlays $ xs ++ ys   where-    xs = map (\b -> fmap (,b) x) $ toList y-    ys = map (\a -> fmap (a,) y) $ toList x---- | 'Focus' on a specified subgraph.-focus :: (a -> Bool) -> Graph a -> Focus a-focus f = foldg emptyFocus (vertexFocus f) overlayFoci connectFoci---- | The context of a subgraph comprises the input and output vertices outside--- the subgraph that are connected to the vertices inside the subgraph.-data Context a = Context { inputs :: [a], outputs :: [a] }---- | Extract the context from a graph 'Focus'. Returns @Nothing@ if the focus--- could not be obtained.-context :: (a -> Bool) -> Graph a -> Maybe (Context a)-context p g | ok f      = Just $ Context (toList $ is f) (toList $ os f)-            | otherwise = Nothing-  where-    f = focus p g+    xs = map (\b -> fmap (,b) x) $ toList $ toListGr y+    ys = map (\a -> fmap (a,) y) $ toList $ toListGr x+    toListGr :: Graph a -> List a+    toListGr = foldg mempty pure (<>) (<>)  -- | /Sparsify/ a graph by adding intermediate 'Left' @Int@ vertices between the -- original vertices (wrapping the latter in 'Right') such that the resulting@@ -1045,3 +1122,105 @@         m <- get         put (m + 1)         overlay <$> s `x` m <*> m `y` t++{- Note [The rules of foldg]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The rules for foldg work very similarly to GHC's mapFB rules; see a note below+this line: http://hackage.haskell.org/package/base/docs/src/GHC.Base.html#mapFB.++* Up to (but not including) phase 1, we use the "buildR/f" rule to rewrite all+  saturated applications of f into its buildR/foldg form, hoping for fusion to+  happen (through the "foldg/buildR" rule).++  In phases 1 and 0, we switch off these rules, inline buildR, and switch on the+  "graph/f" rule, which rewrites "foldg/f" back into plain functions if needed.++  It's important that these two rules aren't both active at once (along with+  build's unfolding) else we'd get an infinite loop in the rules. Hence the+  activation control below.++* composeR and matchR are here to remember the original function after applying+  a "buildR/f" rule. These functions are higher-order functions and therefore+  benefit from inlining in the final phase.++* The "fmapR/fmapR" rule optimises compositions of multiple fmapR's.+-}++type Foldg a = forall b. b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> b++buildR :: Foldg a -> Graph a+buildR g = g Empty Vertex Overlay Connect+{-# INLINE [1] buildR #-}++composeR :: (b -> c) -> (a -> b) -> a -> c+composeR = (.)+{-# INLINE [0] composeR #-}++matchR :: b -> (a -> b) -> (a -> Bool) -> a -> b+matchR e v p = \x -> if p x then v x else e+{-# INLINE [0] matchR #-}++-- These rules transform functions into their buildR equivalents.+{-# RULES+"buildR/fmapR" forall f g.+    fmapR f g = buildR (\e v o c -> foldg e (composeR v f) o c g)++"buildR/induce" [~1] forall p g.+    induce p g = buildR (\e v o c -> foldg e (matchR e v p) o c g)++"buildR/foldg(fc)" [~1] forall (f :: forall b. (b -> b -> b) -> (b -> b -> b)) g.+    foldg Empty Vertex Overlay (f Connect) g = buildR (\e v o c -> foldg e v o (f c) g)++"buildR/foldg(fo)" [~1] forall (f :: forall b. (b -> b -> b) -> (b -> b -> b)) g.+    foldg Empty Vertex (f Overlay) Connect g = buildR (\e v o c -> foldg e v (f o) c g)++"buildR/foldg(fo)(hc)" [~1] forall (f :: forall b. (b -> b -> b) -> (b -> b -> b)) (h :: forall b. (b -> b -> b) -> (b -> b -> b)) g.+    foldg Empty Vertex (f Overlay) (h Connect) g = buildR (\e v o c -> foldg e v (f o) (h c) g)+ #-}++-- Rewrite rules for fusion.+{-# RULES+-- Fuse a foldg followed by a buildR+"foldg/buildR" forall e v o c (g :: Foldg a).+    foldg e v o c (buildR g) = g e v o c++-- Fuse composeR's. This occurs when two adjacent 'fmapR' were rewritted into+-- their buildR form.+"fmapR/fmapR" forall c f g.+    composeR (composeR c f) g = composeR c (f.g)+ #-}++-- Eliminate remaining rewrite-only functions.+{-# RULES+"graph/induce" [1] forall f.+    foldg Empty (matchR Empty Vertex f) Overlay Connect = induce f+ #-}++-- 'Focus' on a specified subgraph.+focus :: (a -> Bool) -> Graph a -> Focus a+focus f = foldg emptyFocus (vertexFocus f) overlayFoci connectFoci++-- | The 'Context' of a subgraph comprises its 'inputs' and 'outputs', i.e. all+-- the vertices that are connected to the subgraph's vertices. Note that inputs+-- and outputs can belong to the subgraph itself. In general, there are no+-- guarantees on the order of vertices in 'inputs' and 'outputs'; furthermore,+-- there may be repetitions.+data Context a = Context { inputs :: [a], outputs :: [a] }+    deriving (Eq, Show)++-- | Extract the 'Context' of a subgraph specified by a given predicate. Returns+-- @Nothing@ if the specified subgraph is empty.+--+-- @+-- context ('const' False) x                   == Nothing+-- context (== 1)        ('edge' 1 2)          == Just ('Context' [   ] [2  ])+-- context (== 2)        ('edge' 1 2)          == Just ('Context' [1  ] [   ])+-- context ('const' True ) ('edge' 1 2)          == Just ('Context' [1  ] [2  ])+-- context (== 4)        (3 * 1 * 4 * 1 * 5) == Just ('Context' [3,1] [1,5])+-- @+context :: (a -> Bool) -> Graph a -> Maybe (Context a)+context p g | ok f      = Just $ Context (toList $ is f) (toList $ os f)+            | otherwise = Nothing+  where+    f = focus p g
src/Algebra/Graph/AdjacencyIntMap.hs view
@@ -10,11 +10,11 @@ -- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the -- motivation behind the library, the underlying theory, and implementation details. ----- This module defines the 'AdjacencyIntMap' data type, as well as associated--- operations and algorithms. 'AdjacencyIntMap' is an instance of the 'C.Graph'--- type class, which can be used for polymorphic graph construction--- and manipulation. See "Algebra.Graph.AdjacencyMap" for graphs with--- non-@Int@ vertices.+-- This module defines the 'AdjacencyIntMap' data type and associated functions.+-- See "Algebra.Graph.AdjacencyIntMap.Algorithm" for implementations of basic+-- graph algorithms. 'AdjacencyIntMap' is an instance of the 'C.Graph' type+-- class, which can be used for polymorphic graph construction and manipulation.+-- See "Algebra.Graph.AdjacencyMap" for graphs with non-@Int@ vertices. ----------------------------------------------------------------------------- module Algebra.Graph.AdjacencyIntMap (     -- * Data structure@@ -31,34 +31,55 @@     adjacencyList, vertexIntSet, edgeSet, preIntSet, postIntSet,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, stars, tree, forest,+    path, circuit, clique, biclique, star, stars, fromAdjacencyIntSets, tree,+    forest,      -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, transpose, gmap,     induce, -    -- * Algorithms-    dfsForest, dfsForestFrom, dfs, reachable, topSort, isAcyclic,--    -- * Correctness properties-    isDfsForestOf, isTopSortOf-  ) where+    -- * Relational operations+    compose, closure, reflexiveClosure, symmetricClosure, transitiveClosure+    ) where -import Control.Monad import Data.Foldable (foldMap) import Data.IntSet (IntSet)-import Data.Maybe import Data.Monoid import Data.Set (Set) import Data.Tree  import Algebra.Graph.AdjacencyIntMap.Internal -import qualified Data.Graph.Typed   as Typed import qualified Data.IntMap.Strict as IntMap import qualified Data.IntSet        as IntSet import qualified Data.Set           as Set +-- | Construct the /empty graph/.+-- Complexity: /O(1)/ time and memory.+--+-- @+-- 'isEmpty'     empty == True+-- 'hasVertex' x empty == False+-- 'vertexCount' empty == 0+-- 'edgeCount'   empty == 0+-- @+empty :: AdjacencyIntMap+empty = AM IntMap.empty+{-# NOINLINE [1] empty #-}++-- | Construct the graph comprising /a single isolated vertex/.+-- Complexity: /O(1)/ time and memory.+--+-- @+-- 'isEmpty'     (vertex x) == False+-- 'hasVertex' x (vertex x) == True+-- 'vertexCount' (vertex x) == 1+-- 'edgeCount'   (vertex x) == 0+-- @+vertex :: Int -> AdjacencyIntMap+vertex x = AM $ IntMap.singleton x IntSet.empty+{-# NOINLINE [1] vertex #-}+ -- | Construct the graph comprising /a single edge/. -- Complexity: /O(1)/ time, memory. --@@ -73,6 +94,47 @@ edge x y | x == y    = AM $ IntMap.singleton x (IntSet.singleton y)          | otherwise = AM $ IntMap.fromList [(x, IntSet.singleton y), (y, IntSet.empty)] +-- | /Overlay/ two graphs. This is a commutative, associative and idempotent+-- operation with the identity 'empty'.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- 'isEmpty'     (overlay x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (overlay x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (overlay x y) >= 'vertexCount' x+-- 'vertexCount' (overlay x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (overlay x y) >= 'edgeCount' x+-- 'edgeCount'   (overlay x y) <= 'edgeCount' x   + 'edgeCount' y+-- 'vertexCount' (overlay 1 2) == 2+-- 'edgeCount'   (overlay 1 2) == 0+-- @+overlay :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap+overlay x y = AM $ IntMap.unionWith IntSet.union (adjacencyIntMap x) (adjacencyIntMap y)+{-# NOINLINE [1] overlay #-}++-- | /Connect/ two graphs. This is an associative operation with the identity+-- 'empty', which distributes over 'overlay' and obeys the decomposition axiom.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. Note that the+-- number of edges in the resulting graph is quadratic with respect to the number+-- of vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.+--+-- @+-- 'isEmpty'     (connect x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (connect x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (connect x y) >= 'vertexCount' x+-- 'vertexCount' (connect x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (connect x y) >= 'edgeCount' x+-- 'edgeCount'   (connect x y) >= 'edgeCount' y+-- 'edgeCount'   (connect x y) >= 'vertexCount' x * 'vertexCount' y+-- 'edgeCount'   (connect x y) <= 'vertexCount' x * 'vertexCount' y + 'edgeCount' x + 'edgeCount' y+-- 'vertexCount' (connect 1 2) == 2+-- 'edgeCount'   (connect 1 2) == 1+-- @+connect :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap+connect x y = AM $ IntMap.unionsWith IntSet.union [ adjacencyIntMap x, adjacencyIntMap y,+    IntMap.fromSet (const . IntMap.keysSet $ adjacencyIntMap y) (IntMap.keysSet $ adjacencyIntMap x) ]+{-# NOINLINE [1] connect #-}+ -- | Construct the graph comprising a given list of isolated vertices. -- Complexity: /O(L * log(L))/ time and /O(L)/ memory, where /L/ is the length -- of the given list.@@ -133,11 +195,12 @@ -- Complexity: /O((n + m) * log(n))/ time. -- -- @--- isSubgraphOf 'empty'         x             == True--- isSubgraphOf ('vertex' x)    'empty'         == False--- isSubgraphOf x             ('overlay' x y) == True--- isSubgraphOf ('overlay' x y) ('connect' x y) == True--- isSubgraphOf ('path' xs)     ('circuit' xs)  == True+-- isSubgraphOf 'empty'         x             ==  True+-- isSubgraphOf ('vertex' x)    'empty'         ==  False+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf ('path' xs)     ('circuit' xs)  ==  True+-- isSubgraphOf x y                         ==> x <= y -- @ isSubgraphOf :: AdjacencyIntMap -> AdjacencyIntMap -> Bool isSubgraphOf x y = IntMap.isSubmapOfBy IntSet.isSubsetOf (adjacencyIntMap x) (adjacencyIntMap y)@@ -162,7 +225,7 @@ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True -- hasVertex 1 ('vertex' 2)       == False--- hasVertex x . 'removeVertex' x == const False+-- hasVertex x . 'removeVertex' x == 'const' False -- @ hasVertex :: Int -> AdjacencyIntMap -> Bool hasVertex x = IntMap.member x . adjacencyIntMap@@ -174,7 +237,7 @@ -- hasEdge x y 'empty'            == False -- hasEdge x y ('vertex' z)       == False -- hasEdge x y ('edge' x y)       == True--- hasEdge x y . 'removeEdge' x y == const False+-- hasEdge x y . 'removeEdge' x y == 'const' False -- hasEdge x y                  == 'elem' (x,y) . 'edgeList' -- @ hasEdge :: Int -> Int -> AdjacencyIntMap -> Bool@@ -186,9 +249,10 @@ -- Complexity: /O(1)/ time. -- -- @--- vertexCount 'empty'      == 0--- vertexCount ('vertex' x) == 1--- vertexCount            == 'length' . 'vertexList'+-- vertexCount 'empty'             ==  0+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y -- @ vertexCount :: AdjacencyIntMap -> Int vertexCount = IntMap.size . adjacencyIntMap@@ -225,7 +289,7 @@ -- edgeList ('edge' x y)     == [(x,y)] -- edgeList ('star' 2 [3,1]) == [(2,1), (2,3)] -- edgeList . 'edges'        == 'Data.List.nub' . 'Data.List.sort'--- edgeList . 'transpose'    == 'Data.List.sort' . map 'Data.Tuple.swap' . edgeList+-- edgeList . 'transpose'    == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . edgeList -- @ edgeList :: AdjacencyIntMap -> [(Int, Int)] edgeList (AM m) = [ (x, y) | (x, ys) <- IntMap.toAscList m, y <- IntSet.toAscList ys ]@@ -381,13 +445,29 @@ -- stars [(x, [])]               == 'vertex' x -- stars [(x, [y])]              == 'edge' x y -- stars [(x, ys)]               == 'star' x ys--- stars                         == 'overlays' . map (uncurry 'star')+-- stars                         == 'overlays' . 'map' ('uncurry' 'star') -- stars . 'adjacencyList'         == id -- 'overlay' (stars xs) (stars ys) == stars (xs ++ ys) -- @ stars :: [(Int, [Int])] -> AdjacencyIntMap stars = fromAdjacencyIntSets . map (fmap IntSet.fromList) +-- | Construct a graph from a list of adjacency sets; a variation of 'stars'.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- fromAdjacencyIntSets []                                     == 'empty'+-- fromAdjacencyIntSets [(x, IntSet.'IntSet.empty')]                    == 'vertex' x+-- fromAdjacencyIntSets [(x, IntSet.'IntSet.singleton' y)]              == 'edge' x y+-- fromAdjacencyIntSets . 'map' ('fmap' IntSet.'IntSet.fromList')           == 'stars'+-- 'overlay' (fromAdjacencyIntSets xs) (fromAdjacencyIntSets ys) == fromAdjacencyIntSets (xs ++ ys)+-- @+fromAdjacencyIntSets :: [(Int, IntSet)] -> AdjacencyIntMap+fromAdjacencyIntSets ss = AM $ IntMap.unionWith IntSet.union vs es+  where+    vs = IntMap.fromSet (const IntSet.empty) . IntSet.unions $ map snd ss+    es = IntMap.fromListWith IntSet.union ss+ -- | The /tree graph/ constructed from a given 'Tree' data structure. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. --@@ -409,7 +489,7 @@ -- forest []                                                  == 'empty' -- forest [x]                                                 == 'tree' x -- forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == 'edges' [(1,2), (1,3), (4,5)]--- forest                                                     == 'overlays' . map 'tree'+-- forest                                                     == 'overlays' . 'map' 'tree' -- @ forest :: Forest Int -> AdjacencyIntMap forest = overlays . map tree@@ -457,10 +537,10 @@ -- /O(1)/ to be evaluated. -- -- @--- mergeVertices (const False) x    == id+-- mergeVertices ('const' False) x    == id -- mergeVertices (== x) y           == 'replaceVertex' x y--- mergeVertices even 1 (0 * 2)     == 1 * 1--- mergeVertices odd  1 (3 + 4 * 5) == 4 * 1+-- mergeVertices 'even' 1 (0 * 2)     == 1 * 1+-- mergeVertices 'odd'  1 (3 + 4 * 5) == 4 * 1 -- @ mergeVertices :: (Int -> Bool) -> Int -> AdjacencyIntMap -> AdjacencyIntMap mergeVertices p v = gmap $ \u -> if p u then v else u@@ -473,7 +553,7 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList'+-- 'edgeList' . transpose  == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: AdjacencyIntMap -> AdjacencyIntMap transpose (AM m) = AM $ IntMap.foldrWithKey combine vs m@@ -516,8 +596,8 @@ -- be evaluated. -- -- @--- induce (const True ) x      == x--- induce (const False) x      == 'empty'+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x) -- 'isSubgraphOf' (induce p x) x == True@@ -525,168 +605,92 @@ induce :: (Int -> Bool) -> AdjacencyIntMap -> AdjacencyIntMap induce p = AM . IntMap.map (IntSet.filter p) . IntMap.filterWithKey (\k _ -> p k) . adjacencyIntMap --- | Compute the /depth-first search/ forest of a graph that corresponds to--- searching from each of the graph vertices in the 'Ord' @a@ order.------ @--- dfsForest 'empty'                       == []--- 'forest' (dfsForest $ 'edge' 1 1)         == 'vertex' 1--- 'forest' (dfsForest $ 'edge' 1 2)         == 'edge' 1 2--- 'forest' (dfsForest $ 'edge' 2 1)         == 'vertices' [1,2]--- 'isSubgraphOf' ('forest' $ dfsForest x) x == True--- 'isDfsForestOf' (dfsForest x) x         == True--- dfsForest . 'forest' . dfsForest        == dfsForest--- dfsForest ('vertices' vs)               == map (\\v -> Node v []) ('Data.List.nub' $ 'Data.List.sort' vs)--- 'dfsForestFrom' ('vertexList' x) x        == dfsForest x--- dfsForest $ 3 * (1 + 4) * (1 + 5)     == [ Node { rootLabel = 1---                                                 , subForest = [ Node { rootLabel = 5---                                                                      , subForest = [] }]}---                                          , Node { rootLabel = 3---                                                 , subForest = [ Node { rootLabel = 4---                                                                      , subForest = [] }]}]--- @-dfsForest :: AdjacencyIntMap -> Forest Int-dfsForest = Typed.dfsForest . Typed.fromAdjacencyIntMap---- | Compute the /depth-first search/ forest of a graph, searching from each of--- the given vertices in order. Note that the resulting forest does not--- necessarily span the whole graph, as some vertices may be unreachable.------ @--- dfsForestFrom vs 'empty'                           == []--- 'forest' (dfsForestFrom [1]   $ 'edge' 1 1)          == 'vertex' 1--- 'forest' (dfsForestFrom [1]   $ 'edge' 1 2)          == 'edge' 1 2--- 'forest' (dfsForestFrom [2]   $ 'edge' 1 2)          == 'vertex' 2--- 'forest' (dfsForestFrom [3]   $ 'edge' 1 2)          == 'empty'--- 'forest' (dfsForestFrom [2,1] $ 'edge' 1 2)          == 'vertices' [1,2]--- 'isSubgraphOf' ('forest' $ dfsForestFrom vs x) x     == True--- 'isDfsForestOf' (dfsForestFrom ('vertexList' x) x) x == True--- dfsForestFrom ('vertexList' x) x                   == 'dfsForest' x--- dfsForestFrom vs             ('vertices' vs)       == map (\\v -> Node v []) ('Data.List.nub' vs)--- dfsForestFrom []             x                   == []--- dfsForestFrom [1,4] $ 3 * (1 + 4) * (1 + 5)      == [ Node { rootLabel = 1---                                                            , subForest = [ Node { rootLabel = 5---                                                                                 , subForest = [] }---                                                     , Node { rootLabel = 4---                                                            , subForest = [] }]--- @-dfsForestFrom :: [Int] -> AdjacencyIntMap -> Forest Int-dfsForestFrom vs = Typed.dfsForestFrom vs . Typed.fromAdjacencyIntMap---- | Compute the list of vertices visited by the /depth-first search/ in a graph,--- when searching from each of the given vertices in order.------ @--- dfs vs    $ 'empty'                    == []--- dfs [1]   $ 'edge' 1 1                 == [1]--- dfs [1]   $ 'edge' 1 2                 == [1,2]--- dfs [2]   $ 'edge' 1 2                 == [2]--- dfs [3]   $ 'edge' 1 2                 == []--- dfs [1,2] $ 'edge' 1 2                 == [1,2]--- dfs [2,1] $ 'edge' 1 2                 == [2,1]--- dfs []    $ x                        == []--- dfs [1,4] $ 3 * (1 + 4) * (1 + 5)    == [1,5,4]--- 'isSubgraphOf' ('vertices' $ dfs vs x) x == True--- @-dfs :: [Int] -> AdjacencyIntMap -> [Int]-dfs vs = concatMap flatten . dfsForestFrom vs---- | Compute the list of vertices that are /reachable/ from a given source--- vertex in a graph. The vertices in the resulting list appear in the--- /depth-first order/.+-- | Left-to-right /relational composition/ of graphs: vertices @x@ and @z@ are+-- connected in the resulting graph if there is a vertex @y@, such that @x@ is+-- connected to @y@ in the first graph, and @y@ is connected to @z@ in the+-- second graph. There are no isolated vertices in the result. This operation is+-- associative, has 'empty' and single-'vertex' graphs as /annihilating zeroes/,+-- and distributes over 'overlay'.+-- Complexity: /O(n * m * log(n))/ time and /O(n + m)/ memory. -- -- @--- reachable x $ 'empty'                       == []--- reachable 1 $ 'vertex' 1                    == [1]--- reachable 1 $ 'vertex' 2                    == []--- reachable 1 $ 'edge' 1 1                    == [1]--- reachable 1 $ 'edge' 1 2                    == [1,2]--- reachable 4 $ 'path'    [1..8]              == [4..8]--- reachable 4 $ 'circuit' [1..8]              == [4..8] ++ [1..3]--- reachable 8 $ 'clique'  [8,7..1]            == [8] ++ [1..7]--- 'isSubgraphOf' ('vertices' $ reachable x y) y == True+-- compose 'empty'            x                == 'empty'+-- compose x                'empty'            == 'empty'+-- compose ('vertex' x)       y                == 'empty'+-- compose x                ('vertex' y)       == 'empty'+-- compose x                (compose y z)    == compose (compose x y) z+-- compose x                ('overlay' y z)    == 'overlay' (compose x y) (compose x z)+-- compose ('overlay' x y)    z                == 'overlay' (compose x z) (compose y z)+-- compose ('edge' x y)       ('edge' y z)       == 'edge' x z+-- compose ('path'    [1..5]) ('path'    [1..5]) == 'edges' [(1,3), (2,4), (3,5)]+-- compose ('circuit' [1..5]) ('circuit' [1..5]) == 'circuit' [1,3,5,2,4] -- @-reachable :: Int -> AdjacencyIntMap -> [Int]-reachable x = dfs [x]+compose :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap+compose x y = fromAdjacencyIntSets+    [ (t, ys) | v <- IntSet.toList vs, let ys = postIntSet v y+              , not (IntSet.null ys), t <- IntSet.toList (postIntSet v tx) ]+  where+    tx = transpose x+    vs = vertexIntSet x `IntSet.union` vertexIntSet y --- | Compute the /topological sort/ of a graph or return @Nothing@ if the graph--- is cyclic.+-- | Compute the /reflexive and transitive closure/ of a graph.+-- Complexity: /O(n * m * log(n)^2)/ time. -- -- @--- topSort (1 * 2 + 3 * 1)               == Just [3,1,2]--- topSort (1 * 2 + 2 * 1)               == Nothing--- fmap (flip 'isTopSortOf' x) (topSort x) /= Just False--- 'isJust' . topSort                      == 'isAcyclic'+-- closure 'empty'            == 'empty'+-- closure ('vertex' x)       == 'edge' x x+-- closure ('edge' x x)       == 'edge' x x+-- closure ('edge' x y)       == 'edges' [(x,x), (x,y), (y,y)]+-- closure ('path' $ 'Data.List.nub' xs) == 'reflexiveClosure' ('clique' $ 'Data.List.nub' xs)+-- closure                  == 'reflexiveClosure' . 'transitiveClosure'+-- closure                  == 'transitiveClosure' . 'reflexiveClosure'+-- closure . closure        == closure+-- 'postIntSet' x (closure y) == IntSet.'IntSet.fromList' ('Algebra.Graph.ToGraph.reachable' x y) -- @-topSort :: AdjacencyIntMap -> Maybe [Int]-topSort m = if isTopSortOf result m then Just result else Nothing-  where-    result = Typed.topSort (Typed.fromAdjacencyIntMap m)+closure :: AdjacencyIntMap -> AdjacencyIntMap+closure = reflexiveClosure . transitiveClosure --- | Check if a given graph is /acyclic/.+-- | Compute the /reflexive closure/ of a graph by adding a self-loop to every+-- vertex.+-- Complexity: /O(n * log(n))/ time. -- -- @--- isAcyclic (1 * 2 + 3 * 1) == True--- isAcyclic (1 * 2 + 2 * 1) == False--- isAcyclic . 'circuit'       == 'null'--- isAcyclic                 == 'isJust' . 'topSort'+-- reflexiveClosure 'empty'              == 'empty'+-- reflexiveClosure ('vertex' x)         == 'edge' x x+-- reflexiveClosure ('edge' x x)         == 'edge' x x+-- reflexiveClosure ('edge' x y)         == 'edges' [(x,x), (x,y), (y,y)]+-- reflexiveClosure . reflexiveClosure == reflexiveClosure -- @-isAcyclic :: AdjacencyIntMap -> Bool-isAcyclic = isJust . topSort+reflexiveClosure :: AdjacencyIntMap -> AdjacencyIntMap+reflexiveClosure (AM m) = AM $ IntMap.mapWithKey (\k -> IntSet.insert k) m --- | Check if a given forest is a correct /depth-first search/ forest of a graph.--- The implementation is based on the paper "Depth-First Search and Strong--- Connectivity in Coq" by François Pottier.+-- | Compute the /symmetric closure/ of a graph by overlaying it with its own+-- transpose.+-- Complexity: /O((n + m) * log(n))/ time. -- -- @--- isDfsForestOf []                              'empty'            == True--- isDfsForestOf []                              ('vertex' 1)       == False--- isDfsForestOf [Node 1 []]                     ('vertex' 1)       == True--- isDfsForestOf [Node 1 []]                     ('vertex' 2)       == False--- isDfsForestOf [Node 1 [], Node 1 []]          ('vertex' 1)       == False--- isDfsForestOf [Node 1 []]                     ('edge' 1 1)       == True--- isDfsForestOf [Node 1 []]                     ('edge' 1 2)       == False--- isDfsForestOf [Node 1 [], Node 2 []]          ('edge' 1 2)       == False--- isDfsForestOf [Node 2 [], Node 1 []]          ('edge' 1 2)       == True--- isDfsForestOf [Node 1 [Node 2 []]]            ('edge' 1 2)       == True--- isDfsForestOf [Node 1 [], Node 2 []]          ('vertices' [1,2]) == True--- isDfsForestOf [Node 2 [], Node 1 []]          ('vertices' [1,2]) == True--- isDfsForestOf [Node 1 [Node 2 []]]            ('vertices' [1,2]) == False--- isDfsForestOf [Node 1 [Node 2 [Node 3 []]]]   ('path' [1,2,3])   == True--- isDfsForestOf [Node 1 [Node 3 [Node 2 []]]]   ('path' [1,2,3])   == False--- isDfsForestOf [Node 3 [], Node 1 [Node 2 []]] ('path' [1,2,3])   == True--- isDfsForestOf [Node 2 [Node 3 []], Node 1 []] ('path' [1,2,3])   == True--- isDfsForestOf [Node 1 [], Node 2 [Node 3 []]] ('path' [1,2,3])   == False+-- symmetricClosure 'empty'              == 'empty'+-- symmetricClosure ('vertex' x)         == 'vertex' x+-- symmetricClosure ('edge' x y)         == 'edges' [(x,y), (y,x)]+-- symmetricClosure x                  == 'overlay' x ('transpose' x)+-- symmetricClosure . symmetricClosure == symmetricClosure -- @-isDfsForestOf :: Forest Int -> AdjacencyIntMap -> Bool-isDfsForestOf f am = case go IntSet.empty f of-    Just seen -> seen == vertexIntSet am-    Nothing   -> False-  where-    go seen []     = Just seen-    go seen (t:ts) = do-        let root = rootLabel t-        guard $ root `IntSet.notMember` seen-        guard $ and [ hasEdge root (rootLabel subTree) am | subTree <- subForest t ]-        newSeen <- go (IntSet.insert root seen) (subForest t)-        guard $ postIntSet root am `IntSet.isSubsetOf` newSeen-        go newSeen ts+symmetricClosure :: AdjacencyIntMap -> AdjacencyIntMap+symmetricClosure m = overlay m (transpose m) --- | Check if a given list of vertices is a correct /topological sort/ of a graph.+-- | Compute the /transitive closure/ of a graph.+-- Complexity: /O(n * m * log(n)^2)/ time. -- -- @--- isTopSortOf [3,1,2] (1 * 2 + 3 * 1) == True--- isTopSortOf [1,2,3] (1 * 2 + 3 * 1) == False--- isTopSortOf []      (1 * 2 + 3 * 1) == False--- isTopSortOf []      'empty'           == True--- isTopSortOf [x]     ('vertex' x)      == True--- isTopSortOf [x]     ('edge' x x)      == False+-- transitiveClosure 'empty'               == 'empty'+-- transitiveClosure ('vertex' x)          == 'vertex' x+-- transitiveClosure ('edge' x y)          == 'edge' x y+-- transitiveClosure ('path' $ 'Data.List.nub' xs)     == 'clique' ('Data.List.nub' xs)+-- transitiveClosure . transitiveClosure == transitiveClosure -- @-isTopSortOf :: [Int] -> AdjacencyIntMap -> Bool-isTopSortOf xs m = go IntSet.empty xs+transitiveClosure :: AdjacencyIntMap -> AdjacencyIntMap+transitiveClosure old+    | old == new = old+    | otherwise  = transitiveClosure new   where-    go seen []     = seen == IntMap.keysSet (adjacencyIntMap m)-    go seen (v:vs) = postIntSet v m `IntSet.intersection` newSeen == IntSet.empty-                  && go newSeen vs-      where-        newSeen = IntSet.insert v seen+    new = overlay old (old `compose` old)
+ src/Algebra/Graph/AdjacencyIntMap/Algorithm.hs view
@@ -0,0 +1,198 @@+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.AdjacencyIntMap.Algorithm+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : unstable+--+-- __Alga__ is a library for algebraic construction and manipulation of graphs+-- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the+-- motivation behind the library, the underlying theory, and implementation details.+--+-- This module provides basic graph algorithms, such as /depth-first search/,+-- implemented for the "Algebra.Graph.AdjacencyIntMap" data type.+-----------------------------------------------------------------------------+module Algebra.Graph.AdjacencyIntMap.Algorithm (+    -- * Algorithms+    dfsForest, dfsForestFrom, dfs, reachable, topSort, isAcyclic,++    -- * Correctness properties+    isDfsForestOf, isTopSortOf+    ) where++import Control.Monad+import Data.Maybe+import Data.Tree++import Algebra.Graph.AdjacencyIntMap++import qualified Data.Graph.Typed   as Typed+import qualified Data.IntMap.Strict as IntMap+import qualified Data.IntSet        as IntSet++-- | Compute the /depth-first search/ forest of a graph that corresponds to+-- searching from each of the graph vertices in the 'Ord' @a@ order.+--+-- @+-- dfsForest 'empty'                       == []+-- 'forest' (dfsForest $ 'edge' 1 1)         == 'vertex' 1+-- 'forest' (dfsForest $ 'edge' 1 2)         == 'edge' 1 2+-- 'forest' (dfsForest $ 'edge' 2 1)         == 'vertices' [1,2]+-- 'isSubgraphOf' ('forest' $ dfsForest x) x == True+-- 'isDfsForestOf' (dfsForest x) x         == True+-- dfsForest . 'forest' . dfsForest        == dfsForest+-- dfsForest ('vertices' vs)               == 'map' (\\v -> Node v []) ('Data.List.nub' $ 'Data.List.sort' vs)+-- 'dfsForestFrom' ('vertexList' x) x        == dfsForest x+-- dfsForest $ 3 * (1 + 4) * (1 + 5)     == [ Node { rootLabel = 1+--                                                 , subForest = [ Node { rootLabel = 5+--                                                                      , subForest = [] }]}+--                                          , Node { rootLabel = 3+--                                                 , subForest = [ Node { rootLabel = 4+--                                                                      , subForest = [] }]}]+-- @+dfsForest :: AdjacencyIntMap -> Forest Int+dfsForest = Typed.dfsForest . Typed.fromAdjacencyIntMap++-- | Compute the /depth-first search/ forest of a graph, searching from each of+-- the given vertices in order. Note that the resulting forest does not+-- necessarily span the whole graph, as some vertices may be unreachable.+--+-- @+-- dfsForestFrom vs 'empty'                           == []+-- 'forest' (dfsForestFrom [1]   $ 'edge' 1 1)          == 'vertex' 1+-- 'forest' (dfsForestFrom [1]   $ 'edge' 1 2)          == 'edge' 1 2+-- 'forest' (dfsForestFrom [2]   $ 'edge' 1 2)          == 'vertex' 2+-- 'forest' (dfsForestFrom [3]   $ 'edge' 1 2)          == 'empty'+-- 'forest' (dfsForestFrom [2,1] $ 'edge' 1 2)          == 'vertices' [1,2]+-- 'isSubgraphOf' ('forest' $ dfsForestFrom vs x) x     == True+-- 'isDfsForestOf' (dfsForestFrom ('vertexList' x) x) x == True+-- dfsForestFrom ('vertexList' x) x                   == 'dfsForest' x+-- dfsForestFrom vs             ('vertices' vs)       == 'map' (\\v -> Node v []) ('Data.List.nub' vs)+-- dfsForestFrom []             x                   == []+-- dfsForestFrom [1,4] $ 3 * (1 + 4) * (1 + 5)      == [ Node { rootLabel = 1+--                                                            , subForest = [ Node { rootLabel = 5+--                                                                                 , subForest = [] }+--                                                     , Node { rootLabel = 4+--                                                            , subForest = [] }]+-- @+dfsForestFrom :: [Int] -> AdjacencyIntMap -> Forest Int+dfsForestFrom vs = Typed.dfsForestFrom vs . Typed.fromAdjacencyIntMap++-- | Compute the list of vertices visited by the /depth-first search/ in a graph,+-- when searching from each of the given vertices in order.+--+-- @+-- dfs vs    $ 'empty'                    == []+-- dfs [1]   $ 'edge' 1 1                 == [1]+-- dfs [1]   $ 'edge' 1 2                 == [1,2]+-- dfs [2]   $ 'edge' 1 2                 == [2]+-- dfs [3]   $ 'edge' 1 2                 == []+-- dfs [1,2] $ 'edge' 1 2                 == [1,2]+-- dfs [2,1] $ 'edge' 1 2                 == [2,1]+-- dfs []    $ x                        == []+-- dfs [1,4] $ 3 * (1 + 4) * (1 + 5)    == [1,5,4]+-- 'isSubgraphOf' ('vertices' $ dfs vs x) x == True+-- @+dfs :: [Int] -> AdjacencyIntMap -> [Int]+dfs vs = concatMap flatten . dfsForestFrom vs++-- | Compute the list of vertices that are /reachable/ from a given source+-- vertex in a graph. The vertices in the resulting list appear in the+-- /depth-first order/.+--+-- @+-- reachable x $ 'empty'                       == []+-- reachable 1 $ 'vertex' 1                    == [1]+-- reachable 1 $ 'vertex' 2                    == []+-- reachable 1 $ 'edge' 1 1                    == [1]+-- reachable 1 $ 'edge' 1 2                    == [1,2]+-- reachable 4 $ 'path'    [1..8]              == [4..8]+-- reachable 4 $ 'circuit' [1..8]              == [4..8] ++ [1..3]+-- reachable 8 $ 'clique'  [8,7..1]            == [8] ++ [1..7]+-- 'isSubgraphOf' ('vertices' $ reachable x y) y == True+-- @+reachable :: Int -> AdjacencyIntMap -> [Int]+reachable x = dfs [x]++-- | Compute the /topological sort/ of a graph or return @Nothing@ if the graph+-- is cyclic.+--+-- @+-- topSort (1 * 2 + 3 * 1)               == Just [3,1,2]+-- topSort (1 * 2 + 2 * 1)               == Nothing+-- fmap ('flip' 'isTopSortOf' x) (topSort x) /= Just False+-- 'isJust' . topSort                      == 'isAcyclic'+-- @+topSort :: AdjacencyIntMap -> Maybe [Int]+topSort m = if isTopSortOf result m then Just result else Nothing+  where+    result = Typed.topSort (Typed.fromAdjacencyIntMap m)++-- | Check if a given graph is /acyclic/.+--+-- @+-- isAcyclic (1 * 2 + 3 * 1) == True+-- isAcyclic (1 * 2 + 2 * 1) == False+-- isAcyclic . 'circuit'       == 'null'+-- isAcyclic                 == 'isJust' . 'topSort'+-- @+isAcyclic :: AdjacencyIntMap -> Bool+isAcyclic = isJust . topSort++-- | Check if a given forest is a correct /depth-first search/ forest of a graph.+-- The implementation is based on the paper "Depth-First Search and Strong+-- Connectivity in Coq" by François Pottier.+--+-- @+-- isDfsForestOf []                              'empty'            == True+-- isDfsForestOf []                              ('vertex' 1)       == False+-- isDfsForestOf [Node 1 []]                     ('vertex' 1)       == True+-- isDfsForestOf [Node 1 []]                     ('vertex' 2)       == False+-- isDfsForestOf [Node 1 [], Node 1 []]          ('vertex' 1)       == False+-- isDfsForestOf [Node 1 []]                     ('edge' 1 1)       == True+-- isDfsForestOf [Node 1 []]                     ('edge' 1 2)       == False+-- isDfsForestOf [Node 1 [], Node 2 []]          ('edge' 1 2)       == False+-- isDfsForestOf [Node 2 [], Node 1 []]          ('edge' 1 2)       == True+-- isDfsForestOf [Node 1 [Node 2 []]]            ('edge' 1 2)       == True+-- isDfsForestOf [Node 1 [], Node 2 []]          ('vertices' [1,2]) == True+-- isDfsForestOf [Node 2 [], Node 1 []]          ('vertices' [1,2]) == True+-- isDfsForestOf [Node 1 [Node 2 []]]            ('vertices' [1,2]) == False+-- isDfsForestOf [Node 1 [Node 2 [Node 3 []]]]   ('path' [1,2,3])   == True+-- isDfsForestOf [Node 1 [Node 3 [Node 2 []]]]   ('path' [1,2,3])   == False+-- isDfsForestOf [Node 3 [], Node 1 [Node 2 []]] ('path' [1,2,3])   == True+-- isDfsForestOf [Node 2 [Node 3 []], Node 1 []] ('path' [1,2,3])   == True+-- isDfsForestOf [Node 1 [], Node 2 [Node 3 []]] ('path' [1,2,3])   == False+-- @+isDfsForestOf :: Forest Int -> AdjacencyIntMap -> Bool+isDfsForestOf f am = case go IntSet.empty f of+    Just seen -> seen == vertexIntSet am+    Nothing   -> False+  where+    go seen []     = Just seen+    go seen (t:ts) = do+        let root = rootLabel t+        guard $ root `IntSet.notMember` seen+        guard $ and [ hasEdge root (rootLabel subTree) am | subTree <- subForest t ]+        newSeen <- go (IntSet.insert root seen) (subForest t)+        guard $ postIntSet root am `IntSet.isSubsetOf` newSeen+        go newSeen ts++-- | Check if a given list of vertices is a correct /topological sort/ of a graph.+--+-- @+-- isTopSortOf [3,1,2] (1 * 2 + 3 * 1) == True+-- isTopSortOf [1,2,3] (1 * 2 + 3 * 1) == False+-- isTopSortOf []      (1 * 2 + 3 * 1) == False+-- isTopSortOf []      'empty'           == True+-- isTopSortOf [x]     ('vertex' x)      == True+-- isTopSortOf [x]     ('edge' x x)      == False+-- @+isTopSortOf :: [Int] -> AdjacencyIntMap -> Bool+isTopSortOf xs m = go IntSet.empty xs+  where+    go seen []     = seen == IntMap.keysSet (adjacencyIntMap m)+    go seen (v:vs) = postIntSet v m `IntSet.intersection` newSeen == IntSet.empty+                  && go newSeen vs+      where+        newSeen = IntSet.insert v seen
src/Algebra/Graph/AdjacencyIntMap/Internal.hs view
@@ -12,10 +12,14 @@ ----------------------------------------------------------------------------- module Algebra.Graph.AdjacencyIntMap.Internal (     -- * Adjacency map implementation-    AdjacencyIntMap (..), empty, vertex, overlay, connect, fromAdjacencyIntSets,-    consistent+    AdjacencyIntMap (..), consistent   ) where +import Prelude ()+import Prelude.Compat hiding (null)++import Data.Foldable (foldMap)+import Data.Monoid (getSum, Sum (..)) import Data.IntMap.Strict (IntMap, keysSet, fromSet) import Data.IntSet (IntSet) import Data.List@@ -35,6 +39,14 @@     > 1 + 2 * 3   == overlay (vertex 1) (connect (vertex 2) (vertex 3))     > 1 * (2 + 3) == connect (vertex 1) (overlay (vertex 2) (vertex 3)) +__Note:__ the 'Num' instance does not satisfy several "customary laws" of 'Num',+which dictate that 'fromInteger' @0@ and 'fromInteger' @1@ should act as+additive and multiplicative identities, and 'negate' as additive inverse.+Nevertheless, overloading 'fromInteger', '+' and '*' is very convenient when+working with algebraic graphs; we hope that in future Haskell's Prelude will+provide a more fine-grained class hierarchy for algebraic structures, which we+would be able to utilise without violating any laws.+ The 'Show' instance is defined using basic graph construction primitives:  @show (empty     :: AdjacencyIntMap Int) == "empty"@@ -84,10 +96,36 @@  When specifying the time and memory complexity of graph algorithms, /n/ and /m/ will denote the number of vertices and edges in the graph, respectively.++The total order on graphs is defined using /size-lexicographic/ comparison:++* Compare the number of vertices. In case of a tie, continue.+* Compare the sets of vertices. In case of a tie, continue.+* Compare the number of edges. In case of a tie, continue.+* Compare the sets of edges.++Here are a few examples:++@'Algebra.Graph.AdjacencyIntMap.vertex' 1 < 'Algebra.Graph.AdjacencyIntMap.vertex' 2+'Algebra.Graph.AdjacencyIntMap.vertex' 3 < 'Algebra.Graph.AdjacencyIntMap.edge' 1 2+'Algebra.Graph.AdjacencyIntMap.vertex' 1 < 'Algebra.Graph.AdjacencyIntMap.edge' 1 1+'Algebra.Graph.AdjacencyIntMap.edge' 1 1 < 'Algebra.Graph.AdjacencyIntMap.edge' 1 2+'Algebra.Graph.AdjacencyIntMap.edge' 1 2 < 'Algebra.Graph.AdjacencyIntMap.edge' 1 1 + 'Algebra.Graph.AdjacencyIntMap.edge' 2 2+'Algebra.Graph.AdjacencyIntMap.edge' 1 2 < 'Algebra.Graph.AdjacencyIntMap.edge' 1 3@++Note that the resulting order refines the 'Algebra.Graph.AdjacencyIntMap.isSubgraphOf'+relation and is compatible with 'Algebra.Graph.AdjacencyIntMap.overlay' and+'Algebra.Graph.AdjacencyIntMap.connect' operations:++@'Algebra.Graph.AdjacencyIntMap.isSubgraphOf' x y ==> x <= y@++@'Algebra.Graph.AdjacencyIntMap.empty' <= x+x     <= x + y+x + y <= x * y@ -} newtype AdjacencyIntMap = AM {-    -- | The /adjacency map/ of the graph: each vertex is associated with a set-    -- of its direct successors. Complexity: /O(1)/ time and memory.+    -- | The /adjacency map/ of a graph: each vertex is associated with a set of+    -- its direct successors. Complexity: /O(1)/ time and memory.     --     -- @     -- adjacencyIntMap 'empty'      == IntMap.'IntMap.empty'@@ -98,113 +136,47 @@     adjacencyIntMap :: IntMap IntSet } deriving Eq  instance Show AdjacencyIntMap where-    show (AM m)-        | null vs    = "empty"-        | null es    = vshow vs-        | vs == used = eshow es-        | otherwise  = "overlay (" ++ vshow (vs \\ used) ++ ") (" ++ eshow es ++ ")"+    showsPrec p (AM m)+        | null vs    = showString "empty"+        | null es    = showParen (p > 10) $ vshow vs+        | vs == used = showParen (p > 10) $ eshow es+        | otherwise  = showParen (p > 10) $+                           showString "overlay (" . vshow (vs \\ used) .+                           showString ") (" . eshow es . showString ")"       where         vs             = IntSet.toAscList (keysSet m)         es             = internalEdgeList m-        vshow [x]      = "vertex "   ++ show x-        vshow xs       = "vertices " ++ show xs-        eshow [(x, y)] = "edge "     ++ show x ++ " " ++ show y-        eshow xs       = "edges "    ++ show xs+        vshow [x]      = showString "vertex "   . showsPrec 11 x+        vshow xs       = showString "vertices " . showsPrec 11 xs+        eshow [(x, y)] = showString "edge "     . showsPrec 11 x .+                         showString " "         . showsPrec 11 y+        eshow xs       = showString "edges "    . showsPrec 11 xs         used           = IntSet.toAscList (referredToVertexSet m) --- | Construct the /empty graph/.--- Complexity: /O(1)/ time and memory.------ @--- 'Algebra.Graph.AdjacencyIntMap.isEmpty'     empty == True--- 'Algebra.Graph.AdjacencyIntMap.hasVertex' x empty == False--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' empty == 0--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   empty == 0--- @-empty :: AdjacencyIntMap-empty = AM IntMap.empty-{-# NOINLINE [1] empty #-}---- | Construct the graph comprising /a single isolated vertex/.--- Complexity: /O(1)/ time and memory.------ @--- 'Algebra.Graph.AdjacencyIntMap.isEmpty'     (vertex x) == False--- 'Algebra.Graph.AdjacencyIntMap.hasVertex' x (vertex x) == True--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' (vertex x) == 1--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (vertex x) == 0--- @-vertex :: Int -> AdjacencyIntMap-vertex x = AM $ IntMap.singleton x IntSet.empty-{-# NOINLINE [1] vertex #-}---- | /Overlay/ two graphs. This is a commutative, associative and idempotent--- operation with the identity 'empty'.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.------ @--- 'Algebra.Graph.AdjacencyIntMap.isEmpty'     (overlay x y) == 'Algebra.Graph.AdjacencyIntMap.isEmpty'   x   && 'Algebra.Graph.AdjacencyIntMap.isEmpty'   y--- 'Algebra.Graph.AdjacencyIntMap.hasVertex' z (overlay x y) == 'Algebra.Graph.AdjacencyIntMap.hasVertex' z x || 'Algebra.Graph.AdjacencyIntMap.hasVertex' z y--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' (overlay x y) >= 'Algebra.Graph.AdjacencyIntMap.vertexCount' x--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' (overlay x y) <= 'Algebra.Graph.AdjacencyIntMap.vertexCount' x + 'Algebra.Graph.AdjacencyIntMap.vertexCount' y--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (overlay x y) >= 'Algebra.Graph.AdjacencyIntMap.edgeCount' x--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (overlay x y) <= 'Algebra.Graph.AdjacencyIntMap.edgeCount' x   + 'Algebra.Graph.AdjacencyIntMap.edgeCount' y--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' (overlay 1 2) == 2--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (overlay 1 2) == 0--- @-overlay :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap-overlay x y = AM $ IntMap.unionWith IntSet.union (adjacencyIntMap x) (adjacencyIntMap y)-{-# NOINLINE [1] overlay #-}---- | /Connect/ two graphs. This is an associative operation with the identity--- 'empty', which distributes over 'overlay' and obeys the decomposition axiom.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. Note that the--- number of edges in the resulting graph is quadratic with respect to the number--- of vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.------ @--- 'Algebra.Graph.AdjacencyIntMap.isEmpty'     (connect x y) == 'Algebra.Graph.AdjacencyIntMap.isEmpty'   x   && 'Algebra.Graph.AdjacencyIntMap.isEmpty'   y--- 'Algebra.Graph.AdjacencyIntMap.hasVertex' z (connect x y) == 'Algebra.Graph.AdjacencyIntMap.hasVertex' z x || 'Algebra.Graph.AdjacencyIntMap.hasVertex' z y--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' (connect x y) >= 'Algebra.Graph.AdjacencyIntMap.vertexCount' x--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' (connect x y) <= 'Algebra.Graph.AdjacencyIntMap.vertexCount' x + 'Algebra.Graph.AdjacencyIntMap.vertexCount' y--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (connect x y) >= 'Algebra.Graph.AdjacencyIntMap.edgeCount' x--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (connect x y) >= 'Algebra.Graph.AdjacencyIntMap.edgeCount' y--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (connect x y) >= 'Algebra.Graph.AdjacencyIntMap.vertexCount' x * 'Algebra.Graph.AdjacencyIntMap.vertexCount' y--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (connect x y) <= 'Algebra.Graph.AdjacencyIntMap.vertexCount' x * 'Algebra.Graph.AdjacencyIntMap.vertexCount' y + 'Algebra.Graph.AdjacencyIntMap.edgeCount' x + 'Algebra.Graph.AdjacencyIntMap.edgeCount' y--- 'Algebra.Graph.AdjacencyIntMap.vertexCount' (connect 1 2) == 2--- 'Algebra.Graph.AdjacencyIntMap.edgeCount'   (connect 1 2) == 1--- @-connect :: AdjacencyIntMap -> AdjacencyIntMap -> AdjacencyIntMap-connect x y = AM $ IntMap.unionsWith IntSet.union [ adjacencyIntMap x, adjacencyIntMap y,-    fromSet (const . keysSet $ adjacencyIntMap y) (keysSet $ adjacencyIntMap x) ]-{-# NOINLINE [1] connect #-}+instance Ord AdjacencyIntMap where+    compare (AM x) (AM y) = mconcat+        [ compare (vNum x) (vNum y)+        , compare (vSet x) (vSet y)+        , compare (eNum x) (eNum y)+        , compare       x        y ]+      where+        vNum = IntMap.size+        vSet = IntMap.keysSet+        eNum = getSum . foldMap (Sum . IntSet.size) +-- | __Note:__ this does not satisfy the usual ring laws; see 'AdjacencyIntMap'+-- for more details. instance Num AdjacencyIntMap where-    fromInteger = vertex . fromInteger-    (+)         = overlay-    (*)         = connect-    signum      = const empty-    abs         = id-    negate      = id+    fromInteger x = AM $ IntMap.singleton (fromInteger x) IntSet.empty+    x + y  = AM $ IntMap.unionWith IntSet.union (adjacencyIntMap x) (adjacencyIntMap y)+    x * y  = AM $ IntMap.unionsWith IntSet.union [ adjacencyIntMap x, adjacencyIntMap y,+        fromSet (const . keysSet $ adjacencyIntMap y) (keysSet $ adjacencyIntMap x) ]+    signum = const (AM IntMap.empty)+    abs    = id+    negate = id  instance NFData AdjacencyIntMap where     rnf (AM a) = rnf a---- | Construct a graph from a list of adjacency sets.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.------ @--- fromAdjacencyIntSets []                                           == 'Algebra.Graph.AdjacencyIntMap.empty'--- fromAdjacencyIntSets [(x, IntSet.'IntSet.empty')]                          == 'Algebra.Graph.AdjacencyIntMap.vertex' x--- fromAdjacencyIntSets [(x, IntSet.'IntSet.singleton' y)]                    == 'Algebra.Graph.AdjacencyIntMap.edge' x y--- fromAdjacencyIntSets . map (fmap IntSet.'IntSet.fromList') . 'Algebra.Graph.AdjacencyIntMap.adjacencyList' == id--- 'Algebra.Graph.AdjacencyIntMap.overlay' (fromAdjacencyIntSets xs) (fromAdjacencyIntSets ys)       == fromAdjacencyIntSets (xs ++ ys)--- @-fromAdjacencyIntSets :: [(Int, IntSet)] -> AdjacencyIntMap-fromAdjacencyIntSets ss = AM $ IntMap.unionWith IntSet.union vs es-  where-    vs = IntMap.fromSet (const IntSet.empty) . IntSet.unions $ map snd ss-    es = IntMap.fromListWith IntSet.union ss  -- | Check if the internal graph representation is consistent, i.e. that all -- edges refer to existing vertices. It should be impossible to create an
src/Algebra/Graph/AdjacencyMap.hs view
@@ -10,9 +10,10 @@ -- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the -- motivation behind the library, the underlying theory, and implementation details. ----- This module defines the 'AdjacencyMap' data type, as well as associated--- operations and algorithms. 'AdjacencyMap' is an instance of the 'C.Graph' type--- class, which can be used for polymorphic graph construction and manipulation.+-- This module defines the 'AdjacencyMap' data type and associated functions.+-- See "Algebra.Graph.AdjacencyMap.Algorithm" for implementations of basic graph+-- algorithms. 'AdjacencyMap' is an instance of the 'C.Graph' type class, which+-- can be used for polymorphic graph construction and manipulation. -- "Algebra.Graph.AdjacencyIntMap" defines adjacency maps specialised to graphs -- with @Int@ vertices. -----------------------------------------------------------------------------@@ -28,37 +29,56 @@      -- * Graph properties     isEmpty, hasVertex, hasEdge, vertexCount, edgeCount, vertexList, edgeList,-    adjacencyList, vertexSet, vertexIntSet, edgeSet, preSet, postSet,+    adjacencyList, vertexSet, edgeSet, preSet, postSet,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, stars, tree, forest,+    path, circuit, clique, biclique, star, stars, fromAdjacencySets, tree,+    forest,      -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, transpose, gmap,     induce, -    -- * Algorithms-    dfsForest, dfsForestFrom, dfs, reachable, topSort, isAcyclic, scc,--    -- * Correctness properties-    isDfsForestOf, isTopSortOf-  ) where+    -- * Relational operations+    compose, closure, reflexiveClosure, symmetricClosure, transitiveClosure+    ) where -import Control.Monad-import Data.Foldable (foldMap, toList)-import Data.Maybe+import Data.Foldable (foldMap) import Data.Monoid import Data.Set (Set) import Data.Tree  import Algebra.Graph.AdjacencyMap.Internal -import qualified Data.Graph.Typed as Typed-import qualified Data.Graph       as KL-import qualified Data.Map.Strict  as Map-import qualified Data.Set         as Set-import qualified Data.IntSet      as IntSet+import qualified Data.Map.Strict as Map+import qualified Data.Set        as Set +-- | Construct the /empty graph/.+-- Complexity: /O(1)/ time and memory.+--+-- @+-- 'isEmpty'     empty == True+-- 'hasVertex' x empty == False+-- 'vertexCount' empty == 0+-- 'edgeCount'   empty == 0+-- @+empty :: AdjacencyMap a+empty = AM Map.empty+{-# NOINLINE [1] empty #-}++-- | Construct the graph comprising /a single isolated vertex/.+-- Complexity: /O(1)/ time and memory.+--+-- @+-- 'isEmpty'     (vertex x) == False+-- 'hasVertex' x (vertex x) == True+-- 'vertexCount' (vertex x) == 1+-- 'edgeCount'   (vertex x) == 0+-- @+vertex :: a -> AdjacencyMap a+vertex x = AM $ Map.singleton x Set.empty+{-# NOINLINE [1] vertex #-}+ -- | Construct the graph comprising /a single edge/. -- Complexity: /O(1)/ time, memory. --@@ -73,6 +93,47 @@ edge x y | x == y    = AM $ Map.singleton x (Set.singleton y)          | otherwise = AM $ Map.fromList [(x, Set.singleton y), (y, Set.empty)] +-- | /Overlay/ two graphs. This is a commutative, associative and idempotent+-- operation with the identity 'empty'.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- 'isEmpty'     (overlay x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (overlay x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (overlay x y) >= 'vertexCount' x+-- 'vertexCount' (overlay x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (overlay x y) >= 'edgeCount' x+-- 'edgeCount'   (overlay x y) <= 'edgeCount' x   + 'edgeCount' y+-- 'vertexCount' (overlay 1 2) == 2+-- 'edgeCount'   (overlay 1 2) == 0+-- @+overlay :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a+overlay x y = AM $ Map.unionWith Set.union (adjacencyMap x) (adjacencyMap y)+{-# NOINLINE [1] overlay #-}++-- | /Connect/ two graphs. This is an associative operation with the identity+-- 'empty', which distributes over 'overlay' and obeys the decomposition axiom.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. Note that the+-- number of edges in the resulting graph is quadratic with respect to the number+-- of vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.+--+-- @+-- 'isEmpty'     (connect x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (connect x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (connect x y) >= 'vertexCount' x+-- 'vertexCount' (connect x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (connect x y) >= 'edgeCount' x+-- 'edgeCount'   (connect x y) >= 'edgeCount' y+-- 'edgeCount'   (connect x y) >= 'vertexCount' x * 'vertexCount' y+-- 'edgeCount'   (connect x y) <= 'vertexCount' x * 'vertexCount' y + 'edgeCount' x + 'edgeCount' y+-- 'vertexCount' (connect 1 2) == 2+-- 'edgeCount'   (connect 1 2) == 1+-- @+connect :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a+connect x y = AM $ Map.unionsWith Set.union $ adjacencyMap x : adjacencyMap y :+    [ Map.fromSet (const . Map.keysSet $ adjacencyMap y) (Map.keysSet $ adjacencyMap x) ]+{-# NOINLINE [1] connect #-}+ -- | Construct the graph comprising a given list of isolated vertices. -- Complexity: /O(L * log(L))/ time and /O(L)/ memory, where /L/ is the length -- of the given list.@@ -133,11 +194,12 @@ -- Complexity: /O((n + m) * log(n))/ time. -- -- @--- isSubgraphOf 'empty'         x             == True--- isSubgraphOf ('vertex' x)    'empty'         == False--- isSubgraphOf x             ('overlay' x y) == True--- isSubgraphOf ('overlay' x y) ('connect' x y) == True--- isSubgraphOf ('path' xs)     ('circuit' xs)  == True+-- isSubgraphOf 'empty'         x             ==  True+-- isSubgraphOf ('vertex' x)    'empty'         ==  False+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf ('path' xs)     ('circuit' xs)  ==  True+-- isSubgraphOf x y                         ==> x <= y -- @ isSubgraphOf :: Ord a => AdjacencyMap a -> AdjacencyMap a -> Bool isSubgraphOf x y = Map.isSubmapOfBy Set.isSubsetOf (adjacencyMap x) (adjacencyMap y)@@ -162,7 +224,7 @@ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True -- hasVertex 1 ('vertex' 2)       == False--- hasVertex x . 'removeVertex' x == const False+-- hasVertex x . 'removeVertex' x == 'const' False -- @ hasVertex :: Ord a => a -> AdjacencyMap a -> Bool hasVertex x = Map.member x . adjacencyMap@@ -174,7 +236,7 @@ -- hasEdge x y 'empty'            == False -- hasEdge x y ('vertex' z)       == False -- hasEdge x y ('edge' x y)       == True--- hasEdge x y . 'removeEdge' x y == const False+-- hasEdge x y . 'removeEdge' x y == 'const' False -- hasEdge x y                  == 'elem' (x,y) . 'edgeList' -- @ hasEdge :: Ord a => a -> a -> AdjacencyMap a -> Bool@@ -186,9 +248,10 @@ -- Complexity: /O(1)/ time. -- -- @--- vertexCount 'empty'      == 0--- vertexCount ('vertex' x) == 1--- vertexCount            == 'length' . 'vertexList'+-- vertexCount 'empty'             ==  0+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y -- @ vertexCount :: AdjacencyMap a -> Int vertexCount = Map.size . adjacencyMap@@ -225,7 +288,7 @@ -- edgeList ('edge' x y)     == [(x,y)] -- edgeList ('star' 2 [3,1]) == [(2,1), (2,3)] -- edgeList . 'edges'        == 'Data.List.nub' . 'Data.List.sort'--- edgeList . 'transpose'    == 'Data.List.sort' . map 'Data.Tuple.swap' . edgeList+-- edgeList . 'transpose'    == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . edgeList -- @ edgeList :: AdjacencyMap a -> [(a, a)] edgeList (AM m) = [ (x, y) | (x, ys) <- Map.toAscList m, y <- Set.toAscList ys ]@@ -237,24 +300,10 @@ -- vertexSet 'empty'      == Set.'Set.empty' -- vertexSet . 'vertex'   == Set.'Set.singleton' -- vertexSet . 'vertices' == Set.'Set.fromList'--- vertexSet . 'clique'   == Set.'Set.fromList' -- @ vertexSet :: AdjacencyMap a -> Set a vertexSet = Map.keysSet . adjacencyMap --- | The set of vertices of a given graph. Like 'vertexSet' but specialised for--- graphs with vertices of type 'Int'.--- Complexity: /O(n)/ time and memory.------ @--- vertexIntSet 'empty'      == IntSet.'IntSet.empty'--- vertexIntSet . 'vertex'   == IntSet.'IntSet.singleton'--- vertexIntSet . 'vertices' == IntSet.'IntSet.fromList'--- vertexIntSet . 'clique'   == IntSet.'IntSet.fromList'--- @-vertexIntSet :: AdjacencyMap Int -> IntSet.IntSet-vertexIntSet = IntSet.fromAscList . Set.toAscList . vertexSet- -- | The set of edges of a given graph. -- Complexity: /O((n + m) * log(m))/ time and /O(m)/ memory. --@@ -264,7 +313,7 @@ -- edgeSet ('edge' x y) == Set.'Set.singleton' (x,y) -- edgeSet . 'edges'    == Set.'Set.fromList' -- @-edgeSet :: Ord a => AdjacencyMap a -> Set (a, a)+edgeSet :: Eq a => AdjacencyMap a -> Set (a, a) edgeSet = Set.fromAscList . edgeList  -- | The sorted /adjacency list/ of a graph.@@ -341,7 +390,7 @@ -- clique [x]        == 'vertex' x -- clique [x,y]      == 'edge' x y -- clique [x,y,z]    == 'edges' [(x,y), (x,z), (y,z)]--- clique (xs ++ ys) == 'connect' (clique xs) (clique ys)+-- clique (xs '++' ys) == 'connect' (clique xs) (clique ys) -- clique . 'reverse'  == 'transpose' . clique -- @ clique :: Ord a => [a] -> AdjacencyMap a@@ -393,13 +442,29 @@ -- stars [(x, [])]               == 'vertex' x -- stars [(x, [y])]              == 'edge' x y -- stars [(x, ys)]               == 'star' x ys--- stars                         == 'overlays' . map (uncurry 'star')+-- stars                         == 'overlays' . 'map' ('uncurry' 'star') -- stars . 'adjacencyList'         == id--- 'overlay' (stars xs) (stars ys) == stars (xs ++ ys)+-- 'overlay' (stars xs) (stars ys) == stars (xs '++' ys) -- @ stars :: Ord a => [(a, [a])] -> AdjacencyMap a stars = fromAdjacencySets . map (fmap Set.fromList) +-- | Construct a graph from a list of adjacency sets; a variation of 'stars'.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- fromAdjacencySets []                                  == 'empty'+-- fromAdjacencySets [(x, Set.'Set.empty')]                    == 'vertex' x+-- fromAdjacencySets [(x, Set.'Set.singleton' y)]              == 'edge' x y+-- fromAdjacencySets . 'map' ('fmap' Set.'Set.fromList')           == 'stars'+-- 'overlay' (fromAdjacencySets xs) (fromAdjacencySets ys) == fromAdjacencySets (xs '++' ys)+-- @+fromAdjacencySets :: Ord a => [(a, Set a)] -> AdjacencyMap a+fromAdjacencySets ss = AM $ Map.unionWith Set.union vs es+  where+    vs = Map.fromSet (const Set.empty) . Set.unions $ map snd ss+    es = Map.fromListWith Set.union ss+ -- | The /tree graph/ constructed from a given 'Tree' data structure. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. --@@ -421,7 +486,7 @@ -- forest []                                                  == 'empty' -- forest [x]                                                 == 'tree' x -- forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == 'edges' [(1,2), (1,3), (4,5)]--- forest                                                     == 'overlays' . map 'tree'+-- forest                                                     == 'overlays' . 'map' 'tree' -- @ forest :: Ord a => Forest a -> AdjacencyMap a forest = overlays . map tree@@ -469,10 +534,10 @@ -- /O(1)/ to be evaluated. -- -- @--- mergeVertices (const False) x    == id+-- mergeVertices ('const' False) x    == id -- mergeVertices (== x) y           == 'replaceVertex' x y--- mergeVertices even 1 (0 * 2)     == 1 * 1--- mergeVertices odd  1 (3 + 4 * 5) == 4 * 1+-- mergeVertices 'even' 1 (0 * 2)     == 1 * 1+-- mergeVertices 'odd'  1 (3 + 4 * 5) == 4 * 1 -- @ mergeVertices :: Ord a => (a -> Bool) -> a -> AdjacencyMap a -> AdjacencyMap a mergeVertices p v = gmap $ \u -> if p u then v else u@@ -485,7 +550,7 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList'+-- 'edgeList' . transpose  == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: Ord a => AdjacencyMap a -> AdjacencyMap a transpose (AM m) = AM $ Map.foldrWithKey combine vs m@@ -516,7 +581,7 @@ -- gmap f 'empty'      == 'empty' -- gmap f ('vertex' x) == 'vertex' (f x) -- gmap f ('edge' x y) == 'edge' (f x) (f y)--- gmap id           == id+-- gmap 'id'           == 'id' -- gmap f . gmap g   == gmap (f . g) -- @ gmap :: (Ord a, Ord b) => (a -> b) -> AdjacencyMap a -> AdjacencyMap b@@ -528,8 +593,8 @@ -- be evaluated. -- -- @--- induce (const True ) x      == x--- induce (const False) x      == 'empty'+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x) -- 'isSubgraphOf' (induce p x) x == True@@ -537,188 +602,92 @@ induce :: (a -> Bool) -> AdjacencyMap a -> AdjacencyMap a induce p = AM . Map.map (Set.filter p) . Map.filterWithKey (\k _ -> p k) . adjacencyMap --- | Compute the /depth-first search/ forest of a graph that corresponds to--- searching from each of the graph vertices in the 'Ord' @a@ order.------ @--- dfsForest 'empty'                       == []--- 'forest' (dfsForest $ 'edge' 1 1)         == 'vertex' 1--- 'forest' (dfsForest $ 'edge' 1 2)         == 'edge' 1 2--- 'forest' (dfsForest $ 'edge' 2 1)         == 'vertices' [1,2]--- 'isSubgraphOf' ('forest' $ dfsForest x) x == True--- 'isDfsForestOf' (dfsForest x) x         == True--- dfsForest . 'forest' . dfsForest        == dfsForest--- dfsForest ('vertices' vs)               == map (\\v -> Node v []) ('Data.List.nub' $ 'Data.List.sort' vs)--- 'dfsForestFrom' ('vertexList' x) x        == dfsForest x--- dfsForest $ 3 * (1 + 4) * (1 + 5)     == [ Node { rootLabel = 1---                                                 , subForest = [ Node { rootLabel = 5---                                                                      , subForest = [] }]}---                                          , Node { rootLabel = 3---                                                 , subForest = [ Node { rootLabel = 4---                                                                      , subForest = [] }]}]--- @-dfsForest :: Ord a => AdjacencyMap a -> Forest a-dfsForest g = dfsForestFrom (vertexList g) g---- | Compute the /depth-first search/ forest of a graph, searching from each of--- the given vertices in order. Note that the resulting forest does not--- necessarily span the whole graph, as some vertices may be unreachable.------ @--- dfsForestFrom vs 'empty'                           == []--- 'forest' (dfsForestFrom [1]   $ 'edge' 1 1)          == 'vertex' 1--- 'forest' (dfsForestFrom [1]   $ 'edge' 1 2)          == 'edge' 1 2--- 'forest' (dfsForestFrom [2]   $ 'edge' 1 2)          == 'vertex' 2--- 'forest' (dfsForestFrom [3]   $ 'edge' 1 2)          == 'empty'--- 'forest' (dfsForestFrom [2,1] $ 'edge' 1 2)          == 'vertices' [1,2]--- 'isSubgraphOf' ('forest' $ dfsForestFrom vs x) x     == True--- 'isDfsForestOf' (dfsForestFrom ('vertexList' x) x) x == True--- dfsForestFrom ('vertexList' x) x                   == 'dfsForest' x--- dfsForestFrom vs             ('vertices' vs)       == map (\\v -> Node v []) ('Data.List.nub' vs)--- dfsForestFrom []             x                   == []--- dfsForestFrom [1,4] $ 3 * (1 + 4) * (1 + 5)      == [ Node { rootLabel = 1---                                                            , subForest = [ Node { rootLabel = 5---                                                                                 , subForest = [] }---                                                     , Node { rootLabel = 4---                                                            , subForest = [] }]--- @-dfsForestFrom :: Ord a => [a] -> AdjacencyMap a -> Forest a-dfsForestFrom vs = Typed.dfsForestFrom vs . Typed.fromAdjacencyMap---- | Compute the list of vertices visited by the /depth-first search/ in a--- graph, when searching from each of the given vertices in order.------ @--- dfs vs    $ 'empty'                    == []--- dfs [1]   $ 'edge' 1 1                 == [1]--- dfs [1]   $ 'edge' 1 2                 == [1,2]--- dfs [2]   $ 'edge' 1 2                 == [2]--- dfs [3]   $ 'edge' 1 2                 == []--- dfs [1,2] $ 'edge' 1 2                 == [1,2]--- dfs [2,1] $ 'edge' 1 2                 == [2,1]--- dfs []    $ x                        == []--- dfs [1,4] $ 3 * (1 + 4) * (1 + 5)    == [1,5,4]--- 'isSubgraphOf' ('vertices' $ dfs vs x) x == True--- @-dfs :: Ord a => [a] -> AdjacencyMap a -> [a]-dfs vs = concatMap flatten . dfsForestFrom vs---- | Compute the list of vertices that are /reachable/ from a given source--- vertex in a graph. The vertices in the resulting list appear in the--- /depth-first order/.------ @--- reachable x $ 'empty'                       == []--- reachable 1 $ 'vertex' 1                    == [1]--- reachable 1 $ 'vertex' 2                    == []--- reachable 1 $ 'edge' 1 1                    == [1]--- reachable 1 $ 'edge' 1 2                    == [1,2]--- reachable 4 $ 'path'    [1..8]              == [4..8]--- reachable 4 $ 'circuit' [1..8]              == [4..8] ++ [1..3]--- reachable 8 $ 'clique'  [8,7..1]            == [8] ++ [1..7]--- 'isSubgraphOf' ('vertices' $ reachable x y) y == True--- @-reachable :: Ord a => a -> AdjacencyMap a -> [a]-reachable x = dfs [x]---- | Compute the /topological sort/ of a graph or return @Nothing@ if the graph--- is cyclic.+-- | Left-to-right /relational composition/ of graphs: vertices @x@ and @z@ are+-- connected in the resulting graph if there is a vertex @y@, such that @x@ is+-- connected to @y@ in the first graph, and @y@ is connected to @z@ in the+-- second graph. There are no isolated vertices in the result. This operation is+-- associative, has 'empty' and single-'vertex' graphs as /annihilating zeroes/,+-- and distributes over 'overlay'.+-- Complexity: /O(n * m * log(n))/ time and /O(n + m)/ memory. -- -- @--- topSort (1 * 2 + 3 * 1)               == Just [3,1,2]--- topSort (1 * 2 + 2 * 1)               == Nothing--- fmap (flip 'isTopSortOf' x) (topSort x) /= Just False--- 'isJust' . topSort                      == 'isAcyclic'+-- compose 'empty'            x                == 'empty'+-- compose x                'empty'            == 'empty'+-- compose ('vertex' x)       y                == 'empty'+-- compose x                ('vertex' y)       == 'empty'+-- compose x                (compose y z)    == compose (compose x y) z+-- compose x                ('overlay' y z)    == 'overlay' (compose x y) (compose x z)+-- compose ('overlay' x y)    z                == 'overlay' (compose x z) (compose y z)+-- compose ('edge' x y)       ('edge' y z)       == 'edge' x z+-- compose ('path'    [1..5]) ('path'    [1..5]) == 'edges' [(1,3), (2,4), (3,5)]+-- compose ('circuit' [1..5]) ('circuit' [1..5]) == 'circuit' [1,3,5,2,4] -- @-topSort :: Ord a => AdjacencyMap a -> Maybe [a]-topSort m = if isTopSortOf result m then Just result else Nothing+compose :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a+compose x y = fromAdjacencySets+    [ (t, ys) | v <- Set.toList vs, let ys = postSet v y, not (Set.null ys)+              , t <- Set.toList (postSet v tx) ]   where-    result = Typed.topSort (Typed.fromAdjacencyMap m)+    tx = transpose x+    vs = vertexSet x `Set.union` vertexSet y --- | Check if a given graph is /acyclic/.+-- | Compute the /reflexive and transitive closure/ of a graph.+-- Complexity: /O(n * m * log(n)^2)/ time. -- -- @--- isAcyclic (1 * 2 + 3 * 1) == True--- isAcyclic (1 * 2 + 2 * 1) == False--- isAcyclic . 'circuit'       == 'null'--- isAcyclic                 == 'isJust' . 'topSort'+-- closure 'empty'           == 'empty'+-- closure ('vertex' x)      == 'edge' x x+-- closure ('edge' x x)      == 'edge' x x+-- closure ('edge' x y)      == 'edges' [(x,x), (x,y), (y,y)]+-- closure ('path' $ 'Data.List.nub' xs) == 'reflexiveClosure' ('clique' $ 'Data.List.nub' xs)+-- closure                 == 'reflexiveClosure' . 'transitiveClosure'+-- closure                 == 'transitiveClosure' . 'reflexiveClosure'+-- closure . closure       == closure+-- 'postSet' x (closure y)   == Set.'Set.fromList' ('Algebra.Graph.ToGraph.reachable' x y) -- @-isAcyclic :: Ord a => AdjacencyMap a -> Bool-isAcyclic = isJust . topSort+closure :: Ord a => AdjacencyMap a -> AdjacencyMap a+closure = reflexiveClosure . transitiveClosure --- | Compute the /condensation/ of a graph, where each vertex corresponds to a--- /strongly-connected component/ of the original graph.+-- | Compute the /reflexive closure/ of a graph by adding a self-loop to every+-- vertex.+-- Complexity: /O(n * log(n))/ time. -- -- @--- scc 'empty'               == 'empty'--- scc ('vertex' x)          == 'vertex' (Set.'Set.singleton' x)--- scc ('edge' x y)          == 'edge' (Set.'Set.singleton' x) (Set.'Set.singleton' y)--- scc ('circuit' (1:xs))    == 'edge' (Set.'Set.fromList' (1:xs)) (Set.'Set.fromList' (1:xs))--- scc (3 * 1 * 4 * 1 * 5) == 'edges' [ (Set.'Set.fromList' [1,4], Set.'Set.fromList' [1,4])---                                  , (Set.'Set.fromList' [1,4], Set.'Set.fromList' [5]  )---                                  , (Set.'Set.fromList' [3]  , Set.'Set.fromList' [1,4])---                                  , (Set.'Set.fromList' [3]  , Set.'Set.fromList' [5]  )]+-- reflexiveClosure 'empty'              == 'empty'+-- reflexiveClosure ('vertex' x)         == 'edge' x x+-- reflexiveClosure ('edge' x x)         == 'edge' x x+-- reflexiveClosure ('edge' x y)         == 'edges' [(x,x), (x,y), (y,y)]+-- reflexiveClosure . reflexiveClosure == reflexiveClosure -- @-scc :: Ord a => AdjacencyMap a -> AdjacencyMap (Set a)-scc m = gmap (\v -> Map.findWithDefault Set.empty v components) m-  where-    (Typed.GraphKL g r _) = Typed.fromAdjacencyMap m-    components = Map.fromList $ concatMap (expand . fmap r . toList) (KL.scc g)-    expand xs  = let s = Set.fromList xs in map (\x -> (x, s)) xs+reflexiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a+reflexiveClosure (AM m) = AM $ Map.mapWithKey (\k -> Set.insert k) m --- | Check if a given forest is a correct /depth-first search/ forest of a graph.--- The implementation is based on the paper "Depth-First Search and Strong--- Connectivity in Coq" by François Pottier.+-- | Compute the /symmetric closure/ of a graph by overlaying it with its own+-- transpose.+-- Complexity: /O((n + m) * log(n))/ time. -- -- @--- isDfsForestOf []                              'empty'            == True--- isDfsForestOf []                              ('vertex' 1)       == False--- isDfsForestOf [Node 1 []]                     ('vertex' 1)       == True--- isDfsForestOf [Node 1 []]                     ('vertex' 2)       == False--- isDfsForestOf [Node 1 [], Node 1 []]          ('vertex' 1)       == False--- isDfsForestOf [Node 1 []]                     ('edge' 1 1)       == True--- isDfsForestOf [Node 1 []]                     ('edge' 1 2)       == False--- isDfsForestOf [Node 1 [], Node 2 []]          ('edge' 1 2)       == False--- isDfsForestOf [Node 2 [], Node 1 []]          ('edge' 1 2)       == True--- isDfsForestOf [Node 1 [Node 2 []]]            ('edge' 1 2)       == True--- isDfsForestOf [Node 1 [], Node 2 []]          ('vertices' [1,2]) == True--- isDfsForestOf [Node 2 [], Node 1 []]          ('vertices' [1,2]) == True--- isDfsForestOf [Node 1 [Node 2 []]]            ('vertices' [1,2]) == False--- isDfsForestOf [Node 1 [Node 2 [Node 3 []]]]   ('path' [1,2,3])   == True--- isDfsForestOf [Node 1 [Node 3 [Node 2 []]]]   ('path' [1,2,3])   == False--- isDfsForestOf [Node 3 [], Node 1 [Node 2 []]] ('path' [1,2,3])   == True--- isDfsForestOf [Node 2 [Node 3 []], Node 1 []] ('path' [1,2,3])   == True--- isDfsForestOf [Node 1 [], Node 2 [Node 3 []]] ('path' [1,2,3])   == False+-- symmetricClosure 'empty'              == 'empty'+-- symmetricClosure ('vertex' x)         == 'vertex' x+-- symmetricClosure ('edge' x y)         == 'edges' [(x,y), (y,x)]+-- symmetricClosure x                  == 'overlay' x ('transpose' x)+-- symmetricClosure . symmetricClosure == symmetricClosure -- @-isDfsForestOf :: Ord a => Forest a -> AdjacencyMap a -> Bool-isDfsForestOf f am = case go Set.empty f of-    Just seen -> seen == vertexSet am-    Nothing   -> False-  where-    go seen []     = Just seen-    go seen (t:ts) = do-        let root = rootLabel t-        guard $ root `Set.notMember` seen-        guard $ and [ hasEdge root (rootLabel subTree) am | subTree <- subForest t ]-        newSeen <- go (Set.insert root seen) (subForest t)-        guard $ postSet root am `Set.isSubsetOf` newSeen-        go newSeen ts+symmetricClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a+symmetricClosure m = overlay m (transpose m) --- | Check if a given list of vertices is a correct /topological sort/ of a graph.+-- | Compute the /transitive closure/ of a graph.+-- Complexity: /O(n * m * log(n)^2)/ time. -- -- @--- isTopSortOf [3,1,2] (1 * 2 + 3 * 1) == True--- isTopSortOf [1,2,3] (1 * 2 + 3 * 1) == False--- isTopSortOf []      (1 * 2 + 3 * 1) == False--- isTopSortOf []      'empty'           == True--- isTopSortOf [x]     ('vertex' x)      == True--- isTopSortOf [x]     ('edge' x x)      == False+-- transitiveClosure 'empty'               == 'empty'+-- transitiveClosure ('vertex' x)          == 'vertex' x+-- transitiveClosure ('edge' x y)          == 'edge' x y+-- transitiveClosure ('path' $ 'Data.List.nub' xs)     == 'clique' ('Data.List.nub' xs)+-- transitiveClosure . transitiveClosure == transitiveClosure -- @-isTopSortOf :: Ord a => [a] -> AdjacencyMap a -> Bool-isTopSortOf xs m = go Set.empty xs+transitiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a+transitiveClosure old+    | old == new = old+    | otherwise  = transitiveClosure new   where-    go seen []     = seen == Map.keysSet (adjacencyMap m)-    go seen (v:vs) = postSet v m `Set.intersection` newSeen == Set.empty-                  && go newSeen vs-      where-        newSeen = Set.insert v seen+    new = overlay old (old `compose` old)
+ src/Algebra/Graph/AdjacencyMap/Algorithm.hs view
@@ -0,0 +1,235 @@+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.AdjacencyMap.Algorithm+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : unstable+--+-- __Alga__ is a library for algebraic construction and manipulation of graphs+-- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the+-- motivation behind the library, the underlying theory, and implementation details.+--+-- This module provides basic graph algorithms, such as /depth-first search/,+-- implemented for the "Algebra.Graph.AdjacencyMap" data type.+-----------------------------------------------------------------------------+module Algebra.Graph.AdjacencyMap.Algorithm (+    -- * Algorithms+    dfsForest, dfsForestFrom, dfs, reachable, topSort, isAcyclic, scc,++    -- * Correctness properties+    isDfsForestOf, isTopSortOf+    ) where++import Control.Monad+import Data.Foldable (toList)+import Data.Maybe+import Data.Tree++import Algebra.Graph.AdjacencyMap++import qualified Algebra.Graph.AdjacencyMap.Internal as AM+import qualified Algebra.Graph.NonEmpty.AdjacencyMap as NonEmpty+import qualified Data.Graph                          as KL+import qualified Data.Graph.Typed                    as Typed+import qualified Data.Map.Strict                     as Map+import qualified Data.Set                            as Set++-- | Compute the /depth-first search/ forest of a graph that corresponds to+-- searching from each of the graph vertices in the 'Ord' @a@ order.+--+-- @+-- dfsForest 'empty'                       == []+-- 'forest' (dfsForest $ 'edge' 1 1)         == 'vertex' 1+-- 'forest' (dfsForest $ 'edge' 1 2)         == 'edge' 1 2+-- 'forest' (dfsForest $ 'edge' 2 1)         == 'vertices' [1,2]+-- 'isSubgraphOf' ('forest' $ dfsForest x) x == True+-- 'isDfsForestOf' (dfsForest x) x         == True+-- dfsForest . 'forest' . dfsForest        == dfsForest+-- dfsForest ('vertices' vs)               == 'map' (\\v -> Node v []) ('Data.List.nub' $ 'Data.List.sort' vs)+-- 'dfsForestFrom' ('vertexList' x) x        == dfsForest x+-- dfsForest $ 3 * (1 + 4) * (1 + 5)     == [ Node { rootLabel = 1+--                                                 , subForest = [ Node { rootLabel = 5+--                                                                      , subForest = [] }]}+--                                          , Node { rootLabel = 3+--                                                 , subForest = [ Node { rootLabel = 4+--                                                                      , subForest = [] }]}]+-- @+dfsForest :: Ord a => AdjacencyMap a -> Forest a+dfsForest g = dfsForestFrom (vertexList g) g++-- | Compute the /depth-first search/ forest of a graph, searching from each of+-- the given vertices in order. Note that the resulting forest does not+-- necessarily span the whole graph, as some vertices may be unreachable.+--+-- @+-- dfsForestFrom vs 'empty'                           == []+-- 'forest' (dfsForestFrom [1]   $ 'edge' 1 1)          == 'vertex' 1+-- 'forest' (dfsForestFrom [1]   $ 'edge' 1 2)          == 'edge' 1 2+-- 'forest' (dfsForestFrom [2]   $ 'edge' 1 2)          == 'vertex' 2+-- 'forest' (dfsForestFrom [3]   $ 'edge' 1 2)          == 'empty'+-- 'forest' (dfsForestFrom [2,1] $ 'edge' 1 2)          == 'vertices' [1,2]+-- 'isSubgraphOf' ('forest' $ dfsForestFrom vs x) x     == True+-- 'isDfsForestOf' (dfsForestFrom ('vertexList' x) x) x == True+-- dfsForestFrom ('vertexList' x) x                   == 'dfsForest' x+-- dfsForestFrom vs             ('vertices' vs)       == 'map' (\\v -> Node v []) ('Data.List.nub' vs)+-- dfsForestFrom []             x                   == []+-- dfsForestFrom [1,4] $ 3 * (1 + 4) * (1 + 5)      == [ Node { rootLabel = 1+--                                                            , subForest = [ Node { rootLabel = 5+--                                                                                 , subForest = [] }+--                                                     , Node { rootLabel = 4+--                                                            , subForest = [] }]+-- @+dfsForestFrom :: Ord a => [a] -> AdjacencyMap a -> Forest a+dfsForestFrom vs = Typed.dfsForestFrom vs . Typed.fromAdjacencyMap++-- | Compute the list of vertices visited by the /depth-first search/ in a+-- graph, when searching from each of the given vertices in order.+--+-- @+-- dfs vs    $ 'empty'                    == []+-- dfs [1]   $ 'edge' 1 1                 == [1]+-- dfs [1]   $ 'edge' 1 2                 == [1,2]+-- dfs [2]   $ 'edge' 1 2                 == [2]+-- dfs [3]   $ 'edge' 1 2                 == []+-- dfs [1,2] $ 'edge' 1 2                 == [1,2]+-- dfs [2,1] $ 'edge' 1 2                 == [2,1]+-- dfs []    $ x                        == []+-- dfs [1,4] $ 3 * (1 + 4) * (1 + 5)    == [1,5,4]+-- 'isSubgraphOf' ('vertices' $ dfs vs x) x == True+-- @+dfs :: Ord a => [a] -> AdjacencyMap a -> [a]+dfs vs = concatMap flatten . dfsForestFrom vs++-- | Compute the list of vertices that are /reachable/ from a given source+-- vertex in a graph. The vertices in the resulting list appear in the+-- /depth-first order/.+--+-- @+-- reachable x $ 'empty'                       == []+-- reachable 1 $ 'vertex' 1                    == [1]+-- reachable 1 $ 'vertex' 2                    == []+-- reachable 1 $ 'edge' 1 1                    == [1]+-- reachable 1 $ 'edge' 1 2                    == [1,2]+-- reachable 4 $ 'path'    [1..8]              == [4..8]+-- reachable 4 $ 'circuit' [1..8]              == [4..8] ++ [1..3]+-- reachable 8 $ 'clique'  [8,7..1]            == [8] ++ [1..7]+-- 'isSubgraphOf' ('vertices' $ reachable x y) y == True+-- @+reachable :: Ord a => a -> AdjacencyMap a -> [a]+reachable x = dfs [x]++-- | Compute the /topological sort/ of a graph or return @Nothing@ if the graph+-- is cyclic.+--+-- @+-- topSort (1 * 2 + 3 * 1)               == Just [3,1,2]+-- topSort (1 * 2 + 2 * 1)               == Nothing+-- fmap ('flip' 'isTopSortOf' x) (topSort x) /= Just False+-- 'isJust' . topSort                      == 'isAcyclic'+-- @+topSort :: Ord a => AdjacencyMap a -> Maybe [a]+topSort m = if isTopSortOf result m then Just result else Nothing+  where+    result = Typed.topSort (Typed.fromAdjacencyMap m)++-- | Check if a given graph is /acyclic/.+--+-- @+-- isAcyclic (1 * 2 + 3 * 1) == True+-- isAcyclic (1 * 2 + 2 * 1) == False+-- isAcyclic . 'circuit'       == 'null'+-- isAcyclic                 == 'isJust' . 'topSort'+-- @+isAcyclic :: Ord a => AdjacencyMap a -> Bool+isAcyclic = isJust . topSort++-- TODO: Benchmark and optimise.+-- | Compute the /condensation/ of a graph, where each vertex corresponds to a+-- /strongly-connected component/ of the original graph. Note that component+-- graphs are non-empty, and are therefore of type+-- "Algebra.Graph.NonEmpty.AdjacencyMap".+--+-- @+-- scc 'empty'               == 'empty'+-- scc ('vertex' x)          == 'vertex' (NonEmpty.'NonEmpty.vertex' x)+-- scc ('edge' 1 1)          == 'vertex' (NonEmpty.'NonEmpty.edge' 1 1)+-- scc ('edge' 1 2)          == 'edge'   (NonEmpty.'NonEmpty.vertex' 1) (NonEmpty.'NonEmpty.vertex' 2)+-- scc ('circuit' (1:xs))    == 'vertex' (NonEmpty.'NonEmpty.circuit1' (1 'Data.List.NonEmpty.:|' xs))+-- scc (3 * 1 * 4 * 1 * 5) == 'edges'  [ (NonEmpty.'NonEmpty.vertex'  3      , NonEmpty.'NonEmpty.vertex'  5      )+--                                   , (NonEmpty.'NonEmpty.vertex'  3      , NonEmpty.'NonEmpty.clique1' [1,4,1])+--                                   , (NonEmpty.'NonEmpty.clique1' [1,4,1], NonEmpty.'NonEmpty.vertex'  5      ) ]+-- 'isAcyclic' . scc == 'const' True+-- 'isAcyclic' x     == (scc x == 'gmap' NonEmpty.'NonEmpty.vertex' x)+-- @+scc :: Ord a => AdjacencyMap a -> AdjacencyMap (NonEmpty.AdjacencyMap a)+scc m = gmap (component Map.!) $ removeSelfLoops $ gmap (leader Map.!) m+  where+    Typed.GraphKL g decode _ = Typed.fromAdjacencyMap m+    sccs      = map toList (KL.scc g)+    leader    = Map.fromList [ (decode y, x)      | x:xs <- sccs, y <- x:xs ]+    component = Map.fromList [ (x, expand (x:xs)) | x:xs <- sccs ]+    expand xs = fromJust $ NonEmpty.toNonEmpty $ induce (`Set.member` s) m+      where+        s = Set.fromList (map decode xs)++-- Remove all self loops from a graph.+removeSelfLoops :: Ord a => AdjacencyMap a -> AdjacencyMap a+removeSelfLoops (AM.AM m) = AM.AM (Map.mapWithKey Set.delete m)++-- | Check if a given forest is a correct /depth-first search/ forest of a graph.+-- The implementation is based on the paper "Depth-First Search and Strong+-- Connectivity in Coq" by François Pottier.+--+-- @+-- isDfsForestOf []                              'empty'            == True+-- isDfsForestOf []                              ('vertex' 1)       == False+-- isDfsForestOf [Node 1 []]                     ('vertex' 1)       == True+-- isDfsForestOf [Node 1 []]                     ('vertex' 2)       == False+-- isDfsForestOf [Node 1 [], Node 1 []]          ('vertex' 1)       == False+-- isDfsForestOf [Node 1 []]                     ('edge' 1 1)       == True+-- isDfsForestOf [Node 1 []]                     ('edge' 1 2)       == False+-- isDfsForestOf [Node 1 [], Node 2 []]          ('edge' 1 2)       == False+-- isDfsForestOf [Node 2 [], Node 1 []]          ('edge' 1 2)       == True+-- isDfsForestOf [Node 1 [Node 2 []]]            ('edge' 1 2)       == True+-- isDfsForestOf [Node 1 [], Node 2 []]          ('vertices' [1,2]) == True+-- isDfsForestOf [Node 2 [], Node 1 []]          ('vertices' [1,2]) == True+-- isDfsForestOf [Node 1 [Node 2 []]]            ('vertices' [1,2]) == False+-- isDfsForestOf [Node 1 [Node 2 [Node 3 []]]]   ('path' [1,2,3])   == True+-- isDfsForestOf [Node 1 [Node 3 [Node 2 []]]]   ('path' [1,2,3])   == False+-- isDfsForestOf [Node 3 [], Node 1 [Node 2 []]] ('path' [1,2,3])   == True+-- isDfsForestOf [Node 2 [Node 3 []], Node 1 []] ('path' [1,2,3])   == True+-- isDfsForestOf [Node 1 [], Node 2 [Node 3 []]] ('path' [1,2,3])   == False+-- @+isDfsForestOf :: Ord a => Forest a -> AdjacencyMap a -> Bool+isDfsForestOf f am = case go Set.empty f of+    Just seen -> seen == vertexSet am+    Nothing   -> False+  where+    go seen []     = Just seen+    go seen (t:ts) = do+        let root = rootLabel t+        guard $ root `Set.notMember` seen+        guard $ and [ hasEdge root (rootLabel subTree) am | subTree <- subForest t ]+        newSeen <- go (Set.insert root seen) (subForest t)+        guard $ postSet root am `Set.isSubsetOf` newSeen+        go newSeen ts++-- | Check if a given list of vertices is a correct /topological sort/ of a graph.+--+-- @+-- isTopSortOf [3,1,2] (1 * 2 + 3 * 1) == True+-- isTopSortOf [1,2,3] (1 * 2 + 3 * 1) == False+-- isTopSortOf []      (1 * 2 + 3 * 1) == False+-- isTopSortOf []      'empty'           == True+-- isTopSortOf [x]     ('vertex' x)      == True+-- isTopSortOf [x]     ('edge' x x)      == False+-- @+isTopSortOf :: Ord a => [a] -> AdjacencyMap a -> Bool+isTopSortOf xs m = go Set.empty xs+  where+    go seen []     = seen == Map.keysSet (adjacencyMap m)+    go seen (v:vs) = postSet v m `Set.intersection` newSeen == Set.empty+                  && go newSeen vs+      where+        newSeen = Set.insert v seen
src/Algebra/Graph/AdjacencyMap/Internal.hs view
@@ -12,16 +12,19 @@ ----------------------------------------------------------------------------- module Algebra.Graph.AdjacencyMap.Internal (     -- * Adjacency map implementation-    AdjacencyMap (..), empty, vertex, overlay, connect, fromAdjacencySets,-    consistent+    AdjacencyMap (..), consistent, internalEdgeList, referredToVertexSet   ) where +import Prelude ()+import Prelude.Compat hiding (null)++import Control.DeepSeq+import Data.Foldable (foldMap) import Data.List import Data.Map.Strict (Map, keysSet, fromSet)+import Data.Monoid import Data.Set (Set) -import Control.DeepSeq (NFData (..))- import qualified Data.Map.Strict as Map import qualified Data.Set        as Set @@ -35,6 +38,14 @@     > 1 + 2 * 3   == overlay (vertex 1) (connect (vertex 2) (vertex 3))     > 1 * (2 + 3) == connect (vertex 1) (overlay (vertex 2) (vertex 3)) +__Note:__ the 'Num' instance does not satisfy several "customary laws" of 'Num',+which dictate that 'fromInteger' @0@ and 'fromInteger' @1@ should act as+additive and multiplicative identities, and 'negate' as additive inverse.+Nevertheless, overloading 'fromInteger', '+' and '*' is very convenient when+working with algebraic graphs; we hope that in future Haskell's Prelude will+provide a more fine-grained class hierarchy for algebraic structures, which we+would be able to utilise without violating any laws.+ The 'Show' instance is defined using basic graph construction primitives:  @show (empty     :: AdjacencyMap Int) == "empty"@@ -84,128 +95,88 @@  When specifying the time and memory complexity of graph algorithms, /n/ and /m/ will denote the number of vertices and edges in the graph, respectively.++The total order on graphs is defined using /size-lexicographic/ comparison:++* Compare the number of vertices. In case of a tie, continue.+* Compare the sets of vertices. In case of a tie, continue.+* Compare the number of edges. In case of a tie, continue.+* Compare the sets of edges.++Here are a few examples:++@'Algebra.Graph.AdjacencyMap.vertex' 1 < 'Algebra.Graph.AdjacencyMap.vertex' 2+'Algebra.Graph.AdjacencyMap.vertex' 3 < 'Algebra.Graph.AdjacencyMap.edge' 1 2+'Algebra.Graph.AdjacencyMap.vertex' 1 < 'Algebra.Graph.AdjacencyMap.edge' 1 1+'Algebra.Graph.AdjacencyMap.edge' 1 1 < 'Algebra.Graph.AdjacencyMap.edge' 1 2+'Algebra.Graph.AdjacencyMap.edge' 1 2 < 'Algebra.Graph.AdjacencyMap.edge' 1 1 + 'Algebra.Graph.AdjacencyMap.edge' 2 2+'Algebra.Graph.AdjacencyMap.edge' 1 2 < 'Algebra.Graph.AdjacencyMap.edge' 1 3@++Note that the resulting order refines the 'Algebra.Graph.AdjacencyMap.isSubgraphOf'+relation and is compatible with 'Algebra.Graph.AdjacencyMap.overlay' and+'Algebra.Graph.AdjacencyMap.connect' operations:++@'Algebra.Graph.AdjacencyMap.isSubgraphOf' x y ==> x <= y@++@'Algebra.Graph.AdjacencyMap.empty' <= x+x     <= x + y+x + y <= x * y@ -} newtype AdjacencyMap a = AM {-    -- | The /adjacency map/ of the graph: each vertex is associated with a set-    -- of its direct successors. Complexity: /O(1)/ time and memory.+    -- | The /adjacency map/ of a graph: each vertex is associated with a set of+    -- its direct successors. Complexity: /O(1)/ time and memory.     --     -- @-    -- adjacencyMap 'empty'      == Map.'Map.empty'-    -- adjacencyMap ('vertex' x) == Map.'Map.singleton' x Set.'Set.empty'+    -- adjacencyMap 'Algebra.Graph.AdjacencyMap.empty'      == Map.'Map.empty'+    -- adjacencyMap ('Algebra.Graph.AdjacencyMap.vertex' x) == Map.'Map.singleton' x Set.'Set.empty'     -- adjacencyMap ('Algebra.Graph.AdjacencyMap.edge' 1 1) == Map.'Map.singleton' 1 (Set.'Set.singleton' 1)     -- adjacencyMap ('Algebra.Graph.AdjacencyMap.edge' 1 2) == Map.'Map.fromList' [(1,Set.'Set.singleton' 2), (2,Set.'Set.empty')]     -- @     adjacencyMap :: Map a (Set a) } deriving Eq +instance Ord a => Ord (AdjacencyMap a) where+    compare (AM x) (AM y) = mconcat+        [ compare (vNum x) (vNum y)+        , compare (vSet x) (vSet y)+        , compare (eNum x) (eNum y)+        , compare       x        y ]+      where+        vNum = Map.size+        vSet = Map.keysSet+        eNum = getSum . foldMap (Sum . Set.size)+ instance (Ord a, Show a) => Show (AdjacencyMap a) where-    show (AM m)-        | null vs    = "empty"-        | null es    = vshow vs-        | vs == used = eshow es-        | otherwise  = "overlay (" ++ vshow (vs \\ used) ++ ") (" ++ eshow es ++ ")"+    showsPrec p (AM m)+        | null vs    = showString "empty"+        | null es    = showParen (p > 10) $ vshow vs+        | vs == used = showParen (p > 10) $ eshow es+        | otherwise  = showParen (p > 10) $+                           showString "overlay (" . vshow (vs \\ used) .+                           showString ") (" . eshow es . showString ")"       where         vs             = Set.toAscList (keysSet m)         es             = internalEdgeList m-        vshow [x]      = "vertex "   ++ show x-        vshow xs       = "vertices " ++ show xs-        eshow [(x, y)] = "edge "     ++ show x ++ " " ++ show y-        eshow xs       = "edges "    ++ show xs+        vshow [x]      = showString "vertex "   . showsPrec 11 x+        vshow xs       = showString "vertices " . showsPrec 11 xs+        eshow [(x, y)] = showString "edge "     . showsPrec 11 x .+                         showString " "         . showsPrec 11 y+        eshow xs       = showString "edges "    . showsPrec 11 xs         used           = Set.toAscList (referredToVertexSet m) --- | Construct the /empty graph/.--- Complexity: /O(1)/ time and memory.------ @--- 'Algebra.Graph.AdjacencyMap.isEmpty'     empty == True--- 'Algebra.Graph.AdjacencyMap.hasVertex' x empty == False--- 'Algebra.Graph.AdjacencyMap.vertexCount' empty == 0--- 'Algebra.Graph.AdjacencyMap.edgeCount'   empty == 0--- @-empty :: AdjacencyMap a-empty = AM Map.empty-{-# NOINLINE [1] empty #-}---- | Construct the graph comprising /a single isolated vertex/.--- Complexity: /O(1)/ time and memory.------ @--- 'Algebra.Graph.AdjacencyMap.isEmpty'     (vertex x) == False--- 'Algebra.Graph.AdjacencyMap.hasVertex' x (vertex x) == True--- 'Algebra.Graph.AdjacencyMap.vertexCount' (vertex x) == 1--- 'Algebra.Graph.AdjacencyMap.edgeCount'   (vertex x) == 0--- @-vertex :: a -> AdjacencyMap a-vertex x = AM $ Map.singleton x Set.empty-{-# NOINLINE [1] vertex #-}---- | /Overlay/ two graphs. This is a commutative, associative and idempotent--- operation with the identity 'empty'.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.------ @--- 'Algebra.Graph.AdjacencyMap.isEmpty'     (overlay x y) == 'Algebra.Graph.AdjacencyMap.isEmpty'   x   && 'Algebra.Graph.AdjacencyMap.isEmpty'   y--- 'Algebra.Graph.AdjacencyMap.hasVertex' z (overlay x y) == 'Algebra.Graph.AdjacencyMap.hasVertex' z x || 'Algebra.Graph.AdjacencyMap.hasVertex' z y--- 'Algebra.Graph.AdjacencyMap.vertexCount' (overlay x y) >= 'Algebra.Graph.AdjacencyMap.vertexCount' x--- 'Algebra.Graph.AdjacencyMap.vertexCount' (overlay x y) <= 'Algebra.Graph.AdjacencyMap.vertexCount' x + 'Algebra.Graph.AdjacencyMap.vertexCount' y--- 'Algebra.Graph.AdjacencyMap.edgeCount'   (overlay x y) >= 'Algebra.Graph.AdjacencyMap.edgeCount' x--- 'Algebra.Graph.AdjacencyMap.edgeCount'   (overlay x y) <= 'Algebra.Graph.AdjacencyMap.edgeCount' x   + 'Algebra.Graph.AdjacencyMap.edgeCount' y--- 'Algebra.Graph.AdjacencyMap.vertexCount' (overlay 1 2) == 2--- 'Algebra.Graph.AdjacencyMap.edgeCount'   (overlay 1 2) == 0--- @-overlay :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a-overlay x y = AM $ Map.unionWith Set.union (adjacencyMap x) (adjacencyMap y)-{-# NOINLINE [1] overlay #-}---- | /Connect/ two graphs. This is an associative operation with the identity--- 'empty', which distributes over 'overlay' and obeys the decomposition axiom.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. Note that the--- number of edges in the resulting graph is quadratic with respect to the number--- of vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.------ @--- 'isEmpty'     (connect x y) == 'isEmpty'   x   && 'Algebra.Graph.AdjacencyMap.isEmpty'   y--- 'hasVertex' z (connect x y) == 'hasVertex' z x || 'Algebra.Graph.AdjacencyMap.hasVertex' z y--- 'vertexCount' (connect x y) >= 'vertexCount' x--- 'vertexCount' (connect x y) <= 'vertexCount' x + 'Algebra.Graph.AdjacencyMap.vertexCount' y--- 'edgeCount'   (connect x y) >= 'edgeCount' x--- 'edgeCount'   (connect x y) >= 'edgeCount' y--- 'edgeCount'   (connect x y) >= 'vertexCount' x * 'Algebra.Graph.AdjacencyMap.vertexCount' y--- 'edgeCount'   (connect x y) <= 'vertexCount' x * 'Algebra.Graph.AdjacencyMap.vertexCount' y + 'Algebra.Graph.AdjacencyMap.edgeCount' x + 'Algebra.Graph.AdjacencyMap.edgeCount' y--- 'vertexCount' (connect 1 2) == 2--- 'edgeCount'   (connect 1 2) == 1--- @-connect :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a-connect x y = AM $ Map.unionsWith Set.union [ adjacencyMap x, adjacencyMap y,-    fromSet (const . keysSet $ adjacencyMap y) (keysSet $ adjacencyMap x) ]-{-# NOINLINE [1] connect #-}-+-- | __Note:__ this does not satisfy the usual ring laws; see 'AdjacencyMap'+-- for more details. instance (Ord a, Num a) => Num (AdjacencyMap a) where-    fromInteger = vertex . fromInteger-    (+)         = overlay-    (*)         = connect-    signum      = const empty-    abs         = id-    negate      = id+    fromInteger x = AM $ Map.singleton (fromInteger x) Set.empty+    x + y  = AM $ Map.unionWith Set.union (adjacencyMap x) (adjacencyMap y)+    x * y  = AM $ Map.unionsWith Set.union [ adjacencyMap x, adjacencyMap y,+        fromSet (const . keysSet $ adjacencyMap y) (keysSet $ adjacencyMap x) ]+    signum = const (AM Map.empty)+    abs    = id+    negate = id  instance NFData a => NFData (AdjacencyMap a) where     rnf (AM a) = rnf a --- | Construct a graph from a list of adjacency sets.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.------ @--- fromAdjacencySets []                                        == 'Algebra.Graph.AdjacencyMap.empty'--- fromAdjacencySets [(x, Set.'Set.empty')]                          == 'Algebra.Graph.AdjacencyMap.vertex' x--- fromAdjacencySets [(x, Set.'Set.singleton' y)]                    == 'Algebra.Graph.AdjacencyMap.edge' x y--- fromAdjacencySets . map (fmap Set.'Set.fromList') . 'Algebra.Graph.AdjacencyMap.adjacencyList' == id--- 'Algebra.Graph.AdjacencyMap.overlay' (fromAdjacencySets xs) (fromAdjacencySets ys)       == fromAdjacencySets (xs ++ ys)--- @-fromAdjacencySets :: Ord a => [(a, Set a)] -> AdjacencyMap a-fromAdjacencySets ss = AM $ Map.unionWith Set.union vs es-  where-    vs = Map.fromSet (const Set.empty) . Set.unions $ map snd ss-    es = Map.fromListWith Set.union ss- -- | Check if the internal graph representation is consistent, i.e. that all -- edges refer to existing vertices. It should be impossible to create an -- inconsistent adjacency map, and we use this function in testing.@@ -223,10 +194,12 @@ consistent :: Ord a => AdjacencyMap a -> Bool consistent (AM m) = referredToVertexSet m `Set.isSubsetOf` keysSet m --- The set of vertices that are referred to by the edges-referredToVertexSet :: Ord a => Map a (Set a) -> Set a-referredToVertexSet = Set.fromList . uncurry (++) . unzip . internalEdgeList---- The list of edges in adjacency map+-- | The list of edges of an adjacency map.+-- /Note: this function is for internal use only/. internalEdgeList :: Map a (Set a) -> [(a, a)] internalEdgeList m = [ (x, y) | (x, ys) <- Map.toAscList m, y <- Set.toAscList ys ]++-- | The set of vertices that are referred to by the edges of an adjacency map.+-- /Note: this function is for internal use only/.+referredToVertexSet :: Ord a => Map a (Set a) -> Set a+referredToVertexSet = Set.fromList . uncurry (++) . unzip . internalEdgeList
src/Algebra/Graph/Class.hs view
@@ -44,20 +44,24 @@     isSubgraphOf,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, starTranspose, tree, forest-  ) where+    path, circuit, clique, biclique, star, tree, forest+    ) where  import Prelude () import Prelude.Compat  import Data.Tree -import qualified Algebra.Graph                 as G-import qualified Algebra.Graph.AdjacencyMap    as AM-import qualified Algebra.Graph.Fold            as F-import qualified Algebra.Graph.AdjacencyIntMap as AIM-import qualified Algebra.Graph.Relation        as R+import Algebra.Graph.Label (Dioid, one) +import qualified Algebra.Graph                       as G+import qualified Algebra.Graph.AdjacencyMap          as AM+import qualified Algebra.Graph.Labelled              as LG+import qualified Algebra.Graph.Labelled.AdjacencyMap as LAM+import qualified Algebra.Graph.Fold                  as F+import qualified Algebra.Graph.AdjacencyIntMap       as AIM+import qualified Algebra.Graph.Relation              as R+ {-| The core type class for constructing algebraic graphs, characterised by the following minimal set of axioms. In equations we use @+@ and @*@ as convenient@@ -145,6 +149,20 @@     overlay = AIM.overlay     connect = AIM.connect +instance Dioid e => Graph (LG.Graph e a) where+    type Vertex (LG.Graph e a) = a+    empty   = LG.empty+    vertex  = LG.vertex+    overlay = LG.overlay+    connect = LG.connect one++instance (Dioid e, Eq e, Ord a) => Graph (LAM.AdjacencyMap e a) where+    type Vertex (LAM.AdjacencyMap e a) = a+    empty   = LAM.empty+    vertex  = LAM.vertex+    overlay = LAM.overlay+    connect = LAM.connect one+ instance Ord a => Graph (R.Relation a) where     type Vertex (R.Relation a) = a     empty   = R.empty@@ -405,21 +423,6 @@ star x [] = vertex x star x ys = connect (vertex x) (vertices ys) --- | The /star transpose/ formed by a list of leaves connected to a centre vertex.--- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the--- given list.------ @--- starTranspose x []    == 'vertex' x--- starTranspose x [y]   == 'edge' y x--- starTranspose x [y,z] == 'edges' [(y,x), (z,x)]--- starTranspose x ys    == 'connect' ('vertices' ys) ('vertex' x)--- starTranspose x ys    == transpose ('star' x ys)--- @-starTranspose :: Graph g => Vertex g -> [Vertex g] -> g-starTranspose x [] = vertex x-starTranspose x ys = connect (vertices ys) (vertex x)- -- | The /tree graph/ constructed from a given 'Tree' data structure. -- Complexity: /O(T)/ time, memory and size, where /T/ is the size of the -- given tree (i.e. the number of vertices in the tree).@@ -443,7 +446,7 @@ -- forest []                                                  == 'empty' -- forest [x]                                                 == 'tree' x -- forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == 'edges' [(1,2), (1,3), (4,5)]--- forest                                                     == 'overlays' . map 'tree'+-- forest                                                     == 'overlays' . 'map' 'tree' -- @ forest :: Graph g => Forest (Vertex g) -> g forest = overlays . map tree
src/Algebra/Graph/Export.hs view
@@ -16,7 +16,7 @@ ----------------------------------------------------------------------------- module Algebra.Graph.Export (     -- * Constructing and exporting documents-    Doc, literal, render,+    Doc, isEmpty, literal, render,      -- * Common combinators for text documents     (<+>), brackets, doubleQuotes, indent, unlines,@@ -39,26 +39,56 @@ -- | An abstract document data type with /O(1)/ time concatenation (the current -- implementation uses difference lists). Here @s@ is the type of abstract -- symbols or strings (text or binary). 'Doc' @s@ is a 'Monoid', therefore--- 'mempty' corresponds to the empty document and two documents can be+-- 'mempty' corresponds to the /empty document/ and two documents can be -- concatenated with 'mappend' (or operator 'Data.Monoid.<>'). Documents -- comprising a single symbol or string can be constructed using the function--- 'literal'. Alternatively, you can construct documents as string literals, e.g.--- simply as @"alga"@, by using the @OverloadedStrings@ GHC extension. To extract--- the document contents use the function 'render'. See some examples below.+-- 'literal'. Alternatively, you can construct documents as string literals,+-- e.g. simply as @"alga"@, by using the @OverloadedStrings@ GHC extension. To+-- extract the document contents use the function 'render'.+--+-- Note that the document comprising a single empty string is considered to be+-- different from the empty document. This design choice is motivated by the+-- desire to support string types @s@ that have no 'Eq' instance, such as+-- "Data.ByteString.Builder", for which there is no way to check whether a+-- string is empty or not. As a consequence, the 'Eq' and 'Ord' instances are+-- defined as follows:+--+-- @+-- 'mempty' /= 'literal' ""+-- 'mempty' <  'literal' ""+-- @ newtype Doc s = Doc (List s) deriving (Monoid, Semigroup)  instance (Monoid s, Show s) => Show (Doc s) where     show = show . render  instance (Monoid s, Eq s) => Eq (Doc s) where-    x == y = render x == render y+    x == y | isEmpty x = isEmpty y+           | isEmpty y = False+           | otherwise = render x == render y +-- | The empty document is smallest. instance (Monoid s, Ord s) => Ord (Doc s) where-    compare x y = compare (render x) (render y)+    compare x y | isEmpty x = if isEmpty y then EQ else LT+                | isEmpty y = GT+                | otherwise = compare (render x) (render y)  instance IsString s => IsString (Doc s) where     fromString = literal . fromString +-- | Check if a document is empty. The result is the same as when comparing the+-- given document to 'mempty', but this function does not require the 'Eq' @s@+-- constraint. Note that the document comprising a single empty string is+-- considered to be different from the empty document.+--+-- @+-- isEmpty 'mempty'       == True+-- isEmpty ('literal' \"\") == False+-- isEmpty x            == (x == 'mempty')+-- @+isEmpty :: Doc s -> Bool+isEmpty (Doc xs) = null xs+ -- | Construct a document comprising a single symbol or string. If @s@ is an -- instance of class 'IsString', then documents of type 'Doc' @s@ can be -- constructed directly from string literals (see the second example below).@@ -66,9 +96,7 @@ -- @ -- literal "Hello, " 'Data.Monoid.<>' literal "World!" == literal "Hello, World!" -- literal "I am just a string literal"  == "I am just a string literal"--- literal 'mempty'                        == 'mempty' -- 'render' . literal                      == 'id'--- literal . 'render'                      == 'id' -- @ literal :: s -> Doc s literal = Doc . pure@@ -80,7 +108,6 @@ -- render ('literal' "al" 'Data.Monoid.<>' 'literal' "ga") == "alga" -- render 'mempty'                         == 'mempty' -- render . 'literal'                      == 'id'--- 'literal' . render                      == 'id' -- @ render :: Monoid s => Doc s -> s render (Doc x) = fold x@@ -94,10 +121,10 @@ -- x \<+\> (y \<+\> z)      == (x \<+\> y) \<+\> z -- "name" \<+\> "surname" == "name surname" -- @-(<+>) :: (Eq s, IsString s, Monoid s) => Doc s -> Doc s -> Doc s-x <+> y | x == mempty = y-        | y == mempty = x-        | otherwise   = x <> " " <> y+(<+>) :: IsString s => Doc s -> Doc s -> Doc s+x <+> y | isEmpty x = y+        | isEmpty y = x+        | otherwise = x <> " " <> y  infixl 7 <+> 
src/Algebra/Graph/Export/Dot.hs view
@@ -43,8 +43,8 @@ data Style a s = Style     { graphName :: s     -- ^ Name of the graph.-    , preamble :: s-    -- ^ Preamble is added at the beginning of the DOT file body.+    , preamble :: [s]+    -- ^ Preamble (a list of lines) is added at the beginning of the DOT file body.     , graphAttributes :: [Attribute s]     -- ^ Graph style, e.g. @["bgcolor" := "azure"]@.     , defaultVertexAttributes :: [Attribute s]@@ -62,7 +62,7 @@ -- | Default style for exporting graphs. All style settings are empty except for -- 'vertexName', which is provided as the only argument. defaultStyle :: Monoid s => (a -> s) -> Style a s-defaultStyle v = Style mempty mempty [] [] [] v (\_ -> []) (\_ _ -> [])+defaultStyle v = Style mempty [] [] [] [] v (\_ -> []) (\_ _ -> [])  -- | Default style for exporting graphs whose vertices are 'Show'-able. All -- style settings are empty except for 'vertexName', which is computed from@@ -82,7 +82,7 @@ -- style :: 'Style' Int String -- style = 'Style' --     { 'graphName'               = \"Example\"---     , 'preamble'                = "  // This is an example\\n"+--     , 'preamble'                = ["  // This is an example", ""] --     , 'graphAttributes'         = ["label" := \"Example\", "labelloc" := "top"] --     , 'defaultVertexAttributes' = ["shape" := "circle"] --     , 'defaultEdgeAttributes'   = 'mempty'@@ -109,14 +109,14 @@ --   "v4" -> "v5" -- } -- @-export :: (IsString s, Monoid s, Eq s, Ord a, ToGraph g, ToVertex g ~ a) => Style a s -> g -> s+export :: (IsString s, Monoid s, Ord a, ToGraph g, ToVertex g ~ a) => Style a s -> g -> s export Style {..} g = render $ header <> body <> "}\n"   where     header    = "digraph" <+> literal graphName <> "\n{\n"-             <> if preamble == mempty then mempty else literal preamble <> "\n"-    with x as = if null as            then mempty else line (x <+> attributes as)+    with x as = if null as then mempty else line (x <+> attributes as)     line s    = indent 2 s <> "\n"-    body      = ("graph" `with` graphAttributes)+    body      = unlines (map literal preamble)+             <> ("graph" `with` graphAttributes)              <> ("node"  `with` defaultVertexAttributes)              <> ("edge"  `with` defaultEdgeAttributes)              <> E.export vDoc eDoc g@@ -150,7 +150,7 @@ --   "c" -> "a" -- } -- @-exportAsIs :: (IsString s, Monoid s, Ord s, ToGraph g, ToVertex g ~ s) => g -> s+exportAsIs :: (IsString s, Monoid s, Ord (ToVertex g), ToGraph g, ToVertex g ~ s) => g -> s exportAsIs = export (defaultStyle id)  -- | Export a graph using the 'defaultStyleViaShow'.@@ -170,5 +170,5 @@ --   "2" -> "4" -- } -- @-exportViaShow :: (IsString s, Monoid s, Eq s, ToGraph g, Ord (ToVertex g), Show (ToVertex g)) => g -> s+exportViaShow :: (IsString s, Monoid s, Ord (ToVertex g), Show (ToVertex g), ToGraph g) => g -> s exportViaShow = export defaultStyleViaShow
src/Algebra/Graph/Fold.hs view
@@ -33,19 +33,19 @@      -- * Graph properties     isEmpty, size, hasVertex, hasEdge, vertexCount, edgeCount, vertexList,-    edgeList, vertexSet, vertexIntSet, edgeSet, adjacencyList,+    edgeList, vertexSet, edgeSet, adjacencyList,      -- * Standard families of graphs     path, circuit, clique, biclique, star, stars,      -- * Graph transformation     removeVertex, removeEdge, transpose, induce, simplify,-  ) where+    ) where  import Prelude () import Prelude.Compat -import Control.Applicative (Alternative, liftA2)+import Control.Applicative (Alternative) import Control.Monad.Compat (MonadPlus (..), ap) import Data.Function @@ -57,7 +57,6 @@ import qualified Algebra.Graph.AdjacencyMap as AM import qualified Algebra.Graph.ToGraph      as T import qualified Control.Applicative        as Ap-import qualified Data.IntSet                as IntSet import qualified Data.Set                   as Set  {-| The 'Fold' data type is the Boehm-Berarducci encoding of the core graph@@ -70,6 +69,14 @@     > 1 + 2 * 3   == overlay (vertex 1) (connect (vertex 2) (vertex 3))     > 1 * (2 + 3) == connect (vertex 1) (overlay (vertex 2) (vertex 3)) +__Note:__ the 'Num' instance does not satisfy several "customary laws" of 'Num',+which dictate that 'fromInteger' @0@ and 'fromInteger' @1@ should act as+additive and multiplicative identities, and 'negate' as additive inverse.+Nevertheless, overloading 'fromInteger', '+' and '*' is very convenient when+working with algebraic graphs; we hope that in future Haskell's Prelude will+provide a more fine-grained class hierarchy for algebraic structures, which we+would be able to utilise without violating any laws.+ The 'Show' instance is defined using basic graph construction primitives:  @show (empty     :: Fold Int) == "empty"@@ -125,36 +132,61 @@ m == 'edgeCount' g s == 'size' g@ -Note that 'size' is slightly different from the 'length' method of the-'Foldable' type class, as the latter does not count 'empty' leaves of the-expression:--@'length' 'empty'           == 0-'size'   'empty'           == 1-'length' ('vertex' x)      == 1-'size'   ('vertex' x)      == 1-'length' ('empty' + 'empty') == 0-'size'   ('empty' + 'empty') == 2@+Note that 'size' counts all leaves of the expression: -The 'size' of any graph is positive, and the difference @('size' g - 'length' g)@-corresponds to the number of occurrences of 'empty' in an expression @g@.+@'vertexCount' 'empty'           == 0+'size'        'empty'           == 1+'vertexCount' ('vertex' x)      == 1+'size'        ('vertex' x)      == 1+'vertexCount' ('empty' + 'empty') == 0+'size'        ('empty' + 'empty') == 2@  Converting a 'Fold' to the corresponding 'AM.AdjacencyMap' takes /O(s + m * log(m))/ time and /O(s + m)/ memory. This is also the complexity of the graph equality test, because it is currently implemented by converting graph expressions to canonical representations based on adjacency maps.++The total order on graphs is defined using /size-lexicographic/ comparison:++* Compare the number of vertices. In case of a tie, continue.+* Compare the sets of vertices. In case of a tie, continue.+* Compare the number of edges. In case of a tie, continue.+* Compare the sets of edges.++Here are a few examples:++@'vertex' 1 < 'vertex' 2+'vertex' 3 < 'edge' 1 2+'vertex' 1 < 'edge' 1 1+'edge' 1 1 < 'edge' 1 2+'edge' 1 2 < 'edge' 1 1 + 'edge' 2 2+'edge' 1 2 < 'edge' 1 3@++Note that the resulting order refines the 'isSubgraphOf' relation and is+compatible with 'overlay' and 'connect' operations:++@'isSubgraphOf' x y ==> x <= y@++@'empty' <= x+x     <= x + y+x + y <= x * y@ -} newtype Fold a = Fold { runFold :: forall b. b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> b }  instance (Ord a, Show a) => Show (Fold a) where-    show = show . foldg AM.empty AM.vertex AM.overlay AM.connect+    showsPrec p = showsPrec p . foldg AM.empty AM.vertex AM.overlay AM.connect  instance Ord a => Eq (Fold a) where-    x == y = T.adjacencyMap x == T.adjacencyMap y+    x == y = T.toAdjacencyMap x == T.toAdjacencyMap y +instance Ord a => Ord (Fold a) where+    compare x y = compare (T.toAdjacencyMap x) (T.toAdjacencyMap y)+ instance NFData a => NFData (Fold a) where     rnf = foldg () rnf seq seq +-- | __Note:__ this does not satisfy the usual ring laws; see 'Fold' for more+-- details. instance Num a => Num (Fold a) where     fromInteger = vertex . fromInteger     (+)         = overlay@@ -182,12 +214,6 @@     return = vertex     g >>=f = foldg empty f overlay connect g -instance Foldable Fold where-    foldMap f = foldg mempty f mappend mappend--instance Traversable Fold where-    traverse f = foldg (pure empty) (fmap vertex . f) (liftA2 overlay) (liftA2 connect)- instance ToGraph (Fold a) where     type ToVertex (Fold a) = a     foldg = foldg@@ -340,11 +366,10 @@ -- -- @ -- foldg 'empty' 'vertex'        'overlay' 'connect'        == id--- foldg 'empty' 'vertex'        'overlay' (flip 'connect') == 'transpose'--- foldg []    return        (++)    (++)           == 'Data.Foldable.toList'--- foldg 0     (const 1)     (+)     (+)            == 'Data.Foldable.length'--- foldg 1     (const 1)     (+)     (+)            == 'size'--- foldg True  (const False) (&&)    (&&)           == 'isEmpty'+-- foldg 'empty' 'vertex'        'overlay' ('flip' 'connect') == 'transpose'+-- foldg 1     ('const' 1)     (+)     (+)            == 'size'+-- foldg True  ('const' False) (&&)    (&&)           == 'isEmpty'+-- foldg False (== x)        (||)    (||)           == 'hasVertex' x -- @ foldg :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Fold a -> b foldg e v o c g = runFold g e v o c@@ -355,11 +380,12 @@ -- graph can be quadratic with respect to the expression size /s/. -- -- @--- isSubgraphOf 'empty'         x             == True--- isSubgraphOf ('vertex' x)    'empty'         == False--- isSubgraphOf x             ('overlay' x y) == True--- isSubgraphOf ('overlay' x y) ('connect' x y) == True--- isSubgraphOf ('path' xs)     ('circuit' xs)  == True+-- isSubgraphOf 'empty'         x             ==  True+-- isSubgraphOf ('vertex' x)    'empty'         ==  False+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf ('path' xs)     ('circuit' xs)  ==  True+-- isSubgraphOf x y                         ==> x <= y -- @ isSubgraphOf :: Ord a => Fold a -> Fold a -> Bool isSubgraphOf x y = overlay x y == y@@ -392,14 +418,14 @@ size :: Fold a -> Int size = T.size --- | Check if a graph contains a given vertex. A convenient alias for `elem`.+-- | Check if a graph contains a given vertex. -- Complexity: /O(s)/ time. -- -- @ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True -- hasVertex 1 ('vertex' 2)       == False--- hasVertex x . 'removeVertex' x == const False+-- hasVertex x . 'removeVertex' x == 'const' False -- @ hasVertex :: Eq a => a -> Fold a -> Bool hasVertex = T.hasVertex@@ -411,7 +437,7 @@ -- hasEdge x y 'empty'            == False -- hasEdge x y ('vertex' z)       == False -- hasEdge x y ('edge' x y)       == True--- hasEdge x y . 'removeEdge' x y == const False+-- hasEdge x y . 'removeEdge' x y == 'const' False -- hasEdge x y                  == 'elem' (x,y) . 'edgeList' -- @ hasEdge :: Eq a => a -> a -> Fold a -> Bool@@ -421,9 +447,10 @@ -- Complexity: /O(s * log(n))/ time. -- -- @--- vertexCount 'empty'      == 0--- vertexCount ('vertex' x) == 1--- vertexCount            == 'length' . 'vertexList'+-- vertexCount 'empty'             ==  0+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y -- @ vertexCount :: Ord a => Fold a -> Int vertexCount = T.vertexCount@@ -462,7 +489,7 @@ -- edgeList ('edge' x y)     == [(x,y)] -- edgeList ('star' 2 [3,1]) == [(2,1), (2,3)] -- edgeList . 'edges'        == 'Data.List.nub' . 'Data.List.sort'--- edgeList . 'transpose'    == 'Data.List.sort' . map 'Data.Tuple.swap' . edgeList+-- edgeList . 'transpose'    == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . edgeList -- @ edgeList :: Ord a => Fold a -> [(a, a)] edgeList = T.edgeList@@ -474,24 +501,10 @@ -- vertexSet 'empty'      == Set.'Set.empty' -- vertexSet . 'vertex'   == Set.'Set.singleton' -- vertexSet . 'vertices' == Set.'Set.fromList'--- vertexSet . 'clique'   == Set.'Set.fromList' -- @ vertexSet :: Ord a => Fold a -> Set.Set a vertexSet = T.vertexSet --- | The set of vertices of a given graph. Like 'vertexSet' but specialised for--- graphs with vertices of type 'Int'.--- Complexity: /O(s * log(n))/ time and /O(n)/ memory.------ @--- vertexIntSet 'empty'      == IntSet.'IntSet.empty'--- vertexIntSet . 'vertex'   == IntSet.'IntSet.singleton'--- vertexIntSet . 'vertices' == IntSet.'IntSet.fromList'--- vertexIntSet . 'clique'   == IntSet.'IntSet.fromList'--- @-vertexIntSet :: Fold Int -> IntSet.IntSet-vertexIntSet = T.vertexIntSet- -- | The set of edges of a given graph. -- Complexity: /O(s * log(m))/ time and /O(m)/ memory. --@@ -604,7 +617,7 @@ -- stars [(x, [])]               == 'vertex' x -- stars [(x, [y])]              == 'edge' x y -- stars [(x, ys)]               == 'star' x ys--- stars                         == 'overlays' . map (uncurry 'star')+-- stars                         == 'overlays' . 'map' ('uncurry' 'star') -- stars . 'adjacencyList'         == id -- 'overlay' (stars xs) (stars ys) == stars (xs ++ ys) -- @@@ -640,12 +653,12 @@ removeEdge s t = filterContext s (/=s) (/=t)  -- TODO: Export--- | Filter vertices in a subgraph context.+-- Filter vertices in a subgraph context. filterContext :: Eq a => a -> (a -> Bool) -> (a -> Bool) -> Fold a -> Fold a filterContext s i o g = maybe g go $ G.context (==s) (toGraph g)   where     go (G.Context is os) = induce (/=s) g `overlay` transpose (star s (filter i is))-                                          `overlay` star      s (filter o os)+                                          `overlay` star            s (filter o os)  -- | Transpose a given graph. -- Complexity: /O(s)/ time, memory and size.@@ -656,7 +669,7 @@ -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id -- transpose ('box' x y)   == 'box' (transpose x) (transpose y)--- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList'+-- 'edgeList' . transpose  == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: Fold a -> Fold a transpose = foldg empty vertex overlay (flip connect)@@ -681,8 +694,8 @@ -- /O(1)/ to be evaluated. -- -- @--- induce (const True ) x      == x--- induce (const False) x      == 'empty'+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x) -- 'isSubgraphOf' (induce p x) x == True
src/Algebra/Graph/HigherKinded/Class.hs view
@@ -43,31 +43,25 @@     isSubgraphOf,      -- * Graph properties-    isEmpty, hasVertex, hasEdge, vertexCount, vertexList, vertexSet, vertexIntSet,+    hasEdge,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, starTranspose, tree, forest, mesh,-    torus, deBruijn,+    path, circuit, clique, biclique, star, stars, tree, forest, mesh, torus,+    deBruijn,      -- * Graph transformation-    removeVertex, replaceVertex, mergeVertices, splitVertex, induce,--    -- * Graph composition-    box-  ) where+    removeVertex, replaceVertex, mergeVertices, splitVertex, induce+    ) where  import Prelude () import Prelude.Compat  import Control.Applicative (Alternative(empty, (<|>)))-import Control.Monad.Compat (MonadPlus, msum, mfilter)-import Data.Foldable (toList)+import Control.Monad.Compat (MonadPlus, mfilter) import Data.Tree  import qualified Algebra.Graph      as G import qualified Algebra.Graph.Fold as F-import qualified Data.IntSet        as IntSet-import qualified Data.Set           as Set  {-| The core type class for constructing algebraic graphs is defined by introducing@@ -128,7 +122,7 @@ edges in the graph, and /s/ will denote the /size/ of the corresponding 'Graph' expression. -}-class (Traversable g,+class ( #if !MIN_VERSION_base(4,8,0)   Alternative g, #endif@@ -282,30 +276,6 @@ isSubgraphOf :: (Graph g, Eq (g a)) => g a -> g a -> Bool isSubgraphOf x y = overlay x y == y --- | Check if a graph is empty. A convenient alias for 'null'.--- Complexity: /O(s)/ time.------ @--- isEmpty 'empty'                       == True--- isEmpty ('overlay' 'empty' 'empty')       == True--- isEmpty ('vertex' x)                  == False--- isEmpty ('removeVertex' x $ 'vertex' x) == True--- @-isEmpty :: Graph g => g a -> Bool-isEmpty = null---- | Check if a graph contains a given vertex. A convenient alias for `elem`.--- Complexity: /O(s)/ time.------ @--- hasVertex x 'empty'            == False--- hasVertex x ('vertex' x)       == True--- hasVertex 1 ('vertex' 2)       == False--- hasVertex x . 'removeVertex' x == const False--- @-hasVertex :: (Eq a, Graph g) => a -> g a -> Bool-hasVertex = elem- -- | Check if a graph contains a given edge. -- Complexity: /O(s)/ time. --@@ -316,54 +286,7 @@ -- hasEdge x y                  == 'elem' (x,y) . 'edgeList' -- @ hasEdge :: (Eq (g a), Graph g, Ord a) => a -> a -> g a -> Bool-hasEdge u v = (edge u v `isSubgraphOf`) . induce (`elem` [u, v])---- | The number of vertices in a graph.--- Complexity: /O(s * log(n))/ time.------ @--- vertexCount 'empty'      == 0--- vertexCount ('vertex' x) == 1--- vertexCount            == 'length' . 'vertexList'--- @-vertexCount :: (Ord a, Graph g) => g a -> Int-vertexCount = length . vertexList---- | The sorted list of vertices of a given graph.--- Complexity: /O(s * log(n))/ time and /O(n)/ memory.------ @--- vertexList 'empty'      == []--- vertexList ('vertex' x) == [x]--- vertexList . 'vertices' == 'Data.List.nub' . 'Data.List.sort'--- @-vertexList :: (Ord a, Graph g) => g a -> [a]-vertexList = Set.toAscList . vertexSet---- | The set of vertices of a given graph.--- Complexity: /O(s * log(n))/ time and /O(n)/ memory.------ @--- vertexSet 'empty'      == Set.'Set.empty'--- vertexSet . 'vertex'   == Set.'Set.singleton'--- vertexSet . 'vertices' == Set.'Set.fromList'--- vertexSet . 'clique'   == Set.'Set.fromList'--- @-vertexSet :: (Ord a, Graph g) => g a -> Set.Set a-vertexSet = foldr Set.insert Set.empty---- | The set of vertices of a given graph. Like 'vertexSet' but specialised for--- graphs with vertices of type 'Int'.--- Complexity: /O(s * log(n))/ time and /O(n)/ memory.------ @--- vertexIntSet 'empty'      == IntSet.'IntSet.empty'--- vertexIntSet . 'vertex'   == IntSet.'IntSet.singleton'--- vertexIntSet . 'vertices' == IntSet.'IntSet.fromList'--- vertexIntSet . 'clique'   == IntSet.'IntSet.fromList'--- @-vertexIntSet :: Graph g => g Int -> IntSet.IntSet-vertexIntSet = foldr IntSet.insert IntSet.empty+hasEdge u v = (edge u v `isSubgraphOf`) . induce (\x -> x == u || x == v)  -- | The /path/ on a list of vertices. -- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the@@ -436,20 +359,22 @@ star x [] = vertex x star x ys = connect (vertex x) (vertices ys) --- | The /star transpose/ formed by a list of leaves connected to a centre vertex.--- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the--- given list.+-- | The /stars/ formed by overlaying a list of 'star's. An inverse of+-- 'adjacencyList'.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the total size of the+-- input. -- -- @--- starTranspose x []    == 'vertex' x--- starTranspose x [y]   == 'edge' y x--- starTranspose x [y,z] == 'edges' [(y,x), (z,x)]--- starTranspose x ys    == 'connect' ('vertices' ys) ('vertex' x)--- starTranspose x ys    == transpose ('star' x ys)+-- stars []                      == 'empty'+-- stars [(x, [])]               == 'vertex' x+-- stars [(x, [y])]              == 'edge' x y+-- stars [(x, ys)]               == 'star' x ys+-- stars                         == 'overlays' . 'map' ('uncurry' 'star')+-- stars . 'adjacencyList'         == id+-- 'overlay' (stars xs) (stars ys) == stars (xs ++ ys) -- @-starTranspose :: Graph g => a -> [a] -> g a-starTranspose x [] = vertex x-starTranspose x ys = connect (vertices ys) (vertex x)+stars :: Graph g => [(a, [a])] -> g a+stars = overlays . map (uncurry star)  -- | The /tree graph/ constructed from a given 'Tree' data structure. -- Complexity: /O(T)/ time, memory and size, where /T/ is the size of the@@ -474,7 +399,7 @@ -- forest []                                                  == 'empty' -- forest [x]                                                 == 'tree' x -- forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == 'edges' [(1,2), (1,3), (4,5)]--- forest                                                     == 'overlays' . map 'tree'+-- forest                                                     == 'overlays' . 'map' 'tree' -- @ forest :: Graph g => Forest a -> g a forest = overlays . map tree@@ -492,7 +417,17 @@ --                           , ((2,\'a\'),(3,\'a\')), ((2,\'b\'),(3,\'b\')), ((3,\'a\'),(3,\'b\')) ] -- @ mesh :: Graph g => [a] -> [b] -> g (a, b)-mesh xs ys = path xs `box` path ys+mesh []  _   = empty+mesh _   []  = empty+mesh [x] [y] = vertex (x, y)+mesh xs  ys  = stars $  [ ((a1, b1), [(a1, b2), (a2, b1)]) | (a1, a2) <- ipxs, (b1, b2) <- ipys ]+                     ++ [ ((lx,y1), [(lx,y2)]) | (y1,y2) <- ipys]+                     ++ [ ((x1,ly), [(x2,ly)]) | (x1,x2) <- ipxs]+  where+    lx = last xs+    ly = last ys+    ipxs = init (pairs xs)+    ipys = init (pairs ys)  -- | Construct a /torus graph/ from two lists of vertices. -- Complexity: /O(L1 * L2)/ time, memory and size, where /L1/ and /L2/ are the@@ -507,8 +442,13 @@ --                           , ((2,\'a\'),(1,\'a\')), ((2,\'a\'),(2,\'b\')), ((2,\'b\'),(1,\'b\')), ((2,\'b\'),(2,\'a\')) ] -- @ torus :: Graph g => [a] -> [b] -> g (a, b)-torus xs ys = circuit xs `box` circuit ys+torus xs ys = stars [ ((a1, b1), [(a1, b2), (a2, b1)]) | (a1, a2) <- pairs xs, (b1, b2) <- pairs ys ] +-- | Auxiliary function for 'mesh' and 'torus'+pairs :: [a] -> [(a, a)]+pairs [] = []+pairs as@(x:xs) = zip as (xs ++ [x])+ -- | Construct a /De Bruijn graph/ of a given non-negative dimension using symbols -- from a given alphabet. -- Complexity: /O(A^(D + 1))/ time, memory and size, where /A/ is the size of the@@ -539,8 +479,8 @@ -- /O(1)/ to be evaluated. -- -- @--- induce (const True ) x      == x--- induce (const False) x      == 'empty'+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x) -- 'isSubgraphOf' (induce p x) x == True@@ -578,10 +518,10 @@ -- /O(1)/ to be evaluated. -- -- @--- mergeVertices (const False) x    == id+-- mergeVertices ('const' False) x    == id -- mergeVertices (== x) y           == 'replaceVertex' x y--- mergeVertices even 1 (0 * 2)     == 1 * 1--- mergeVertices odd  1 (3 + 4 * 5) == 4 * 1+-- mergeVertices 'even' 1 (0 * 2)     == 1 * 1+-- mergeVertices 'odd'  1 (3 + 4 * 5) == 4 * 1 -- @ mergeVertices :: Graph g => (a -> Bool) -> a -> g a -> g a mergeVertices p v = fmap $ \w -> if p w then v else w@@ -599,33 +539,3 @@ -- @ splitVertex :: (Eq a, Graph g) => a -> [a] -> g a -> g a splitVertex v us g = g >>= \w -> if w == v then vertices us else vertex w---- | Compute the /Cartesian product/ of graphs.--- Complexity: /O(s1 * s2)/ time, memory and size, where /s1/ and /s2/ are the--- sizes of the given graphs.------ @--- box ('path' [0,1]) ('path' "ab") == 'edges' [ ((0,\'a\'), (0,\'b\'))---                                       , ((0,\'a\'), (1,\'a\'))---                                       , ((0,\'b\'), (1,\'b\'))---                                       , ((1,\'a\'), (1,\'b\')) ]--- @--- Up to an isomorphism between the resulting vertex types, this operation--- is /commutative/, /associative/, /distributes/ over 'overlay', has singleton--- graphs as /identities/ and 'empty' as the /annihilating zero/. Below @~~@--- stands for the equality up to an isomorphism, e.g. @(x, ()) ~~ x@.------ @--- box x y               ~~ box y x--- box x (box y z)       ~~ box (box x y) z--- box x ('overlay' y z)   == 'overlay' (box x y) (box x z)--- box x ('vertex' ())     ~~ x--- box x 'empty'           ~~ 'empty'--- 'vertexCount' (box x y) == 'vertexCount' x * 'vertexCount' y--- 'edgeCount'   (box x y) <= 'vertexCount' x * 'edgeCount' y + 'edgeCount' x * 'vertexCount' y--- @-box :: Graph g => g a -> g b -> g (a, b)-box x y = msum $ xs ++ ys-  where-    xs = map (\b -> fmap (,b) x) $ toList y-    ys = map (\a -> fmap (a,) y) $ toList x
src/Algebra/Graph/Internal.hs view
@@ -16,13 +16,15 @@ -- is unstable and unsafe, and is exposed only for documentation. ----------------------------------------------------------------------------- module Algebra.Graph.Internal (-    -- * General data structures+    -- * Data structures     List (..), -    -- * Data structures for graph traversal+    -- * Graph traversal     Focus (..), emptyFocus, vertexFocus, overlayFoci, connectFoci, Hit (..),+    foldr1Safe, maybeF, -    foldr1Safe+    -- * Utilities+    setProduct, setProductWith   ) where  import Prelude ()@@ -30,7 +32,9 @@  import Data.Foldable import Data.Semigroup+import Data.Set (Set) +import qualified Data.Set as Set import qualified GHC.Exts as Exts  -- | An abstract list data type with /O(1)/ time concatenation (the current@@ -110,11 +114,33 @@ -- its 'Tail', i.e. the source vertex, the whole 'Edge', or 'Miss' it entirely. data Hit = Miss | Tail | Edge deriving (Eq, Ord) --- | A safe version of 'foldr1'+-- | A safe version of 'foldr1'. foldr1Safe :: (a -> a -> a) -> [a] -> Maybe a-foldr1Safe f = foldr mf Nothing-  where-    mf x m = Just (case m of-                        Nothing -> x-                        Just y  -> f x y)-{-# INLINE foldr1Safe #-}+foldr1Safe f = foldr (maybeF f) Nothing+{-# INLINE [0] foldr1Safe #-}++-- | Tragetting 'map' directly+{-# RULES+"foldr1Safe/build"+  forall k f lst.+  foldr1Safe k (map f lst) = foldr (maybeF k . f) Nothing lst+ #-}++-- | Auxiliary function that try to apply a function to a base case and a 'Maybe'+-- value and return 'Just' the result or 'Just' the base case.+maybeF :: (a -> b -> a) -> a -> Maybe b -> Maybe a+maybeF f x = Just . maybe x (f x)+{-# INLINE maybeF #-}++-- | Compute the Cartesian product of two sets.+setProduct :: Set a -> Set b -> Set (a, b)+#if MIN_VERSION_containers(0,5,11)+setProduct = Set.cartesianProduct+#else+setProduct x y = Set.fromDistinctAscList [ (a, b) | a <- Set.toAscList x, b <- Set.toAscList y ]+#endif++-- | Compute the Cartesian product of two sets, applying a function to each+-- resulting pair.+setProductWith :: Ord c => (a -> b -> c) -> Set a -> Set b -> Set c+setProductWith f x y = Set.fromList [ f a b | a <- Set.toAscList x, b <- Set.toAscList y ]
src/Algebra/Graph/Label.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveFunctor, OverloadedLists #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Label@@ -15,112 +16,459 @@ -- ----------------------------------------------------------------------------- module Algebra.Graph.Label (-    -- * Type classes for edge labels-    Semilattice (..), Dioid (..),+    -- * Semirings and dioids+    Semiring (..), zero, (<+>), StarSemiring (..), Dioid,      -- * Data types for edge labels-    Distance (..)-  ) where+    NonNegative, finite, finiteWord, unsafeFinite, infinite, getFinite,+    Distance, distance, getDistance, Capacity, capacity, getCapacity,+    Count, count, getCount, PowerSet (..), Minimum, getMinimum, noMinimum,+    Path, Label, isZero, RegularExpression, +    -- * Combining edge labels+    Optimum (..), ShortestPath, AllShortestPaths, CountShortestPaths, WidestPath+    ) where+ import Prelude () import Prelude.Compat++import Control.Applicative+import Control.Monad+import Data.Maybe+import Data.Monoid (Any (..), Monoid (..), Sum (..))+import Data.Semigroup (Min (..), Max (..), Semigroup (..)) import Data.Set (Set)+import GHC.Exts (IsList (..)) +import Algebra.Graph.Internal+ import qualified Data.Set as Set -{-| A /bounded join semilattice/, satisfying the following laws:+{-| A /semiring/ extends a commutative 'Monoid' with operation '<.>' that acts+similarly to multiplication over the underlying (additive) monoid and has 'one'+as the identity. This module also provides two convenient aliases: 'zero' for+'mempty', and '<+>' for '<>', which makes the interface more uniform. -    * Commutativity:+Instances of this type class must satisfy the following semiring laws: -        > x \/ y == y \/ x+    * Associativity of '<+>' and '<.>': -    * Associativity:+        > x <+> (y <+> z) == (x <+> y) <+> z+        > x <.> (y <.> z) == (x <.> y) <.> z -        > x \/ (y \/ z) == (x \/ y) \/ z+    * Identities of '<+>' and '<.>': -    * Identity:+        > zero <+> x == x == x <+> zero+        >  one <.> x == x == x <.> one -        > x \/ zero == x+    * Commutativity of '<+>': -    * Idempotence:+        > x <+> y == y <+> x -        > x \/ x == x+    * Annihilating 'zero':++        > x <.> zero == zero+        > zero <.> x == zero++    * Distributivity:++        > x <.> (y <+> z) == x <.> y <+> x <.> z+        > (x <+> y) <.> z == x <.> z <+> y <.> z -}-class Semilattice a where-    zero :: a-    (\/) :: a -> a -> a+class (Monoid a, Semigroup a) => Semiring a where+    one   :: a+    (<.>) :: a -> a -> a -{-| A /dioid/ is an /idempotent semiring/, i.e. it satisfies the following laws:+{-| A /star semiring/ is a 'Semiring' with an additional unary operator 'star'+satisfying the following two laws: -    * Associativity:+    > star a = one <+> a <.> star a+    > star a = one <+> star a <.> a+-}+class Semiring a => StarSemiring a where+    star :: a -> a -        > x /\ (y /\ z) == (x /\ y) /\ z+{-| A /dioid/ is an /idempotent semiring/, i.e. it satisfies the following+/idempotence/ law in addition to the 'Semiring' laws: -    * Identity:+    > x <+> x == x+-}+class Semiring a => Dioid a -        > x /\ one == x-        > one /\ x == x+-- | An alias for 'mempty'.+zero :: Monoid a => a+zero = mempty -    * Annihilating zero:+-- | An alias for '<>'.+(<+>) :: Semigroup a => a -> a -> a+(<+>) = (<>) -        > x /\ zero == zero-        > zero /\ x == zero+infixr 6 <+>+infixr 7 <.> -    * Distributivity:+instance Semiring Any where+    one             = Any True+    Any x <.> Any y = Any (x && y) -        > x /\ (y \/ z) == x /\ y \/ x /\ z-        > (x \/ y) /\ z == x /\ z \/ y /\ z--}-class Semilattice a => Dioid a where-    one  :: a-    (/\) :: a -> a -> a+instance StarSemiring Any where+    star _ = Any True -infixl 6 \/-infixl 7 /\+instance Dioid Any -instance Semilattice Bool where-    zero = False-    (\/) = (||)+-- | A non-negative value that can be 'finite' or 'infinite'. Note: the current+-- implementation of the 'Num' instance raises an error on negative literals+-- and on the 'negate' method.+newtype NonNegative a = NonNegative (Extended a)+    deriving (Applicative, Eq, Functor, Ord, Monad) -instance Dioid Bool where-    one  = True-    (/\) = (&&)+instance (Num a, Show a) => Show (NonNegative a) where+    show (NonNegative Infinite  ) = "infinite"+    show (NonNegative (Finite x)) = show x --- | A /distance/ is a non-negative value that can be 'Finite' or 'Infinite'.-data Distance a = Finite a | Infinite deriving (Eq, Ord, Show)+instance Num a => Bounded (NonNegative a) where+    minBound = unsafeFinite 0+    maxBound = infinite -instance (Ord a, Num a) => Num (Distance a) where+instance (Num a, Ord a) => Num (NonNegative a) where+    fromInteger x | f < 0     = error "NonNegative values cannot be negative"+                  | otherwise = unsafeFinite f+      where+        f = fromInteger x++    (+) = liftA2 (+)+    (*) = liftA2 (*)++    negate _ = error "NonNegative values cannot be negated"++    signum (NonNegative Infinite) = 1+    signum x = signum <$> x++    abs = id++-- | A finite non-negative value or @Nothing@ if the argument is negative.+finite :: (Num a, Ord a) => a -> Maybe (NonNegative a)+finite x | x < 0      = Nothing+         | otherwise  = Just (unsafeFinite x)++-- | A finite 'Word'.+finiteWord :: Word -> NonNegative Word+finiteWord = unsafeFinite++-- | A non-negative finite value, created /unsafely/: the argument is not+-- checked for being non-negative, so @unsafeFinite (-1)@ compiles just fine.+unsafeFinite :: a -> NonNegative a+unsafeFinite = NonNegative . Finite++-- | The (non-negative) infinite value.+infinite :: NonNegative a+infinite = NonNegative Infinite++-- | Get a finite value or @Nothing@ if the value is infinite.+getFinite :: NonNegative a -> Maybe a+getFinite (NonNegative x) = fromExtended x++-- | A /capacity/ is a non-negative value that can be 'finite' or 'infinite'.+-- Capacities form a 'Dioid' as follows:+--+-- @+-- 'zero'  = 0+-- 'one'   = 'capacity' 'infinite'+-- ('<+>') = 'max'+-- ('<.>') = 'min'+-- @+newtype Capacity a = Capacity (Max (NonNegative a))+    deriving (Bounded, Eq, Monoid, Num, Ord, Semigroup)++instance Show a => Show (Capacity a) where+    show (Capacity (Max (NonNegative (Finite x)))) = show x+    show _ = "capacity infinite"++instance (Num a, Ord a) => Semiring (Capacity a) where+    one   = capacity infinite+    (<.>) = min++instance (Num a, Ord a) => StarSemiring (Capacity a) where+    star _ = one++instance (Num a, Ord a) => Dioid (Capacity a)++-- | A non-negative capacity.+capacity :: NonNegative a -> Capacity a+capacity = Capacity . Max++-- | Get the value of a capacity.+getCapacity :: Capacity a -> NonNegative a+getCapacity (Capacity (Max x)) = x++-- | A /count/ is a non-negative value that can be 'finite' or 'infinite'.+-- Counts form a 'Semiring' as follows:+--+-- @+-- 'zero'  = 0+-- 'one'   = 1+-- ('<+>') = ('+')+-- ('<.>') = ('*')+-- @+newtype Count a = Count (Sum (NonNegative a))+    deriving (Bounded, Eq, Monoid, Num, Ord, Semigroup)++instance Show a => Show (Count a) where+    show (Count (Sum (NonNegative (Finite x)))) = show x+    show _ = "count infinite"++instance (Num a, Ord a) => Semiring (Count a) where+    one   = 1+    (<.>) = (*)++instance (Num a, Ord a) => StarSemiring (Count a) where+    star x | x == zero = one+           | otherwise = count infinite++-- | A non-negative count.+count :: NonNegative a -> Count a+count = Count . Sum++-- | Get the value of a count.+getCount :: Count a -> NonNegative a+getCount (Count (Sum x)) = x++-- | A /distance/ is a non-negative value that can be 'finite' or 'infinite'.+-- Distances form a 'Dioid' as follows:+--+-- @+-- 'zero'  = 'distance' 'infinite'+-- 'one'   = 0+-- ('<+>') = 'min'+-- ('<.>') = ('+')+-- @+newtype Distance a = Distance (Min (NonNegative a))+    deriving (Bounded, Eq, Monoid, Num, Ord, Semigroup)++instance Show a => Show (Distance a) where+    show (Distance (Min (NonNegative (Finite x)))) = show x+    show _ = "distance infinite"++instance (Num a, Ord a) => Semiring (Distance a) where+    one   = 0+    (<.>) = (+)++instance (Num a, Ord a) => StarSemiring (Distance a) where+    star _ = one++instance (Num a, Ord a) => Dioid (Distance a)++-- | A non-negative distance.+distance :: NonNegative a -> Distance a+distance = Distance . Min++-- | Get the value of a distance.+getDistance :: Distance a -> NonNegative a+getDistance (Distance (Min x)) = x++-- This data type extends the underlying type @a@ with a new 'Infinite' value.+data Extended a = Finite a | Infinite+    deriving (Eq, Functor, Ord, Show)++instance Applicative Extended where+    pure  = Finite+    (<*>) = ap++instance Monad Extended where+    return = pure++    Infinite >>= _ = Infinite+    Finite x >>= f = f x++-- Extract the finite value or @Nothing@ if the value is 'Infinite'.+fromExtended :: Extended a -> Maybe a+fromExtended (Finite a) = Just a+fromExtended Infinite   = Nothing++instance Num a => Num (Extended a) where     fromInteger = Finite . fromInteger -    Infinite + _        = Infinite-    _        + Infinite = Infinite-    Finite x + Finite y = Finite (x + y)+    (+) = liftA2 (+)+    (*) = liftA2 (*) -    Infinite * _        = Infinite-    _        * Infinite = Infinite-    Finite x * Finite y = Finite (x * y)+    negate = fmap negate+    signum = fmap signum+    abs    = fmap abs -    negate _ = error "Negative distances not allowed"+-- | If @a@ is a monoid, 'Minimum' @a@ forms the following 'Dioid':+--+-- @+-- 'zero'  = 'pure' 'mempty'+-- 'one'   = 'noMinimum'+-- ('<+>') = 'liftA2' 'min'+-- ('<.>') = 'liftA2' 'mappend'+-- @+--+-- To create a singleton value of type 'Minimum' @a@ use the 'pure' function.+-- For example:+--+-- @+-- getMinimum ('pure' "Hello, " '<+>' 'pure' "World!") == Just "Hello, "+-- getMinimum ('pure' "Hello, " '<.>' 'pure' "World!") == Just "Hello, World!"+-- @+newtype Minimum a = Minimum (Extended a)+    deriving (Applicative, Eq, Functor, Ord, Monad) -    signum (Finite 0) = 0-    signum _          = 1+-- | Extract the minimum or @Nothing@ if it does not exist.+getMinimum :: Minimum a -> Maybe a+getMinimum (Minimum x) = fromExtended x -    abs = id+-- | The value corresponding to the lack of minimum, e.g. the minimum of the+-- empty set.+noMinimum :: Minimum a+noMinimum = Minimum Infinite -instance Ord a => Semilattice (Distance a) where-    zero = Infinite+instance (Num a, Show a) => Show (Minimum a) where+    show (Minimum Infinite  ) = "one"+    show (Minimum (Finite x)) = show x -    Infinite \/ x        = x-    x        \/ Infinite = x-    Finite x \/ Finite y = Finite (min x y)+instance IsList a => IsList (Minimum a) where+    type Item (Minimum a) = Item a+    fromList = Minimum . Finite . fromList+    toList (Minimum x) = toList $ fromMaybe errorMessage (fromExtended x)+      where+        errorMessage = error "Minimum.toList applied to noMinimum value." -instance (Num a, Ord a) => Dioid (Distance a) where-    one = Finite 0+-- | The /power set/ over the underlying set of elements @a@. If @a@ is a+-- monoid, then the power set forms a 'Dioid' as follows:+--+-- @+-- 'zero'    = PowerSet Set.'Set.empty'+-- 'one'     = PowerSet $ Set.'Set.singleton' 'mempty'+-- x '<+>' y = PowerSet $ Set.'Set.union' (getPowerSet x) (getPowerSet y)+-- x '<.>' y = PowerSet $ 'setProductWith' 'mappend' (getPowerSet x) (getPowerSet y)+-- @+newtype PowerSet a = PowerSet { getPowerSet :: Set a }+    deriving (Eq, Monoid, Ord, Semigroup) -    Infinite /\ _        = Infinite-    _        /\ Infinite = Infinite-    Finite x /\ Finite y = Finite (x + y)+instance (Monoid a, Ord a) => Semiring (PowerSet a) where+    one                       = PowerSet (Set.singleton mempty)+    PowerSet x <.> PowerSet y = PowerSet (setProductWith mappend x y) -instance Ord a => Semilattice (Set a) where-    zero = Set.empty-    (\/) = Set.union+instance (Monoid a, Ord a) => StarSemiring (PowerSet a) where+    star _ = one++instance (Monoid a, Ord a) => Dioid (PowerSet a) where++-- | The type of /free labels/ over the underlying set of symbols @a@. This data+-- type is an instance of classes 'StarSemiring' and 'Dioid'.+data Label a = Zero+             | One+             | Symbol a+             | Label a :+: Label a+             | Label a :*: Label a+             | Star (Label a)+             deriving Functor++infixl 6 :+:+infixl 7 :*:++instance IsList (Label a) where+    type Item (Label a) = a+    fromList = foldr ((<>) . Symbol) Zero+    toList   = error "Label.toList cannot be given a reasonable definition"++instance Show a => Show (Label a) where+    showsPrec p label = case label of+        Zero     -> shows (0 :: Int)+        One      -> shows (1 :: Int)+        Symbol x -> shows x+        x :+: y  -> showParen (p >= 6) $ showsPrec 6 x . (" | " ++) . showsPrec 6 y+        x :*: y  -> showParen (p >= 7) $ showsPrec 7 x . (" ; " ++) . showsPrec 7 y+        Star x   -> showParen (p >= 8) $ showsPrec 8 x . ("*"   ++)++instance Semigroup (Label a) where+    Zero   <> x      = x+    x      <> Zero   = x+    One    <> One    = One+    One    <> Star x = Star x+    Star x <> One    = Star x+    x      <> y      = x :+: y++instance Monoid (Label a) where+    mempty  = Zero+    mappend = (<>)++instance Semiring (Label a) where+    one = One++    One  <.> x    = x+    x    <.> One  = x+    Zero <.> _    = Zero+    _    <.> Zero = Zero+    x    <.> y    = x :*: y++instance StarSemiring (Label a) where+    star Zero     = One+    star One      = One+    star (Star x) = star x+    star x        = Star x++-- | Check if a 'Label' is 'zero'.+isZero :: Label a -> Bool+isZero Zero = True+isZero _    = False++-- | A type synonym for /regular expressions/, built on top of /free labels/.+type RegularExpression a = Label a++-- | An /optimum semiring/ obtained by combining a semiring @o@ that defines an+-- /optimisation criterion/, and a semiring @a@ that describes the /arguments/+-- of an optimisation problem. For example, by choosing @o = 'Distance' Int@ and+-- and @a = 'Minimum' ('Path' String)@, we obtain the /shortest path semiring/+-- for computing the shortest path in an @Int@-labelled graph with @String@+-- vertices.+--+-- We assume that the semiring @o@ is /selective/ i.e. for all @x@ and @y@:+--+-- > x <+> y == x || x <+> y == y+--+-- In words, the operation '<+>' always simply selects one of its arguments. For+-- example, the 'Capacity' and 'Distance' semirings are selective, whereas the+-- the 'Count' semiring is not.+data Optimum o a = Optimum { getOptimum :: o, getArgument :: a }+    deriving (Eq, Ord, Show)++-- This is similar to geodetic semirings.+-- See http://vlado.fmf.uni-lj.si/vlado/papers/SemiRingSNA.pdf+instance (Eq o, Monoid a, Monoid o) => Semigroup (Optimum o a) where+    Optimum o1 a1 <> Optimum o2 a2+        | o1 == o2  = Optimum o1 (mappend a1 a2)+        | otherwise = Optimum o a+            where+              o = mappend o1 o2+              a = if o == o1 then a1 else a2++instance (Eq o, Monoid a, Monoid o) => Monoid (Optimum o a) where+    mempty  = Optimum mempty mempty+    mappend = (<>)++instance (Eq o, Semiring a, Semiring o) => Semiring (Optimum o a) where+    one = Optimum one one+    Optimum o1 a1 <.> Optimum o2 a2 = Optimum (o1 <.> o2) (a1 <.> a2)++instance (Eq o, StarSemiring a, StarSemiring o) => StarSemiring (Optimum o a) where+    star (Optimum o a) = Optimum (star o) (star a)++instance (Eq o, Dioid a, Dioid o) => Dioid (Optimum o a) where++-- | A /path/ is a list of edges.+type Path a = [(a, a)]++-- | The 'Optimum' semiring specialised to /finding the lexicographically+-- smallest shortest path/.+type ShortestPath e a = Optimum (Distance e) (Minimum (Path a))++-- | The 'Optimum' semiring specialised to /finding all shortest paths/.+type AllShortestPaths e a = Optimum (Distance e) (PowerSet (Path a))++-- | The 'Optimum' semiring specialised to /counting all shortest paths/.+type CountShortestPaths e a = Optimum (Distance e) (Count Integer)++-- | The 'Optimum' semiring specialised to /finding the lexicographically+-- smallest widest path/.+type WidestPath e a = Optimum (Capacity e) (Minimum (Path a))
src/Algebra/Graph/Labelled.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+{-# LANGUAGE DeriveFunctor, FlexibleInstances #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Labelled@@ -16,107 +16,619 @@ ----------------------------------------------------------------------------- module Algebra.Graph.Labelled (     -- * Algebraic data type for edge-labeleld graphs-    Graph (..), UnlabelledGraph, empty, vertex, edge, overlay, connect,-    connectBy, (-<), (>-),+    Graph (..), empty, vertex, edge, (-<), (>-), overlay, connect, vertices,+    edges, overlays, -    -- * Operations-    edgeLabel-  ) where+    -- * Graph folding+    foldg, +    -- * Relations on graphs+    isSubgraphOf,++    -- * Graph properties+    isEmpty, size, hasVertex, hasEdge, edgeLabel, vertexList, edgeList,+    vertexSet, edgeSet,++    -- * Graph transformation+    removeVertex, removeEdge, replaceVertex, replaceEdge, transpose, emap,+    induce,++    -- * Relational operations+    closure, reflexiveClosure, symmetricClosure, transitiveClosure,++    -- * Types of edge-labelled graphs+    UnlabelledGraph, Automaton, Network,++    -- * Context+    Context (..), context+    ) where+ import Prelude () import Prelude.Compat +import Data.Monoid (Any (..))+import Data.Semigroup ((<>))++import Algebra.Graph.Internal (List (..)) import Algebra.Graph.Label-import qualified Algebra.Graph.Class as C +import qualified Algebra.Graph.Labelled.AdjacencyMap as AM+import qualified Data.Set                            as Set+import qualified Data.Map                            as Map+import qualified GHC.Exts                            as Exts+ -- | Edge-labelled graphs, where the type variable @e@ stands for edge labels.--- For example, @Graph Bool a@ is isomorphic to unlabelled graphs defined in+-- For example, 'Graph' @Bool@ @a@ is isomorphic to unlabelled graphs defined in -- the top-level module "Algebra.Graph.Graph", where @False@ and @True@ denote -- the lack of and the existence of an unlabelled edge, respectively. data Graph e a = Empty                | Vertex a                | Connect e (Graph e a) (Graph e a)-               deriving (Foldable, Functor, Show, Traversable)+               deriving (Functor, Show) --- | A type synonym for unlabelled graphs.-type UnlabelledGraph a = Graph Bool a+instance (Eq e, Monoid e, Ord a) => Eq (Graph e a) where+    x == y = toAdjacencyMap x == toAdjacencyMap y +instance (Eq e, Monoid e, Ord a, Ord e) => Ord (Graph e a) where+    compare x y = compare (toAdjacencyMap x) (toAdjacencyMap y)++-- | __Note:__ this does not satisfy the usual ring laws; see 'Graph'+-- for more details.+instance (Ord a, Num a, Dioid e) => Num (Graph e a) where+    fromInteger = vertex . fromInteger+    (+)         = overlay+    (*)         = connect one+    signum      = const empty+    abs         = id+    negate      = id++-- TODO: This is a very inefficient implementation. Find a way to construct an+-- adjacency map directly, without building intermediate representations for all+-- subgraphs.+-- Extract the adjacency map of a graph.+toAdjacencyMap :: (Eq e, Monoid e, Ord a) => Graph e a -> AM.AdjacencyMap e a+toAdjacencyMap = foldg AM.empty AM.vertex AM.connect++-- Convert the adjacency map to a graph.+fromAdjacencyMap :: Monoid e => AM.AdjacencyMap e a -> Graph e a+fromAdjacencyMap = overlays . map go . Map.toList . AM.adjacencyMap+  where+    go (u, m) = overlay (vertex u) (edges [ (e, u, v) | (v, e) <- Map.toList m])++-- | Generalised 'Graph' folding: recursively collapse a 'Graph' by applying+-- the provided functions to the leaves and internal nodes of the expression.+-- The order of arguments is: empty, vertex and connect.+-- Complexity: /O(s)/ applications of given functions. As an example, the+-- complexity of 'size' is /O(s)/, since all functions have cost /O(1)/.+--+-- @+-- foldg 'empty'     'vertex'        'connect'             == 'id'+-- foldg 'empty'     'vertex'        ('fmap' 'flip' 'connect') == 'transpose'+-- foldg 1         ('const' 1)     ('const' (+))         == 'size'+-- foldg True      ('const' False) ('const' (&&))        == 'isEmpty'+-- foldg False     (== x)        ('const' (||))        == 'hasVertex' x+-- foldg Set.'Set.empty' Set.'Set.singleton' ('const' Set.'Set.union')   == 'vertexSet'+-- @+foldg :: b -> (a -> b) -> (e -> b -> b -> b) -> Graph e a -> b+foldg e v c = go+  where+    go Empty           = e+    go (Vertex    x  ) = v x+    go (Connect e x y) = c e (go x) (go y)++-- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the+-- first graph is a /subgraph/ of the second.+-- Complexity: /O(s + m * log(m))/ time. Note that the number of edges /m/ of a+-- graph can be quadratic with respect to the expression size /s/.+--+-- @+-- isSubgraphOf 'empty'         x             ==  True+-- isSubgraphOf ('vertex' x)    'empty'         ==  False+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf x y                         ==> x <= y+-- @+isSubgraphOf :: (Eq e, Monoid e, Ord a) => Graph e a -> Graph e a -> Bool+isSubgraphOf x y = overlay x y == y+ -- | Construct the /empty graph/. An alias for the constructor 'Empty'. -- Complexity: /O(1)/ time, memory and size.+--+-- @+-- 'isEmpty'     empty == True+-- 'hasVertex' x empty == False+-- 'Algebra.Graph.ToGraph.vertexCount' empty == 0+-- 'Algebra.Graph.ToGraph.edgeCount'   empty == 0+-- @ empty :: Graph e a empty = Empty  -- | Construct the graph comprising /a single isolated vertex/. An alias for the -- constructor 'Vertex'. -- Complexity: /O(1)/ time, memory and size.+--+-- @+-- 'isEmpty'     (vertex x) == False+-- 'hasVertex' x (vertex x) == True+-- 'Algebra.Graph.ToGraph.vertexCount' (vertex x) == 1+-- 'Algebra.Graph.ToGraph.edgeCount'   (vertex x) == 0+-- @ vertex :: a -> Graph e a vertex = Vertex --- | Construct the graph comprising /a single edge/ with the label 'one'.+-- | Construct the graph comprising /a single labelled edge/. -- Complexity: /O(1)/ time, memory and size.-edge :: Dioid e => a -> a -> Graph e a-edge = C.edge+--+-- @+-- edge e    x y              == 'connect' e ('vertex' x) ('vertex' y)+-- edge 'zero' x y              == 'vertices' [x,y]+-- 'hasEdge'   x y (edge e x y) == (e /= 'zero')+-- 'edgeLabel' x y (edge e x y) == e+-- 'Algebra.Graph.ToGraph.edgeCount'     (edge e x y) == if e == 'zero' then 0 else 1+-- 'Algebra.Graph.ToGraph.vertexCount'   (edge e 1 1) == 1+-- 'Algebra.Graph.ToGraph.vertexCount'   (edge e 1 2) == 2+-- @+edge :: e -> a -> a -> Graph e a+edge e x y = connect e (vertex x) (vertex y) --- | /Overlay/ two graphs. An alias for 'Connect' 'zero'. This is a commutative,--- associative and idempotent operation with the identity 'empty'.--- Complexity: /O(1)/ time and memory, /O(s1 + s2)/ size.-overlay :: Semilattice e => Graph e a -> Graph e a -> Graph e a-overlay = Connect zero+-- | The left-hand part of a convenient ternary-ish operator @x-\<e\>-y@ for+-- creating labelled edges.+--+-- @+-- x -\<e\>- y == 'edge' e x y+-- @+(-<) :: a -> e -> (a, e)+g -< e = (g, e) --- | /Connect/ two graphs. An alias for 'Connect' 'one'. This is an associative--- operation with the identity 'empty', which distributes over 'overlay' and--- obeys the decomposition axiom. See the full list of laws in "Algebra.Graph".--- Complexity: /O(1)/ time and memory, /O(s1 + s2)/ size. Note that the number--- of edges in the resulting graph is quadratic with respect to the number of--- vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.-connect :: Dioid e => Graph e a -> Graph e a -> Graph e a-connect = Connect one+-- | The right-hand part of a convenient ternary-ish operator @x-\<e\>-y@ for+-- creating labelled edges.+--+-- @+-- x -\<e\>- y == 'edge' e x y+-- @+(>-) :: (a, e) -> a -> Graph e a+(x, e) >- y = edge e x y +infixl 5 -<+infixl 5 >-++-- | /Overlay/ two graphs. An alias for 'Connect' 'zero'.+-- Complexity: /O(1)/ time and memory, /O(s1 + s2)/ size.+--+-- @+-- 'isEmpty'     (overlay x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (overlay x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'Algebra.Graph.ToGraph.vertexCount' (overlay x y) >= 'Algebra.Graph.ToGraph.vertexCount' x+-- 'Algebra.Graph.ToGraph.vertexCount' (overlay x y) <= 'Algebra.Graph.ToGraph.vertexCount' x + 'Algebra.Graph.ToGraph.vertexCount' y+-- 'Algebra.Graph.ToGraph.edgeCount'   (overlay x y) >= 'Algebra.Graph.ToGraph.edgeCount' x+-- 'Algebra.Graph.ToGraph.edgeCount'   (overlay x y) <= 'Algebra.Graph.ToGraph.edgeCount' x   + 'Algebra.Graph.ToGraph.edgeCount' y+-- 'Algebra.Graph.ToGraph.vertexCount' (overlay 1 2) == 2+-- 'Algebra.Graph.ToGraph.edgeCount'   (overlay 1 2) == 0+-- @+--+-- Note: 'overlay' composes edges in parallel using the operator '<+>' with+-- 'zero' acting as the identity:+--+-- @+-- 'edgeLabel' x y $ overlay ('edge' e x y) ('edge' 'zero' x y) == e+-- 'edgeLabel' x y $ overlay ('edge' e x y) ('edge' f    x y) == e '<+>' f+-- @+--+-- Furthermore, when applied to transitive graphs, 'overlay' composes edges in+-- sequence using the operator '<.>' with 'one' acting as the identity:+--+-- @+-- 'edgeLabel' x z $ 'transitiveClosure' (overlay ('edge' e x y) ('edge' 'one' y z)) == e+-- 'edgeLabel' x z $ 'transitiveClosure' (overlay ('edge' e x y) ('edge' f   y z)) == e '<.>' f+-- @+overlay :: Monoid e => Graph e a -> Graph e a -> Graph e a+overlay = connect zero+ -- | /Connect/ two graphs with edges labelled by a given label. An alias for -- 'Connect'. -- Complexity: /O(1)/ time and memory, /O(s1 + s2)/ size. Note that the number -- of edges in the resulting graph is quadratic with respect to the number of -- vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.-connectBy :: e -> Graph e a -> Graph e a -> Graph e a-connectBy = Connect+--+-- @+-- 'isEmpty'     (connect e x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (connect e x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'Algebra.Graph.ToGraph.vertexCount' (connect e x y) >= 'Algebra.Graph.ToGraph.vertexCount' x+-- 'Algebra.Graph.ToGraph.vertexCount' (connect e x y) <= 'Algebra.Graph.ToGraph.vertexCount' x + 'Algebra.Graph.ToGraph.vertexCount' y+-- 'Algebra.Graph.ToGraph.edgeCount'   (connect e x y) <= 'Algebra.Graph.ToGraph.vertexCount' x * 'Algebra.Graph.ToGraph.vertexCount' y + 'Algebra.Graph.ToGraph.edgeCount' x + 'Algebra.Graph.ToGraph.edgeCount' y+-- 'Algebra.Graph.ToGraph.vertexCount' (connect e 1 2) == 2+-- 'Algebra.Graph.ToGraph.edgeCount'   (connect e 1 2) == if e == 'zero' then 0 else 1+-- @+connect :: e -> Graph e a -> Graph e a -> Graph e a+connect = Connect --- | The left-hand part of a convenient ternary-ish operator @x -\<e\>- y@ for--- connecting graphs with labelled edges. For example:+-- | Construct the graph comprising a given list of isolated vertices.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the+-- given list. -- -- @--- x = 'vertex' "x"--- y = 'vertex' "y"--- z = x -\<2\>- y+-- vertices []            == 'empty'+-- vertices [x]           == 'vertex' x+-- 'hasVertex' x . vertices == 'elem' x+-- 'Algebra.Graph.ToGraph.vertexCount' . vertices == 'length' . 'Data.List.nub'+-- 'Algebra.Graph.ToGraph.vertexSet'   . vertices == Set.'Set.fromList' -- @-(-<) :: Graph e a -> e -> (Graph e a, e)-g -< e = (g, e)+vertices :: Monoid e => [a] -> Graph e a+vertices = overlays . map vertex --- | The right-hand part of a convenient ternary-ish operator @x -\<e\>- y@ for--- connecting graphs with labelled edges. For example:+-- | Construct the graph from a list of labelled edges.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the+-- given list. -- -- @--- x = 'vertex' "x"--- y = 'vertex' "y"--- z = x -\<2\>- y+-- edges []        == 'empty'+-- edges [(e,x,y)] == 'edge' e x y+-- edges           == 'overlays' . 'map' (\\(e, x, y) -> 'edge' e x y) -- @-(>-) :: (Graph e a, e) -> Graph e a -> Graph e a-(g, e) >- h = Connect e g h+edges :: Monoid e => [(e, a, a)] -> Graph e a+edges = overlays . map (\(e, x, y) -> edge e x y) -infixl 5 -<-infixl 5 >-+-- | Overlay a given list of graphs.+-- Complexity: /O(L)/ time and memory, and /O(S)/ size, where /L/ is the length+-- of the given list, and /S/ is the sum of sizes of the graphs in the list.+--+-- @+-- overlays []        == 'empty'+-- overlays [x]       == x+-- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty'+-- 'isEmpty' . overlays == 'all' 'isEmpty'+-- @+overlays :: Monoid e => [Graph e a] -> Graph e a+overlays = foldr overlay empty -instance Dioid e => C.Graph (Graph e a) where-    type Vertex (Graph e a) = a-    empty   = Empty-    vertex  = Vertex-    overlay = overlay-    connect = connect+-- | Check if a graph is empty. A convenient alias for 'null'.+-- Complexity: /O(s)/ time.+--+-- @+-- isEmpty 'empty'                         == True+-- isEmpty ('overlay' 'empty' 'empty')         == True+-- isEmpty ('vertex' x)                    == False+-- isEmpty ('removeVertex' x $ 'vertex' x)   == True+-- isEmpty ('removeEdge' x y $ 'edge' e x y) == False+-- @+isEmpty :: Graph e a -> Bool+isEmpty = foldg True (const False) (const (&&)) +-- | The /size/ of a graph, i.e. the number of leaves of the expression+-- including 'empty' leaves.+-- Complexity: /O(s)/ time.+--+-- @+-- size 'empty'         == 1+-- size ('vertex' x)    == 1+-- size ('overlay' x y) == size x + size y+-- size ('connect' x y) == size x + size y+-- size x             >= 1+-- size x             >= 'Algebra.Graph.ToGraph.vertexCount' x+-- @+size :: Graph e a -> Int+size = foldg 1 (const 1) (const (+))++-- | Check if a graph contains a given vertex.+-- Complexity: /O(s)/ time.+--+-- @+-- hasVertex x 'empty'            == False+-- hasVertex x ('vertex' x)       == True+-- hasVertex 1 ('vertex' 2)       == False+-- hasVertex x . 'removeVertex' x == 'const' False+-- @+hasVertex :: Eq a => a -> Graph e a -> Bool+hasVertex x = foldg False (==x) (const (||))++-- | Check if a graph contains a given edge.+-- Complexity: /O(s)/ time.+--+-- @+-- hasEdge x y 'empty'            == False+-- hasEdge x y ('vertex' z)       == False+-- hasEdge x y ('edge' e x y)     == (e /= 'zero')+-- hasEdge x y . 'removeEdge' x y == 'const' False+-- hasEdge x y                  == 'not' . 'null' . 'filter' (\\(_,ex,ey) -> ex == x && ey == y) . 'edgeList'+-- @+hasEdge :: (Eq e, Monoid e, Ord a) => a -> a -> Graph e a -> Bool+hasEdge x y = (/= zero) . edgeLabel x y+ -- | Extract the label of a specified edge from a graph.-edgeLabel :: (Eq a, Semilattice e) => a -> a -> Graph e a -> e-edgeLabel _ _ Empty           = zero-edgeLabel _ _ (Vertex _)      = zero-edgeLabel x y (Connect e g h) = edgeLabel x y g \/ edgeLabel x y h \/ new+edgeLabel :: (Eq a, Monoid e) => a -> a -> Graph e a -> e+edgeLabel s t g = let (res, _, _) = foldg e v c g in res   where-    new | x `elem` g && y `elem` h = e-        | otherwise                = zero+    e                                         = (zero               , False   , False   )+    v x                                       = (zero               , x == s  , x == t  )+    c l (l1, s1, t1) (l2, s2, t2) | s1 && t2  = (mconcat [l1, l, l2], s1 || s2, t1 || t2)+                                  | otherwise = (mconcat [l1,    l2], s1 || s2, t1 || t2)++-- | The sorted list of vertices of a given graph.+-- Complexity: /O(s * log(n))/ time and /O(n)/ memory.+--+-- @+-- vertexList 'empty'      == []+-- vertexList ('vertex' x) == [x]+-- vertexList . 'vertices' == 'Data.List.nub' . 'Data.List.sort'+-- @+vertexList :: Ord a => Graph e a -> [a]+vertexList = Set.toAscList . vertexSet++-- | The list of edges of a graph, sorted lexicographically with respect to+-- pairs of connected vertices (i.e. edge-labels are ignored when sorting).+-- Complexity: /O(n + m)/ time and /O(m)/ memory.+--+-- @+-- edgeList 'empty'        == []+-- edgeList ('vertex' x)   == []+-- edgeList ('edge' e x y) == if e == 'zero' then [] else [(e,x,y)]+-- @+edgeList :: (Eq e, Monoid e, Ord a) => Graph e a -> [(e, a, a)]+edgeList = AM.edgeList . toAdjacencyMap++-- | The set of vertices of a given graph.+-- Complexity: /O(s * log(n))/ time and /O(n)/ memory.+--+-- @+-- vertexSet 'empty'      == Set.'Set.empty'+-- vertexSet . 'vertex'   == Set.'Set.singleton'+-- vertexSet . 'vertices' == Set.'Set.fromList'+-- @+vertexSet :: Ord a => Graph e a -> Set.Set a+vertexSet = foldg Set.empty Set.singleton (const Set.union)++-- | The set of edges of a given graph.+-- Complexity: /O(n + m)/ time and /O(m)/ memory.+--+-- @+-- edgeSet 'empty'        == Set.'Set.empty'+-- edgeSet ('vertex' x)   == Set.'Set.empty'+-- edgeSet ('edge' e x y) == if e == 'zero' then Set.'Set.empty' else Set.'Set.singleton' (e,x,y)+-- @+edgeSet :: (Eq e, Monoid e, Ord a) => Graph e a -> Set.Set (e, a, a)+edgeSet = Set.fromAscList . edgeList++-- | Remove a vertex from a given graph.+-- Complexity: /O(s)/ time, memory and size.+--+-- @+-- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' e x x)     == 'empty'+-- removeVertex 1 ('edge' e 1 2)     == 'vertex' 2+-- removeVertex x . removeVertex x == removeVertex x+-- @+removeVertex :: Eq a => a -> Graph e a -> Graph e a+removeVertex x = induce (/= x)++-- | Remove an edge from a given graph.+-- Complexity: /O(s)/ time, memory and size.+--+-- @+-- removeEdge x y ('edge' e x y)     == 'vertices' [x,y]+-- removeEdge x y . removeEdge x y == removeEdge x y+-- removeEdge x y . 'removeVertex' x == 'removeVertex' x+-- removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2+-- removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2+-- @+removeEdge :: (Eq a, Eq e, Monoid e) => a -> a -> Graph e a -> Graph e a+removeEdge s t = filterContext s (/=s) (/=t)++-- | The function @'replaceVertex' x y@ replaces vertex @x@ with vertex @y@ in a+-- given 'Graph'. If @y@ already exists, @x@ and @y@ will be merged.+-- Complexity: /O(s)/ time, memory and size.+--+-- @+-- replaceVertex x x            == id+-- replaceVertex x y ('vertex' x) == 'vertex' y+-- replaceVertex x y            == 'fmap' (\\v -> if v == x then y else v)+-- @+replaceVertex :: Eq a => a -> a -> Graph e a -> Graph e a+replaceVertex u v = fmap $ \w -> if w == u then v else w++-- | Replace an edge from a given graph. If it doesn't exist, it will be created.+-- Complexity: /O(log(n))/ time.+--+-- @+-- replaceEdge e x y z                 == 'overlay' (removeEdge x y z) ('edge' e x y)+-- replaceEdge e x y ('edge' f x y)      == 'edge' e x y+-- 'edgeLabel' x y (replaceEdge e x y z) == e+-- @+replaceEdge :: (Eq e, Monoid e, Ord a) => e -> a -> a -> Graph e a -> Graph e a+replaceEdge e x y = overlay (edge e x y) . removeEdge x y++-- | Transpose a given graph.+-- Complexity: /O(s)/ time, memory and size.+--+-- @+-- transpose 'empty'        == 'empty'+-- transpose ('vertex' x)   == 'vertex' x+-- transpose ('edge' e x y) == 'edge' e y x+-- transpose . transpose  == id+-- @+transpose :: Graph e a -> Graph e a+transpose = foldg empty vertex (fmap flip connect)++-- | Transform a graph by applying a function to each of its edge labels.+-- Complexity: /O(s)/ time, memory and size.+--+-- The function @h@ is required to be a /homomorphism/ on the underlying type of+-- labels @e@. At the very least it must preserve 'zero' and '<+>':+--+-- @+-- h 'zero'      == 'zero'+-- h x '<+>' h y == h (x '<+>' y)+-- @+--+-- If @e@ is also a semiring, then @h@ must also preserve the multiplicative+-- structure:+--+-- @+-- h 'one'       == 'one'+-- h x '<.>' h y == h (x '<.>' y)+-- @+--+-- If the above requirements hold, then the implementation provides the+-- following guarantees.+--+-- @+-- emap h 'empty'           == 'empty'+-- emap h ('vertex' x)      == 'vertex' x+-- emap h ('edge' e x y)    == 'edge' (h e) x y+-- emap h ('overlay' x y)   == 'overlay' (emap h x) (emap h y)+-- emap h ('connect' e x y) == 'connect' (h e) (emap h x) (emap h y)+-- emap 'id'                == 'id'+-- emap g . emap h        == emap (g . h)+-- @+emap :: (e -> f) -> Graph e a -> Graph f a+emap f = foldg Empty Vertex (Connect . f)++-- | Construct the /induced subgraph/ of a given graph by removing the+-- vertices that do not satisfy a given predicate.+-- Complexity: /O(s)/ time, memory and size, assuming that the predicate takes+-- /O(1)/ to be evaluated.+--+-- @+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty'+-- induce (/= x)               == 'removeVertex' x+-- induce p . induce q         == induce (\\x -> p x && q x)+-- 'isSubgraphOf' (induce p x) x == True+-- @+induce :: (a -> Bool) -> Graph e a -> Graph e a+induce p = foldg Empty (\x -> if p x then Vertex x else Empty) c+  where+    c _ x     Empty = x -- Constant folding to get rid of Empty leaves+    c _ Empty y     = y+    c e x     y     = Connect e x y++-- | Compute the /reflexive and transitive closure/ of a graph over the+-- underlying star semiring using the Warshall-Floyd-Kleene algorithm.+--+-- @+-- closure 'empty'         == 'empty'+-- closure ('vertex' x)    == 'edge' 'one' x x+-- closure ('edge' e x x)  == 'edge' 'one' x x+-- closure ('edge' e x y)  == 'edges' [('one',x,x), (e,x,y), ('one',y,y)]+-- closure               == 'reflexiveClosure' . 'transitiveClosure'+-- closure               == 'transitiveClosure' . 'reflexiveClosure'+-- closure . closure     == closure+-- 'Algebra.Graph.ToGraph.postSet' x (closure y) == Set.'Set.fromList' ('Algebra.Graph.ToGraph.reachable' x y)+-- @+closure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a+closure = fromAdjacencyMap . AM.closure . toAdjacencyMap++-- | Compute the /reflexive closure/ of a graph over the underlying semiring by+-- adding a self-loop of weight 'one' to every vertex.+-- Complexity: /O(n * log(n))/ time.+--+-- @+-- reflexiveClosure 'empty'              == 'empty'+-- reflexiveClosure ('vertex' x)         == 'edge' 'one' x x+-- reflexiveClosure ('edge' e x x)       == 'edge' 'one' x x+-- reflexiveClosure ('edge' e x y)       == 'edges' [('one',x,x), (e,x,y), ('one',y,y)]+-- reflexiveClosure . reflexiveClosure == reflexiveClosure+-- @+reflexiveClosure :: (Ord a, Semiring e) => Graph e a -> Graph e a+reflexiveClosure x = overlay x $ edges [ (one, v, v) | v <- vertexList x ]++-- | Compute the /symmetric closure/ of a graph by overlaying it with its own+-- transpose.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- symmetricClosure 'empty'              == 'empty'+-- symmetricClosure ('vertex' x)         == 'vertex' x+-- symmetricClosure ('edge' e x y)       == 'edges' [(e,x,y), (e,y,x)]+-- symmetricClosure x                  == 'overlay' x ('transpose' x)+-- symmetricClosure . symmetricClosure == symmetricClosure+-- @+symmetricClosure :: Monoid e => Graph e a -> Graph e a+symmetricClosure m = overlay m (transpose m)++-- | Compute the /transitive closure/ of a graph over the underlying star+-- semiring using a modified version of the Warshall-Floyd-Kleene algorithm,+-- which omits the reflexivity step.+--+-- @+-- transitiveClosure 'empty'               == 'empty'+-- transitiveClosure ('vertex' x)          == 'vertex' x+-- transitiveClosure ('edge' e x y)        == 'edge' e x y+-- transitiveClosure . transitiveClosure == transitiveClosure+-- @+transitiveClosure :: (Eq e, Ord a, StarSemiring e) => Graph e a -> Graph e a+transitiveClosure = fromAdjacencyMap . AM.transitiveClosure . toAdjacencyMap++-- | A type synonym for /unlabelled graphs/.+type UnlabelledGraph a = Graph Any a++-- | A type synonym for /automata/ or /labelled transition systems/.+type Automaton a s = Graph (RegularExpression a) s++-- | A /network/ is a graph whose edges are labelled with distances.+type Network e a = Graph (Distance e) a++-- Filter vertices in a subgraph context.+filterContext :: (Eq a, Eq e, Monoid e) => a -> (a -> Bool) -> (a -> Bool) -> Graph e a -> Graph e a+filterContext s i o g = maybe g go $ context (==s) g+  where+    go (Context is os) = overlays [ vertex s+                                  , induce (/=s) g+                                  , edges [ (e, v, s) | (e, v) <- is, i v ]+                                  , edges [ (e, s, v) | (e, v) <- os, o v ] ]++-- The /focus/ of a graph expression is a flattened represenentation of the+-- subgraph under focus, its context, as well as the list of all encountered+-- vertices. See 'removeEdge' for a use-case example.+data Focus e a = Focus+    { ok :: Bool        -- ^ True if focus on the specified subgraph is obtained.+    , is :: List (e, a) -- ^ Inputs into the focused subgraph.+    , os :: List (e, a) -- ^ Outputs out of the focused subgraph.+    , vs :: List a    } -- ^ All vertices (leaves) of the graph expression.++-- Focus on the 'empty' graph.+emptyFocus :: Focus e a+emptyFocus = Focus False mempty mempty mempty++-- | Focus on the graph with a single vertex, given a predicate indicating+-- whether the vertex is of interest.+vertexFocus :: (a -> Bool) -> a -> Focus e a+vertexFocus f x = Focus (f x) mempty mempty (pure x)++-- | Connect two foci.+connectFoci :: (Eq e, Monoid e) => e -> Focus e a -> Focus e a -> Focus e a+connectFoci e x y+    | e == mempty = Focus (ok x || ok y) (is x <> is y) (os x <> os y) (vs x <> vs y)+    | otherwise   = Focus (ok x || ok y) (xs   <> is y) (os x <> ys  ) (vs x <> vs y)+  where+    xs = if ok y then fmap (e,) (vs x) else is x+    ys = if ok x then fmap (e,) (vs y) else os y++-- | 'Focus' on a specified subgraph.+focus :: (Eq e, Monoid e) => (a -> Bool) -> Graph e a -> Focus e a+focus f = foldg emptyFocus (vertexFocus f) connectFoci++-- | The 'Context' of a subgraph comprises its 'inputs' and 'outputs', i.e. all+-- the vertices that are connected to the subgraph's vertices (along with the+-- corresponding edge labels). Note that inputs and outputs can belong to the+-- subgraph itself. In general, there are no guarantees on the order of vertices+-- in 'inputs' and 'outputs'; furthermore, there may be repetitions.+data Context e a = Context { inputs :: [(e, a)], outputs :: [(e, a)] }+    deriving (Eq, Show)++-- | Extract the 'Context' of a subgraph specified by a given predicate. Returns+-- @Nothing@ if the specified subgraph is empty.+--+-- @+-- context ('const' False) x                   == Nothing+-- context (== 1)        ('edge' e 1 2)        == if e == 'zero' then Just ('Context' [] []) else Just ('Context' [     ] [(e,2)])+-- context (== 2)        ('edge' e 1 2)        == if e == 'zero' then Just ('Context' [] []) else Just ('Context' [(e,1)] [     ])+-- context ('const' True ) ('edge' e 1 2)        == if e == 'zero' then Just ('Context' [] []) else Just ('Context' [(e,1)] [(e,2)])+-- context (== 4)        (3 * 1 * 4 * 1 * 5) == Just ('Context' [('one',3), ('one',1)] [('one',1), ('one',5)])+-- @+context :: (Eq e, Monoid e) => (a -> Bool) -> Graph e a -> Maybe (Context e a)+context p g | ok f      = Just $ Context (Exts.toList $ is f) (Exts.toList $ os f)+            | otherwise = Nothing+  where+    f = focus p g
+ src/Algebra/Graph/Labelled/AdjacencyMap.hs view
@@ -0,0 +1,612 @@+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Labelled.AdjacencyMap+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- __Alga__ is a library for algebraic construction and manipulation of graphs+-- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the+-- motivation behind the library, the underlying theory, and implementation details.+--+-- This module defines the 'AdjacencyMap' data type for edge-labelled graphs, as+-- well as associated operations and algorithms. 'AdjacencyMap' is an instance+-- of the 'C.Graph' type class, which can be used for polymorphic graph+-- construction and manipulation.+-----------------------------------------------------------------------------+module Algebra.Graph.Labelled.AdjacencyMap (+    -- * Data structure+    AdjacencyMap, adjacencyMap,++    -- * Basic graph construction primitives+    empty, vertex, edge, (-<), (>-), overlay, connect, vertices, edges,+    overlays, fromAdjacencyMaps,++    -- * Relations on graphs+    isSubgraphOf,++    -- * Graph properties+    isEmpty, hasVertex, hasEdge, edgeLabel, vertexCount, edgeCount, vertexList,+    edgeList, vertexSet, edgeSet, preSet, postSet, skeleton,++    -- * Graph transformation+    removeVertex, removeEdge, replaceVertex, replaceEdge, transpose, gmap,+    emap, induce,++    -- * Relational operations+    closure, reflexiveClosure, symmetricClosure, transitiveClosure+  ) where++import Prelude ()+import Prelude.Compat++import Data.Foldable (foldMap)+import Data.Maybe+import Data.Map (Map)+import Data.Monoid (Monoid, Sum (..))+import Data.Set (Set)++import Algebra.Graph.Label+import Algebra.Graph.Labelled.AdjacencyMap.Internal++import qualified Algebra.Graph.AdjacencyMap          as AM+import qualified Algebra.Graph.AdjacencyMap.Internal as AMI+import qualified Data.Map.Strict                     as Map+import qualified Data.Set                            as Set++-- | Construct the /empty graph/.+-- Complexity: /O(1)/ time and memory.+--+-- @+-- 'isEmpty'     empty == True+-- 'hasVertex' x empty == False+-- 'vertexCount' empty == 0+-- 'edgeCount'   empty == 0+-- @+empty :: AdjacencyMap e a+empty = AM Map.empty++-- | Construct the graph comprising /a single isolated vertex/.+-- Complexity: /O(1)/ time and memory.+--+-- @+-- 'isEmpty'     (vertex x) == False+-- 'hasVertex' x (vertex x) == True+-- 'vertexCount' (vertex x) == 1+-- 'edgeCount'   (vertex x) == 0+-- @+vertex :: a -> AdjacencyMap e a+vertex x = AM $ Map.singleton x Map.empty++-- | Construct the graph comprising /a single edge/.+-- Complexity: /O(1)/ time, memory.+--+-- @+-- edge e    x y              == 'connect' e ('vertex' x) ('vertex' y)+-- edge 'zero' x y              == 'vertices' [x,y]+-- 'hasEdge'   x y (edge e x y) == (e /= 'zero')+-- 'edgeLabel' x y (edge e x y) == e+-- 'edgeCount'     (edge e x y) == if e == 'zero' then 0 else 1+-- 'vertexCount'   (edge e 1 1) == 1+-- 'vertexCount'   (edge e 1 2) == 2+-- @+edge :: (Eq e, Monoid e, Ord a) => e -> a -> a -> AdjacencyMap e a+edge e x y | e == zero = vertices [x, y]+           | x == y    = AM $ Map.singleton x (Map.singleton x e)+           | otherwise = AM $ Map.fromList [(x, Map.singleton y e), (y, Map.empty)]++-- | The left-hand part of a convenient ternary-ish operator @x-\<e\>-y@ for+-- creating labelled edges.+--+-- @+-- x -\<e\>- y == 'edge' e x y+-- @+(-<) :: a -> e -> (a, e)+g -< e = (g, e)++-- | The right-hand part of a convenient ternary-ish operator @x-\<e\>-y@ for+-- creating labelled edges.+--+-- @+-- x -\<e\>- y == 'edge' e x y+-- @+(>-) :: (Eq e, Monoid e, Ord a) => (a, e) -> a -> AdjacencyMap e a+(x, e) >- y = edge e x y++infixl 5 -<+infixl 5 >-++-- | /Overlay/ two graphs. This is a commutative, associative and idempotent+-- operation with the identity 'empty'.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- 'isEmpty'     (overlay x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (overlay x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (overlay x y) >= 'vertexCount' x+-- 'vertexCount' (overlay x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (overlay x y) >= 'edgeCount' x+-- 'edgeCount'   (overlay x y) <= 'edgeCount' x   + 'edgeCount' y+-- 'vertexCount' (overlay 1 2) == 2+-- 'edgeCount'   (overlay 1 2) == 0+-- @+--+-- Note: 'overlay' composes edges in parallel using the operator '<+>' with+-- 'zero' acting as the identity:+--+-- @+-- 'edgeLabel' x y $ overlay ('edge' e x y) ('edge' 'zero' x y) == e+-- 'edgeLabel' x y $ overlay ('edge' e x y) ('edge' f    x y) == e '<+>' f+-- @+--+-- Furthermore, when applied to transitive graphs, 'overlay' composes edges in+-- sequence using the operator '<.>' with 'one' acting as the identity:+--+-- @+-- 'edgeLabel' x z $ 'transitiveClosure' (overlay ('edge' e x y) ('edge' 'one' y z)) == e+-- 'edgeLabel' x z $ 'transitiveClosure' (overlay ('edge' e x y) ('edge' f   y z)) == e '<.>' f+-- @+overlay :: (Eq e, Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a -> AdjacencyMap e a+overlay (AM x) (AM y) = AM $ Map.unionWith nonZeroUnion x y++-- Union maps, removing zero elements from the result.+nonZeroUnion :: (Eq e, Monoid e, Ord a) => Map a e -> Map a e -> Map a e+nonZeroUnion x y = Map.filter (/= zero) $ Map.unionWith mappend x y++-- Drop all edges with zero labels.+trimZeroes :: (Eq e, Monoid e) => Map a (Map a e) -> Map a (Map a e)+trimZeroes = Map.map (Map.filter (/= zero))++-- | /Connect/ two graphs with edges labelled by a given label. When applied to+-- the same labels, this is an associative operation with the identity 'empty',+-- which distributes over 'overlay' and obeys the decomposition axiom.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. Note that the+-- number of edges in the resulting graph is quadratic with respect to the+-- number of vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.+--+-- @+-- 'isEmpty'     (connect e x y) == 'isEmpty'   x   && 'isEmpty'   y+-- 'hasVertex' z (connect e x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (connect e x y) >= 'vertexCount' x+-- 'vertexCount' (connect e x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (connect e x y) <= 'vertexCount' x * 'vertexCount' y + 'edgeCount' x + 'edgeCount' y+-- 'vertexCount' (connect e 1 2) == 2+-- 'edgeCount'   (connect e 1 2) == if e == 'zero' then 0 else 1+-- @+connect :: (Eq e, Monoid e, Ord a) => e -> AdjacencyMap e a -> AdjacencyMap e a -> AdjacencyMap e a+connect e (AM x) (AM y)+    | e == mempty = overlay (AM x) (AM y)+    | otherwise   = AM $ Map.unionsWith nonZeroUnion $ x : y :+        [ Map.fromSet (const targets) (Map.keysSet x) ]+  where+    targets = Map.fromSet (const e) (Map.keysSet y)++-- | Construct the graph comprising a given list of isolated vertices.+-- Complexity: /O(L * log(L))/ time and /O(L)/ memory, where /L/ is the length+-- of the given list.+--+-- @+-- vertices []            == 'empty'+-- vertices [x]           == 'vertex' x+-- 'hasVertex' x . vertices == 'elem' x+-- 'vertexCount' . vertices == 'length' . 'Data.List.nub'+-- 'vertexSet'   . vertices == Set.'Set.fromList'+-- @+vertices :: Ord a => [a] -> AdjacencyMap e a+vertices = AM . Map.fromList . map (, Map.empty)++-- | Construct the graph from a list of edges.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- edges []        == 'empty'+-- edges [(e,x,y)] == 'edge' e x y+-- edges           == 'overlays' . 'map' (\\(e, x, y) -> 'edge' e x y)+-- @+edges :: (Eq e, Monoid e, Ord a) => [(e, a, a)] -> AdjacencyMap e a+edges es = fromAdjacencyMaps [ (x, Map.singleton y e) | (e, x, y) <- es ]++-- | Overlay a given list of graphs.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- overlays []        == 'empty'+-- overlays [x]       == x+-- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty'+-- 'isEmpty' . overlays == 'all' 'isEmpty'+-- @+overlays :: (Eq e, Monoid e, Ord a) => [AdjacencyMap e a] -> AdjacencyMap e a+overlays = AM . Map.unionsWith nonZeroUnion . map adjacencyMap++-- | Construct a graph from a list of adjacency sets.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- fromAdjacencyMaps []                                  == 'empty'+-- fromAdjacencyMaps [(x, Map.'Map.empty')]                    == 'vertex' x+-- fromAdjacencyMaps [(x, Map.'Map.singleton' y e)]            == if e == 'zero' then 'vertices' [x,y] else 'edge' e x y+-- 'overlay' (fromAdjacencyMaps xs) (fromAdjacencyMaps ys) == fromAdjacencyMaps (xs '++' ys)+-- @+fromAdjacencyMaps :: (Eq e, Monoid e, Ord a) => [(a, Map a e)] -> AdjacencyMap e a+fromAdjacencyMaps xs = AM $ trimZeroes $ Map.unionWith mappend vs es+  where+    vs = Map.fromSet (const Map.empty) . Set.unions $ map (Map.keysSet . snd) xs+    es = Map.fromListWith (Map.unionWith mappend) xs++-- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the+-- first graph is a /subgraph/ of the second.+-- Complexity: /O(s + m * log(m))/ time. Note that the number of edges /m/ of a+-- graph can be quadratic with respect to the expression size /s/.+--+-- @+-- isSubgraphOf 'empty'      x     ==  True+-- isSubgraphOf ('vertex' x) 'empty' ==  False+-- isSubgraphOf x y              ==> x <= y+-- @+isSubgraphOf :: (Eq e, Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a -> Bool+isSubgraphOf (AM x) (AM y) = Map.isSubmapOfBy (Map.isSubmapOfBy le) x y+  where+    le x y = mappend x y == y++-- | Check if a graph is empty.+-- Complexity: /O(1)/ time.+--+-- @+-- isEmpty 'empty'                         == True+-- isEmpty ('overlay' 'empty' 'empty')         == True+-- isEmpty ('vertex' x)                    == False+-- isEmpty ('removeVertex' x $ 'vertex' x)   == True+-- isEmpty ('removeEdge' x y $ 'edge' e x y) == False+-- @+isEmpty :: AdjacencyMap e a -> Bool+isEmpty = Map.null . adjacencyMap++-- | Check if a graph contains a given vertex.+-- Complexity: /O(log(n))/ time.+--+-- @+-- hasVertex x 'empty'            == False+-- hasVertex x ('vertex' x)       == True+-- hasVertex 1 ('vertex' 2)       == False+-- hasVertex x . 'removeVertex' x == 'const' False+-- @+hasVertex :: Ord a => a -> AdjacencyMap e a -> Bool+hasVertex x = Map.member x . adjacencyMap++-- | Check if a graph contains a given edge.+-- Complexity: /O(log(n))/ time.+--+-- @+-- hasEdge x y 'empty'            == False+-- hasEdge x y ('vertex' z)       == False+-- hasEdge x y ('edge' e x y)     == (e /= 'zero')+-- hasEdge x y . 'removeEdge' x y == 'const' False+-- hasEdge x y                  == 'not' . 'null' . 'filter' (\\(_,ex,ey) -> ex == x && ey == y) . 'edgeList'+-- @+hasEdge :: Ord a => a -> a -> AdjacencyMap e a -> Bool+hasEdge x y (AM m) = fromMaybe False (Map.member y <$> Map.lookup x m)++-- | Extract the label of a specified edge in a graph.+-- Complexity: /O(log(n))/ time.+--+-- @+-- edgeLabel x y 'empty'         == 'zero'+-- edgeLabel x y ('vertex' z)    == 'zero'+-- edgeLabel x y ('edge' e x y)  == e+-- edgeLabel s t ('overlay' x y) == edgeLabel s t x <+> edgeLabel s t y+-- @+edgeLabel :: (Monoid e, Ord a) => a -> a -> AdjacencyMap e a -> e+edgeLabel x y (AM m) = fromMaybe zero (Map.lookup x m >>= Map.lookup y)++-- | The number of vertices in a graph.+-- Complexity: /O(1)/ time.+--+-- @+-- vertexCount 'empty'             ==  0+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y+-- @+vertexCount :: AdjacencyMap e a -> Int+vertexCount = Map.size . adjacencyMap++-- | The number of (non-'zero') edges in a graph.+-- Complexity: /O(n)/ time.+--+-- @+-- edgeCount 'empty'        == 0+-- edgeCount ('vertex' x)   == 0+-- edgeCount ('edge' e x y) == if e == 'zero' then 0 else 1+-- edgeCount              == 'length' . 'edgeList'+-- @+edgeCount :: AdjacencyMap e a -> Int+edgeCount = getSum . foldMap (Sum . Map.size) . adjacencyMap++-- | The sorted list of vertices of a given graph.+-- Complexity: /O(n)/ time and memory.+--+-- @+-- vertexList 'empty'      == []+-- vertexList ('vertex' x) == [x]+-- vertexList . 'vertices' == 'Data.List.nub' . 'Data.List.sort'+-- @+vertexList :: AdjacencyMap e a -> [a]+vertexList = Map.keys . adjacencyMap++-- | The list of edges of a graph, sorted lexicographically with respect to+-- pairs of connected vertices (i.e. edge-labels are ignored when sorting).+-- Complexity: /O(n + m)/ time and /O(m)/ memory.+--+-- @+-- edgeList 'empty'        == []+-- edgeList ('vertex' x)   == []+-- edgeList ('edge' e x y) == if e == 'zero' then [] else [(e,x,y)]+-- @+edgeList :: AdjacencyMap e a -> [(e, a, a)]+edgeList (AM m) =+    [ (e, x, y) | (x, ys) <- Map.toAscList m, (y, e) <- Map.toAscList ys ]++-- | The set of vertices of a given graph.+-- Complexity: /O(n)/ time and memory.+--+-- @+-- vertexSet 'empty'      == Set.'Set.empty'+-- vertexSet . 'vertex'   == Set.'Set.singleton'+-- vertexSet . 'vertices' == Set.'Set.fromList'+-- @+vertexSet :: AdjacencyMap e a -> Set a+vertexSet = Map.keysSet . adjacencyMap++-- | The set of edges of a given graph.+-- Complexity: /O(n + m)/ time and /O(m)/ memory.+--+-- @+-- edgeSet 'empty'        == Set.'Set.empty'+-- edgeSet ('vertex' x)   == Set.'Set.empty'+-- edgeSet ('edge' e x y) == if e == 'zero' then Set.'Set.empty' else Set.'Set.singleton' (e,x,y)+-- @+edgeSet :: (Eq a, Eq e) => AdjacencyMap e a -> Set (e, a, a)+edgeSet = Set.fromAscList . edgeList++-- | The /preset/ of an element @x@ is the set of its /direct predecessors/.+-- Complexity: /O(n * log(n))/ time and /O(n)/ memory.+--+-- @+-- preSet x 'empty'        == Set.'Set.empty'+-- preSet x ('vertex' x)   == Set.'Set.empty'+-- preSet 1 ('edge' e 1 2) == Set.'Set.empty'+-- preSet y ('edge' e x y) == if e == 'zero' then Set.'Set.empty' else Set.'Set.fromList' [x]+-- @+preSet :: Ord a => a -> AdjacencyMap e a -> Set a+preSet x (AM m) = Set.fromAscList+    [ a | (a, es) <- Map.toAscList m, Map.member x es ]++-- | The /postset/ of a vertex is the set of its /direct successors/.+-- Complexity: /O(log(n))/ time and /O(1)/ memory.+--+-- @+-- postSet x 'empty'        == Set.'Set.empty'+-- postSet x ('vertex' x)   == Set.'Set.empty'+-- postSet x ('edge' e x y) == if e == 'zero' then Set.'Set.empty' else Set.'Set.fromList' [y]+-- postSet 2 ('edge' e 1 2) == Set.'Set.empty'+-- @+postSet :: Ord a => a -> AdjacencyMap e a -> Set a+postSet x = Map.keysSet . Map.findWithDefault Map.empty x . adjacencyMap++-- | Convert a graph to the corresponding unlabelled 'AM.AdjacencyMap' by+-- forgetting labels on all non-'zero' edges.+--+-- @+-- 'hasEdge' x y == 'AM.hasEdge' x y . skeleton+-- @+skeleton :: AdjacencyMap e a -> AM.AdjacencyMap a+skeleton (AM m) = AMI.AM (Map.map Map.keysSet m)++-- | Remove a vertex from a given graph.+-- Complexity: /O(n*log(n))/ time.+--+-- @+-- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' e x x)     == 'empty'+-- removeVertex 1 ('edge' e 1 2)     == 'vertex' 2+-- removeVertex x . removeVertex x == removeVertex x+-- @+removeVertex :: Ord a => a -> AdjacencyMap e a -> AdjacencyMap e a+removeVertex x = AM . Map.map (Map.delete x) . Map.delete x . adjacencyMap++-- | Remove an edge from a given graph.+-- Complexity: /O(log(n))/ time.+--+-- @+-- removeEdge x y ('edge' e x y)     == 'vertices' [x,y]+-- removeEdge x y . removeEdge x y == removeEdge x y+-- removeEdge x y . 'removeVertex' x == 'removeVertex' x+-- removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2+-- removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2+-- @+removeEdge :: Ord a => a -> a -> AdjacencyMap e a -> AdjacencyMap e a+removeEdge x y = AM . Map.adjust (Map.delete y) x . adjacencyMap++-- | The function @'replaceVertex' x y@ replaces vertex @x@ with vertex @y@ in a+-- given 'AdjacencyMap'. If @y@ already exists, @x@ and @y@ will be merged.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- replaceVertex x x            == id+-- replaceVertex x y ('vertex' x) == 'vertex' y+-- replaceVertex x y            == 'gmap' (\\v -> if v == x then y else v)+-- @+replaceVertex :: (Eq e, Monoid e, Ord a) => a -> a -> AdjacencyMap e a -> AdjacencyMap e a+replaceVertex u v = gmap $ \w -> if w == u then v else w++-- | Replace an edge from a given graph. If it doesn't exist, it will be created.+-- Complexity: /O(log(n))/ time.+--+-- @+-- replaceEdge e x y z                 == 'overlay' (removeEdge x y z) ('edge' e x y)+-- replaceEdge e x y ('edge' f x y)      == 'edge' e x y+-- 'edgeLabel' x y (replaceEdge e x y z) == e+-- @+replaceEdge :: (Eq e, Monoid e, Ord a) => e -> a -> a -> AdjacencyMap e a -> AdjacencyMap e a+replaceEdge e x y+    | e == zero  = AM . addY . Map.alter (Just . maybe Map.empty (Map.delete y)) x . adjacencyMap+    | otherwise  = AM . addY . Map.alter replace x . adjacencyMap+  where+    addY             = Map.alter (Just . fromMaybe Map.empty) y+    replace (Just m) = Just $ Map.insert y e m+    replace Nothing  = Just $ Map.singleton y e++-- | Transpose a given graph.+-- Complexity: /O(m * log(n))/ time, /O(n + m)/ memory.+--+-- @+-- transpose 'empty'        == 'empty'+-- transpose ('vertex' x)   == 'vertex' x+-- transpose ('edge' e x y) == 'edge' e y x+-- transpose . transpose  == id+-- @+transpose :: (Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a+transpose (AM m) = AM $ Map.foldrWithKey combine vs m+  where+    -- No need to use @nonZeroUnion@ here, since we do not add any new edges+    combine v es = Map.unionWith (Map.unionWith mappend) $+        Map.fromAscList [ (u, Map.singleton v e) | (u, e) <- Map.toAscList es ]+    vs = Map.fromSet (const Map.empty) (Map.keysSet m)++-- | Transform a graph by applying a function to each of its vertices. This is+-- similar to @Functor@'s 'fmap' but can be used with non-fully-parametric+-- 'AdjacencyMap'.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- gmap f 'empty'        == 'empty'+-- gmap f ('vertex' x)   == 'vertex' (f x)+-- gmap f ('edge' e x y) == 'edge' e (f x) (f y)+-- gmap 'id'             == 'id'+-- gmap f . gmap g     == gmap (f . g)+-- @+gmap :: (Eq e, Monoid e, Ord a, Ord b) => (a -> b) -> AdjacencyMap e a -> AdjacencyMap e b+gmap f = AM . trimZeroes . Map.map (Map.mapKeysWith mappend f) .+    Map.mapKeysWith (Map.unionWith mappend) f . adjacencyMap++-- | Transform a graph by applying a function @h@ to each of its edge labels.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- The function @h@ is required to be a /homomorphism/ on the underlying type of+-- labels @e@. At the very least it must preserve 'zero' and '<+>':+--+-- @+-- h 'zero'      == 'zero'+-- h x '<+>' h y == h (x '<+>' y)+-- @+--+-- If @e@ is also a semiring, then @h@ must also preserve the multiplicative+-- structure:+--+-- @+-- h 'one'       == 'one'+-- h x '<.>' h y == h (x '<.>' y)+-- @+--+-- If the above requirements hold, then the implementation provides the+-- following guarantees.+--+-- @+-- emap h 'empty'           == 'empty'+-- emap h ('vertex' x)      == 'vertex' x+-- emap h ('edge' e x y)    == 'edge' (h e) x y+-- emap h ('overlay' x y)   == 'overlay' (emap h x) (emap h y)+-- emap h ('connect' e x y) == 'connect' (h e) (emap h x) (emap h y)+-- emap 'id'                == 'id'+-- emap g . emap h        == emap (g . h)+-- @+emap :: (Eq f, Monoid f) => (e -> f) -> AdjacencyMap e a -> AdjacencyMap f a+emap h = AM . trimZeroes . Map.map (Map.map h) . adjacencyMap++-- | Construct the /induced subgraph/ of a given graph by removing the+-- vertices that do not satisfy a given predicate.+-- Complexity: /O(m)/ time, assuming that the predicate takes /O(1)/ to+-- be evaluated.+--+-- @+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty'+-- induce (/= x)               == 'removeVertex' x+-- induce p . induce q         == induce (\\x -> p x && q x)+-- 'isSubgraphOf' (induce p x) x == True+-- @+induce :: (a -> Bool) -> AdjacencyMap e a -> AdjacencyMap e a+induce p = AM . Map.map (Map.filterWithKey (\k _ -> p k)) .+    Map.filterWithKey (\k _ -> p k) . adjacencyMap++-- | Compute the /reflexive and transitive closure/ of a graph over the+-- underlying star semiring using the Warshall-Floyd-Kleene algorithm.+--+-- @+-- closure 'empty'         == 'empty'+-- closure ('vertex' x)    == 'edge' 'one' x x+-- closure ('edge' e x x)  == 'edge' 'one' x x+-- closure ('edge' e x y)  == 'edges' [('one',x,x), (e,x,y), ('one',y,y)]+-- closure               == 'reflexiveClosure' . 'transitiveClosure'+-- closure               == 'transitiveClosure' . 'reflexiveClosure'+-- closure . closure     == closure+-- 'postSet' x (closure y) == Set.'Set.fromList' ('Algebra.Graph.ToGraph.reachable' x y)+-- @+closure :: (Eq e, Ord a, StarSemiring e) => AdjacencyMap e a -> AdjacencyMap e a+closure = goWarshallFloydKleene . reflexiveClosure++-- | Compute the /reflexive closure/ of a graph over the underlying semiring by+-- adding a self-loop of weight 'one' to every vertex.+-- Complexity: /O(n * log(n))/ time.+--+-- @+-- reflexiveClosure 'empty'              == 'empty'+-- reflexiveClosure ('vertex' x)         == 'edge' 'one' x x+-- reflexiveClosure ('edge' e x x)       == 'edge' 'one' x x+-- reflexiveClosure ('edge' e x y)       == 'edges' [('one',x,x), (e,x,y), ('one',y,y)]+-- reflexiveClosure . reflexiveClosure == reflexiveClosure+-- @+reflexiveClosure :: (Ord a, Semiring e) => AdjacencyMap e a -> AdjacencyMap e a+reflexiveClosure (AM m) = AM $ Map.mapWithKey (\k -> Map.insertWith (<+>) k one) m++-- | Compute the /symmetric closure/ of a graph by overlaying it with its own+-- transpose.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- symmetricClosure 'empty'              == 'empty'+-- symmetricClosure ('vertex' x)         == 'vertex' x+-- symmetricClosure ('edge' e x y)       == 'edges' [(e,x,y), (e,y,x)]+-- symmetricClosure x                  == 'overlay' x ('transpose' x)+-- symmetricClosure . symmetricClosure == symmetricClosure+-- @+symmetricClosure :: (Eq e, Monoid e, Ord a) => AdjacencyMap e a -> AdjacencyMap e a+symmetricClosure m = overlay m (transpose m)++-- | Compute the /transitive closure/ of a graph over the underlying star+-- semiring using a modified version of the Warshall-Floyd-Kleene algorithm,+-- which omits the reflexivity step.+--+-- @+-- transitiveClosure 'empty'               == 'empty'+-- transitiveClosure ('vertex' x)          == 'vertex' x+-- transitiveClosure ('edge' e x y)        == 'edge' e x y+-- transitiveClosure . transitiveClosure == transitiveClosure+-- @+transitiveClosure :: (Eq e, Ord a, StarSemiring e) => AdjacencyMap e a -> AdjacencyMap e a+transitiveClosure = goWarshallFloydKleene++-- The iterative part of the Warshall-Floyd-Kleene algorithm+goWarshallFloydKleene :: (Eq e, Ord a, StarSemiring e) => AdjacencyMap e a -> AdjacencyMap e a+goWarshallFloydKleene (AM m) = AM $ foldr update m vs+  where+    vs = Set.toAscList (Map.keysSet m)+    update k cur = Map.fromAscList [ (i, go i (get i k <.> starkk)) | i <- vs ]+      where+        get i j = edgeLabel i j (AM cur)+        starkk  = star (get k k)+        go i ik = Map.fromAscList+            [ (j, e) | j <- vs, let e = get i j <+> ik <.> get k j, e /= zero ]
+ src/Algebra/Graph/Labelled/AdjacencyMap/Internal.hs view
@@ -0,0 +1,113 @@+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Labelled.AdjdacencyMap.Internal+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : unstable+--+-- This module exposes the implementation of edge-labelled adjacency maps. The+-- API is unstable and unsafe, and is exposed only for documentation. You should+-- use the non-internal module "Algebra.Graph.Labelled.AdjdacencyMap" instead.+-----------------------------------------------------------------------------+module Algebra.Graph.Labelled.AdjacencyMap.Internal (+    -- * Labelled adjacency map implementation+    AdjacencyMap (..), consistent+    ) where++import Prelude ()+import Prelude.Compat++import Control.DeepSeq+import Data.Map.Strict (Map)+import Data.Monoid (Monoid, getSum, Sum (..))+import Data.Set (Set, (\\))++import qualified Data.Map.Strict as Map+import qualified Data.Set        as Set++import Algebra.Graph.Label++-- | Edge-labelled graphs, where the type variable @e@ stands for edge labels.+-- For example, 'AdjacencyMap' @Bool@ @a@ is isomorphic to unlabelled graphs+-- defined in the top-level module "Algebra.Graph.AdjacencyMap", where @False@+-- and @True@ denote the lack of and the existence of an unlabelled edge,+-- respectively.+newtype AdjacencyMap e a = AM {+    -- | The /adjacency map/ of an edge-labelled graph: each vertex is+    -- associated with a map from its direct successors to the corresponding+    -- edge labels.+    adjacencyMap :: Map a (Map a e) } deriving (Eq, NFData)++instance (Ord a, Show a, Ord e, Show e) => Show (AdjacencyMap e a) where+    showsPrec p (AM m)+        | Set.null vs = showString "empty"+        | null es     = showParen (p > 10) $ vshow vs+        | vs == used  = showParen (p > 10) $ eshow es+        | otherwise   = showParen (p > 10) $+                            showString "overlay (" . vshow (vs \\ used) .+                            showString ") ("       . eshow es . showString ")"+      where+        vs   = Map.keysSet m+        es   = internalEdgeList m+        used = referredToVertexSet m+        vshow vs = case Set.toAscList vs of+            [x] -> showString "vertex "   . showsPrec 11 x+            xs  -> showString "vertices " . showsPrec 11 xs+        eshow es = case es of+            [(e, x, y)] -> showString "edge "  . showsPrec 11 e .+                           showString " "      . showsPrec 11 x .+                           showString " "      . showsPrec 11 y+            xs          -> showString "edges " . showsPrec 11 xs++instance (Ord e, Monoid e, Ord a) => Ord (AdjacencyMap e a) where+    compare (AM x) (AM y) = mconcat+        [ compare (vNum x) (vNum y)+        , compare (vSet x) (vSet y)+        , compare (eNum x) (eNum y)+        , compare (eSet x) (eSet y)+        , cmp ]+      where+        vNum   = Map.size+        vSet   = Map.keysSet+        eNum   = getSum . foldMap (Sum . Map.size)+        eSet m = [ (x, y) | (x, ys) <- Map.toAscList m, (y, _) <- Map.toAscList ys ]+        cmp | x == y               = EQ+            | overlays [x, y] == y = LT+            | otherwise            = compare x y++-- Overlay a list of adjacency maps.+overlays :: (Eq e, Monoid e, Ord a) => [Map a (Map a e)] -> Map a (Map a e)+overlays = Map.unionsWith (\x -> Map.filter (/= zero) . Map.unionWith mappend x)++-- | __Note:__ this does not satisfy the usual ring laws; see 'AdjacencyMap'+-- for more details.+instance (Eq e, Dioid e, Num a, Ord a) => Num (AdjacencyMap e a) where+    fromInteger x = AM $ Map.singleton (fromInteger x) Map.empty+    AM x + AM y   = AM $ overlays [x, y]+    AM x * AM y   = AM $ overlays $ x : y :+        [ Map.fromSet (const targets) (Map.keysSet x) ]+      where+        targets = Map.fromSet (const one) (Map.keysSet y)+    signum      = const (AM Map.empty)+    abs         = id+    negate      = id++-- | Check if the internal graph representation is consistent, i.e. that all+-- edges refer to existing vertices, and there are no 'zero'-labelled edges. It+-- should be impossible to create an inconsistent adjacency map, and we use this+-- function in testing.+-- /Note: this function is for internal use only/.+consistent :: (Ord a, Eq e, Monoid e) => AdjacencyMap e a -> Bool+consistent (AM m) = referredToVertexSet m `Set.isSubsetOf` Map.keysSet m+    && and [ e /= zero | (_, es) <- Map.toAscList m, (_, e) <- Map.toAscList es ]++-- The set of vertices that are referred to by the edges in an adjacency map+referredToVertexSet :: Ord a => Map a (Map a e) -> Set a+referredToVertexSet m = Set.fromList $ concat+    [ [x, y] | (x, ys) <- Map.toAscList m, (y, _) <- Map.toAscList ys ]++-- The list of edges in an adjacency map+internalEdgeList :: Map a (Map a e) -> [(e, a, a)]+internalEdgeList m =+    [ (e, x, y) | (x, ys) <- Map.toAscList m, (y, e) <- Map.toAscList ys ]
+ src/Algebra/Graph/Labelled/Example/Automaton.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE CPP, OverloadedLists, TypeFamilies #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Labelled.Example.Automaton+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- __Alga__ is a library for algebraic construction and manipulation of graphs+-- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the+-- motivation behind the library, the underlying theory, and implementation details.+--+-- This module contains a simple example of using edge-labelled graphs defined+-- in the module "Algebra.Graph.Labelled" for working with finite automata.+-----------------------------------------------------------------------------+module Algebra.Graph.Labelled.Example.Automaton where++import Data.Map    (Map)+import Data.Monoid (Any (..))++import Algebra.Graph.Label+import Algebra.Graph.Labelled+import Algebra.Graph.ToGraph++import qualified Data.Map as Map++#if !MIN_VERSION_base(4,8,0)+import Data.Set (Set)+import qualified Data.Set as Set+import GHC.Exts hiding (Any)++instance Ord a => IsList (Set a) where+    type Item (Set a) = a+    fromList = Set.fromList+    toList   = Set.toList+#endif++-- | The alphabet of actions for ordering coffee or tea.+data Alphabet = Coffee -- ^ Order coffee+              | Tea    -- ^ Order tea+              | Cancel -- ^ Cancel payment or order+              | Pay    -- ^ Pay for the order+              deriving (Bounded, Enum, Eq, Ord, Show)++-- | The state of the order.+data State = Choice   -- ^ Choosing what to order+           | Payment  -- ^ Making the payment+           | Complete -- ^ The order is complete+           deriving (Bounded, Enum, Eq, Ord, Show)++-- TODO: Add an illustration.+-- | An example automaton for ordering coffee or tea.+--+-- @+-- order = 'overlays' [ 'Choice'  '-<'['Coffee', 'Tea']'>-' 'Payment'+--                  , 'Choice'  '-<'['Cancel'     ]'>-' 'Complete'+--                  , 'Payment' '-<'['Cancel'     ]'>-' 'Choice'+--                  , 'Payment' '-<'['Pay'        ]'>-' 'Complete' ]+-- @+coffeeTeaAutomaton :: Automaton Alphabet State+coffeeTeaAutomaton = overlays [ Choice  -<[Coffee, Tea]>- Payment+                              , Payment -<[Pay        ]>- Complete+                              , Choice  -<[Cancel     ]>- Complete+                              , Payment -<[Cancel     ]>- Choice ]++-- | The map of 'State' reachability.+--+-- @+-- reachability = Map.'Map.fromList' $ map (\s -> (s, 'reachable' s 'order')) ['Choice' ..]+-- @+--+-- Or, when evaluated:+--+-- @+-- reachability = Map.'Map.fromList' [ ('Choice'  , ['Choice'  , 'Payment', 'Complete'])+--                             , ('Payment' , ['Payment' , 'Choice' , 'Complete'])+--                             , ('Complete', ['Complete'                   ]) ]+-- @+reachability :: Map State [State]+reachability = Map.fromList $ map (\s -> (s, reachable s skeleton)) [Choice ..]+  where+    skeleton :: Graph Any State+    skeleton = emap (Any . not . isZero) coffeeTeaAutomaton
+ src/Algebra/Graph/Labelled/Example/Network.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE TypeFamilies #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Labelled.Example.Network+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- __Alga__ is a library for algebraic construction and manipulation of graphs+-- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the+-- motivation behind the library, the underlying theory, and implementation details.+--+-- This module contains a simple example of using edge-labelled graphs defined+-- in the module "Algebra.Graph.Labelled" for working with networks, i.e. graphs+-- whose edges are labelled with distances.+-----------------------------------------------------------------------------+module Algebra.Graph.Labelled.Example.Network where++import Algebra.Graph.Labelled++-- | Our example networks have /cities/ as vertices.+data City = Aberdeen+          | Edinburgh+          | Glasgow+          | London+          | Newcastle+          deriving (Bounded, Enum, Eq, Ord, Show)++-- | For simplicity we measure /journey times/ in integer number of minutes.+type JourneyTime = Int++-- | A part of the EastCoast train network between 'Aberdeen' and 'London'.+--+-- @+-- eastCoast = 'overlays' [ 'Aberdeen'  '-<'&#49;50'>-' 'Edinburgh'+--                      , 'Edinburgh' '-<' 90'>-' 'Newcastle'+--                      , 'Newcastle' '-<'&#49;70'>-' 'London' ]+-- @+eastCoast :: Network JourneyTime City+eastCoast = overlays [ Aberdeen  -<150>- Edinburgh+                     , Edinburgh -< 90>- Newcastle+                     , Newcastle -<170>- London ]++-- | A part of the ScotRail train network between 'Aberdeen' and 'Glasgow'.+--+-- @+-- scotRail = 'overlays' [ 'Aberdeen'  '-<'&#49;40'>-' 'Edinburgh'+--                     , 'Edinburgh' '-<' 50'>-' 'Glasgow'+--                     , 'Edinburgh' '-<' 70'>-' 'Glasgow' ]+-- @+scotRail :: Network JourneyTime City+scotRail = overlays [ Aberdeen  -<140>- Edinburgh+                    , Edinburgh -< 50>- Glasgow+                    , Edinburgh -< 70>- Glasgow ]++-- TODO: Add an illustration.+-- | An example train network.+--+-- @+-- network = 'overlay' 'scotRail' 'eastCoast'+-- @+network :: Network JourneyTime City+network = overlay scotRail eastCoast
src/Algebra/Graph/NonEmpty.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+{-# LANGUAGE CPP, DeriveFunctor #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.NonEmpty@@ -11,15 +11,22 @@ -- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the -- motivation behind the library, the underlying theory, and implementation details. ----- This module defines the data type 'NonEmptyGraph' for graphs that are known--- to be non-empty at compile time. The naming convention generally follows that--- of "Data.List.NonEmpty": we use suffix @1@ to indicate the functions whose--- interface must be changed compared to "Algebra.Graph", e.g. 'vertices1'.+-- This module defines the data type 'Graph' for algebraic graphs that are known+-- to be non-empty at compile time. To avoid name clashes with "Algebra.Graph",+-- this module can be imported qualified: --+-- @+-- import qualified Algebra.Graph.NonEmpty as NonEmpty+-- @+--+-- The naming convention generally follows that of "Data.List.NonEmpty": we use+-- suffix @1@ to indicate the functions whose interface must be changed compared+-- to "Algebra.Graph", e.g. 'vertices1'.+-- ----------------------------------------------------------------------------- module Algebra.Graph.NonEmpty (-    -- * Algebraic data type for non-empty graphs-    NonEmptyGraph (..), toNonEmptyGraph,+    -- * Non-empty algebraic graphs+    Graph (..), toNonEmpty,      -- * Basic graph construction primitives     vertex, edge, overlay, overlay1, connect, vertices1, edges1, overlays1,@@ -33,7 +40,7 @@      -- * Graph properties     size, hasVertex, hasEdge, vertexCount, edgeCount, vertexList1, edgeList,-    vertexSet, vertexIntSet, edgeSet,+    vertexSet, edgeSet,      -- * Standard families of graphs     path1, circuit1, clique1, biclique1, star, stars1, tree, mesh1, torus1,@@ -44,7 +51,7 @@      -- * Graph composition     box-  ) where+    ) where  import Prelude () import Prelude.Compat@@ -53,40 +60,43 @@ import Data.Semigroup #endif -import Control.DeepSeq (NFData (..))+import Control.DeepSeq import Control.Monad.Compat-import Control.Monad.State (runState, get, put)+import Control.Monad.State import Data.List.NonEmpty (NonEmpty (..))  import Algebra.Graph.Internal -import qualified Algebra.Graph                 as G-import qualified Algebra.Graph.AdjacencyIntMap as AIM-import qualified Algebra.Graph.ToGraph         as T-import qualified Data.IntSet                   as IntSet-import qualified Data.List.NonEmpty            as NonEmpty-import qualified Data.Set                      as Set-import qualified Data.Tree                     as Tree+import qualified Algebra.Graph         as G+import qualified Algebra.Graph.ToGraph as T+import qualified Data.IntSet           as IntSet+import qualified Data.List.NonEmpty    as NonEmpty+import qualified Data.Set              as Set+import qualified Data.Tree             as Tree -{-| The 'NonEmptyGraph' data type is a deep embedding of the core graph-construction primitives 'vertex', 'overlay' and 'connect'. As one can guess from-the name, the empty graph cannot be represented using this data type. See module-"Algebra.Graph" for a graph data type that allows for the construction of the-empty graph.+{-| Non-empty algebraic graphs, which are constructed using three primitives:+'vertex', 'overlay' and 'connect'. See module "Algebra.Graph" for algebraic+graphs that can be empty.  We define a 'Num' instance as a convenient notation for working with graphs: -    > 0           == Vertex 0-    > 1 + 2       == Overlay (Vertex 1) (Vertex 2)-    > 1 * 2       == Connect (Vertex 1) (Vertex 2)-    > 1 + 2 * 3   == Overlay (Vertex 1) (Connect (Vertex 2) (Vertex 3))-    > 1 * (2 + 3) == Connect (Vertex 1) (Overlay (Vertex 2) (Vertex 3))+    > 0           == vertex 0+    > 1 + 2       == overlay (vertex 1) (vertex 2)+    > 1 * 2       == connect (vertex 1) (vertex 2)+    > 1 + 2 * 3   == overlay (vertex 1) (connect (vertex 2) (vertex 3))+    > 1 * (2 + 3) == connect (vertex 1) (overlay (vertex 2) (vertex 3)) -Note that the 'signum' method of the 'Num' type class cannot be implemented.+__Note:__ the 'signum' method of the type class 'Num' cannot be implemented and+will throw an error. Furthermore, the 'Num' instance does not satisfy several+"customary laws" of 'Num', which dictate that 'fromInteger' @0@ and+'fromInteger' @1@ should act as additive and multiplicative identities, and+'negate' as additive inverse. Nevertheless, overloading 'fromInteger', '+' and+'*' is very convenient when working with algebraic graphs; we hope that in+future Haskell's Prelude will provide a more fine-grained class hierarchy for+algebraic structures, which we would be able to utilise without violating any+laws. -The 'Eq' instance is currently implemented using the 'AM.AdjacencyMap' as the-/canonical graph representation/ and satisfies the following laws of algebraic-graphs:+The 'Eq' instance satisfies the following laws of non-empty algebraic graphs.      * 'overlay' is commutative, associative and idempotent: @@ -114,78 +124,115 @@  When specifying the time and memory complexity of graph algorithms, /n/ will denote the number of vertices in the graph, /m/ will denote the number of-edges in the graph, and /s/ will denote the /size/ of the corresponding-'NonEmptyGraph' expression, defined as the number of vertex leaves. For example,-if @g@ is a 'NonEmptyGraph' then /n/, /m/ and /s/ can be computed as follows:+edges in the graph, and /s/ will denote the /size/ of the corresponding 'Graph'+expression, defined as the number of vertex leaves (note that /n/ <= /s/). If+@g@ is a 'Graph', the corresponding /n/, /m/ and /s/ can be computed as follows:  @n == 'vertexCount' g m == 'edgeCount' g s == 'size' g@ -The 'size' of any graph is positive and coincides with the result of 'length'-method of the 'Foldable' type class. We define 'size' only for the consistency-with the API of other graph representations, such as "Algebra.Graph".+Converting a 'Graph' to the corresponding+'Algebra.Graph.NonEmpty.AdjacencyMap.AdjacencyMap' takes /O(s + m * log(m))/ time and /O(s + m)/ memory. This is also the+complexity of the graph equality test, because it is currently implemented by+converting graph expressions to canonical representations based on adjacency+maps. -Converting a 'NonEmptyGraph' to the corresponding 'AM.AdjacencyMap' takes-/O(s + m * log(m))/ time and /O(s + m)/ memory. This is also the complexity of-the graph equality test, because it is currently implemented by converting graph-expressions to canonical representations based on adjacency maps.+The total order 'Ord' on graphs is defined using /size-lexicographic/ comparison:++* Compare the number of vertices. In case of a tie, continue.+* Compare the sets of vertices. In case of a tie, continue.+* Compare the number of edges. In case of a tie, continue.+* Compare the sets of edges.++Here are a few examples:++@'vertex' 1 < 'vertex' 2+'vertex' 3 < 'edge' 1 2+'vertex' 1 < 'edge' 1 1+'edge' 1 1 < 'edge' 1 2+'edge' 1 2 < 'edge' 1 1 + 'edge' 2 2+'edge' 1 2 < 'edge' 1 3@++Note that the resulting order refines the 'isSubgraphOf' relation and is+compatible with 'overlay' and 'connect' operations:++@'isSubgraphOf' x y ==> x <= y@++@x     <= x + y+x + y <= x * y@ -}-data NonEmptyGraph a = Vertex a-                     | Overlay (NonEmptyGraph a) (NonEmptyGraph a)-                     | Connect (NonEmptyGraph a) (NonEmptyGraph a)-                     deriving (Foldable, Functor, Show, Traversable)+data Graph a = Vertex a+             | Overlay (Graph a) (Graph a)+             | Connect (Graph a) (Graph a)+             deriving (Functor, Show) -instance NFData a => NFData (NonEmptyGraph a) where+instance NFData a => NFData (Graph a) where     rnf (Vertex  x  ) = rnf x     rnf (Overlay x y) = rnf x `seq` rnf y     rnf (Connect x y) = rnf x `seq` rnf y -instance T.ToGraph (NonEmptyGraph a) where-    type ToVertex (NonEmptyGraph a) = a+instance T.ToGraph (Graph a) where+    type ToVertex (Graph a) = a     foldg _ = foldg1     hasEdge = hasEdge -instance Num a => Num (NonEmptyGraph a) where+-- | __Note:__ this does not satisfy the usual ring laws; see 'Graph' for more+-- details.+instance Num a => Num (Graph a) where     fromInteger = Vertex . fromInteger     (+)         = Overlay     (*)         = Connect-    signum      = error "NonEmptyGraph.signum cannot be implemented."+    signum      = error "NonEmpty.Graph.signum cannot be implemented."     abs         = id     negate      = id -instance Ord a => Eq (NonEmptyGraph a) where-    (==) = equals+instance Ord a => Eq (Graph a) where+    (==) = eq +instance Ord a => Ord (Graph a) where+    compare = ord+ -- TODO: Find a more efficient equality check.--- | Compare two graphs by converting them to their adjacency maps.-{-# NOINLINE [1] equals #-}-{-# RULES "equalsInt" equals = equalsInt #-}-equals :: Ord a => NonEmptyGraph a -> NonEmptyGraph a -> Bool-equals x y = T.adjacencyMap x == T.adjacencyMap y+-- | Check if two graphs are equal by converting them to their adjacency maps.+eq :: Ord a => Graph a -> Graph a -> Bool+eq x y = T.toAdjacencyMap x == T.toAdjacencyMap y+{-# NOINLINE [1] eq #-}+{-# RULES "eqInt" eq = eqInt #-} --- | Like @equals@ but specialised for graphs with vertices of type 'Int'.-equalsInt :: NonEmptyGraph Int -> NonEmptyGraph Int -> Bool-equalsInt x y = T.adjacencyIntMap x == T.adjacencyIntMap y+-- Like @eq@ but specialised for graphs with vertices of type 'Int'.+eqInt :: Graph Int -> Graph Int -> Bool+eqInt x y = T.toAdjacencyIntMap x == T.toAdjacencyIntMap y -instance Applicative NonEmptyGraph where+-- TODO: Find a more efficient comparison.+-- Compare two graphs by converting them to their adjacency maps.+ord :: Ord a => Graph a -> Graph a -> Ordering+ord x y = compare (T.toAdjacencyMap x) (T.toAdjacencyMap y)+{-# NOINLINE [1] ord #-}+{-# RULES "ordInt" ord = ordInt #-}++-- Like @ord@ but specialised for graphs with vertices of type 'Int'.+ordInt :: Graph Int -> Graph Int -> Ordering+ordInt x y = compare (T.toAdjacencyIntMap x) (T.toAdjacencyIntMap y)++instance Applicative Graph where     pure  = Vertex     (<*>) = ap -instance Monad NonEmptyGraph where+instance Monad Graph where     return  = pure     g >>= f = foldg1 f Overlay Connect g --- | Convert a 'G.Graph' into 'NonEmptyGraph'. Returns 'Nothing' if the argument--- is 'G.empty'.+-- | Convert an algebraic graph (from "Algebra.Graph") into a non-empty+-- algebraic graph. Returns 'Nothing' if the argument is 'G.empty'. -- Complexity: /O(s)/ time, memory and size. -- -- @--- toNonEmptyGraph 'G.empty'       == Nothing--- toNonEmptyGraph ('C.toGraph' x) == Just (x :: NonEmptyGraph a)+-- toNonEmpty 'G.empty'       == Nothing+-- toNonEmpty ('T.toGraph' x) == Just (x :: 'Graph' a) -- @-toNonEmptyGraph :: G.Graph a -> Maybe (NonEmptyGraph a)-toNonEmptyGraph = G.foldg Nothing (Just . Vertex) (go Overlay) (go Connect)+toNonEmpty :: G.Graph a -> Maybe (Graph a)+toNonEmpty = G.foldg Nothing (Just . Vertex) (go Overlay) (go Connect)   where     go _ Nothing  y        = y     go _ x        Nothing  = x@@ -201,7 +248,7 @@ -- 'edgeCount'   (vertex x) == 0 -- 'size'        (vertex x) == 1 -- @-vertex :: a -> NonEmptyGraph a+vertex :: a -> Graph a vertex = Vertex {-# INLINE vertex #-} @@ -215,7 +262,7 @@ -- 'vertexCount' (edge 1 1) == 1 -- 'vertexCount' (edge 1 2) == 2 -- @-edge :: a -> a -> NonEmptyGraph a+edge :: a -> a -> Graph a edge u v = connect (vertex u) (vertex v)  -- | /Overlay/ two graphs. An alias for the constructor 'Overlay'. This is a@@ -232,21 +279,21 @@ -- 'vertexCount' (overlay 1 2) == 2 -- 'edgeCount'   (overlay 1 2) == 0 -- @-overlay :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a+overlay :: Graph a -> Graph a -> Graph a overlay = Overlay {-# INLINE overlay #-} --- | Overlay a possibly empty graph with a non-empty graph. If the first--- argument is 'G.empty', the function returns the second argument; otherwise--- it is semantically the same as 'overlay'.+-- | Overlay a possibly empty graph (from "Algebra.Graph") with a non-empty+-- graph. If the first argument is 'G.empty', the function returns the second+-- argument; otherwise it is semantically the same as 'overlay'. -- Complexity: /O(s1)/ time and memory, and /O(s1 + s2)/ size. -- -- @ --                overlay1 'G.empty' x == x--- x /= 'G.empty' ==> overlay1 x     y == overlay (fromJust $ toNonEmptyGraph x) y+-- x /= 'G.empty' ==> overlay1 x     y == overlay (fromJust $ toNonEmpty x) y -- @-overlay1 :: G.Graph a -> NonEmptyGraph a -> NonEmptyGraph a-overlay1 = maybe id overlay . toNonEmptyGraph+overlay1 :: G.Graph a -> Graph a -> Graph a+overlay1 = maybe id overlay . toNonEmpty  -- | /Connect/ two graphs. An alias for the constructor 'Connect'. This is an -- associative operation, which distributes over 'overlay' and obeys the@@ -267,7 +314,7 @@ -- 'vertexCount' (connect 1 2) == 2 -- 'edgeCount'   (connect 1 2) == 1 -- @-connect :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a+connect :: Graph a -> Graph a -> Graph a connect = Connect {-# INLINE connect #-} @@ -276,12 +323,12 @@ -- given list. -- -- @--- vertices1 (x ':|' [])     == 'vertex' x+-- vertices1 [x]           == 'vertex' x -- 'hasVertex' x . vertices1 == 'elem' x -- 'vertexCount' . vertices1 == 'length' . 'Data.List.NonEmpty.nub' -- 'vertexSet'   . vertices1 == Set.'Set.fromList' . 'Data.List.NonEmpty.toList' -- @-vertices1 :: NonEmpty a -> NonEmptyGraph a+vertices1 :: NonEmpty a -> Graph a vertices1 = overlays1 . fmap vertex {-# NOINLINE [1] vertices1 #-} @@ -290,10 +337,10 @@ -- given list. -- -- @--- edges1 ((x,y) ':|' []) == 'edge' x y--- 'edgeCount' . edges1   == 'Data.List.NonEmpty.length' . 'Data.List.NonEmpty.nub'+-- edges1 [(x,y)]     == 'edge' x y+-- 'edgeCount' . edges1 == 'Data.List.NonEmpty.length' . 'Data.List.NonEmpty.nub' -- @-edges1 :: NonEmpty (a, a) -> NonEmptyGraph a+edges1 :: NonEmpty (a, a) -> Graph a edges1  = overlays1 . fmap (uncurry edge)  -- | Overlay a given list of graphs.@@ -301,10 +348,10 @@ -- of the given list, and /S/ is the sum of sizes of the graphs in the list. -- -- @--- overlays1 (x ':|' [] ) == x--- overlays1 (x ':|' [y]) == 'overlay' x y+-- overlays1 [x]   == x+-- overlays1 [x,y] == 'overlay' x y -- @-overlays1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a+overlays1 :: NonEmpty (Graph a) -> Graph a overlays1 = concatg1 overlay {-# INLINE [2] overlays1 #-} @@ -313,28 +360,30 @@ -- of the given list, and /S/ is the sum of sizes of the graphs in the list. -- -- @--- connects1 (x ':|' [] ) == x--- connects1 (x ':|' [y]) == 'connect' x y+-- connects1 [x]   == x+-- connects1 [x,y] == 'connect' x y -- @-connects1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a+connects1 :: NonEmpty (Graph a) -> Graph a connects1 = concatg1 connect {-# INLINE [2] connects1 #-} --- | Auxiliary function, similar to 'sconcat'.-concatg1 :: (NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a) -> NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a+-- Auxiliary function, similar to 'sconcat'.+concatg1 :: (Graph a -> Graph a -> Graph a) -> NonEmpty (Graph a) -> Graph a concatg1 combine (x :| xs) = maybe x (combine x) $ foldr1Safe combine xs --- | Generalised graph folding: recursively collapse a 'NonEmptyGraph' by+-- | Generalised graph folding: recursively collapse a 'Graph' by -- applying the provided functions to the leaves and internal nodes of the -- expression. The order of arguments is: vertex, overlay and connect. -- Complexity: /O(s)/ applications of given functions. As an example, the -- complexity of 'size' is /O(s)/, since all functions have cost /O(1)/. -- -- @--- foldg1 (const 1) (+)  (+)  == 'size'--- foldg1 (==x)     (||) (||) == 'hasVertex' x+-- foldg1 'vertex'    'overlay' 'connect'        == id+-- foldg1 'vertex'    'overlay' ('flip' 'connect') == 'transpose'+-- foldg1 ('const' 1) (+)     (+)            == 'size'+-- foldg1 (== x)    (||)    (||)           == 'hasVertex' x -- @-foldg1 :: (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> NonEmptyGraph a -> b+foldg1 :: (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> b foldg1 v o c = go   where     go (Vertex  x  ) = v x@@ -347,13 +396,14 @@ -- graph can be quadratic with respect to the expression size /s/. -- -- @--- isSubgraphOf x             ('overlay' x y) == True--- isSubgraphOf ('overlay' x y) ('connect' x y) == True--- isSubgraphOf ('path1' xs)    ('circuit1' xs) == True+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf ('path1' xs)    ('circuit1' xs) ==  True+-- isSubgraphOf x y                         ==> x <= y -- @-{-# SPECIALISE isSubgraphOf :: NonEmptyGraph Int -> NonEmptyGraph Int -> Bool #-}-isSubgraphOf :: Ord a => NonEmptyGraph a -> NonEmptyGraph a -> Bool+isSubgraphOf :: Ord a => Graph a -> Graph a -> Bool isSubgraphOf x y = overlay x y == y+{-# SPECIALISE isSubgraphOf :: Graph Int -> Graph Int -> Bool #-}  -- | Structural equality on graph expressions. -- Complexity: /O(s)/ time.@@ -364,12 +414,12 @@ -- 1 + 2 === 2 + 1 == False -- x + y === x * y == False -- @-{-# SPECIALISE (===) :: NonEmptyGraph Int -> NonEmptyGraph Int -> Bool #-}-(===) :: Eq a => NonEmptyGraph a -> NonEmptyGraph a -> Bool+(===) :: Eq a => Graph a -> Graph a -> Bool (Vertex  x1   ) === (Vertex  x2   ) = x1 ==  x2 (Overlay x1 y1) === (Overlay x2 y2) = x1 === x2 && y1 === y2 (Connect x1 y1) === (Connect x2 y2) = x1 === x2 && y1 === y2 _               === _               = False+{-# SPECIALISE (===) :: Graph Int -> Graph Int -> Bool #-}  infix 4 === @@ -383,19 +433,19 @@ -- size x             >= 1 -- size x             >= 'vertexCount' x -- @-size :: NonEmptyGraph a -> Int+size :: Graph a -> Int size = foldg1 (const 1) (+) (+) --- | Check if a graph contains a given vertex. A convenient alias for `elem`.+-- | Check if a graph contains a given vertex. -- Complexity: /O(s)/ time. -- -- @ -- hasVertex x ('vertex' x) == True -- hasVertex 1 ('vertex' 2) == False -- @-{-# SPECIALISE hasVertex :: Int -> NonEmptyGraph Int -> Bool #-}-hasVertex :: Eq a => a -> NonEmptyGraph a -> Bool+hasVertex :: Eq a => a -> Graph a -> Bool hasVertex v = foldg1 (==v) (||) (||)+{-# SPECIALISE hasVertex :: Int -> Graph Int -> Bool #-}  -- TODO: Reduce code duplication with 'Algebra.Graph.hasEdge'. -- | Check if a graph contains a given edge.@@ -404,11 +454,10 @@ -- @ -- hasEdge x y ('vertex' z)       == False -- hasEdge x y ('edge' x y)       == True--- hasEdge x y . 'removeEdge' x y == const False+-- hasEdge x y . 'removeEdge' x y == 'const' False -- hasEdge x y                  == 'elem' (x,y) . 'edgeList' -- @-{-# SPECIALISE hasEdge :: Int -> Int -> NonEmptyGraph Int -> Bool #-}-hasEdge :: Eq a => a -> a -> NonEmptyGraph a -> Bool+hasEdge :: Eq a => a -> a -> Graph a -> Bool hasEdge s t g = hit g == Edge   where     hit (Vertex x   ) = if x == s then Tail else Miss@@ -420,22 +469,23 @@         Miss -> hit y         Tail -> if hasVertex t y then Edge else Tail         Edge -> Edge+{-# SPECIALISE hasEdge :: Int -> Int -> Graph Int -> Bool #-}  -- | The number of vertices in a graph. -- Complexity: /O(s * log(n))/ time. -- -- @--- vertexCount ('vertex' x) == 1--- vertexCount x          >= 1--- vertexCount            == 'length' . 'vertexList1'+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y -- @+vertexCount :: Ord a => Graph a -> Int+vertexCount = T.vertexCount {-# RULES "vertexCount/Int" vertexCount = vertexIntCount #-} {-# INLINE [1] vertexCount #-}-vertexCount :: Ord a => NonEmptyGraph a -> Int-vertexCount = T.vertexCount --- | Like 'vertexCount' but specialised for NonEmptyGraph with vertices of type 'Int'.-vertexIntCount :: NonEmptyGraph Int -> Int+-- Like 'vertexCount' but specialised for Graph with vertices of type 'Int'.+vertexIntCount :: Graph Int -> Int vertexIntCount = IntSet.size . vertexIntSet  -- | The number of edges in a graph.@@ -447,29 +497,29 @@ -- edgeCount ('edge' x y) == 1 -- edgeCount            == 'length' . 'edgeList' -- @+edgeCount :: Ord a => Graph a -> Int+edgeCount = T.edgeCount {-# INLINE [1] edgeCount #-} {-# RULES "edgeCount/Int" edgeCount = edgeCountInt #-}-edgeCount :: Ord a => NonEmptyGraph a -> Int-edgeCount = T.edgeCount --- | Like 'edgeCount' but specialised for graphs with vertices of type 'Int'.-edgeCountInt :: NonEmptyGraph Int -> Int-edgeCountInt = AIM.edgeCount . T.toAdjacencyIntMap+-- Like 'edgeCount' but specialised for graphs with vertices of type 'Int'.+edgeCountInt :: Graph Int -> Int+edgeCountInt = T.edgeCount . T.toAdjacencyIntMap  -- | The sorted list of vertices of a given graph. -- Complexity: /O(s * log(n))/ time and /O(n)/ memory. -- -- @--- vertexList1 ('vertex' x)  == x ':|' []+-- vertexList1 ('vertex' x)  == [x] -- vertexList1 . 'vertices1' == 'Data.List.NonEmpty.nub' . 'Data.List.NonEmpty.sort' -- @+vertexList1 :: Ord a => Graph a -> NonEmpty a+vertexList1 = NonEmpty.fromList . Set.toAscList . vertexSet {-# RULES "vertexList1/Int" vertexList1 = vertexIntList1 #-} {-# INLINE [1] vertexList1 #-}-vertexList1 :: Ord a => NonEmptyGraph a -> NonEmpty a-vertexList1 = NonEmpty.fromList . Set.toAscList . vertexSet --- | Like 'vertexList1' but specialised for NonEmptyGraph with vertices of type 'Int'.-vertexIntList1 :: NonEmptyGraph Int -> NonEmpty Int+-- | Like 'vertexList1' but specialised for Graph with vertices of type 'Int'.+vertexIntList1 :: Graph Int -> NonEmpty Int vertexIntList1 = NonEmpty.fromList . IntSet.toAscList . vertexIntSet  -- | The sorted list of edges of a graph.@@ -481,16 +531,16 @@ -- edgeList ('edge' x y)     == [(x,y)] -- edgeList ('star' 2 [3,1]) == [(2,1), (2,3)] -- edgeList . 'edges1'       == 'Data.List.nub' . 'Data.List.sort' . 'Data.List.NonEmpty.toList'--- edgeList . 'transpose'    == 'Data.List.sort' . map 'Data.Tuple.swap' . edgeList+-- edgeList . 'transpose'    == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . edgeList -- @+edgeList :: Ord a => Graph a -> [(a, a)]+edgeList = T.edgeList {-# RULES "edgeList/Int" edgeList = edgeIntList #-} {-# INLINE [1] edgeList #-}-edgeList :: Ord a => NonEmptyGraph a -> [(a, a)]-edgeList = T.edgeList --- | Like 'edgeList' but specialised for NonEmptyGraph with vertices of type 'Int'.-edgeIntList :: NonEmptyGraph Int -> [(Int,Int)]-edgeIntList = AIM.edgeList . T.toAdjacencyIntMap+-- Like 'edgeList' but specialised for Graph with vertices of type 'Int'.+edgeIntList :: Graph Int -> [(Int, Int)]+edgeIntList = T.edgeList . T.toAdjacencyIntMap  -- | The set of vertices of a given graph. -- Complexity: /O(s * log(n))/ time and /O(n)/ memory.@@ -500,19 +550,11 @@ -- vertexSet . 'vertices1' == Set.'Set.fromList' . 'Data.List.NonEmpty.toList' -- vertexSet . 'clique1'   == Set.'Set.fromList' . 'Data.List.NonEmpty.toList' -- @-vertexSet :: Ord a => NonEmptyGraph a -> Set.Set a+vertexSet :: Ord a => Graph a -> Set.Set a vertexSet = T.vertexSet --- | The set of vertices of a given graph. Like 'vertexSet' but specialised for--- graphs with vertices of type 'Int'.--- Complexity: /O(s * log(n))/ time and /O(n)/ memory.------ @--- vertexIntSet . 'vertex'    == IntSet.'IntSet.singleton'--- vertexIntSet . 'vertices1' == IntSet.'IntSet.fromList' . 'Data.List.NonEmpty.toList'--- vertexIntSet . 'clique1'   == IntSet.'IntSet.fromList' . 'Data.List.NonEmpty.toList'--- @-vertexIntSet :: NonEmptyGraph Int -> IntSet.IntSet+-- Like 'vertexSet' but specialised for graphs with vertices of type 'Int'.+vertexIntSet :: Graph Int -> IntSet.IntSet vertexIntSet = T.vertexIntSet  -- | The set of edges of a given graph.@@ -523,7 +565,7 @@ -- edgeSet ('edge' x y) == Set.'Set.singleton' (x,y) -- edgeSet . 'edges1'   == Set.'Set.fromList' . 'Data.List.NonEmpty.toList' -- @-edgeSet :: Ord a => NonEmptyGraph a -> Set.Set (a, a)+edgeSet :: Ord a => Graph a -> Set.Set (a, a) edgeSet = T.edgeSet  -- | The /path/ on a list of vertices.@@ -531,11 +573,11 @@ -- given list. -- -- @--- path1 (x ':|' [] ) == 'vertex' x--- path1 (x ':|' [y]) == 'edge' x y--- path1 . 'Data.List.NonEmpty.reverse'  == 'transpose' . path1+-- path1 [x]       == 'vertex' x+-- path1 [x,y]     == 'edge' x y+-- path1 . 'Data.List.NonEmpty.reverse' == 'transpose' . path1 -- @-path1 :: NonEmpty a -> NonEmptyGraph a+path1 :: NonEmpty a -> Graph a path1 (x :| []    ) = vertex x path1 (x :| (y:ys)) = edges1 ((x, y) :| zip (y:ys) ys) @@ -544,11 +586,11 @@ -- given list. -- -- @--- circuit1 (x ':|' [] ) == 'edge' x x--- circuit1 (x ':|' [y]) == 'edges1' ((x,y) ':|' [(y,x)])--- circuit1 . 'Data.List.NonEmpty.reverse'  == 'transpose' . circuit1+-- circuit1 [x]       == 'edge' x x+-- circuit1 [x,y]     == 'edges1' [(x,y), (y,x)]+-- circuit1 . 'Data.List.NonEmpty.reverse' == 'transpose' . circuit1 -- @-circuit1 :: NonEmpty a -> NonEmptyGraph a+circuit1 :: NonEmpty a -> Graph a circuit1 (x :| xs) = path1 (x :| xs ++ [x])  -- | The /clique/ on a list of vertices.@@ -556,13 +598,13 @@ -- given list. -- -- @--- clique1 (x ':|' []   ) == 'vertex' x--- clique1 (x ':|' [y]  ) == 'edge' x y--- clique1 (x ':|' [y,z]) == 'edges1' ((x,y) ':|' [(x,z), (y,z)])--- clique1 (xs '<>' ys)   == 'connect' (clique1 xs) (clique1 ys)--- clique1 . 'Data.List.NonEmpty.reverse'    == 'transpose' . clique1+-- clique1 [x]        == 'vertex' x+-- clique1 [x,y]      == 'edge' x y+-- clique1 [x,y,z]    == 'edges1' [(x,y), (x,z), (y,z)]+-- clique1 (xs '<>' ys) == 'connect' (clique1 xs) (clique1 ys)+-- clique1 . 'Data.List.NonEmpty.reverse'  == 'transpose' . clique1 -- @-clique1 :: NonEmpty a -> NonEmptyGraph a+clique1 :: NonEmpty a -> Graph a clique1 = connects1 . fmap vertex {-# NOINLINE [1] clique1 #-} @@ -571,10 +613,10 @@ -- lengths of the given lists. -- -- @--- biclique1 (x1 ':|' [x2]) (y1 ':|' [y2]) == 'edges1' ((x1,y1) ':|' [(x1,y2), (x2,y1), (x2,y2)])--- biclique1 xs            ys          == 'connect' ('vertices1' xs) ('vertices1' ys)+-- biclique1 [x1,x2] [y1,y2] == 'edges1' [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]+-- biclique1 xs      ys      == 'connect' ('vertices1' xs) ('vertices1' ys) -- @-biclique1 :: NonEmpty a -> NonEmpty a -> NonEmptyGraph a+biclique1 :: NonEmpty a -> NonEmpty a -> Graph a biclique1 xs ys = connect (vertices1 xs) (vertices1 ys)  -- | The /star/ formed by a centre vertex connected to a list of leaves.@@ -584,9 +626,9 @@ -- @ -- star x []    == 'vertex' x -- star x [y]   == 'edge' x y--- star x [y,z] == 'edges1' ((x,y) ':|' [(x,z)])+-- star x [y,z] == 'edges1' [(x,y), (x,z)] -- @-star :: a -> [a] -> NonEmptyGraph a+star :: a -> [a] -> Graph a star x []     = vertex x star x (y:ys) = connect (vertex x) (vertices1 $ y :| ys) {-# INLINE star #-}@@ -596,13 +638,13 @@ -- input. -- -- @--- stars1 ((x, [])  ':|' [])         == 'vertex' x--- stars1 ((x, [y]) ':|' [])         == 'edge' x y--- stars1 ((x, ys)  ':|' [])         == 'star' x ys--- stars1                          == 'overlays1' . fmap (uncurry 'star')--- 'overlay' (stars1 xs) (stars1 ys) == stars1 (xs <> ys)+-- stars1 [(x, [] )]               == 'vertex' x+-- stars1 [(x, [y])]               == 'edge' x y+-- stars1 [(x, ys )]               == 'star' x ys+-- stars1                          == 'overlays1' . 'fmap' ('uncurry' 'star')+-- 'overlay' (stars1 xs) (stars1 ys) == stars1 (xs '<>' ys) -- @-stars1 :: NonEmpty (a, [a]) -> NonEmptyGraph a+stars1 :: NonEmpty (a, [a]) -> Graph a stars1 = overlays1 . fmap (uncurry star) {-# INLINE stars1 #-} @@ -612,11 +654,11 @@ -- -- @ -- tree (Node x [])                                         == 'vertex' x--- tree (Node x [Node y [Node z []]])                       == 'path1' (x ':|' [y,z])+-- tree (Node x [Node y [Node z []]])                       == 'path1' [x,y,z] -- tree (Node x [Node y [], Node z []])                     == 'star' x [y,z]--- tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == 'edges1' ((1,2) ':|' [(1,3), (3,4), (3,5)])+-- tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == 'edges1' [(1,2), (1,3), (3,4), (3,5)] -- @-tree :: Tree.Tree a -> NonEmptyGraph a+tree :: Tree.Tree a -> Graph a tree (Tree.Node x f) = overlays1 $ star x (map Tree.rootLabel f) :| map tree f  -- | Construct a /mesh graph/ from two lists of vertices.@@ -624,14 +666,14 @@ -- lengths of the given lists. -- -- @--- mesh1 (x ':|' [])    (y ':|' [])    == 'vertex' (x, y)--- mesh1 xs           ys           == 'box' ('path1' xs) ('path1' ys)--- mesh1 (1 ':|' [2,3]) (\'a\' ':|' "b") == 'edges1' ('Data.List.NonEmpty.fromList' [ ((1,\'a\'),(1,\'b\')), ((1,\'a\'),(2,\'a\'))---                                                     , ((1,\'b\'),(2,\'b\')), ((2,\'a\'),(2,\'b\'))---                                                     , ((2,\'a\'),(3,\'a\')), ((2,\'b\'),(3,\'b\'))---                                                     , ((3,\'a\'),(3,\'b\')) ])+-- mesh1 [x]     [y]        == 'vertex' (x, y)+-- mesh1 xs      ys         == 'box' ('path1' xs) ('path1' ys)+-- mesh1 [1,2,3] [\'a\', \'b\'] == 'edges1' [ ((1,\'a\'),(1,\'b\')), ((1,\'a\'),(2,\'a\'))+--                                    , ((1,\'b\'),(2,\'b\')), ((2,\'a\'),(2,\'b\'))+--                                    , ((2,\'a\'),(3,\'a\')), ((2,\'b\'),(3,\'b\'))+--                                    , ((3,\'a\'),(3,\'b\')) ] -- @-mesh1 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)+mesh1 :: NonEmpty a -> NonEmpty b -> Graph (a, b) mesh1 xx@(x:|xs) yy@(y:|ys) =   case NonEmpty.nonEmpty ipxs of     Nothing ->@@ -659,21 +701,22 @@ -- lengths of the given lists. -- -- @--- torus1 (x ':|' [])  (y ':|' [])    == 'edge' (x,y) (x,y)--- torus1 xs         ys           == 'box' ('circuit1' xs) ('circuit1' ys)--- torus1 (1 ':|' [2]) (\'a\' ':|' "b") == 'edges1' ('Data.List.NonEmpty.fromList' [ ((1,\'a\'),(1,\'b\')), ((1,\'a\'),(2,\'a\'))---                                                    , ((1,\'b\'),(1,\'a\')), ((1,\'b\'),(2,\'b\'))---                                                    , ((2,\'a\'),(1,\'a\')), ((2,\'a\'),(2,\'b\'))---                                                    , ((2,\'b\'),(1,\'b\')), ((2,\'b\'),(2,\'a\')) ])+-- torus1 [x]   [y]        == 'edge' (x,y) (x,y)+-- torus1 xs    ys         == 'box' ('circuit1' xs) ('circuit1' ys)+-- torus1 [1,2] [\'a\', \'b\'] == 'edges1' [ ((1,\'a\'),(1,\'b\')), ((1,\'a\'),(2,\'a\'))+--                                   , ((1,\'b\'),(1,\'a\')), ((1,\'b\'),(2,\'b\'))+--                                   , ((2,\'a\'),(1,\'a\')), ((2,\'a\'),(2,\'b\'))+--                                   , ((2,\'b\'),(1,\'b\')), ((2,\'b\'),(2,\'a\')) ] -- @-torus1 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)-torus1 xs ys = stars1 $ fmap (\((a1,a2),(b1,b2)) -> ((a1, b1), [(a1, b2), (a2, b1)])) $ liftM2 (,) (pairs1 xs) (pairs1 ys)+torus1 :: NonEmpty a -> NonEmpty b -> Graph (a, b)+torus1 xs ys = stars1 $ fmap (\((a1,a2),(b1,b2)) -> ((a1, b1), [(a1, b2), (a2, b1)]))+    $ liftM2 (,) (pairs1 xs) (pairs1 ys) --- | Auxiliary function for 'mesh1' and 'torus1'+-- Auxiliary function for 'mesh1' and 'torus1' pairs1 :: NonEmpty a -> NonEmpty (a, a) pairs1 as@(x:|xs) = NonEmpty.zip as $ maybe (x :| []) (`appendNonEmpty` [x]) $ NonEmpty.nonEmpty xs --- | Append a list to a non-empty one+-- Append a list to a non-empty one appendNonEmpty :: NonEmpty a -> [a] -> NonEmpty a appendNonEmpty (w:|ws) zs = w :| (ws++zs) @@ -688,34 +731,34 @@ -- removeVertex1 1 ('edge' 1 2)          == Just ('vertex' 2) -- removeVertex1 x '>=>' removeVertex1 x == removeVertex1 x -- @-{-# SPECIALISE removeVertex1 :: Int -> NonEmptyGraph Int -> Maybe (NonEmptyGraph Int) #-}-removeVertex1 :: Eq a => a -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)+removeVertex1 :: Eq a => a -> Graph a -> Maybe (Graph a) removeVertex1 x = induce1 (/= x)+{-# SPECIALISE removeVertex1 :: Int -> Graph Int -> Maybe (Graph Int) #-}  -- | Remove an edge from a given graph. -- Complexity: /O(s)/ time, memory and size. -- -- @--- removeEdge x y ('edge' x y)       == 'vertices1' (x ':|' [y])+-- removeEdge x y ('edge' x y)       == 'vertices1' [x,y] -- removeEdge x y . removeEdge x y == removeEdge x y -- removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2 -- removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2 -- 'size' (removeEdge x y z)         <= 3 * 'size' z -- @-{-# SPECIALISE removeEdge :: Int -> Int -> NonEmptyGraph Int -> NonEmptyGraph Int #-}-removeEdge :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a+removeEdge :: Eq a => a -> a -> Graph a -> Graph a removeEdge s t = filterContext s (/=s) (/=t)+{-# SPECIALISE removeEdge :: Int -> Int -> Graph Int -> Graph Int #-}  -- TODO: Export-{-# SPECIALISE filterContext :: Int -> (Int -> Bool) -> (Int -> Bool) -> NonEmptyGraph Int -> NonEmptyGraph Int #-}-filterContext :: Eq a => a -> (a -> Bool) -> (a -> Bool) -> NonEmptyGraph a -> NonEmptyGraph a+filterContext :: Eq a => a -> (a -> Bool) -> (a -> Bool) -> Graph a -> Graph a filterContext s i o g = maybe g go $ G.context (==s) (T.toGraph g)   where     go (G.Context is os) = G.induce (/=s) (T.toGraph g)     `overlay1`                            transpose (star s (filter i is)) `overlay` star s (filter o os)+{-# SPECIALISE filterContext :: Int -> (Int -> Bool) -> (Int -> Bool) -> Graph Int -> Graph Int #-} --- | The function @'replaceVertex' x y@ replaces vertex @x@ with vertex @y@ in a--- given 'NonEmptyGraph'. If @y@ already exists, @x@ and @y@ will be merged.+-- | The function 'replaceVertex' @x y@ replaces vertex @x@ with vertex @y@ in a+-- given 'Graph'. If @y@ already exists, @x@ and @y@ will be merged. -- Complexity: /O(s)/ time, memory and size. -- -- @@@ -723,21 +766,21 @@ -- replaceVertex x y ('vertex' x) == 'vertex' y -- replaceVertex x y            == 'mergeVertices' (== x) y -- @-{-# SPECIALISE replaceVertex :: Int -> Int -> NonEmptyGraph Int -> NonEmptyGraph Int #-}-replaceVertex :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a+replaceVertex :: Eq a => a -> a -> Graph a -> Graph a replaceVertex u v = fmap $ \w -> if w == u then v else w+{-# SPECIALISE replaceVertex :: Int -> Int -> Graph Int -> Graph Int #-}  -- | Merge vertices satisfying a given predicate into a given vertex. -- Complexity: /O(s)/ time, memory and size, assuming that the predicate takes -- /O(1)/ to be evaluated. -- -- @--- mergeVertices (const False) x    == id+-- mergeVertices ('const' False) x    == id -- mergeVertices (== x) y           == 'replaceVertex' x y--- mergeVertices even 1 (0 * 2)     == 1 * 1--- mergeVertices odd  1 (3 + 4 * 5) == 4 * 1+-- mergeVertices 'even' 1 (0 * 2)     == 1 * 1+-- mergeVertices 'odd'  1 (3 + 4 * 5) == 4 * 1 -- @-mergeVertices :: (a -> Bool) -> a -> NonEmptyGraph a -> NonEmptyGraph a+mergeVertices :: (a -> Bool) -> a -> Graph a -> Graph a mergeVertices p v = fmap $ \w -> if p w then v else w  -- | Split a vertex into a list of vertices with the same connectivity.@@ -746,13 +789,13 @@ -- given list. -- -- @--- splitVertex1 x (x ':|' [] )               == id--- splitVertex1 x (y ':|' [] )               == 'replaceVertex' x y--- splitVertex1 1 (0 ':|' [1]) $ 1 * (2 + 3) == (0 + 1) * (2 + 3)+-- splitVertex1 x [x]                 == id+-- splitVertex1 x [y]                 == 'replaceVertex' x y+-- splitVertex1 1 [0,1] $ 1 * (2 + 3) == (0 + 1) * (2 + 3) -- @-{-# SPECIALISE splitVertex1 :: Int -> NonEmpty Int -> NonEmptyGraph Int -> NonEmptyGraph Int #-}-splitVertex1 :: Eq a => a -> NonEmpty a -> NonEmptyGraph a -> NonEmptyGraph a+splitVertex1 :: Eq a => a -> NonEmpty a -> Graph a -> Graph a splitVertex1 v us g = g >>= \w -> if w == v then vertices1 us else vertex w+{-# SPECIALISE splitVertex1 :: Int -> NonEmpty Int -> Graph Int -> Graph Int #-}  -- | Transpose a given graph. -- Complexity: /O(s)/ time, memory and size.@@ -762,9 +805,9 @@ -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id -- transpose ('box' x y)   == 'box' (transpose x) (transpose y)--- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList'+-- 'edgeList' . transpose  == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . 'edgeList' -- @-transpose :: NonEmptyGraph a -> NonEmptyGraph a+transpose :: Graph a -> Graph a transpose = foldg1 vertex overlay (flip connect) {-# NOINLINE [1] transpose #-} @@ -787,12 +830,12 @@ -- /O(1)/ to be evaluated. -- -- @--- induce1 (const True ) x == Just x--- induce1 (const False) x == Nothing+-- induce1 ('const' True ) x == Just x+-- induce1 ('const' False) x == Nothing -- induce1 (/= x)          == 'removeVertex1' x -- induce1 p '>=>' induce1 q == induce1 (\\x -> p x && q x) -- @-induce1 :: (a -> Bool) -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)+induce1 :: (a -> Bool) -> Graph a -> Maybe (Graph a) induce1 p = foldg1   (\x -> if p x then Just (Vertex x) else Nothing)   (k Overlay)@@ -810,18 +853,17 @@ -- that the size of the result does not exceed the size of the given expression. -- -- @--- simplify              == id--- 'size' (simplify x)     <= 'size' x+-- simplify             ==  id+-- 'size' (simplify x)    <=  'size' x -- simplify 1           '===' 1 -- simplify (1 + 1)     '===' 1 -- simplify (1 + 2 + 1) '===' 1 + 2 -- simplify (1 * 1 * 1) '===' 1 * 1 -- @-{-# SPECIALISE simplify :: NonEmptyGraph Int -> NonEmptyGraph Int #-}-simplify :: Ord a => NonEmptyGraph a -> NonEmptyGraph a+simplify :: Ord a => Graph a -> Graph a simplify = foldg1 Vertex (simple Overlay) (simple Connect)+{-# SPECIALISE simplify :: Graph Int -> Graph Int #-} -{-# SPECIALISE simple :: (NonEmptyGraph Int -> NonEmptyGraph Int -> NonEmptyGraph Int) -> NonEmptyGraph Int -> NonEmptyGraph Int -> NonEmptyGraph Int #-} simple :: Eq g => (g -> g -> g) -> g -> g -> g simple op x y     | x == z    = x@@ -829,16 +871,17 @@     | otherwise = z   where     z = op x y+{-# SPECIALISE simple :: (Graph Int -> Graph Int -> Graph Int) -> Graph Int -> Graph Int -> Graph Int #-}  -- | Compute the /Cartesian product/ of graphs. -- Complexity: /O(s1 * s2)/ time, memory and size, where /s1/ and /s2/ are the -- sizes of the given graphs. -- -- @--- box ('path1' $ 'Data.List.NonEmpty.fromList' [0,1]) ('path1' $ 'Data.List.NonEmpty.fromList' "ab") == 'edges1' ('Data.List.NonEmpty.fromList' [ ((0,\'a\'), (0,\'b\'))---                                                                          , ((0,\'a\'), (1,\'a\'))---                                                                          , ((0,\'b\'), (1,\'b\'))---                                                                          , ((1,\'a\'), (1,\'b\')) ])+-- box ('path1' [0,1]) ('path1' [\'a\',\'b\']) == 'edges1' [ ((0,\'a\'), (0,\'b\'))+--                                               , ((0,\'a\'), (1,\'a\'))+--                                               , ((0,\'b\'), (1,\'b\'))+--                                               , ((1,\'a\'), (1,\'b\')) ] -- @ -- Up to an isomorphism between the resulting vertex types, this operation -- is /commutative/, /associative/, /distributes/ over 'overlay', and has@@ -854,12 +897,15 @@ -- 'vertexCount' (box x y) == 'vertexCount' x * 'vertexCount' y -- 'edgeCount'   (box x y) <= 'vertexCount' x * 'edgeCount' y + 'edgeCount' x * 'vertexCount' y -- @-box :: NonEmptyGraph a -> NonEmptyGraph b -> NonEmptyGraph (a, b)+box :: Graph a -> Graph b -> Graph (a, b) box x y = overlays1 xs `overlay` overlays1 ys   where-    xs = fmap (\b -> fmap (,b) x) $ toNonEmpty y-    ys = fmap (\a -> fmap (a,) y) $ toNonEmpty x+    xs = fmap (\b -> fmap (,b) x) $ toNonEmptyList y+    ys = fmap (\a -> fmap (a,) y) $ toNonEmptyList x +toNonEmptyList :: Graph a -> NonEmpty a+toNonEmptyList = foldg1 (:| []) (<>) (<>)+ -- | /Sparsify/ a graph by adding intermediate 'Left' @Int@ vertices between the -- original vertices (wrapping the latter in 'Right') such that the resulting -- graph is /sparse/, i.e. contains only O(s) edges, but preserves the@@ -875,7 +921,7 @@ -- 'edgeCount'   (sparsify x) <= 3 * 'size' x -- 'size'        (sparsify x) <= 3 * 'size' x -- @-sparsify :: NonEmptyGraph a -> NonEmptyGraph (Either Int a)+sparsify :: Graph a -> Graph (Either Int a) sparsify graph = res   where     (res, end) = runState (foldg1 v o c graph 0 end) 1@@ -885,7 +931,3 @@         m <- get         put (m + 1)         overlay <$> s `x` m <*> m `y` t---- Shall we export this? I suggest to wait for Foldable1 type class instead.-toNonEmpty :: NonEmptyGraph a -> NonEmpty a-toNonEmpty = foldg1 (:| []) (<>) (<>)
+ src/Algebra/Graph/NonEmpty/AdjacencyMap.hs view
@@ -0,0 +1,568 @@+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.NonEmpty.AdjacencyMap+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- __Alga__ is a library for algebraic construction and manipulation of graphs+-- in Haskell. See <https://github.com/snowleopard/alga-paper this paper> for the+-- motivation behind the library, the underlying theory, and implementation details.+--+-- This module defines the data type 'AdjacencyMap' for graphs that are known+-- to be non-empty at compile time. To avoid name clashes with+-- "Algebra.Graph.AdjacencyMap", this module can be imported qualified:+--+-- @+-- import qualified Algebra.Graph.NonEmpty.AdjacencyMap as NonEmpty+-- @+--+-- The naming convention generally follows that of "Data.List.NonEmpty": we use+-- suffix @1@ to indicate the functions whose interface must be changed compared+-- to "Algebra.Graph.AdjacencyMap", e.g. 'vertices1'.+-----------------------------------------------------------------------------+module Algebra.Graph.NonEmpty.AdjacencyMap (+    -- * Data structure+    AdjacencyMap, toNonEmpty,++    -- * Basic graph construction primitives+    vertex, edge, overlay, connect, vertices1, edges1, overlays1, connects1,++    -- * Relations on graphs+    isSubgraphOf,++    -- * Graph properties+    hasVertex, hasEdge, vertexCount, edgeCount, vertexList1, edgeList,+    vertexSet, edgeSet, preSet, postSet,++    -- * Standard families of graphs+    path1, circuit1, clique1, biclique1, star, stars1, tree,++    -- * Graph transformation+    removeVertex1, removeEdge, replaceVertex, mergeVertices, transpose, gmap,+    induce1,++    -- * Graph closure+    closure, reflexiveClosure, symmetricClosure, transitiveClosure+    ) where++import Prelude hiding (reverse)+import Data.List.NonEmpty (NonEmpty (..), nonEmpty, toList, reverse)+import Data.Maybe+import Data.Set (Set)+import Data.Tree++import Algebra.Graph.NonEmpty.AdjacencyMap.Internal++import qualified Algebra.Graph.AdjacencyMap as AM+import qualified Data.Set                   as Set++-- Lift a function to non-empty adjacency maps+via :: (AM.AdjacencyMap a -> AM.AdjacencyMap b)+    ->     AdjacencyMap a ->    AdjacencyMap b+via f = NAM . f . am++-- Lift a two-argument function to non-empty adjacency maps+via2 :: (AM.AdjacencyMap a -> AM.AdjacencyMap b -> AM.AdjacencyMap c)+     ->     AdjacencyMap a ->    AdjacencyMap b ->    AdjacencyMap c+via2 f (NAM x) (NAM y) = NAM (f x y)++-- Lift a list function to non-empty adjacency maps+viaL :: (         [AM.AdjacencyMap a] -> AM.AdjacencyMap b)+     ->  NonEmpty (   AdjacencyMap a) ->    AdjacencyMap b+viaL f = NAM . f . fmap am . toList++-- Unsafe creation of a NonEmpty list.+unsafeNonEmpty :: [a] -> NonEmpty a+unsafeNonEmpty = fromMaybe (error msg) . nonEmpty+  where+    msg = "Algebra.Graph.AdjacencyMap.unsafeNonEmpty: Graph is empty"++-- | Convert a possibly empty 'AM.AdjacencyMap' into NonEmpty.'AdjacencyMap'.+-- Returns 'Nothing' if the argument is 'AM.empty'.+-- Complexity: /O(1)/ time, memory and size.+--+-- @+-- toNonEmpty 'AM.empty'              == Nothing+-- toNonEmpty ('Algebra.Graph.ToGraph.toAdjacencyMap' x) == Just (x :: 'AdjacencyMap' a)+-- @+toNonEmpty :: AM.AdjacencyMap a -> Maybe (AdjacencyMap a)+toNonEmpty x | AM.isEmpty x = Nothing+             | otherwise    = Just (NAM x)++-- | Construct the graph comprising /a single isolated vertex/.+-- Complexity: /O(1)/ time and memory.+--+-- @+-- 'AdjacencyMap.hasVertex' x (vertex x) == True+-- 'AdjacencyMap.vertexCount' (vertex x) == 1+-- 'AdjacencyMap.edgeCount'   (vertex x) == 0+-- @+vertex :: a -> AdjacencyMap a+vertex = NAM . AM.vertex+{-# NOINLINE [1] vertex #-}++-- | /Overlay/ two graphs. This is a commutative, associative and idempotent+-- operation with the identity 'empty'.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- 'hasVertex' z (overlay x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (overlay x y) >= 'vertexCount' x+-- 'vertexCount' (overlay x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (overlay x y) >= 'edgeCount' x+-- 'edgeCount'   (overlay x y) <= 'edgeCount' x   + 'edgeCount' y+-- 'vertexCount' (overlay 1 2) == 2+-- 'edgeCount'   (overlay 1 2) == 0+-- @+overlay :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a+overlay = via2 AM.overlay+{-# NOINLINE [1] overlay #-}++-- | /Connect/ two graphs. This is an associative operation with the identity+-- 'empty', which distributes over 'overlay' and obeys the decomposition axiom.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. Note that the+-- number of edges in the resulting graph is quadratic with respect to the number+-- of vertices of the arguments: /m = O(m1 + m2 + n1 * n2)/.+--+-- @+-- 'hasVertex' z (connect x y) == 'hasVertex' z x || 'hasVertex' z y+-- 'vertexCount' (connect x y) >= 'vertexCount' x+-- 'vertexCount' (connect x y) <= 'vertexCount' x + 'vertexCount' y+-- 'edgeCount'   (connect x y) >= 'edgeCount' x+-- 'edgeCount'   (connect x y) >= 'edgeCount' y+-- 'edgeCount'   (connect x y) >= 'vertexCount' x * 'vertexCount' y+-- 'edgeCount'   (connect x y) <= 'vertexCount' x * 'vertexCount' y + 'edgeCount' x + 'edgeCount' y+-- 'vertexCount' (connect 1 2) == 2+-- 'edgeCount'   (connect 1 2) == 1+-- @+connect :: Ord a => AdjacencyMap a -> AdjacencyMap a -> AdjacencyMap a+connect = via2 AM.connect+{-# NOINLINE [1] connect #-}++-- | Construct the graph comprising /a single edge/.+-- Complexity: /O(1)/ time, memory.+--+-- @+-- edge x y               == 'connect' ('vertex' x) ('vertex' y)+-- 'hasEdge' x y (edge x y) == True+-- 'edgeCount'   (edge x y) == 1+-- 'vertexCount' (edge 1 1) == 1+-- 'vertexCount' (edge 1 2) == 2+-- @+edge :: Ord a => a -> a -> AdjacencyMap a+edge x y = NAM (AM.edge x y)++-- | Construct the graph comprising a given list of isolated vertices.+-- Complexity: /O(L * log(L))/ time and /O(L)/ memory, where /L/ is the length+-- of the given list.+--+-- @+-- vertices1 [x]           == 'vertex' x+-- 'hasVertex' x . vertices1 == 'elem' x+-- 'vertexCount' . vertices1 == 'length' . 'Data.List.NonEmpty.nub'+-- 'vertexSet'   . vertices1 == Set.'Set.fromList' . 'Data.List.NonEmpty.toList'+-- @+vertices1 :: Ord a => NonEmpty a -> AdjacencyMap a+vertices1 = NAM . AM.vertices . toList+{-# NOINLINE [1] vertices1 #-}++-- | Construct the graph from a list of edges.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- edges1 [(x,y)]     == 'edge' x y+-- 'edgeCount' . edges1 == 'Data.List.NonEmpty.length' . 'Data.List.NonEmpty.nub'+-- @+edges1 :: Ord a => NonEmpty (a, a) -> AdjacencyMap a+edges1 = NAM . AM.edges . toList++-- | Overlay a given list of graphs.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- overlays1 [x]   == x+-- overlays1 [x,y] == 'overlay' x y+-- @+overlays1 :: Ord a => NonEmpty (AdjacencyMap a) -> AdjacencyMap a+overlays1 = viaL AM.overlays+{-# NOINLINE overlays1 #-}++-- | Connect a given list of graphs.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- connects1 [x]   == x+-- connects1 [x,y] == 'connect' x y+-- @+connects1 :: Ord a => NonEmpty (AdjacencyMap a) -> AdjacencyMap a+connects1 = viaL AM.connects+{-# NOINLINE connects1 #-}++-- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the+-- first graph is a /subgraph/ of the second.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf ('path1' xs)    ('circuit1' xs) ==  True+-- isSubgraphOf x y                         ==> x <= y+-- @+isSubgraphOf :: Ord a => AdjacencyMap a -> AdjacencyMap a -> Bool+isSubgraphOf (NAM x) (NAM y) = AM.isSubgraphOf x y++-- | Check if a graph contains a given vertex.+-- Complexity: /O(log(n))/ time.+--+-- @+-- hasVertex x ('vertex' x) == True+-- hasVertex 1 ('vertex' 2) == False+-- @+hasVertex :: Ord a => a -> AdjacencyMap a -> Bool+hasVertex x = AM.hasVertex x . am++-- | Check if a graph contains a given edge.+-- Complexity: /O(log(n))/ time.+--+-- @+-- hasEdge x y ('vertex' z)       == False+-- hasEdge x y ('edge' x y)       == True+-- hasEdge x y . 'removeEdge' x y == 'const' False+-- hasEdge x y                  == 'elem' (x,y) . 'edgeList'+-- @+hasEdge :: Ord a => a -> a -> AdjacencyMap a -> Bool+hasEdge x y = AM.hasEdge x y . am++-- | The number of vertices in a graph.+-- Complexity: /O(1)/ time.+--+-- @+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y+-- @+vertexCount :: AdjacencyMap a -> Int+vertexCount = AM.vertexCount . am++-- | The number of edges in a graph.+-- Complexity: /O(n)/ time.+--+-- @+-- edgeCount ('vertex' x) == 0+-- edgeCount ('edge' x y) == 1+-- edgeCount            == 'length' . 'edgeList'+-- @+edgeCount :: AdjacencyMap a -> Int+edgeCount = AM.edgeCount . am++-- | The sorted list of vertices of a given graph.+-- Complexity: /O(n)/ time and memory.+--+-- @+-- vertexList1 ('vertex' x)  == [x]+-- vertexList1 . 'vertices1' == 'Data.List.NonEmpty.nub' . 'Data.List.NonEmpty.sort'+-- @+vertexList1 :: AdjacencyMap a -> NonEmpty a+vertexList1 = unsafeNonEmpty . AM.vertexList . am++-- | The sorted list of edges of a graph.+-- Complexity: /O(n + m)/ time and /O(m)/ memory.+--+-- @+-- edgeList ('vertex' x)     == []+-- edgeList ('edge' x y)     == [(x,y)]+-- edgeList ('star' 2 [3,1]) == [(2,1), (2,3)]+-- edgeList . 'edges'        == 'Data.List.NonEmpty.nub' . 'Data.List.sort'+-- edgeList . 'transpose'    == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . edgeList+-- @+edgeList :: AdjacencyMap a -> [(a, a)]+edgeList = AM.edgeList . am++-- | The set of vertices of a given graph.+-- Complexity: /O(n)/ time and memory.+--+-- @+-- vertexSet . 'vertex'    == Set.'Set.singleton'+-- vertexSet . 'vertices1' == Set.'Set.fromList' . 'Data.List.NonEmpty.toList'+-- vertexSet . 'clique1'   == Set.'Set.fromList' . 'Data.List.NonEmpty.toList'+-- @+vertexSet :: AdjacencyMap a -> Set a+vertexSet = AM.vertexSet . am++-- | The set of edges of a given graph.+-- Complexity: /O((n + m) * log(m))/ time and /O(m)/ memory.+--+-- @+-- edgeSet ('vertex' x) == Set.'Set.empty'+-- edgeSet ('edge' x y) == Set.'Set.singleton' (x,y)+-- edgeSet . 'edges'    == Set.'Set.fromList'+-- @+edgeSet :: Ord a => AdjacencyMap a -> Set (a, a)+edgeSet = Set.fromAscList . edgeList++-- | The /preset/ of an element @x@ is the set of its /direct predecessors/.+-- Complexity: /O(n * log(n))/ time and /O(n)/ memory.+--+-- @+-- preSet x ('vertex' x) == Set.'Set.empty'+-- preSet 1 ('edge' 1 2) == Set.'Set.empty'+-- preSet y ('edge' x y) == Set.'Set.fromList' [x]+-- @+preSet :: Ord a => a -> AdjacencyMap a -> Set.Set a+preSet x = AM.preSet x . am++-- | The /postset/ of a vertex is the set of its /direct successors/.+-- Complexity: /O(log(n))/ time and /O(1)/ memory.+--+-- @+-- postSet x ('vertex' x) == Set.'Set.empty'+-- postSet x ('edge' x y) == Set.'Set.fromList' [y]+-- postSet 2 ('edge' 1 2) == Set.'Set.empty'+-- @+postSet :: Ord a => a -> AdjacencyMap a -> Set a+postSet x = AM.postSet x . am++-- | The /path/ on a list of vertices.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- path1 [x]       == 'vertex' x+-- path1 [x,y]     == 'edge' x y+-- path1 . 'Data.List.NonEmpty.reverse' == 'transpose' . path1+-- @+path1 :: Ord a => NonEmpty a -> AdjacencyMap a+path1 = NAM . AM.path . toList++-- | The /circuit/ on a list of vertices.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- circuit1 [x]       == 'edge' x x+-- circuit1 [x,y]     == 'edges1' [(x,y), (y,x)]+-- circuit1 . 'Data.List.NonEmpty.reverse' == 'transpose' . circuit1+-- @+circuit1 :: Ord a => NonEmpty a -> AdjacencyMap a+circuit1 = NAM . AM.circuit . toList++-- | The /clique/ on a list of vertices.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- clique1 [x]        == 'vertex' x+-- clique1 [x,y]      == 'edge' x y+-- clique1 [x,y,z]    == 'edges1' [(x,y), (x,z), (y,z)]+-- clique1 (xs '<>' ys) == 'connect' (clique1 xs) (clique1 ys)+-- clique1 . 'Data.List.NonEmpty.reverse'  == 'transpose' . clique1+-- @+clique1 :: Ord a => NonEmpty a -> AdjacencyMap a+clique1 = NAM . AM.clique . toList+{-# NOINLINE [1] clique1 #-}++-- | The /biclique/ on two lists of vertices.+-- Complexity: /O(n * log(n) + m)/ time and /O(n + m)/ memory.+--+-- @+-- biclique1 [x1,x2] [y1,y2] == 'edges1' [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]+-- biclique1 xs      ys      == 'connect' ('vertices1' xs) ('vertices1' ys)+-- @+biclique1 :: Ord a => NonEmpty a -> NonEmpty a -> AdjacencyMap a+biclique1 xs ys = NAM $ AM.biclique (toList xs) (toList ys)++-- TODO: Optimise.+-- | The /star/ formed by a centre vertex connected to a list of leaves.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- star x []    == 'vertex' x+-- star x [y]   == 'edge' x y+-- star x [y,z] == 'edges1' [(x,y), (x,z)]+-- @+star :: Ord a => a -> [a] -> AdjacencyMap a+star x = NAM . AM.star x+{-# INLINE star #-}++-- | The /stars/ formed by overlaying a list of 'star's. An inverse of+-- 'adjacencyList'.+-- Complexity: /O(L * log(n))/ time, memory and size, where /L/ is the total+-- size of the input.+--+-- @+-- stars1 [(x, [] )]               == 'vertex' x+-- stars1 [(x, [y])]               == 'edge' x y+-- stars1 [(x, ys )]               == 'star' x ys+-- stars1                          == 'overlays1' . 'fmap' ('uncurry' 'star')+-- 'overlay' (stars1 xs) (stars1 ys) == stars1 (xs '<>' ys)+-- @+stars1 :: Ord a => NonEmpty (a, [a]) -> AdjacencyMap a+stars1 = NAM . AM.stars . toList++-- | The /tree graph/ constructed from a given 'Tree' data structure.+-- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.+--+-- @+-- tree (Node x [])                                         == 'vertex' x+-- tree (Node x [Node y [Node z []]])                       == 'path1' [x,y,z]+-- tree (Node x [Node y [], Node z []])                     == 'star' x [y,z]+-- tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == 'edges1' [(1,2), (1,3), (3,4), (3,5)]+-- @+tree :: Ord a => Tree a -> AdjacencyMap a+tree = NAM . AM.tree++-- | Remove a vertex from a given graph.+-- Complexity: /O(n*log(n))/ time.+--+-- @+-- removeVertex1 x ('vertex' x)          == Nothing+-- removeVertex1 1 ('vertex' 2)          == Just ('vertex' 2)+-- removeVertex1 x ('edge' x x)          == Nothing+-- removeVertex1 1 ('edge' 1 2)          == Just ('vertex' 2)+-- removeVertex1 x 'Control.Monad.>=>' removeVertex1 x == removeVertex1 x+-- @+removeVertex1 :: Ord a => a -> AdjacencyMap a -> Maybe (AdjacencyMap a)+removeVertex1 x = toNonEmpty . AM.removeVertex x . am++-- | Remove an edge from a given graph.+-- Complexity: /O(log(n))/ time.+--+-- @+-- removeEdge x y ('edge' x y)       == 'vertices1' [x,y]+-- removeEdge x y . removeEdge x y == removeEdge x y+-- removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2+-- removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2+-- @+removeEdge :: Ord a => a -> a -> AdjacencyMap a -> AdjacencyMap a+removeEdge x y = via (AM.removeEdge x y)++-- | The function @'replaceVertex' x y@ replaces vertex @x@ with vertex @y@ in a+-- given 'AdjacencyMap'. If @y@ already exists, @x@ and @y@ will be merged.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- replaceVertex x x            == id+-- replaceVertex x y ('vertex' x) == 'vertex' y+-- replaceVertex x y            == 'mergeVertices' (== x) y+-- @+replaceVertex :: Ord a => a -> a -> AdjacencyMap a -> AdjacencyMap a+replaceVertex u v = via (AM.replaceVertex u v)++-- | Merge vertices satisfying a given predicate into a given vertex.+-- Complexity: /O((n + m) * log(n))/ time, assuming that the predicate takes+-- /O(1)/ to be evaluated.+--+-- @+-- mergeVertices ('const' False) x    == id+-- mergeVertices (== x) y           == 'replaceVertex' x y+-- mergeVertices 'even' 1 (0 * 2)     == 1 * 1+-- mergeVertices 'odd'  1 (3 + 4 * 5) == 4 * 1+-- @+mergeVertices :: Ord a => (a -> Bool) -> a -> AdjacencyMap a -> AdjacencyMap a+mergeVertices p v = via (AM.mergeVertices p v)++-- | Transpose a given graph.+-- Complexity: /O(m * log(n))/ time, /O(n + m)/ memory.+--+-- @+-- transpose ('vertex' x)  == 'vertex' x+-- transpose ('edge' x y)  == 'edge' y x+-- transpose . transpose == id+-- 'edgeList' . transpose  == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . 'edgeList'+-- @+transpose :: Ord a => AdjacencyMap a -> AdjacencyMap a+transpose = via AM.transpose+{-# NOINLINE [1] transpose #-}++{-# RULES+"transpose/vertex"   forall x. transpose (vertex x) = vertex x+"transpose/overlay"  forall g1 g2. transpose (overlay g1 g2) = overlay (transpose g1) (transpose g2)+"transpose/connect"  forall g1 g2. transpose (connect g1 g2) = connect (transpose g2) (transpose g1)++"transpose/overlays1" forall xs. transpose (overlays1 xs) = overlays1 (fmap transpose xs)+"transpose/connects1" forall xs. transpose (connects1 xs) = connects1 (reverse (fmap transpose xs))++"transpose/vertices1" forall xs. transpose (vertices1 xs) = vertices1 xs+"transpose/clique1"   forall xs. transpose (clique1 xs)   = clique1 (reverse xs)+ #-}++-- | Transform a graph by applying a function to each of its vertices. This is+-- similar to @Functor@'s 'fmap' but can be used with non-fully-parametric+-- 'AdjacencyMap'.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- gmap f ('vertex' x) == 'vertex' (f x)+-- gmap f ('edge' x y) == 'edge' (f x) (f y)+-- gmap id           == id+-- gmap f . gmap g   == gmap (f . g)+-- @+gmap :: (Ord a, Ord b) => (a -> b) -> AdjacencyMap a -> AdjacencyMap b+gmap f = via (AM.gmap f)++-- | Construct the /induced subgraph/ of a given graph by removing the+-- vertices that do not satisfy a given predicate.+-- Complexity: /O(m)/ time, assuming that the predicate takes /O(1)/ to+-- be evaluated.+--+-- @+-- induce1 ('const' True ) x == Just x+-- induce1 ('const' False) x == Nothing+-- induce1 (/= x)          == 'removeVertex1' x+-- induce1 p 'Control.Monad.>=>' induce1 q == induce1 (\\x -> p x && q x)+-- @+induce1 :: (a -> Bool) -> AdjacencyMap a -> Maybe (AdjacencyMap a)+induce1 p = toNonEmpty . AM.induce p . am++-- | Compute the /reflexive and transitive closure/ of a graph.+-- Complexity: /O(n * m * log(n)^2)/ time.+--+-- @+-- closure ('vertex' x)       == 'edge' x x+-- closure ('edge' x x)       == 'edge' x x+-- closure ('edge' x y)       == 'edges1' [(x,x), (x,y), (y,y)]+-- closure ('path1' $ 'Data.List.NonEmpty.nub' xs) == 'reflexiveClosure' ('clique1' $ 'Data.List.NonEmpty.nub' xs)+-- closure                  == 'reflexiveClosure' . 'transitiveClosure'+-- closure                  == 'transitiveClosure' . 'reflexiveClosure'+-- closure . closure        == closure+-- 'postSet' x (closure y)    == Set.'Set.fromList' ('Algebra.Graph.ToGraph.reachable' x y)+-- @+closure :: Ord a => AdjacencyMap a -> AdjacencyMap a+closure = via (AM.closure)++-- | Compute the /reflexive closure/ of a graph by adding a self-loop to every+-- vertex.+-- Complexity: /O(n * log(n))/ time.+--+-- @+-- reflexiveClosure ('vertex' x)         == 'edge' x x+-- reflexiveClosure ('edge' x x)         == 'edge' x x+-- reflexiveClosure ('edge' x y)         == 'edges1' [(x,x), (x,y), (y,y)]+-- reflexiveClosure . reflexiveClosure == reflexiveClosure+-- @+reflexiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a+reflexiveClosure = via AM.reflexiveClosure++-- | Compute the /symmetric closure/ of a graph by overlaying it with its own+-- transpose.+-- Complexity: /O((n + m) * log(n))/ time.+--+-- @+-- symmetricClosure ('vertex' x)         == 'vertex' x+-- symmetricClosure ('edge' x y)         == 'edges1' [(x,y), (y,x)]+-- symmetricClosure x                  == 'overlay' x ('transpose' x)+-- symmetricClosure . symmetricClosure == symmetricClosure+-- @+symmetricClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a+symmetricClosure = via AM.symmetricClosure++-- | Compute the /transitive closure/ of a graph.+-- Complexity: /O(n * m * log(n)^2)/ time.+--+-- @+-- transitiveClosure ('vertex' x)          == 'vertex' x+-- transitiveClosure ('edge' x y)          == 'edge' x y+-- transitiveClosure ('path1' $ 'Data.List.NonEmpty.nub' xs)    == 'clique1' ('Data.List.NonEmpty.nub' xs)+-- transitiveClosure . transitiveClosure == transitiveClosure+-- @+transitiveClosure :: Ord a => AdjacencyMap a -> AdjacencyMap a+transitiveClosure = via AM.transitiveClosure
+ src/Algebra/Graph/NonEmpty/AdjacencyMap/Internal.hs view
@@ -0,0 +1,163 @@+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.NonEmpty.AdjacencyMap.Internal+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- This module exposes the implementation of non-empty adjacency maps. The API+-- is unstable and unsafe, and is exposed only for documentation. You should use+-- the non-internal module "Algebra.Graph.NonEmpty.AdjacencyMap" instead.+-----------------------------------------------------------------------------+module Algebra.Graph.NonEmpty.AdjacencyMap.Internal (+    -- * Adjacency map implementation+    AdjacencyMap (..), consistent+    ) where++import Control.DeepSeq+import Data.List++import qualified Algebra.Graph.AdjacencyMap          as AM+import qualified Algebra.Graph.AdjacencyMap.Internal as AM+import qualified Data.Map.Strict                     as Map+import qualified Data.Set                            as Set++{-| The 'AdjacencyMap' data type represents a graph by a map of vertices to+their adjacency sets. We define a 'Num' instance as a convenient notation for+working with graphs:++    > 0           == vertex 0+    > 1 + 2       == overlay (vertex 1) (vertex 2)+    > 1 * 2       == connect (vertex 1) (vertex 2)+    > 1 + 2 * 3   == overlay (vertex 1) (connect (vertex 2) (vertex 3))+    > 1 * (2 + 3) == connect (vertex 1) (overlay (vertex 2) (vertex 3))++__Note:__ the 'signum' method of the type class 'Num' cannot be implemented and+will throw an error. Furthermore, the 'Num' instance does not satisfy several+"customary laws" of 'Num', which dictate that 'fromInteger' @0@ and+'fromInteger' @1@ should act as additive and multiplicative identities, and+'negate' as additive inverse. Nevertheless, overloading 'fromInteger', '+' and+'*' is very convenient when working with algebraic graphs; we hope that in+future Haskell's Prelude will provide a more fine-grained class hierarchy for+algebraic structures, which we would be able to utilise without violating any+laws.++The 'Show' instance is defined using basic graph construction primitives:++@show (1         :: AdjacencyMap Int) == "vertex 1"+show (1 + 2     :: AdjacencyMap Int) == "vertices1 [1,2]"+show (1 * 2     :: AdjacencyMap Int) == "edge 1 2"+show (1 * 2 * 3 :: AdjacencyMap Int) == "edges1 [(1,2),(1,3),(2,3)]"+show (1 * 2 + 3 :: AdjacencyMap Int) == "overlay (vertex 3) (edge 1 2)"@++The 'Eq' instance satisfies the following laws of algebraic graphs:++    * 'Algebra.Graph.NonEmpty.AdjacencyMap.overlay' is commutative, associative and idempotent:++        >       x + y == y + x+        > x + (y + z) == (x + y) + z+        >       x + x == x++    * 'Algebra.Graph.NonEmpty.AdjacencyMap.connect' is associative:++        > x * (y * z) == (x * y) * z++    * 'Algebra.Graph.NonEmpty.AdjacencyMap.connect' distributes over 'Algebra.Graph.NonEmpty.AdjacencyMap.overlay':++        > x * (y + z) == x * y + x * z+        > (x + y) * z == x * z + y * z++    * 'Algebra.Graph.NonEmpty.AdjacencyMap.connect' can be decomposed:++        > x * y * z == x * y + x * z + y * z++    * 'Algebra.Graph.NonEmpty.AdjacencyMap.connect' satisfies absorption and saturation:++        > x * y + x + y == x * y+        >     x * x * x == x * x++When specifying the time and memory complexity of graph algorithms, /n/ and /m/+will denote the number of vertices and edges in the graph, respectively.++The total order on graphs is defined using /size-lexicographic/ comparison:++* Compare the number of vertices. In case of a tie, continue.+* Compare the sets of vertices. In case of a tie, continue.+* Compare the number of edges. In case of a tie, continue.+* Compare the sets of edges.++Here are a few examples:++@'Algebra.Graph.NonEmpty.AdjacencyMap.vertex' 1 < 'Algebra.Graph.NonEmpty.AdjacencyMap.vertex' 2+'Algebra.Graph.NonEmpty.AdjacencyMap.vertex' 3 < 'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 2+'Algebra.Graph.NonEmpty.AdjacencyMap.vertex' 1 < 'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 1+'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 1 < 'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 2+'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 2 < 'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 1 + 'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 2 2+'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 2 < 'Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 3@++Note that the resulting order refines the+'Algebra.Graph.NonEmpty.AdjacencyMap.isSubgraphOf' relation and is compatible+with 'Algebra.Graph.NonEmpty.AdjacencyMap.overlay' and+'Algebra.Graph.NonEmpty.AdjacencyMap.connect' operations:++@'Algebra.Graph.NonEmpty.AdjacencyMap.isSubgraphOf' x y ==> x <= y@++@x     <= x + y+x + y <= x * y@+-}+newtype AdjacencyMap a = NAM {+    -- | The /adjacency map/ of a graph: each vertex is associated with a set of+    -- its direct successors. Complexity: /O(1)/ time and memory.+    --+    -- @+    -- adjacencyMap ('vertex' x) == Map.'Map.singleton' x Set.'Set.empty'+    -- adjacencyMap ('Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 1) == Map.'Map.singleton' 1 (Set.'Set.singleton' 1)+    -- adjacencyMap ('Algebra.Graph.NonEmpty.AdjacencyMap.edge' 1 2) == Map.'Map.fromList' [(1,Set.'Set.singleton' 2), (2,Set.'Set.empty')]+    -- @+    am :: AM.AdjacencyMap a } deriving (Eq, NFData, Ord)++-- | __Note:__ this does not satisfy the usual ring laws; see 'AdjacencyMap' for+-- more details.+instance (Ord a, Num a) => Num (AdjacencyMap a) where+    fromInteger   = NAM . AM.vertex . fromInteger+    NAM x + NAM y = NAM (AM.overlay x y)+    NAM x * NAM y = NAM (AM.connect x y)+    signum        = error "NonEmpty.AdjacencyMap.signum cannot be implemented."+    abs           = id+    negate        = id++instance (Ord a, Show a) => Show (AdjacencyMap a) where+    showsPrec p (NAM (AM.AM m))+        | null vs    = error "NonEmpty.AdjacencyMap.Show: Graph is empty"+        | null es    = showParen (p > 10) $ vshow vs+        | vs == used = showParen (p > 10) $ eshow es+        | otherwise  = showParen (p > 10) $+                           showString "overlay (" . vshow (vs \\ used) .+                           showString ") (" . eshow es . showString ")"+      where+        vs             = Set.toAscList (Map.keysSet m)+        es             = AM.internalEdgeList m+        vshow [x]      = showString "vertex "    . showsPrec 11 x+        vshow xs       = showString "vertices1 " . showsPrec 11 xs+        eshow [(x, y)] = showString "edge "      . showsPrec 11 x .+                         showString " "          . showsPrec 11 y+        eshow xs       = showString "edges1 "    . showsPrec 11 xs+        used           = Set.toAscList (AM.referredToVertexSet m)++-- | Check if the internal graph representation is consistent, i.e. that all+-- edges refer to existing vertices, and the graph is non-empty. It should be+-- impossible to create an inconsistent adjacency map, and we use this function+-- in testing.+-- /Note: this function is for internal use only/.+--+-- @+-- consistent ('vertex' x)    == True+-- consistent ('overlay' x y) == True+-- consistent ('connect' x y) == True+-- consistent ('Algebra.Graph.NonEmpty.AdjacencyMap.edge' x y)    == True+-- consistent ('Algebra.Graph.NonEmpty.AdjacencyMap.edges' xs)    == True+-- consistent ('Algebra.Graph.NonEmpty.AdjacencyMap.stars' xs)    == True+-- @+consistent :: Ord a => AdjacencyMap a -> Bool+consistent (NAM x) = AM.consistent x && not (AM.isEmpty x)
src/Algebra/Graph/Relation.hs view
@@ -26,7 +26,7 @@      -- * Graph properties     isEmpty, hasVertex, hasEdge, vertexCount, edgeCount, vertexList, edgeList,-    adjacencyList, vertexSet, vertexIntSet, edgeSet, preSet, postSet,+    adjacencyList, vertexSet, edgeSet, preSet, postSet,      -- * Standard families of graphs     path, circuit, clique, biclique, star, stars, tree, forest,@@ -34,8 +34,8 @@     -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, transpose, gmap, induce, -    -- * Operations on binary relations-    compose, reflexiveClosure, symmetricClosure, transitiveClosure, preorderClosure+    -- * Relational operations+    compose, closure, reflexiveClosure, symmetricClosure, transitiveClosure   ) where  import Prelude ()@@ -46,7 +46,6 @@  import Algebra.Graph.Relation.Internal -import qualified Data.IntSet as IntSet import qualified Data.Set    as Set import qualified Data.Tree   as Tree @@ -119,14 +118,16 @@ -- Complexity: /O((n + m) * log(n))/ time. -- -- @--- isSubgraphOf 'empty'         x             == True--- isSubgraphOf ('vertex' x)    'empty'         == False--- isSubgraphOf x             ('overlay' x y) == True--- isSubgraphOf ('overlay' x y) ('connect' x y) == True--- isSubgraphOf ('path' xs)     ('circuit' xs)  == True+-- isSubgraphOf 'empty'         x             ==  True+-- isSubgraphOf ('vertex' x)    'empty'         ==  False+-- isSubgraphOf x             ('overlay' x y) ==  True+-- isSubgraphOf ('overlay' x y) ('connect' x y) ==  True+-- isSubgraphOf ('path' xs)     ('circuit' xs)  ==  True+-- isSubgraphOf x y                         ==> x <= y -- @ isSubgraphOf :: Ord a => Relation a -> Relation a -> Bool-isSubgraphOf x y = domain x `Set.isSubsetOf` domain y && relation x `Set.isSubsetOf` relation y+isSubgraphOf x y = domain   x `Set.isSubsetOf` domain   y+                && relation x `Set.isSubsetOf` relation y  -- | Check if a relation is empty. -- Complexity: /O(1)/ time.@@ -148,7 +149,7 @@ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True -- hasVertex 1 ('vertex' 2)       == False--- hasVertex x . 'removeVertex' x == const False+-- hasVertex x . 'removeVertex' x == 'const' False -- @ hasVertex :: Ord a => a -> Relation a -> Bool hasVertex x = Set.member x . domain@@ -160,7 +161,7 @@ -- hasEdge x y 'empty'            == False -- hasEdge x y ('vertex' z)       == False -- hasEdge x y ('edge' x y)       == True--- hasEdge x y . 'removeEdge' x y == const False+-- hasEdge x y . 'removeEdge' x y == 'const' False -- hasEdge x y                  == 'elem' (x,y) . 'edgeList' -- @ hasEdge :: Ord a => a -> a -> Relation a -> Bool@@ -170,9 +171,10 @@ -- Complexity: /O(1)/ time. -- -- @--- vertexCount 'empty'      == 0--- vertexCount ('vertex' x) == 1--- vertexCount            == 'length' . 'vertexList'+-- vertexCount 'empty'             ==  0+-- vertexCount ('vertex' x)        ==  1+-- vertexCount                   ==  'length' . 'vertexList'+-- vertexCount x \< vertexCount y ==> x \< y -- @ vertexCount :: Relation a -> Int vertexCount = Set.size . domain@@ -209,7 +211,7 @@ -- edgeList ('edge' x y)     == [(x,y)] -- edgeList ('star' 2 [3,1]) == [(2,1), (2,3)] -- edgeList . 'edges'        == 'Data.List.nub' . 'Data.List.sort'--- edgeList . 'transpose'    == 'Data.List.sort' . map 'Data.Tuple.swap' . edgeList+-- edgeList . 'transpose'    == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . edgeList -- @ edgeList :: Relation a -> [(a, a)] edgeList = Set.toAscList . relation@@ -221,24 +223,10 @@ -- vertexSet 'empty'      == Set.'Set.empty' -- vertexSet . 'vertex'   == Set.'Set.singleton' -- vertexSet . 'vertices' == Set.'Set.fromList'--- vertexSet . 'clique'   == Set.'Set.fromList' -- @ vertexSet :: Relation a -> Set.Set a vertexSet = domain --- | The set of vertices of a given graph. Like 'vertexSet' but specialised for--- graphs with vertices of type 'Int'.--- Complexity: /O(n)/ time.------ @--- vertexIntSet 'empty'      == IntSet.'IntSet.empty'--- vertexIntSet . 'vertex'   == IntSet.'IntSet.singleton'--- vertexIntSet . 'vertices' == IntSet.'IntSet.fromList'--- vertexIntSet . 'clique'   == IntSet.'IntSet.fromList'--- @-vertexIntSet :: Relation Int -> IntSet.IntSet-vertexIntSet = IntSet.fromAscList . vertexList- -- | The set of edges of a given graph. -- Complexity: /O(1)/ time. --@@ -382,7 +370,7 @@ -- stars [(x, [])]               == 'vertex' x -- stars [(x, [y])]              == 'edge' x y -- stars [(x, ys)]               == 'star' x ys--- stars                         == 'overlays' . map (uncurry 'star')+-- stars                         == 'overlays' . 'map' ('uncurry' 'star') -- stars . 'adjacencyList'         == id -- 'overlay' (stars xs) (stars ys) == stars (xs ++ ys) -- @@@ -413,7 +401,7 @@ -- forest []                                                  == 'empty' -- forest [x]                                                 == 'tree' x -- forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == 'edges' [(1,2), (1,3), (4,5)]--- forest                                                     == 'overlays' . map 'tree'+-- forest                                                     == 'overlays' . 'map' 'tree' -- @ forest :: Ord a => Tree.Forest a -> Relation a forest = overlays. map tree@@ -463,10 +451,10 @@ -- /O(1)/ to be evaluated. -- -- @--- mergeVertices (const False) x    == id+-- mergeVertices ('const' False) x    == id -- mergeVertices (== x) y           == 'replaceVertex' x y--- mergeVertices even 1 (0 * 2)     == 1 * 1--- mergeVertices odd  1 (3 + 4 * 5) == 4 * 1+-- mergeVertices 'even' 1 (0 * 2)     == 1 * 1+-- mergeVertices 'odd'  1 (3 + 4 * 5) == 4 * 1 -- @ mergeVertices :: Ord a => (a -> Bool) -> a -> Relation a -> Relation a mergeVertices p v = gmap $ \u -> if p u then v else u@@ -479,7 +467,7 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList'+-- 'edgeList' . transpose  == 'Data.List.sort' . 'map' 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: Ord a => Relation a -> Relation a transpose (Relation d r) = Relation d (Set.map swap r)@@ -505,8 +493,8 @@ -- be evaluated. -- -- @--- induce (const True ) x      == x--- induce (const False) x      == 'empty'+-- induce ('const' True ) x      == x+-- induce ('const' False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x) -- 'isSubgraphOf' (induce p x) x == True@@ -516,55 +504,85 @@   where     pp (x, y) = p x && p y --- | /Compose/ two relations: @R = 'compose' Q P@. Two elements @x@ and @y@ are--- related in the resulting relation, i.e. @xRy@, if there exists an element @z@,--- such that @xPz@ and @zQy@. This is an associative operation which has 'empty'--- as the /annihilating zero/.+-- | Left-to-right /relational composition/ of graphs: vertices @x@ and @z@ are+-- connected in the resulting graph if there is a vertex @y@, such that @x@ is+-- connected to @y@ in the first graph, and @y@ is connected to @z@ in the+-- second graph. There are no isolated vertices in the result. This operation is+-- associative, has 'empty' and single-'vertex' graphs as /annihilating zeroes/,+-- and distributes over 'overlay'. -- Complexity: /O(n * m * log(m))/ time and /O(n + m)/ memory. -- -- @ -- compose 'empty'            x                == 'empty' -- compose x                'empty'            == 'empty'+-- compose ('vertex' x)       y                == 'empty'+-- compose x                ('vertex' y)       == 'empty' -- compose x                (compose y z)    == compose (compose x y) z--- compose ('edge' y z)       ('edge' x y)       == 'edge' x z--- compose ('path'    [1..5]) ('path'    [1..5]) == 'edges' [(1,3),(2,4),(3,5)]+-- compose x                ('overlay' y z)    == 'overlay' (compose x y) (compose x z)+-- compose ('overlay' x y)    z                == 'overlay' (compose x z) (compose y z)+-- compose ('edge' x y)       ('edge' y z)       == 'edge' x z+-- compose ('path'    [1..5]) ('path'    [1..5]) == 'edges' [(1,3), (2,4), (3,5)] -- compose ('circuit' [1..5]) ('circuit' [1..5]) == 'circuit' [1,3,5,2,4] -- @ compose :: Ord a => Relation a -> Relation a -> Relation a compose x y = Relation (referredToVertexSet r) r   where     d = domain x `Set.union` domain y-    r = Set.unions [ preSet z y `setProduct` postSet z x | z <- Set.toAscList d ]+    r = Set.unions [ preSet v x `setProduct` postSet v y | v <- Set.toAscList d ] --- | Compute the /reflexive closure/ of a 'Relation'.+-- | Compute the /reflexive and transitive closure/ of a graph.+-- Complexity: /O(n * m * log(n) * log(m))/ time.+--+-- @+-- closure 'empty'           == 'empty'+-- closure ('vertex' x)      == 'edge' x x+-- closure ('edge' x x)      == 'edge' x x+-- closure ('edge' x y)      == 'edges' [(x,x), (x,y), (y,y)]+-- closure ('path' $ 'Data.List.nub' xs) == 'reflexiveClosure' ('clique' $ 'Data.List.nub' xs)+-- closure                 == 'reflexiveClosure' . 'transitiveClosure'+-- closure                 == 'transitiveClosure' . 'reflexiveClosure'+-- closure . closure       == closure+-- 'postSet' x (closure y)   == Set.'Set.fromList' ('Algebra.Graph.ToGraph.reachable' x y)+-- @+closure :: Ord a => Relation a -> Relation a+closure = reflexiveClosure . transitiveClosure++-- | Compute the /reflexive closure/ of a graph. -- Complexity: /O(n * log(m))/ time. -- -- @--- reflexiveClosure 'empty'      == 'empty'--- reflexiveClosure ('vertex' x) == 'edge' x x+-- reflexiveClosure 'empty'              == 'empty'+-- reflexiveClosure ('vertex' x)         == 'edge' x x+-- reflexiveClosure ('edge' x x)         == 'edge' x x+-- reflexiveClosure ('edge' x y)         == 'edges' [(x,x), (x,y), (y,y)]+-- reflexiveClosure . reflexiveClosure == reflexiveClosure -- @ reflexiveClosure :: Ord a => Relation a -> Relation a reflexiveClosure (Relation d r) =     Relation d $ r `Set.union` Set.fromDistinctAscList [ (a, a) | a <- Set.toAscList d ] --- | Compute the /symmetric closure/ of a 'Relation'.+-- | Compute the /symmetric closure/ of a graph. -- Complexity: /O(m * log(m))/ time. -- -- @--- symmetricClosure 'empty'      == 'empty'--- symmetricClosure ('vertex' x) == 'vertex' x--- symmetricClosure ('edge' x y) == 'edges' [(x, y), (y, x)]+-- symmetricClosure 'empty'              == 'empty'+-- symmetricClosure ('vertex' x)         == 'vertex' x+-- symmetricClosure ('edge' x y)         == 'edges' [(x,y), (y,x)]+-- symmetricClosure x                  == 'overlay' x ('transpose' x)+-- symmetricClosure . symmetricClosure == symmetricClosure -- @ symmetricClosure :: Ord a => Relation a -> Relation a symmetricClosure (Relation d r) = Relation d $ r `Set.union` Set.map swap r --- | Compute the /transitive closure/ of a 'Relation'.+-- | Compute the /transitive closure/ of a graph. -- Complexity: /O(n * m * log(n) * log(m))/ time. -- -- @--- transitiveClosure 'empty'           == 'empty'--- transitiveClosure ('vertex' x)      == 'vertex' x--- transitiveClosure ('path' $ 'Data.List.nub' xs) == 'clique' ('Data.List.nub' xs)+-- transitiveClosure 'empty'               == 'empty'+-- transitiveClosure ('vertex' x)          == 'vertex' x+-- transitiveClosure ('edge' x y)          == 'edge' x y+-- transitiveClosure ('path' $ 'Data.List.nub' xs)     == 'clique' ('Data.List.nub' xs)+-- transitiveClosure . transitiveClosure == transitiveClosure -- @ transitiveClosure :: Ord a => Relation a -> Relation a transitiveClosure old@@ -572,14 +590,3 @@     | otherwise  = transitiveClosure new   where     new = overlay old (old `compose` old)---- | Compute the /preorder closure/ of a 'Relation'.--- Complexity: /O(n * m * log(m))/ time.------ @--- preorderClosure 'empty'           == 'empty'--- preorderClosure ('vertex' x)      == 'edge' x x--- preorderClosure ('path' $ 'Data.List.nub' xs) == 'reflexiveClosure' ('clique' $ 'Data.List.nub' xs)--- @-preorderClosure :: Ord a => Relation a -> Relation a-preorderClosure = reflexiveClosure . transitiveClosure
src/Algebra/Graph/Relation/Internal.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation.Internal@@ -14,13 +15,15 @@     -- * Binary relation implementation     Relation (..), empty, vertex, overlay, connect, setProduct, consistent,     referredToVertexSet-  ) where+    ) where +import Control.DeepSeq (NFData, rnf)+import Data.Monoid (mconcat) import Data.Set (Set, union) -import qualified Data.Set as Set+import Algebra.Graph.Internal -import Control.DeepSeq (NFData, rnf)+import qualified Data.Set as Set  {-| The 'Relation' data type represents a graph as a /binary relation/. We define a 'Num' instance as a convenient notation for working with graphs:@@ -31,6 +34,14 @@     > 1 + 2 * 3   == overlay (vertex 1) (connect (vertex 2) (vertex 3))     > 1 * (2 + 3) == connect (vertex 1) (overlay (vertex 2) (vertex 3)) +__Note:__ the 'Num' instance does not satisfy several "customary laws" of 'Num',+which dictate that 'fromInteger' @0@ and 'fromInteger' @1@ should act as+additive and multiplicative identities, and 'negate' as additive inverse.+Nevertheless, overloading 'fromInteger', '+' and '*' is very convenient when+working with algebraic graphs; we hope that in future Haskell's Prelude will+provide a more fine-grained class hierarchy for algebraic structures, which we+would be able to utilise without violating any laws.+ The 'Show' instance is defined using basic graph construction primitives:  @show (empty     :: Relation Int) == "empty"@@ -80,6 +91,31 @@  When specifying the time and memory complexity of graph algorithms, /n/ and /m/ will denote the number of vertices and edges in the graph, respectively.++The total order on graphs is defined using /size-lexicographic/ comparison:++* Compare the number of vertices. In case of a tie, continue.+* Compare the sets of vertices. In case of a tie, continue.+* Compare the number of edges. In case of a tie, continue.+* Compare the sets of edges.++Here are a few examples:++@'vertex' 1 < 'vertex' 2+'vertex' 3 < 'Algebra.Graph.AdjacencyMap.edge' 1 2+'vertex' 1 < 'Algebra.Graph.AdjacencyMap.edge' 1 1+'Algebra.Graph.AdjacencyMap.edge' 1 1 < 'Algebra.Graph.AdjacencyMap.edge' 1 2+'Algebra.Graph.AdjacencyMap.edge' 1 2 < 'Algebra.Graph.AdjacencyMap.edge' 1 1 + 'Algebra.Graph.AdjacencyMap.edge' 2 2+'Algebra.Graph.AdjacencyMap.edge' 1 2 < 'Algebra.Graph.AdjacencyMap.edge' 1 3@++Note that the resulting order refines the 'isSubgraphOf' relation and is+compatible with 'overlay' and 'connect' operations:++@'Algebra.Graph.AdjacencyMap.isSubgraphOf' x y ==> x <= y@++@'empty' <= x+x     <= x + y+x + y <= x * y@ -} data Relation a = Relation {     -- | The /domain/ of the relation.@@ -90,19 +126,30 @@   } deriving Eq  instance (Ord a, Show a) => Show (Relation a) where-    show (Relation d r)-        | Set.null d = "empty"-        | Set.null r = vshow (Set.toAscList d)-        | d == used  = eshow (Set.toAscList r)-        | otherwise  = "overlay (" ++ vshow (Set.toAscList $ Set.difference d used)-                    ++ ") (" ++ eshow (Set.toAscList r) ++ ")"+    showsPrec p (Relation d r)+        | Set.null d = showString "empty"+        | Set.null r = showParen (p > 10) $ vshow (Set.toAscList d)+        | d == used  = showParen (p > 10) $ eshow (Set.toAscList r)+        | otherwise  = showParen (p > 10) $+                           showString "overlay (" .+                           vshow (Set.toAscList $ Set.difference d used) .+                           showString ") (" . eshow (Set.toAscList r) .+                           showString ")"       where-        vshow [x]      = "vertex "   ++ show x-        vshow xs       = "vertices " ++ show xs-        eshow [(x, y)] = "edge "     ++ show x ++ " " ++ show y-        eshow xs       = "edges "    ++ show xs+        vshow [x]      = showString "vertex "   . showsPrec 11 x+        vshow xs       = showString "vertices " . showsPrec 11 xs+        eshow [(x, y)] = showString "edge "     . showsPrec 11 x .+                         showString " "         . showsPrec 11 y+        eshow xs       = showString "edges "    . showsPrec 11 xs         used           = referredToVertexSet r +instance Ord a => Ord (Relation a) where+    compare x y = mconcat+        [ compare (Set.size $ domain   x) (Set.size $ domain   y)+        , compare (           domain   x) (           domain   y)+        , compare (Set.size $ relation x) (Set.size $ relation y)+        , compare (           relation x) (           relation y) ]+ -- | Construct the /empty graph/. -- Complexity: /O(1)/ time and memory. --@@ -169,10 +216,8 @@ instance NFData a => NFData (Relation a) where     rnf (Relation d r) = rnf d `seq` rnf r `seq` () --- | Compute the Cartesian product of two sets. /Note: this function is for internal use only/.-setProduct :: Set a -> Set b -> Set (a, b)-setProduct x y = Set.fromDistinctAscList [ (a, b) | a <- Set.toAscList x, b <- Set.toAscList y ]-+-- | __Note:__ this does not satisfy the usual ring laws; see 'Relation' for+-- more details. instance (Ord a, Num a) => Num (Relation a) where     fromInteger = vertex . fromInteger     (+)         = overlay
src/Algebra/Graph/Relation/InternalDerived.hs view
@@ -23,7 +23,7 @@  import Algebra.Graph.Class import Algebra.Graph.Relation (Relation, reflexiveClosure, symmetricClosure,-                               transitiveClosure, preorderClosure)+                               transitiveClosure, closure)  {-| The 'ReflexiveRelation' data type represents a /reflexive binary relation/ over a set of elements. Reflexive relations satisfy all laws of the@@ -146,10 +146,10 @@     deriving (Num, NFData)  instance (Ord a, Show a) => Show (PreorderRelation a) where-    show = show . preorderClosure . fromPreorder+    show = show . closure . fromPreorder  instance Ord a => Eq (PreorderRelation a) where-    x == y = preorderClosure (fromPreorder x) == preorderClosure (fromPreorder y)+    x == y = closure (fromPreorder x) == closure (fromPreorder y)  -- TODO: To be derived automatically using GeneralizedNewtypeDeriving in GHC 8.2 instance Ord a => Graph (PreorderRelation a) where
src/Algebra/Graph/Relation/Preorder.hs view
@@ -25,4 +25,4 @@ -- | Extract the underlying relation. -- Complexity: /O(n * m * log(m))/ time. toRelation :: Ord a => PreorderRelation a -> Relation a-toRelation = preorderClosure . fromPreorder+toRelation = closure . fromPreorder
src/Algebra/Graph/ToGraph.hs view
@@ -14,36 +14,66 @@ -- This module defines the type class 'ToGraph' for capturing data types that -- can be converted to algebraic graphs. To make an instance of this class you -- need to define just a single method ('toGraph' or 'foldg'), which gives you--- access to many other useful methods for free. This type class is similar to--- the standard "Data.Foldable" defined for lists.+-- access to many other useful methods for free (although note that the default+-- implementations may be suboptimal performance-wise). --+-- This type class is similar to the standard type class 'Data.Foldable.Foldable'+-- defined for lists. Furthermore, one can define 'Foldable' methods 'foldMap'+-- and 'Data.Foldable.toList' using @ToGraph@.'foldg':+--+-- @+-- 'foldMap' f = 'foldg' 'mempty' f    ('<>') ('<>')+-- 'Data.Foldable.toList'    = 'foldg' []     'pure' ('++') ('++')+-- @+--+-- However, the resulting 'Foldable' instance is problematic. For example,+-- folding equivalent algebraic graphs @1@ and @1@ + @1@ leads to different+-- results:+--+-- @+-- 'Data.Foldable.toList' (1    ) == [1]+-- 'Data.Foldable.toList' (1 + 1) == [1, 1]+-- @+--+-- To avoid such cases, we do not provide 'Foldable' instances for algebraic+-- graph datatypes. Furthermore, we require that the four arguments passed to+-- 'foldg' satisfy the laws of the algebra of graphs. The above definitions+-- of 'foldMap' and 'Data.Foldable.toList' violate this requirement, for example+-- @[1] ++ [1] /= [1]@, and are therefore disallowed. ----------------------------------------------------------------------------- module Algebra.Graph.ToGraph (ToGraph (..)) where  import Prelude () import Prelude.Compat- import Data.IntMap (IntMap) import Data.IntSet (IntSet) import Data.Map    (Map) import Data.Set    (Set) import Data.Tree -import qualified Algebra.Graph                          as G-import qualified Algebra.Graph.AdjacencyMap             as AM-import qualified Algebra.Graph.AdjacencyMap.Internal    as AM-import qualified Algebra.Graph.AdjacencyIntMap          as AIM-import qualified Algebra.Graph.AdjacencyIntMap.Internal as AIM-import qualified Algebra.Graph.Relation                 as R-import qualified Data.IntMap                            as IntMap-import qualified Data.IntSet                            as IntSet-import qualified Data.Map                               as Map-import qualified Data.Set                               as Set+import qualified Algebra.Graph                                as G+import qualified Algebra.Graph.AdjacencyMap                   as AM+import qualified Algebra.Graph.AdjacencyMap.Algorithm         as AM+import qualified Algebra.Graph.AdjacencyMap.Internal          as AM+import qualified Algebra.Graph.Labelled                       as LG+import qualified Algebra.Graph.Labelled.AdjacencyMap          as LAM+import qualified Algebra.Graph.NonEmpty.AdjacencyMap          as NAM+import qualified Algebra.Graph.NonEmpty.AdjacencyMap.Internal as NAM+import qualified Algebra.Graph.AdjacencyIntMap                as AIM+import qualified Algebra.Graph.AdjacencyIntMap.Algorithm      as AIM+import qualified Algebra.Graph.AdjacencyIntMap.Internal       as AIM+import qualified Algebra.Graph.Relation                       as R+import qualified Data.IntMap                                  as IntMap+import qualified Data.IntSet                                  as IntSet+import qualified Data.Map                                     as Map+import qualified Data.Set                                     as Set  -- | The 'ToGraph' type class captures data types that can be converted to--- algebraic graphs.+-- algebraic graphs. Instances of this type class should satisfy the laws+-- specified by the default method definitions. class ToGraph t where     {-# MINIMAL toGraph | foldg #-}+    -- | The type of vertices of the resulting graph.     type ToVertex t      -- | Convert a value to the corresponding algebraic graph, see "Algebra.Graph".@@ -68,7 +98,7 @@     -- | Check if a graph is empty.     --     -- @-    -- isEmpty == 'foldg' True (const False) (&&) (&&)+    -- isEmpty == 'foldg' True ('const' False) (&&) (&&)     -- @     isEmpty :: t -> Bool     isEmpty = foldg True (const False) (&&) (&&)@@ -76,8 +106,12 @@     -- | The /size/ of a graph, i.e. the number of leaves of the expression     -- including 'empty' leaves.     --+    -- __Note:__ The default implementation of this function violates the+    -- requirement that the four arguments of 'foldg' should satisfy the laws+    -- of algebraic graphs, since @1 + 1 /= 1@. Use this function with care.+    --     -- @-    -- size == 'foldg' 1 (const 1) (+) (+)+    -- size == 'foldg' 1 ('const' 1) (+) (+)     -- @     size :: t -> Int     size = foldg 1 (const 1) (+) (+)@@ -304,7 +338,7 @@     -- result.     --     -- @-    -- toAdjacencyMapTranspose == 'foldg' 'AM.empty' 'AM.vertex' 'AM.overlay' (flip 'AM.connect')+    -- toAdjacencyMapTranspose == 'foldg' 'AM.empty' 'AM.vertex' 'AM.overlay' ('flip' 'AM.connect')     -- @     toAdjacencyMapTranspose :: Ord (ToVertex t) => t -> AM.AdjacencyMap (ToVertex t)     toAdjacencyMapTranspose = foldg AM.empty AM.vertex AM.overlay (flip AM.connect)@@ -321,7 +355,7 @@     -- the result.     --     -- @-    -- toAdjacencyIntMapTranspose == 'foldg' 'AIM.empty' 'AIM.vertex' 'AIM.overlay' (flip 'AIM.connect')+    -- toAdjacencyIntMapTranspose == 'foldg' 'AIM.empty' 'AIM.vertex' 'AIM.overlay' ('flip' 'AIM.connect')     -- @     toAdjacencyIntMapTranspose :: ToVertex t ~ Int => t -> AIM.AdjacencyIntMap     toAdjacencyIntMapTranspose = foldg AIM.empty AIM.vertex AIM.overlay (flip AIM.connect)@@ -350,6 +384,7 @@     foldg   = G.foldg     hasEdge = G.hasEdge +-- | See "Algebra.Graph.AdjacencyMap". instance Ord a => ToGraph (AM.AdjacencyMap a) where     type ToVertex (AM.AdjacencyMap a) = a     toGraph                    = G.stars@@ -363,7 +398,7 @@     edgeCount                  = AM.edgeCount     vertexList                 = AM.vertexList     vertexSet                  = AM.vertexSet-    vertexIntSet               = AM.vertexIntSet+    vertexIntSet               = IntSet.fromAscList . AM.vertexList     edgeList                   = AM.edgeList     edgeSet                    = AM.edgeSet     adjacencyList              = AM.adjacencyList@@ -424,6 +459,74 @@     isDfsForestOf              = AIM.isDfsForestOf     isTopSortOf                = AIM.isTopSortOf +-- | See "Algebra.Graph.Labelled".+instance (Eq e, Monoid e, Ord a) => ToGraph (LG.Graph e a) where+    type ToVertex (LG.Graph e a) = a+    foldg e v o c              = LG.foldg e v (\e -> if e == mempty then o else c)+    vertexList                 = LG.vertexList+    vertexSet                  = LG.vertexSet+    toAdjacencyMap             = LAM.skeleton+                               . LG.foldg LAM.empty LAM.vertex LAM.connect+    toAdjacencyMapTranspose    = LAM.skeleton+                               . LG.foldg LAM.empty LAM.vertex (fmap flip LAM.connect)+    toAdjacencyIntMap          = toAdjacencyIntMap . toAdjacencyMap+    toAdjacencyIntMapTranspose = toAdjacencyIntMapTranspose . toAdjacencyMapTranspose++-- | See "Algebra.Graph.Labelled.AdjacencyMap".+instance (Eq e, Monoid e, Ord a) => ToGraph (LAM.AdjacencyMap e a) where+    type ToVertex (LAM.AdjacencyMap e a) = a+    toGraph                    = toGraph . LAM.skeleton+    foldg e v o c              = foldg e v o c . LAM.skeleton+    isEmpty                    = LAM.isEmpty+    hasVertex                  = LAM.hasVertex+    hasEdge                    = LAM.hasEdge+    vertexCount                = LAM.vertexCount+    edgeCount                  = LAM.edgeCount+    vertexList                 = LAM.vertexList+    vertexSet                  = LAM.vertexSet+    vertexIntSet               = IntSet.fromAscList . LAM.vertexList+    edgeList                   = edgeList . LAM.skeleton+    edgeSet                    = edgeSet . LAM.skeleton+    adjacencyList              = adjacencyList . LAM.skeleton+    preSet                     = LAM.preSet+    postSet                    = LAM.postSet+    toAdjacencyMap             = LAM.skeleton+    toAdjacencyIntMap          = toAdjacencyIntMap . LAM.skeleton+    toAdjacencyMapTranspose    = toAdjacencyMapTranspose . LAM.skeleton+    toAdjacencyIntMapTranspose = toAdjacencyIntMapTranspose . LAM.skeleton++-- | See "Algebra.Graph.NonEmpty.AdjacencyMap".+instance Ord a => ToGraph (NAM.AdjacencyMap a) where+    type ToVertex (NAM.AdjacencyMap a) = a+    toGraph                    = toGraph . NAM.am+    isEmpty _                  = False+    hasVertex                  = NAM.hasVertex+    hasEdge                    = NAM.hasEdge+    vertexCount                = NAM.vertexCount+    edgeCount                  = NAM.edgeCount+    vertexList                 = vertexList . NAM.am+    vertexSet                  = NAM.vertexSet+    vertexIntSet               = vertexIntSet . NAM.am+    edgeList                   = NAM.edgeList+    edgeSet                    = NAM.edgeSet+    adjacencyList              = adjacencyList . NAM.am+    preSet                     = NAM.preSet+    postSet                    = NAM.postSet+    adjacencyMap               = adjacencyMap . NAM.am+    adjacencyIntMap            = adjacencyIntMap . NAM.am+    dfsForest                  = dfsForest . NAM.am+    dfsForestFrom xs           = dfsForestFrom xs . NAM.am+    dfs xs                     = dfs xs . NAM.am+    reachable x                = reachable x . NAM.am+    topSort                    = topSort . NAM.am+    isAcyclic                  = isAcyclic . NAM.am+    toAdjacencyMap             = NAM.am+    toAdjacencyIntMap          = toAdjacencyIntMap . NAM.am+    toAdjacencyMapTranspose    = NAM.am . NAM.transpose+    toAdjacencyIntMapTranspose = toAdjacencyIntMap . NAM.transpose+    isDfsForestOf f            = isDfsForestOf f . NAM.am+    isTopSortOf x              = isTopSortOf x . NAM.am+ -- TODO: Get rid of "Relation.Internal" and move this instance to "Relation". instance Ord a => ToGraph (R.Relation a) where     type ToVertex (R.Relation a) = a@@ -436,7 +539,7 @@     edgeCount                  = R.edgeCount     vertexList                 = R.vertexList     vertexSet                  = R.vertexSet-    vertexIntSet               = R.vertexIntSet+    vertexIntSet               = IntSet.fromAscList . R.vertexList     edgeList                   = R.edgeList     edgeSet                    = R.edgeSet     adjacencyList              = R.adjacencyList
src/Data/Graph/Typed.hs view
@@ -96,7 +96,7 @@ -- 'Algebra.Graph.AdjacencyMap.forest' (dfsForest % 'Algebra.Graph.AdjacencyMap.edge' 2 1)           == 'AM.vertices' [1, 2] -- 'AM.isSubgraphOf' ('Algebra.Graph.AdjacencyMap.forest' $ dfsForest % x) x == True -- dfsForest % 'Algebra.Graph.AdjacencyMap.forest' (dfsForest % x)      == dfsForest % x--- dfsForest % 'AM.vertices' vs                 == map (\\v -> Node v []) ('Data.List.nub' $ 'Data.List.sort' vs)+-- dfsForest % 'AM.vertices' vs                 == 'map' (\\v -> Node v []) ('Data.List.nub' $ 'Data.List.sort' vs) -- 'Algebra.Graph.AdjacencyMap.dfsForestFrom' ('Algebra.Graph.AdjacencyMap.vertexList' x) % x        == dfsForest % x -- dfsForest % (3 * (1 + 4) * (1 + 5))     == [ Node { rootLabel = 1 --                                                   , subForest = [ Node { rootLabel = 5@@ -120,7 +120,7 @@ -- 'Algebra.Graph.AdjacencyMap.forest' (dfsForestFrom [2, 1] % 'Algebra.Graph.AdjacencyMap.edge' 1 2)       == 'Algebra.Graph.AdjacencyMap.vertices' [1, 2] -- 'Algebra.Graph.AdjacencyMap.isSubgraphOf' ('Algebra.Graph.AdjacencyMap.forest' $ dfsForestFrom vs % x) x == True -- dfsForestFrom ('Algebra.Graph.AdjacencyMap.vertexList' x) % x               == 'dfsForest' % x--- dfsForestFrom vs               % 'Algebra.Graph.AdjacencyMap.vertices' vs   == map (\\v -> Node v []) ('Data.List.nub' vs)+-- dfsForestFrom vs               % 'Algebra.Graph.AdjacencyMap.vertices' vs   == 'map' (\\v -> Node v []) ('Data.List.nub' vs) -- dfsForestFrom []               % x             == [] -- dfsForestFrom [1, 4] % (3 * (1 + 4) * (1 + 5)) == [ Node { rootLabel = 1 --                                                          , subForest = [ Node { rootLabel = 5
test/Algebra/Graph/Test.hs view
@@ -11,7 +11,7 @@  import Data.List (sort) import Data.List.Extra (nubOrd)-import Prelude hiding ((+), (*), (<=))+import Prelude hiding ((+), (*)) import System.Exit (exitFailure) import Test.QuickCheck hiding ((===)) import Test.QuickCheck.Function@@ -36,14 +36,10 @@ (*) :: Graph g => g -> g -> g (*) = connect -(<=) :: (Eq g, Graph g) => g -> g -> Bool-(<=) = isSubgraphOf- (//) :: Testable prop => prop -> String -> Property p // s = label s $ counterexample ("Failed when checking '" ++ s ++ "'") p  infixl 1 //-infixl 4 <= infixl 6 + infixl 7 * @@ -60,7 +56,7 @@     , (x + y) * z == x * z + y * z              // "Right distributivity"     ,   x * y * z == x * y + x * z + y * z      // "Decomposition" ] -theorems :: (Eq g, Graph g) => GraphTestsuite g+theorems :: (Ord g, Graph g) => GraphTestsuite g theorems x y z = conjoin     [     x + empty == x                        // "Overlay identity"     ,         x + x == x                        // "Overlay idempotence"
test/Algebra/Graph/Test/API.hs view
@@ -14,20 +14,21 @@     GraphAPI (..)   ) where +import Data.Monoid (Any) import Data.Tree  import Algebra.Graph.Class (Graph (..)) -import qualified Algebra.Graph                          as Graph-import qualified Algebra.Graph.AdjacencyMap             as AdjacencyMap-import qualified Algebra.Graph.AdjacencyMap.Internal    as AdjacencyMap-import qualified Algebra.Graph.Fold                     as Fold-import qualified Algebra.Graph.HigherKinded.Class       as HClass-import qualified Algebra.Graph.AdjacencyIntMap          as AdjacencyIntMap-import qualified Algebra.Graph.AdjacencyIntMap.Internal as AdjacencyIntMap-import qualified Algebra.Graph.Relation                 as Relation-import qualified Data.Set                               as Set-import qualified Data.IntSet                            as IntSet+import qualified Algebra.Graph                       as Graph+import qualified Algebra.Graph.AdjacencyMap          as AM+import qualified Algebra.Graph.Labelled              as LG+import qualified Algebra.Graph.Labelled.AdjacencyMap as LAM+import qualified Algebra.Graph.Fold                  as Fold+import qualified Algebra.Graph.HigherKinded.Class    as HClass+import qualified Algebra.Graph.AdjacencyIntMap       as AIM+import qualified Algebra.Graph.Relation              as R+import qualified Data.Set                            as Set+import qualified Data.IntSet                         as IntSet  class Graph g => GraphAPI g where     edge                 :: Vertex g -> Vertex g -> g@@ -86,6 +87,16 @@     gmap                 = notImplemented     induce               :: (Vertex g -> Bool) -> g -> g     induce               = notImplemented+    compose              :: g -> g -> g+    compose              = notImplemented+    closure              :: g -> g+    closure              = notImplemented+    reflexiveClosure     :: g -> g+    reflexiveClosure     = notImplemented+    symmetricClosure     :: g -> g+    symmetricClosure     = notImplemented+    transitiveClosure    :: g -> g+    transitiveClosure    = notImplemented     bind                 :: Vertex g ~ Int => g -> (Int -> g) -> g     bind                 = notImplemented     simplify             :: g -> g@@ -96,29 +107,34 @@ notImplemented :: a notImplemented = error "Not implemented" -instance Ord a => GraphAPI (AdjacencyMap.AdjacencyMap a) where-    edge              = AdjacencyMap.edge-    vertices          = AdjacencyMap.vertices-    edges             = AdjacencyMap.edges-    overlays          = AdjacencyMap.overlays-    connects          = AdjacencyMap.connects-    fromAdjacencySets = AdjacencyMap.fromAdjacencySets-    isSubgraphOf      = AdjacencyMap.isSubgraphOf-    path              = AdjacencyMap.path-    circuit           = AdjacencyMap.circuit-    clique            = AdjacencyMap.clique-    biclique          = AdjacencyMap.biclique-    star              = AdjacencyMap.star-    stars             = AdjacencyMap.stars-    tree              = AdjacencyMap.tree-    forest            = AdjacencyMap.forest-    removeVertex      = AdjacencyMap.removeVertex-    removeEdge        = AdjacencyMap.removeEdge-    replaceVertex     = AdjacencyMap.replaceVertex-    mergeVertices     = AdjacencyMap.mergeVertices-    transpose         = AdjacencyMap.transpose-    gmap              = AdjacencyMap.gmap-    induce            = AdjacencyMap.induce+instance Ord a => GraphAPI (AM.AdjacencyMap a) where+    edge              = AM.edge+    vertices          = AM.vertices+    edges             = AM.edges+    overlays          = AM.overlays+    connects          = AM.connects+    fromAdjacencySets = AM.fromAdjacencySets+    isSubgraphOf      = AM.isSubgraphOf+    path              = AM.path+    circuit           = AM.circuit+    clique            = AM.clique+    biclique          = AM.biclique+    star              = AM.star+    stars             = AM.stars+    tree              = AM.tree+    forest            = AM.forest+    removeVertex      = AM.removeVertex+    removeEdge        = AM.removeEdge+    replaceVertex     = AM.replaceVertex+    mergeVertices     = AM.mergeVertices+    transpose         = AM.transpose+    gmap              = AM.gmap+    induce            = AM.induce+    compose           = AM.compose+    closure           = AM.closure+    reflexiveClosure  = AM.reflexiveClosure+    symmetricClosure  = AM.symmetricClosure+    transitiveClosure = AM.transitiveClosure  instance Ord a => GraphAPI (Fold.Fold a) where     edge          = Fold.edge@@ -148,7 +164,6 @@     induce        = Fold.induce     bind          = (>>=)     simplify      = Fold.simplify-    box           = HClass.box  instance Ord a => GraphAPI (Graph.Graph a) where     edge          = Graph.edge@@ -177,53 +192,78 @@     transpose     = Graph.transpose     gmap          = fmap     induce        = Graph.induce+    compose       = Graph.compose     bind          = (>>=)     simplify      = Graph.simplify     box           = Graph.box -instance GraphAPI AdjacencyIntMap.AdjacencyIntMap where-    edge                 = AdjacencyIntMap.edge-    vertices             = AdjacencyIntMap.vertices-    edges                = AdjacencyIntMap.edges-    overlays             = AdjacencyIntMap.overlays-    connects             = AdjacencyIntMap.connects-    fromAdjacencyIntSets = AdjacencyIntMap.fromAdjacencyIntSets-    isSubgraphOf         = AdjacencyIntMap.isSubgraphOf-    path                 = AdjacencyIntMap.path-    circuit              = AdjacencyIntMap.circuit-    clique               = AdjacencyIntMap.clique-    biclique             = AdjacencyIntMap.biclique-    star                 = AdjacencyIntMap.star-    stars                = AdjacencyIntMap.stars-    tree                 = AdjacencyIntMap.tree-    forest               = AdjacencyIntMap.forest-    removeVertex         = AdjacencyIntMap.removeVertex-    removeEdge           = AdjacencyIntMap.removeEdge-    replaceVertex        = AdjacencyIntMap.replaceVertex-    mergeVertices        = AdjacencyIntMap.mergeVertices-    transpose            = AdjacencyIntMap.transpose-    gmap                 = AdjacencyIntMap.gmap-    induce               = AdjacencyIntMap.induce+instance GraphAPI AIM.AdjacencyIntMap where+    edge                 = AIM.edge+    vertices             = AIM.vertices+    edges                = AIM.edges+    overlays             = AIM.overlays+    connects             = AIM.connects+    fromAdjacencyIntSets = AIM.fromAdjacencyIntSets+    isSubgraphOf         = AIM.isSubgraphOf+    path                 = AIM.path+    circuit              = AIM.circuit+    clique               = AIM.clique+    biclique             = AIM.biclique+    star                 = AIM.star+    stars                = AIM.stars+    tree                 = AIM.tree+    forest               = AIM.forest+    removeVertex         = AIM.removeVertex+    removeEdge           = AIM.removeEdge+    replaceVertex        = AIM.replaceVertex+    mergeVertices        = AIM.mergeVertices+    transpose            = AIM.transpose+    gmap                 = AIM.gmap+    induce               = AIM.induce+    compose              = AIM.compose+    closure              = AIM.closure+    reflexiveClosure     = AIM.reflexiveClosure+    symmetricClosure     = AIM.symmetricClosure+    transitiveClosure    = AIM.transitiveClosure -instance Ord a => GraphAPI (Relation.Relation a) where-    edge          = Relation.edge-    vertices      = Relation.vertices-    edges         = Relation.edges-    overlays      = Relation.overlays-    connects      = Relation.connects-    isSubgraphOf  = Relation.isSubgraphOf-    path          = Relation.path-    circuit       = Relation.circuit-    clique        = Relation.clique-    biclique      = Relation.biclique-    star          = Relation.star-    stars         = Relation.stars-    tree          = Relation.tree-    forest        = Relation.forest-    removeVertex  = Relation.removeVertex-    removeEdge    = Relation.removeEdge-    replaceVertex = Relation.replaceVertex-    mergeVertices = Relation.mergeVertices-    transpose     = Relation.transpose-    gmap          = Relation.gmap-    induce        = Relation.induce+instance Ord a => GraphAPI (R.Relation a) where+    edge              = R.edge+    vertices          = R.vertices+    edges             = R.edges+    overlays          = R.overlays+    connects          = R.connects+    isSubgraphOf      = R.isSubgraphOf+    path              = R.path+    circuit           = R.circuit+    clique            = R.clique+    biclique          = R.biclique+    star              = R.star+    stars             = R.stars+    tree              = R.tree+    forest            = R.forest+    removeVertex      = R.removeVertex+    removeEdge        = R.removeEdge+    replaceVertex     = R.replaceVertex+    mergeVertices     = R.mergeVertices+    transpose         = R.transpose+    gmap              = R.gmap+    induce            = R.induce+    compose           = R.compose+    closure           = R.closure+    reflexiveClosure  = R.reflexiveClosure+    symmetricClosure  = R.symmetricClosure+    transitiveClosure = R.transitiveClosure++instance Ord a => GraphAPI (LG.Graph Any a) where+    vertices     = LG.vertices+    overlays     = LG.overlays+    isSubgraphOf = LG.isSubgraphOf+    removeVertex = LG.removeVertex+    induce       = LG.induce++instance Ord a => GraphAPI (LAM.AdjacencyMap Any a) where+    vertices     = LAM.vertices+    overlays     = LAM.overlays+    isSubgraphOf = LAM.isSubgraphOf+    removeVertex = LAM.removeVertex+    induce       = LAM.induce
test/Algebra/Graph/Test/AdjacencyIntMap.hs view
@@ -36,6 +36,7 @@     testToGraph              t     testGraphFamilies        t     testTransformations      t+    testRelational           t     testDfsForest            t     testDfsForestFrom        t     testDfs                  t
test/Algebra/Graph/Test/AdjacencyMap.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedLists #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.AdjacencyMap@@ -13,12 +14,15 @@     testAdjacencyMap   ) where +import Data.List.NonEmpty+ import Algebra.Graph.AdjacencyMap+import Algebra.Graph.AdjacencyMap.Algorithm import Algebra.Graph.AdjacencyMap.Internal import Algebra.Graph.Test import Algebra.Graph.Test.Generic -import qualified Data.Set   as Set+import qualified Algebra.Graph.NonEmpty.AdjacencyMap as NonEmpty  t :: Testsuite t = testsuite "AdjacencyMap." empty@@ -40,6 +44,7 @@     testToGraph           t     testGraphFamilies     t     testTransformations   t+    testRelational        t     testDfsForest         t     testDfsForestFrom     t     testDfs               t@@ -51,19 +56,27 @@      putStrLn "\n============ AdjacencyMap.scc ============"     test "scc empty               == empty" $-          scc(empty :: AI)        == empty+          scc (empty :: AI)       == empty -    test "scc (vertex x)          == vertex (Set.singleton x)" $ \(x :: Int) ->-          scc (vertex x)          == vertex (Set.singleton x)+    test "scc (vertex x)          == vertex (NonEmpty.vertex x)" $ \(x :: Int) ->+          scc (vertex x)          == vertex (NonEmpty.vertex x) -    test "scc (edge x y)          == edge (Set.singleton x) (Set.singleton y)" $ \(x :: Int) y ->-          scc (edge x y)          == edge (Set.singleton x) (Set.singleton y)+    test "scc (edge 1 1)          == vertex (NonEmpty.edge 1 1)" $+          scc (edge 1 1 :: AI)    == vertex (NonEmpty.edge 1 1) -    test "scc (circuit (1:xs))    == edge (Set.fromList (1:xs)) (Set.fromList (1:xs))" $ \(xs :: [Int]) ->-          scc (circuit (1:xs))    == edge (Set.fromList (1:xs)) (Set.fromList (1:xs))+    test "scc (edge 1 2)          == edge   (NonEmpty.vertex 1) (NonEmpty.vertex 2)" $+          scc (edge 1 2 :: AI)    == edge   (NonEmpty.vertex 1) (NonEmpty.vertex 2) +    test "scc (circuit (1:xs))    == vertex (NonEmpty.circuit1 (1 :| xs))" $ \(xs :: [Int]) ->+          scc (circuit (1:xs))    == vertex (NonEmpty.circuit1 (1 :| xs))+     test "scc (3 * 1 * 4 * 1 * 5) == <correct result>" $-          scc (3 * 1 * 4 * 1 * 5) == edges [ (Set.fromList [1,4], Set.fromList [1,4])-                                           , (Set.fromList [1,4], Set.fromList [5]  )-                                           , (Set.fromList [3]  , Set.fromList [1,4])-                                           , (Set.fromList [3]  , Set.fromList [5 :: Int])]+          scc (3 * 1 * 4 * 1 * 5) == edges [ (NonEmpty.vertex 3       , NonEmpty.vertex  5      )+                                           , (NonEmpty.vertex 3       , NonEmpty.clique1 [1,4,1])+                                           , (NonEmpty.clique1 [1,4,1], NonEmpty.vertex  (5 :: Int)) ]++    test "isAcyclic . scc == const True" $ \(x :: AI) ->+          (isAcyclic . scc) x == (const True) x++    test "isAcyclic x     == (scc x == gmap NonEmpty.vertex x)" $ \(x :: AI) ->+          isAcyclic x     == (scc x == gmap NonEmpty.vertex x)
test/Algebra/Graph/Test/Arbitrary.hs view
@@ -18,24 +18,29 @@ import Prelude.Compat  import Control.Monad+import Data.List.NonEmpty (NonEmpty (..)) import Data.Tree import Test.QuickCheck  import Algebra.Graph import Algebra.Graph.AdjacencyMap.Internal+import Algebra.Graph.AdjacencyIntMap.Internal import Algebra.Graph.Export import Algebra.Graph.Fold (Fold)-import Algebra.Graph.AdjacencyIntMap.Internal+import Algebra.Graph.Label 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+import qualified Algebra.Graph.AdjacencyIntMap       as AdjacencyIntMap+import qualified Algebra.Graph.AdjacencyMap          as AdjacencyMap+import qualified Algebra.Graph.NonEmpty.AdjacencyMap as NAM+import qualified Algebra.Graph.Class                 as C+import qualified Algebra.Graph.Labelled              as LG+import qualified Algebra.Graph.Labelled.AdjacencyMap as LAM+import qualified Algebra.Graph.NonEmpty              as NonEmpty+import qualified Algebra.Graph.Relation              as Relation --- | Generate an arbitrary 'Graph' value of a specified size.+-- | Generate an arbitrary 'C.Graph' value of a specified size. arbitraryGraph :: (C.Graph g, Arbitrary (C.Vertex g)) => Gen g arbitraryGraph = sized expr   where@@ -56,40 +61,34 @@     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)+-- TODO: Implement a custom shrink method.+instance Arbitrary a => Arbitrary (Fold a) where+    arbitrary = arbitraryGraph++-- | Generate an arbitrary 'NonEmpty.Graph' value of a specified size.+arbitraryNonEmptyGraph :: Arbitrary a => Gen (NonEmpty.Graph 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 0 = NonEmpty.vertex <$> arbitrary -- can't generate non-empty graph of size 0+    expr 1 = NonEmpty.vertex <$> arbitrary     expr n = do         left <- choose (1, n)-        oneof [ NE.overlay <$> expr left <*> expr (n - left)-              , NE.connect <$> expr left <*> expr (n - left) ]+        oneof [ NonEmpty.overlay <$> expr left <*> expr (n - left)+              , NonEmpty.connect <$> expr left <*> expr (n - left) ] -instance Arbitrary a => Arbitrary (NE.NonEmptyGraph a) where+instance Arbitrary a => Arbitrary (NonEmpty.Graph 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) ]+    shrink (NonEmpty.Vertex    _) = []+    shrink (NonEmpty.Overlay x y) = [x, y]+        ++ [NonEmpty.Overlay x' y' | (x', y') <- shrink (x, y) ]+    shrink (NonEmpty.Connect x y) = [x, y, NonEmpty.Overlay x y]+        ++ [NonEmpty.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@@ -106,15 +105,70 @@ instance (Arbitrary a, Ord a) => Arbitrary (PreorderRelation a) where     arbitrary = PreorderRelation <$> arbitraryRelation +-- | 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++-- TODO: Implement a custom shrink method. instance (Arbitrary a, Ord a) => Arbitrary (AdjacencyMap a) where     arbitrary = arbitraryAdjacencyMap +-- | Generate an arbitrary non-empty 'NAM.AdjacencyMap'. It is guaranteed that+-- the resulting adjacency map is 'consistent'.+arbitraryNonEmptyAdjacencyMap :: (Arbitrary a, Ord a) => Gen (NAM.AdjacencyMap a)+arbitraryNonEmptyAdjacencyMap = NAM.stars1 <$> nonEmpty+  where+    nonEmpty = do+        xs <- arbitrary+        case xs of+            [] -> do+                x <- arbitrary+                return ((x, []) :| []) -- There must be at least one vertex+            (x:xs) -> return (x :| xs)++-- TODO: Implement a custom shrink method.+instance (Arbitrary a, Ord a) => Arbitrary (NAM.AdjacencyMap a) where+    arbitrary = arbitraryNonEmptyAdjacencyMap++-- | 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 AdjacencyIntMap where     arbitrary = arbitraryAdjacencyIntMap -instance Arbitrary a => Arbitrary (Fold a) where-    arbitrary = arbitraryGraph+-- | Generate an arbitrary labelled 'LAM.AdjacencyMap'. It is guaranteed+-- that the resulting adjacency map is 'consistent'.+arbitraryLabelledAdjacencyMap :: (Arbitrary a, Ord a, Eq e, Arbitrary e, Monoid e) => Gen (LAM.AdjacencyMap e a)+arbitraryLabelledAdjacencyMap = LAM.fromAdjacencyMaps <$> arbitrary +-- TODO: Implement a custom shrink method.+instance (Arbitrary a, Ord a, Eq e, Arbitrary e, Monoid e) => Arbitrary (LAM.AdjacencyMap e a) where+    arbitrary = arbitraryLabelledAdjacencyMap++-- | Generate an arbitrary labelled 'LAM.Graph' value of a specified size.+arbitraryLabelledGraph :: (Arbitrary a, Arbitrary e) => Gen (LG.Graph e a)+arbitraryLabelledGraph = sized expr+  where+    expr 0 = return LG.empty+    expr 1 = LG.vertex <$> arbitrary+    expr n = do+        label <- arbitrary+        left  <- choose (0, n)+        LG.connect label <$> expr left <*> expr (n - left)++instance (Arbitrary a, Arbitrary e, Monoid e) => Arbitrary (LG.Graph e a) where+    arbitrary = arbitraryLabelledGraph++    shrink LG.Empty           = []+    shrink (LG.Vertex      _) = [LG.Empty]+    shrink (LG.Connect e x y) = [LG.Empty, x, y, LG.Connect mempty x y]+                             ++ [LG.Connect e x' y' | (x', y') <- shrink (x, y) ]++-- TODO: Implement a custom shrink method. instance Arbitrary a => Arbitrary (Tree a) where     arbitrary = sized go       where@@ -128,5 +182,9 @@             children <- replicateM subTrees (go subSize)             return $ Node root children +-- TODO: Implement a custom shrink method. instance Arbitrary s => Arbitrary (Doc s) where     arbitrary = (mconcat . map literal) <$> arbitrary++instance (Arbitrary a, Num a, Ord a) => Arbitrary (Distance a) where+    arbitrary = (\x -> if x < 0 then distance infinite else distance (unsafeFinite x)) <$> arbitrary
test/Algebra/Graph/Test/Export.hs view
@@ -31,6 +31,24 @@  testExport :: IO () testExport = do+    putStrLn "\n============ Export.Eq ============"+    test "mempty /= literal \"\"" $+          mempty /= (literal "" :: Doc String)++    putStrLn "\n============ Export.Ord ============"+    test "mempty <  literal \"\"" $+          mempty < (literal "" :: Doc String)++    putStrLn "\n============ Export.isEmpty ============"+    test "isEmpty mempty       == True" $+          isEmpty mempty       == True++    test "isEmpty (literal \"\") == False" $+          isEmpty (literal "" :: Doc String) == False++    test "isEmpty x            == (x == mempty)" $ \(x :: Doc String) ->+          isEmpty x            == (x == mempty)+     putStrLn "\n============ Export.literal ============"     test "literal \"Hello, \" <> literal \"World!\" == literal \"Hello, World!\"" $           literal "Hello, " <> literal "World!" == literal ("Hello, World!" :: String)@@ -38,15 +56,9 @@     test "literal \"I am just a string literal\"  == \"I am just a string literal\"" $           literal "I am just a string literal"  == ("I am just a string literal" :: Doc String) -    test "literal mempty                        == mempty" $-          literal mempty                        == (mempty :: Doc String)-     test "render . literal                      == id" $ \(x :: String) ->          (render . literal) x                   == x -    test "literal . render                      == id" $ \(xs :: [String]) -> let x = mconcat (map literal xs) in-         (literal . render) x                   == x-     putStrLn "\n============ Export.render ============"     test "render (literal \"al\" <> literal \"ga\") == \"alga\"" $           render (literal "al" <> literal "ga") == ("alga" :: String)@@ -113,7 +125,7 @@     putStrLn "\n============ Export.Dot.export ============"     let style = ED.Style             { ED.graphName               = "Example"-            , ED.preamble                = "  // This is an example\n"+            , ED.preamble                = ["  // This is an example", ""]             , ED.graphAttributes         = ["label" := "Example", "labelloc" := "top"]             , ED.defaultVertexAttributes = ["shape" := "circle"]             , ED.defaultEdgeAttributes   = mempty@@ -142,7 +154,7 @@     putStrLn "\n============ Export.Dot.exportAsIs ============"     test "exportAsIs (circuit [\"a\", \"b\", \"c\"] :: Graph String)" $         (ED.exportAsIs (circuit ["a", "b", "c"] :: Graph String) :: String) ==-            unlines [ "digraph"+            unlines [ "digraph "                     , "{"                     , "  \"a\""                     , "  \"b\""@@ -155,7 +167,7 @@     putStrLn "\n============ Export.Dot.exportViaShow ============"     test "exportViaShow (1 + 2 * (3 + 4) :: Graph Int)" $         (ED.exportViaShow (1 + 2 * (3 + 4) :: Graph Int) :: String) ==-            unlines [ "digraph"+            unlines [ "digraph "                     , "{"                     , "  \"1\""                     , "  \"2\""
test/Algebra/Graph/Test/Generic.hs view
@@ -9,15 +9,7 @@ -- -- Generic graph API testing. ------------------------------------------------------------------------------module Algebra.Graph.Test.Generic (-    -- * Generic tests-    Testsuite, testsuite, testShow, testFromAdjacencySets,-    testFromAdjacencyIntSets, testBasicPrimitives, testIsSubgraphOf, testSize,-    testToGraph, testAdjacencyList, testPreSet, testPreIntSet, testPostSet,-    testPostIntSet, testGraphFamilies, testTransformations, testSplitVertex,-    testBind, testSimplify, testDfsForest, testDfsForestFrom, testDfs,-    testReachable, testTopSort, testIsAcyclic, testIsDfsForestOf, testIsTopSortOf-  ) where+module Algebra.Graph.Test.Generic where  import Prelude () import Prelude.Compat@@ -36,22 +28,27 @@ import Algebra.Graph.Test import Algebra.Graph.Test.API -import qualified Algebra.Graph                 as G-import qualified Algebra.Graph.AdjacencyMap    as AM-import qualified Algebra.Graph.AdjacencyIntMap as AIM-import qualified Data.Set                      as Set-import qualified Data.IntSet                   as IntSet+import qualified Algebra.Graph                        as G+import qualified Algebra.Graph.AdjacencyMap           as AM+import qualified Algebra.Graph.AdjacencyMap.Algorithm as AM+import qualified Algebra.Graph.AdjacencyIntMap        as AIM+import qualified Data.Set                             as Set+import qualified Data.IntSet                          as IntSet  data Testsuite where-    Testsuite :: (Arbitrary g, Eq g, GraphAPI g, Num g, Show g, ToGraph g, ToVertex g ~ Int, Vertex g ~ Int)+    Testsuite :: (Arbitrary g, GraphAPI g, Num g, Ord g, Show g, ToGraph g, ToVertex g ~ Int, Vertex g ~ Int)               => String -> (forall r. (g -> r) -> g -> r) -> Testsuite -testsuite :: (Arbitrary g, Eq g, GraphAPI g, Num g, Show g, ToGraph g, ToVertex g ~ Int, Vertex g ~ Int)+testsuite :: (Arbitrary g, GraphAPI g, Num g, Ord g, Show g, ToGraph g, ToVertex g ~ Int, Vertex g ~ Int)           => String -> g -> Testsuite testsuite prefix g = Testsuite prefix (\f x -> f (x `asTypeOf` g)) +size10 :: Testable prop => prop -> Property+size10 = mapSize (min 10)+ testBasicPrimitives :: Testsuite -> IO ()-testBasicPrimitives = mconcat [ testEmpty+testBasicPrimitives = mconcat [ testOrd+                              , testEmpty                               , testVertex                               , testEdge                               , testOverlay@@ -80,6 +77,13 @@                       , testPostSet                       , testPostIntSet ] +testRelational :: Testsuite -> IO ()+testRelational = mconcat [ testCompose+                         , testClosure+                         , testReflexiveClosure+                         , testSymmetricClosure+                         , testTransitiveClosure ]+ testGraphFamilies :: Testsuite -> IO () testGraphFamilies = mconcat [ testPath                             , testCircuit@@ -120,6 +124,50 @@     test "show (1 * 2 + 3) == \"overlay (vertex 3) (edge 1 2)\"" $           show % (1 * 2 + 3) == "overlay (vertex 3) (edge 1 2)" +    putStrLn ""+    test "show (vertex (-1)                            ) == \"vertex (-1)\"" $+          show % (vertex (-1)                            ) == "vertex (-1)"++    test "show (vertex (-1) + vertex (-2)              ) == \"vertices [-2,-1]\"" $+          show % (vertex (-1) + vertex (-2)              ) == "vertices [-2,-1]"++    test "show (vertex (-1) * vertex (-2)              ) == \"edge (-1) (-2)\"" $+          show % (vertex (-1) * vertex (-2)              ) == "edge (-1) (-2)"++    test "show (vertex (-1) * vertex (-2) * vertex (-3)) == \"edges [(-2,-3),(-1,-3),(-1,-2)]\"" $+          show % (vertex (-1) * vertex (-2) * vertex (-3)) == "edges [(-2,-3),(-1,-3),(-1,-2)]"++    test "show (vertex (-1) * vertex (-2) + vertex (-3)) == \"overlay (vertex (-3)) (edge (-1) (-2))\"" $+          show % (vertex (-1) * vertex (-2) + vertex (-3)) == "overlay (vertex (-3)) (edge (-1) (-2))"+++testOrd :: Testsuite -> IO ()+testOrd (Testsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "Ord ============"+    test "vertex 1 <  vertex 2" $+          vertex 1 < id % vertex 2++    test "vertex 3 <  edge 1 2" $+          vertex 3 < id % edge 1 2++    test "vertex 1 <  edge 1 1" $+          vertex 1 < id % edge 1 1++    test "edge 1 1 <  edge 1 2" $+          edge 1 1 < id % edge 1 2++    test "edge 1 2 <  edge 1 1 + edge 2 2" $+          edge 1 2 < id % edge 1 1 + edge 2 2++    test "edge 1 2 <  edge 1 3" $+          edge 1 2 < id % edge 1 3++    test "x        <= x + y" $ \x y ->+          id % x   <= x + y++    test "x + y    <= x * y" $ \x y ->+          id % x + y <= x * y+ testEmpty :: Testsuite -> IO () testEmpty (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "empty ============"@@ -270,10 +318,10 @@     test "overlays [x,y]     == overlay x y" $ \x y ->           overlays [x,y]     == id % overlay x y -    test "overlays           == foldr overlay empty" $ mapSize (min 10) $ \xs ->+    test "overlays           == foldr overlay empty" $ size10 $ \xs ->           overlays xs        == id % foldr overlay empty xs -    test "isEmpty . overlays == all isEmpty" $ mapSize (min 10) $ \xs ->+    test "isEmpty . overlays == all isEmpty" $ size10 $ \xs ->           isEmpty % overlays xs == all isEmpty xs  testConnects :: Testsuite -> IO ()@@ -288,10 +336,10 @@     test "connects [x,y]     == connect x y" $ \x y ->           connects [x,y]     == id % connect x y -    test "connects           == foldr connect empty" $ mapSize (min 10) $ \xs ->+    test "connects           == foldr connect empty" $ size10 $ \xs ->           connects xs        == id % foldr connect empty xs -    test "isEmpty . connects == all isEmpty" $ mapSize (min 10) $ \xs ->+    test "isEmpty . connects == all isEmpty" $ size10 $ \xs ->           isEmpty % connects xs == all isEmpty xs  testStars :: Testsuite -> IO ()@@ -321,57 +369,61 @@ testFromAdjacencySets :: Testsuite -> IO () testFromAdjacencySets (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "fromAdjacencySets ============"-    test "fromAdjacencySets []                                        == empty" $-          fromAdjacencySets []                                        == id % empty+    test "fromAdjacencySets []                                  == empty" $+          fromAdjacencySets []                                  == id % empty -    test "fromAdjacencySets [(x, Set.empty)]                          == vertex x" $ \x ->-          fromAdjacencySets [(x, Set.empty)]                          == id % vertex x+    test "fromAdjacencySets [(x, Set.empty)]                    == vertex x" $ \x ->+          fromAdjacencySets [(x, Set.empty)]                    == id % vertex x -    test "fromAdjacencySets [(x, Set.singleton y)]                    == edge x y" $ \x y ->-          fromAdjacencySets [(x, Set.singleton y)]                    == id % edge x y+    test "fromAdjacencySets [(x, Set.singleton y)]              == edge x y" $ \x y ->+          fromAdjacencySets [(x, Set.singleton y)]              == id % edge x y -    test "fromAdjacencySets . map (fmap Set.fromList) . adjacencyList == id" $ \x ->-         (fromAdjacencySets . map (fmap Set.fromList) . adjacencyList) % x == x+    test "fromAdjacencySets . map (fmap Set.fromList)           == stars" $ \x ->+         (fromAdjacencySets . map (fmap Set.fromList)) x        == id % stars x -    test "overlay (fromAdjacencySets xs) (fromAdjacencySets ys)       == fromAdjacencySets (xs ++ ys)" $ \xs ys ->-          overlay (fromAdjacencySets xs) % fromAdjacencySets ys       == fromAdjacencySets (xs ++ ys)+    test "overlay (fromAdjacencySets xs) (fromAdjacencySets ys) == fromAdjacencySets (xs ++ ys)" $ \xs ys ->+          overlay (fromAdjacencySets xs) % fromAdjacencySets ys == fromAdjacencySets (xs ++ ys)  testFromAdjacencyIntSets :: Testsuite -> IO () testFromAdjacencyIntSets (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "fromAdjacencyIntSets ============"-    test "fromAdjacencyIntSets []                                           == empty" $-          fromAdjacencyIntSets []                                           == id % empty+    test "fromAdjacencyIntSets []                                     == empty" $+          fromAdjacencyIntSets []                                     == id % empty -    test "fromAdjacencyIntSets [(x, IntSet.empty)]                          == vertex x" $ \x ->-          fromAdjacencyIntSets [(x, IntSet.empty)]                          == id % vertex x+    test "fromAdjacencyIntSets [(x, IntSet.empty)]                    == vertex x" $ \x ->+          fromAdjacencyIntSets [(x, IntSet.empty)]                    == id % vertex x -    test "fromAdjacencyIntSets [(x, IntSet.singleton y)]                    == edge x y" $ \x y ->-          fromAdjacencyIntSets [(x, IntSet.singleton y)]                    == id % edge x y+    test "fromAdjacencyIntSets [(x, IntSet.singleton y)]              == edge x y" $ \x y ->+          fromAdjacencyIntSets [(x, IntSet.singleton y)]              == id % edge x y -    test "fromAdjacencyIntSets . map (fmap IntSet.fromList) . adjacencyList == id" $ \x ->-         (fromAdjacencyIntSets . map (fmap IntSet.fromList) . adjacencyList) % x == x+    test "fromAdjacencyIntSets . map (fmap IntSet.fromList)           == stars" $ \x ->+         (fromAdjacencyIntSets . map (fmap IntSet.fromList)) x        == id % stars x -    test "overlay (fromAdjacencyIntSets xs) (fromAdjacencyIntSets ys)       == fromAdjacencyIntSets (xs ++ ys)" $ \xs ys ->-          overlay (fromAdjacencyIntSets xs) % fromAdjacencyIntSets ys       == fromAdjacencyIntSets (xs ++ ys)+    test "overlay (fromAdjacencyIntSets xs) (fromAdjacencyIntSets ys) == fromAdjacencyIntSets (xs ++ ys)" $ \xs ys ->+          overlay (fromAdjacencyIntSets xs) % fromAdjacencyIntSets ys == fromAdjacencyIntSets (xs ++ ys)  testIsSubgraphOf :: Testsuite -> IO () testIsSubgraphOf (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "isSubgraphOf ============"-    test "isSubgraphOf empty         x             == True" $ \x ->-          isSubgraphOf empty       % x             == True+    test "isSubgraphOf empty         x             ==  True" $ \x ->+          isSubgraphOf empty       % x             ==  True -    test "isSubgraphOf (vertex x)    empty         == False" $ \x ->-          isSubgraphOf (vertex x)  % empty         == False+    test "isSubgraphOf (vertex x)    empty         ==  False" $ \x ->+          isSubgraphOf (vertex x)  % empty         ==  False -    test "isSubgraphOf x             (overlay x y) == True" $ \x y ->-          isSubgraphOf x            % overlay x y  == True+    test "isSubgraphOf x             (overlay x y) ==  True" $ \x y ->+          isSubgraphOf x            % overlay x y  ==  True -    test "isSubgraphOf (overlay x y) (connect x y) == True" $ \x y ->-          isSubgraphOf (overlay x y) % connect x y == True+    test "isSubgraphOf (overlay x y) (connect x y) ==  True" $ \x y ->+          isSubgraphOf (overlay x y) % connect x y ==  True -    test "isSubgraphOf (path xs)     (circuit xs)  == True" $ \xs ->-          isSubgraphOf (path xs)    % circuit xs   == True+    test "isSubgraphOf (path xs)     (circuit xs)  ==  True" $ \xs ->+          isSubgraphOf (path xs)    % circuit xs   ==  True +    test "isSubgraphOf x y                         ==> x <= y" $ \x z ->+        let y = x + z -- Make sure we hit the precondition+        in isSubgraphOf x % y                      ==> x <= y+ testToGraphDefault :: Testsuite -> IO () testToGraphDefault (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "toGraph et al. ============"@@ -571,15 +623,20 @@ testVertexCount :: Testsuite -> IO () testVertexCount (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "vertexCount ============"-    test "vertexCount empty      == 0" $-          vertexCount % empty    == 0+    test "vertexCount empty             ==  0" $+          vertexCount % empty           ==  0 -    test "vertexCount (vertex x) == 1" $ \x ->-          vertexCount % vertex x == 1+    test "vertexCount (vertex x)        ==  1" $ \x ->+          vertexCount % (vertex x)      ==  1 -    test "vertexCount            == length . vertexList" $ \x ->-          vertexCount % x        == (length . vertexList) x+    test "vertexCount                   ==  length . vertexList" $ \x ->+          vertexCount % x               == (length . vertexList) x +    test "vertexCount x < vertexCount y ==> x < y" $ \x y ->+        if vertexCount x < vertexCount % y+        then property (x < y)+        else (vertexCount x > vertexCount y ==> x > y)+ testEdgeCount :: Testsuite -> IO () testEdgeCount (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "edgeCount ============"@@ -652,9 +709,6 @@     test "vertexSet . vertices == Set.fromList" $ \xs ->           vertexSet % vertices xs == Set.fromList xs -    test "vertexSet . clique   == Set.fromList" $ \xs ->-          vertexSet % clique xs == Set.fromList xs- testVertexIntSet :: Testsuite -> IO () testVertexIntSet (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "vertexIntSet ============"@@ -930,7 +984,7 @@     test "transpose (edge x y)  == edge y x" $ \x y ->           transpose % edge x y  == edge y x -    test "transpose . transpose == id" $ mapSize (min 10) $ \x ->+    test "transpose . transpose == id" $ size10 $ \x ->          (transpose . transpose) % x == x      test "edgeList . transpose  == sort . map swap . edgeList" $ \x ->@@ -972,6 +1026,123 @@     test "isSubgraphOf (induce p x) x == True" $ \(apply -> p) x ->           isSubgraphOf (induce p x) % x == True +testCompose :: Testsuite -> IO ()+testCompose (Testsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "compose ============"+    test "compose empty            x                == empty" $ \x ->+          compose empty          % x                == empty++    test "compose x                empty            == empty" $ \x ->+          compose x              % empty            == empty++    test "compose (vertex x)       y                == empty" $ \x y ->+          compose (vertex x)     % y                == empty++    test "compose x                (vertex y)       == empty" $ \x y ->+          compose x              % (vertex y)       == empty++    test "compose x                (compose y z)    == compose (compose x y) z" $ size10 $ \x y z ->+          compose x              % (compose y z)    == compose (compose x y) z++    test "compose x                (overlay y z)    == overlay (compose x y) (compose x z)" $ size10 $ \x y z ->+          compose x              % (overlay y z)    == overlay (compose x y) (compose x z)++    test "compose (overlay x y) z                   == overlay (compose x z) (compose y z)" $ size10 $ \x y z ->+          compose (overlay x y) % z                 == overlay (compose x z) (compose y z)++    test "compose (edge x y)       (edge y z)       == edge x z" $ \x y z ->+          compose (edge x y) %     (edge y z)       == edge x z++    test "compose (path    [1..5]) (path    [1..5]) == edges [(1,3),(2,4),(3,5)]" $+          compose (path    [1..5])%(path    [1..5]) == edges [(1,3),(2,4),(3,5)]++    test "compose (circuit [1..5]) (circuit [1..5]) == circuit [1,3,5,2,4]" $+          compose (circuit [1..5])%(circuit [1..5]) == circuit [1,3,5,2,4]++testClosure :: Testsuite -> IO ()+testClosure (Testsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "closure ============"+    test "closure empty           == empty" $+          closure % empty         == empty++    test "closure (vertex x)      == edge x x" $ \x ->+          closure % (vertex x)    == edge x x++    test "closure (edge x x)      == edge x x" $ \x ->+          closure % (edge x x)    == edge x x++    test "closure (edge x y)      == edges [(x,x), (x,y), (y,y)]" $ \x y ->+          closure % (edge x y)    == edges [(x,x), (x,y), (y,y)]++    test "closure (path $ nub xs) == reflexiveClosure (clique $ nub xs)" $ \xs ->+          closure % (path $ nubOrd xs) == reflexiveClosure (clique $ nubOrd xs)++    test "closure                 == reflexiveClosure . transitiveClosure" $ size10 $ \x ->+          closure % x             == (reflexiveClosure . transitiveClosure) x++    test "closure                 == transitiveClosure . reflexiveClosure" $ size10 $ \x ->+          closure % x             == (transitiveClosure . reflexiveClosure) x++    test "closure . closure       == closure" $ size10 $ \x ->+         (closure . closure) % x  == closure x++    test "postSet x (closure y)   == Set.fromList (reachable x y)" $ size10 $ \x y ->+          postSet x % (closure y) == Set.fromList (reachable x y)++testReflexiveClosure :: Testsuite -> IO ()+testReflexiveClosure (Testsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "reflexiveClosure ============"+    test "reflexiveClosure empty              == empty" $+          reflexiveClosure % empty            == empty++    test "reflexiveClosure (vertex x)         == edge x x" $ \x ->+          reflexiveClosure % vertex x         == edge x x++    test "reflexiveClosure (edge x x)         == edge x x" $ \x ->+          reflexiveClosure % edge x x         == edge x x++    test "reflexiveClosure (edge x y)         == edges [(x,x), (x,y), (y,y)]" $ \x y ->+          reflexiveClosure % edge x y         == edges [(x,x), (x,y), (y,y)]++    test "reflexiveClosure . reflexiveClosure == reflexiveClosure" $ \x ->+         (reflexiveClosure . reflexiveClosure) x == reflexiveClosure % x++testSymmetricClosure :: Testsuite -> IO ()+testSymmetricClosure (Testsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "symmetricClosure ============"+    test "symmetricClosure empty              == empty" $+          symmetricClosure % empty            == empty++    test "symmetricClosure (vertex x)         == vertex x" $ \x ->+          symmetricClosure % vertex x         == vertex x++    test "symmetricClosure (edge x y)         == edges [(x,y), (y,x)]" $ \x y ->+          symmetricClosure % edge x y         == edges [(x,y), (y,x)]++    test "symmetricClosure x                  == overlay x (transpose x)" $ \x ->+          symmetricClosure % x                == overlay x (transpose x)++    test "symmetricClosure . symmetricClosure == symmetricClosure" $ \x ->+         (symmetricClosure . symmetricClosure) x == symmetricClosure % x++testTransitiveClosure :: Testsuite -> IO ()+testTransitiveClosure (Testsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "transitiveClosure ============"+    test "transitiveClosure empty               == empty" $+          transitiveClosure % empty             == empty++    test "transitiveClosure (vertex x)          == vertex x" $ \x ->+          transitiveClosure % (vertex x)        == vertex x++    test "transitiveClosure (edge x y)          == edge x y" $ \x y ->+          transitiveClosure % (edge x y)        == edge x y++    test "transitiveClosure (path $ nub xs)     == clique (nub $ xs)" $ \xs ->+          transitiveClosure % (path $ nubOrd xs) == clique (nubOrd xs)++    test "transitiveClosure . transitiveClosure == transitiveClosure" $ size10 $ \x ->+         (transitiveClosure . transitiveClosure) x == transitiveClosure % x+ testSplitVertex :: Testsuite -> IO () testSplitVertex (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "splitVertex ============"@@ -999,7 +1170,7 @@     test "bind (edge x y) f    == connect (f x) (f y)" $ \(apply -> f) x y ->           bind (edge x y) f    == connect (f x) % f y -    test "bind (vertices xs) f == overlays (map f xs)" $ mapSize (min 10) $ \xs (apply -> f) ->+    test "bind (vertices xs) f == overlays (map f xs)" $ size10 $ \xs (apply -> f) ->           bind (vertices xs) f == id % overlays (map f xs)      test "bind x (const empty) == empty" $ \x ->@@ -1008,7 +1179,7 @@     test "bind x vertex        == x" $ \x ->           bind x vertex        == id % x -    test "bind (bind x f) g    == bind x (\\y -> bind (f y) g)" $ mapSize (min 10) $ \x (apply -> f) (apply -> g) ->+    test "bind (bind x f) g    == bind x (\\y -> bind (f y) g)" $ size10 $ \x (apply -> f) (apply -> g) ->           bind (bind x f) g    == bind (id % x) (\y -> bind (f y) g)  testSimplify :: Testsuite -> IO ()
test/Algebra/Graph/Test/Graph.hs view
@@ -39,6 +39,13 @@     testGraphFamilies   t     testTransformations t +    ----------------------------------------------------------------+    -- Generic relational composition tests, plus an additional one+    testCompose         t+    test "size (compose x y)                        <= edgeCount x + edgeCount y + 1" $ \(x :: G) y ->+          size (compose x y)                        <= edgeCount x + edgeCount y + 1+    ----------------------------------------------------------------+     putStrLn "\n============ Graph.(===) ============"     test "    x === x         == True" $ \(x :: G) ->              (x === x)        == True@@ -165,3 +172,19 @@      test "size        (sparsify x) <= 3 * size x" $ \(x :: G) ->           size        (sparsify x) <= 3 * size x++    putStrLn "\n============ Labelled.Graph.context ============"+    test "context (const False) x                   == Nothing" $ \x ->+          context (const False) (x :: G)            == Nothing++    test "context (== 1)        (edge 1 2)          == Just (Context [   ] [2  ])" $+          context (== 1)        (edge 1 2 :: G)     == Just (Context [   ] [2  ])++    test "context (== 2)        (edge 1 2)          == Just (Context [1  ] [   ])" $+          context (== 2)        (edge 1 2 :: G)     == Just (Context [1  ] [   ])++    test "context (const True ) (edge 1 2)          == Just (Context [1  ] [2  ])" $+          context (const True ) (edge 1 2 :: G)     == Just (Context [1  ] [2  ])++    test "context (== 4)        (3 * 1 * 4 * 1 * 5) == Just (Context [3,1] [1,5])" $+          context (== 4)        (3 * 1 * 4 * 1 * 5 :: G) == Just (Context [3,1] [1,5])
+ test/Algebra/Graph/Test/Labelled/AdjacencyMap.hs view
@@ -0,0 +1,475 @@+{-# LANGUAGE ViewPatterns #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Test.Labelled.AdjacencyMap+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- Testsuite for "Algebra.Graph.Labelled.AdjacencyMap".+-----------------------------------------------------------------------------+module Algebra.Graph.Test.Labelled.AdjacencyMap (+    -- * Testsuite+    testLabelledAdjacencyMap+    ) where++import Data.Monoid++import Algebra.Graph.Label+import Algebra.Graph.Labelled.AdjacencyMap+import Algebra.Graph.Labelled.AdjacencyMap.Internal+import Algebra.Graph.Test+import Algebra.Graph.Test.Generic+import Algebra.Graph.ToGraph (reachable)++import qualified Algebra.Graph.AdjacencyMap as AM+import qualified Data.Map                   as Map+import qualified Data.Set                   as Set++t :: Testsuite+t = testsuite "Labelled.AdjacencyMap." (empty :: LAI)++type S = Sum Int+type D = Distance Int++type LAI = AdjacencyMap Any Int+type LAS = AdjacencyMap S   Int+type LAD = AdjacencyMap D   Int++testLabelledAdjacencyMap :: IO ()+testLabelledAdjacencyMap = do+    putStrLn "\n============ Labelled.AdjacencyMap.Internal.consistent ============"+    test "arbitraryLabelledAdjacencyMap" $ \x -> consistent (x           :: LAS)+    test "empty" $                      consistent (empty                :: LAS)+    test "vertex" $ \x               -> consistent (vertex x             :: LAS)+    test "edge" $ \e x y             -> consistent (edge e x y           :: LAS)+    test "overlay" $ \x y            -> consistent (overlay x y          :: LAS)+    test "connect" $ size10 $ \e x y -> consistent (connect e x y        :: LAS)+    test "vertices" $ \xs            -> consistent (vertices xs          :: LAS)+    test "edges" $ \es               -> consistent (edges es             :: LAS)+    test "overlays" $ size10 $ \xs   -> consistent (overlays xs          :: LAS)+    test "fromAdjacencyMaps" $ \xs   -> consistent (fromAdjacencyMaps xs :: LAS)+    test "removeVertex" $ \x y       -> consistent (removeVertex x y     :: LAS)+    test "removeEdge" $ \x y z       -> consistent (removeEdge x y z     :: LAS)+    test "replaceVertex" $ \x y z    -> consistent (replaceVertex x y z  :: LAS)+    test "replaceEdge" $ \e x y z    -> consistent (replaceEdge e x y z  :: LAS)+    test "transpose" $ \x            -> consistent (transpose x          :: LAS)+    test "gmap" $ \(apply -> f) x    -> consistent (gmap f (x :: LAS)    :: LAS)+    test "emap" $ \(apply -> f) x    -> consistent (emap (fmap f::S->S) x:: LAS)+    test "induce" $ \(apply -> p) x  -> consistent (induce p x           :: LAS)++    test "closure"           $ size10 $ \x -> consistent (closure           x :: LAD)+    test "reflexiveClosure"  $ size10 $ \x -> consistent (reflexiveClosure  x :: LAD)+    test "symmetricClosure"  $ size10 $ \x -> consistent (symmetricClosure  x :: LAD)+    test "transitiveClosure" $ size10 $ \x -> consistent (transitiveClosure x :: LAD)++    testEmpty  t+    testVertex t++    putStrLn "\n============ Labelled.AdjacencyMap.edge ============"+    test "edge e    x y              == connect e (vertex x) (vertex y)" $ \(e :: S) (x :: Int) y ->+          edge e    x y              == connect e (vertex x) (vertex y)++    test "edge zero x y              == vertices [x,y]" $ \(x :: Int) y ->+          edge (zero :: S) x y       == vertices [x,y]++    test "hasEdge   x y (edge e x y) == (e /= mempty)" $ \(e :: S) (x :: Int) y ->+          hasEdge   x y (edge e x y) == (e /= mempty)++    test "edgeLabel x y (edge e x y) == e" $ \(e :: S) (x :: Int) y ->+          edgeLabel x y (edge e x y) == e++    test "edgeCount     (edge e x y) == if e == mempty then 0 else 1" $ \(e :: S) (x :: Int) y ->+          edgeCount     (edge e x y) == if e == mempty then 0 else 1++    test "vertexCount   (edge e 1 1) == 1" $ \(e :: S) ->+          vertexCount   (edge e 1 (1 :: Int)) == 1++    test "vertexCount   (edge e 1 2) == 2" $ \(e :: S) ->+          vertexCount   (edge e 1 (2 :: Int)) == 2++    test "x -<e>- y                  == edge e x y" $ \(e :: S) (x :: Int) y ->+          x -<e>- y                  == edge e x y++    testOverlay t++    putStrLn ""+    test "edgeLabel x y $ overlay (edge e x y) (edge zero x y) == e" $ \(e :: S) (x :: Int) y ->+          edgeLabel x y (overlay (edge e x y) (edge zero x y)) == e++    test "edgeLabel x y $ overlay (edge e x y) (edge f    x y) == e <+> f" $ \(e :: S) f (x :: Int) y ->+          edgeLabel x y (overlay (edge e x y) (edge f    x y)) == e <+> f++    putStrLn ""+    test "edgeLabel 1 3 $ transitiveClosure (overlay (edge e 1 2) (edge one 2 3)) == e" $ \(e :: D) ->+          edgeLabel 1 3 (transitiveClosure (overlay (edge e 1 2) (edge one 2 (3 :: Int)))) == e++    test "edgeLabel 1 3 $ transitiveClosure (overlay (edge e 1 2) (edge f   2 3)) == e <.> f" $ \(e :: D) f ->+          edgeLabel 1 3 (transitiveClosure (overlay (edge e 1 2) (edge f   2 (3 :: Int))))== e <.> f++    putStrLn "\n============ Labelled.AdjacencyMap.connect ============"+    test "isEmpty     (connect e x y) == isEmpty   x   && isEmpty   y" $ size10 $ \(e :: S) (x :: LAS) y ->+          isEmpty     (connect e x y) ==(isEmpty   x   && isEmpty   y)++    test "hasVertex z (connect e x y) == hasVertex z x || hasVertex z y" $ size10 $ \(e :: S) (x :: LAS) y z ->+          hasVertex z (connect e x y) ==(hasVertex z x || hasVertex z y)++    test "vertexCount (connect e x y) >= vertexCount x" $ size10 $ \(e :: S) (x :: LAS) y ->+          vertexCount (connect e x y) >= vertexCount x++    test "vertexCount (connect e x y) <= vertexCount x + vertexCount y" $ size10 $ \(e :: S) (x :: LAS) y ->+          vertexCount (connect e x y) <= vertexCount x + vertexCount y++    test "edgeCount   (connect e x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y" $ size10 $ \(e :: S) (x :: LAS) y ->+          edgeCount   (connect e x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y++    test "vertexCount (connect e 1 2) == 2" $ \(e :: Any) ->+          vertexCount (connect e 1 (2 :: LAI)) == 2++    test "edgeCount   (connect e 1 2) == if e == zero then 0 else 1" $ \(e :: Any) ->+          edgeCount   (connect e 1 (2 :: LAI)) == if e == zero then 0 else 1++    testVertices t++    putStrLn "\n============ Labelled.AdjacencyMap.edges ============"+    test "edges []        == empty" $+          edges []        == (empty :: LAS)++    test "edges [(e,x,y)] == edge e x y" $ \(e :: S) (x :: Int) y ->+          edges [(e,x,y)] == edge e x y++    test "edges           == overlays . map (\\(e, x, y) -> edge e x y)" $ \(es :: [(S, Int, Int)]) ->+          edges es        ==(overlays . map (\(e, x, y) -> edge e x y)) es++    testOverlays t++    putStrLn "\n============ Labelled.AdjacencyMap.fromAdjacencyMaps ============"+    test "fromAdjacencyMaps []                                  == empty" $+          fromAdjacencyMaps []                                  == (empty :: LAS)++    test "fromAdjacencyMaps [(x, Map.empty)]                    == vertex x" $ \(x :: Int) ->+          fromAdjacencyMaps [(x, Map.empty)]                    == (vertex x :: LAS)++    test "fromAdjacencyMaps [(x, Map.singleton y e)]            == if e == zero then vertices [x,y] else edge e x y" $ \(e :: S) (x :: Int) y ->+          fromAdjacencyMaps [(x, Map.singleton y e)]            == if e == zero then vertices [x,y] else edge e x y++    test "overlay (fromAdjacencyMaps xs) (fromAdjacencyMaps ys) == fromAdjacencyMaps (xs ++ ys)" $ \xs ys ->+          overlay (fromAdjacencyMaps xs) (fromAdjacencyMaps ys) == (fromAdjacencyMaps (xs ++ ys) :: LAS)++    putStrLn "\n============ Labelled.AdjacencyMap.isSubgraphOf ============"+    test "isSubgraphOf empty      x     ==  True" $ \(x :: LAS) ->+          isSubgraphOf empty      x     ==  True++    test "isSubgraphOf (vertex x) empty ==  False" $ \(x :: Int) ->+          isSubgraphOf (vertex x)(empty :: LAS)==  False++    test "isSubgraphOf x y              ==> x <= y" $ \(x :: LAD) z ->+        let y = x + z -- Make sure we hit the precondition+        in isSubgraphOf x y             ==> x <= y++    putStrLn "\n============ Labelled.AdjacencyMap.isEmpty ============"+    test "isEmpty empty                         == True" $+          isEmpty empty                         == True++    test "isEmpty (overlay empty empty)         == True" $+          isEmpty (overlay empty empty :: LAS)  == True++    test "isEmpty (vertex x)                    == False" $ \(x :: Int) ->+          isEmpty (vertex x)                    == False++    test "isEmpty (removeVertex x $ vertex x)   == True" $ \(x :: Int) ->+          isEmpty (removeVertex x $ vertex x)   == True++    test "isEmpty (removeEdge x y $ edge e x y) == False" $ \(e :: S) (x :: Int) y ->+          isEmpty (removeEdge x y $ edge e x y) == False++    testHasVertex t++    putStrLn "\n============ Labelled.AdjacencyMap.hasEdge ============"+    test "hasEdge x y empty            == False" $ \(x :: Int) y ->+          hasEdge x y empty            == False++    test "hasEdge x y (vertex z)       == False" $ \(x :: Int) y z ->+          hasEdge x y (vertex z)       == False++    test "hasEdge x y (edge e x y)     == (e /= zero)" $ \(e :: S) (x :: Int) y ->+          hasEdge x y (edge e x y)     == (e /= zero)++    test "hasEdge x y . removeEdge x y == const False" $ \x y (z :: LAS) ->+         (hasEdge x y . removeEdge x y) z == const False z++    test "hasEdge x y                  == not . null . filter (\\(_,ex,ey) -> ex == x && ey == y) . edgeList" $ \x y (z :: LAS) -> do+        (_, u, v) <- elements ((zero, x, y) : edgeList z)+        return $ hasEdge u v z         == (not . null . filter (\(_,ex,ey) -> ex == u && ey == v) . edgeList) z++    putStrLn "\n============ Labelled.AdjacencyMap.edgeLabel ============"+    test "edgeLabel x y empty         == zero" $ \(x :: Int) y ->+          edgeLabel x y empty         == (zero :: S)++    test "edgeLabel x y (vertex z)    == zero" $ \(x :: Int) y z ->+          edgeLabel x y (vertex z)    == (zero :: S)++    test "edgeLabel x y (edge e x y)  == e" $ \(e :: S) (x :: Int) y ->+          edgeLabel x y (edge e x y)  == e++    test "edgeLabel s t (overlay x y) == edgeLabel s t x + edgeLabel s t y" $ \(x :: LAS) y -> do+        z <- arbitrary+        s <- elements ([z] ++ vertexList x ++ vertexList y)+        t <- elements ([z] ++ vertexList x ++ vertexList y)+        return $ edgeLabel s t (overlay x y) == edgeLabel s t x + edgeLabel s t y++    testVertexCount t++    putStrLn "\n============ Labelled.AdjacencyMap.edgeCount ============"+    test "edgeCount empty        == 0" $+          edgeCount empty        == 0++    test "edgeCount (vertex x)   == 0" $ \(x :: Int) ->+          edgeCount (vertex x)   == 0++    test "edgeCount (edge e x y) == if e == zero then 0 else 1" $ \(e :: S) (x :: Int) y ->+          edgeCount (edge e x y) == if e == zero then 0 else 1++    test "edgeCount              == length . edgeList" $ \(x :: LAS) ->+          edgeCount x            == (length . edgeList) x++    testVertexList t++    putStrLn "\n============ Labelled.AdjacencyMap.edgeList ============"+    test "edgeList empty        == []" $+          edgeList (empty :: LAS) == []++    test "edgeList (vertex x)   == []" $ \(x :: Int) ->+          edgeList (vertex x :: LAS) == []++    test "edgeList (edge e x y) == if e == zero then [] else [(e,x,y)]" $ \(e :: S) (x :: Int) y ->+          edgeList (edge e x y) == if e == zero then [] else [(e,x,y)]++    testVertexSet t++    putStrLn "\n============ Labelled.AdjacencyMap.edgeSet ============"+    test "edgeSet empty        == Set.empty" $+          edgeSet (empty :: LAS) == Set.empty++    test "edgeSet (vertex x)   == Set.empty" $ \(x :: Int) ->+          edgeSet (vertex x :: LAS) == Set.empty++    test "edgeSet (edge e x y) == if e == zero then Set.empty else Set.singleton (e,x,y)" $ \(e :: S) (x :: Int) y ->+          edgeSet (edge e x y) == if e == zero then Set.empty else Set.singleton (e,x,y)++    putStrLn "\n============ Labelled.AdjacencyMap.preSet ============"+    test "preSet x empty        == Set.empty" $ \x ->+          preSet x (empty :: LAS) == Set.empty++    test "preSet x (vertex x)   == Set.empty" $ \x ->+          preSet x (vertex x :: LAS) == Set.empty++    test "preSet 1 (edge e 1 2) == Set.empty" $ \e ->+          preSet 1 (edge e 1 2 :: LAS) == Set.empty++    test "preSet y (edge e x y) == if e == zero then Set.empty else Set.fromList [x]" $ \(e :: S) (x :: Int) y ->+          preSet y (edge e x y) == if e == zero then Set.empty else Set.fromList [x]++    putStrLn "\n============ Labelled.AdjacencyMap.postSet ============"+    test "postSet x empty        == Set.empty" $ \x ->+          postSet x (empty :: LAS) == Set.empty++    test "postSet x (vertex x)   == Set.empty" $ \x ->+          postSet x (vertex x :: LAS) == Set.empty++    test "postSet x (edge e x y) == if e == zero then Set.empty else Set.fromList [y]" $ \(e :: S) (x :: Int) y ->+          postSet x (edge e x y) == if e == zero then Set.empty else Set.fromList [y]++    test "postSet 2 (edge e 1 2) == Set.empty" $ \e ->+          postSet 2 (edge e 1 2 :: LAS) == Set.empty++    putStrLn "\n============ Labelled.AdjacencyMap.skeleton ============"+    test "hasEdge x y == hasEdge x y . skeleton" $ \x y (z :: LAS) ->+          hasEdge x y z == (AM.hasEdge x y . skeleton) z++    putStrLn "\n============ Labelled.AdjacencyMap.removeVertex ============"+    test "removeVertex x (vertex x)       == empty" $ \x ->+          removeVertex x (vertex x)       == (empty :: LAS)++    test "removeVertex 1 (vertex 2)       == vertex 2" $+          removeVertex 1 (vertex 2)       == (vertex 2 :: LAS)++    test "removeVertex x (edge e x x)     == empty" $ \(e :: S) (x :: Int) ->+          removeVertex x (edge e x x)     == empty++    test "removeVertex 1 (edge e 1 2)     == vertex 2" $ \(e :: S) ->+          removeVertex 1 (edge e 1 2)     == vertex (2 :: Int)++    test "removeVertex x . removeVertex x == removeVertex x" $ \x (y :: LAS) ->+         (removeVertex x . removeVertex x) y == removeVertex x y++    putStrLn "\n============ Labelled.AdjacencyMap.removeEdge ============"+    test "removeEdge x y (edge e x y)     == vertices [x,y]" $ \(e :: S) (x :: Int) y ->+          removeEdge x y (edge e x y)     == vertices [x,y]++    test "removeEdge x y . removeEdge x y == removeEdge x y" $ \x y (z :: LAS) ->+         (removeEdge x y . removeEdge x y) z == removeEdge x y z++    test "removeEdge x y . removeVertex x == removeVertex x" $ \x y (z :: LAS) ->+         (removeEdge x y . removeVertex x) z == removeVertex x z++    test "removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2" $+          removeEdge 1 1 (1 * 1 * 2 * 2)  == (1 * 2 * 2 :: LAD)++    test "removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2" $+          removeEdge 1 2 (1 * 1 * 2 * 2)  == (1 * 1 + 2 * 2 :: LAD)++    putStrLn "\n============ Labelled.AdjacencyMap.replaceVertex ============"+    test "replaceVertex x x            == id" $ \x y ->+          replaceVertex x x y          == (y :: LAS)++    test "replaceVertex x y (vertex x) == vertex y" $ \x y ->+          replaceVertex x y (vertex x) == (vertex y :: LAS)++    test "replaceVertex x y            == gmap (\\v -> if v == x then y else v)" $ \x y (z :: LAS) ->+          replaceVertex x y z          == gmap (\v -> if v == x then y else v) z++    putStrLn "\n============ Labelled.AdjacencyMap.replaceEdge ============"+    test "replaceEdge e x y z                 == overlay (removeEdge x y z) (edge e x y)" $ \(e :: S) (x :: Int) y z ->+          replaceEdge e x y z                 == overlay (removeEdge x y z) (edge e x y)++    test "replaceEdge e x y (edge f x y)      == edge e x y" $ \(e :: S) f (x :: Int) y ->+          replaceEdge e x y (edge f x y)      == edge e x y++    test "edgeLabel x y (replaceEdge e x y z) == e" $ \(e :: S) (x :: Int) y z ->+          edgeLabel x y (replaceEdge e x y z) == e++    putStrLn "\n============ Labelled.AdjacencyMap.transpose ============"+    test "transpose empty        == empty" $+          transpose empty        == (empty :: LAS)++    test "transpose (vertex x)   == vertex x" $ \x ->+          transpose (vertex x)   == (vertex x :: LAS)++    test "transpose (edge e x y) == edge e y x" $ \e x y ->+          transpose (edge e x y) == (edge e y x :: LAS)++    test "transpose . transpose == id" $ size10 $ \x ->+         (transpose . transpose) x == (x :: LAS)++    putStrLn "\n============ Labelled.AdjacencyMap.gmap ============"+    test "gmap f empty        == empty" $ \(apply -> f) ->+          gmap f (empty :: LAS) == (empty :: LAS)++    test "gmap f (vertex x)   == vertex (f x)" $ \(apply -> f) x ->+          gmap f (vertex x :: LAS) == (vertex (f x) :: LAS)++    test "gmap f (edge e x y) == edge e (f x) (f y)" $ \(apply -> f) e x y ->+          gmap f (edge e x y :: LAS) == (edge e (f x) (f y) :: LAS)++    test "gmap id             == id" $ \x ->+          gmap id x           == (x :: LAS)++    test "gmap f . gmap g     == gmap (f . g)" $ \(apply -> f) (apply -> g) x ->+         ((gmap f :: LAS -> LAS) . gmap g) (x :: LAS)  == gmap (f . g) x++    -- TODO: We only test homomorphisms @h@ on @Sum Int@, which all happen to be+    -- just linear transformations: @h = (k*)@ for some @k :: Int@. These tests+    -- are therefore rather weak and do not cover the ruch space of possible+    -- monoid homomorphisms. How can we improve this?+    putStrLn "\n============ Labelled.AdjacencyMap.emap ============"+    test "emap h empty           == empty" $ \(k :: S) ->+        let h = (k*)+        in emap h empty          == (empty :: LAS)++    test "emap h (vertex x)      == vertex x" $ \(k :: S) x ->+        let h = (k*)+        in emap h (vertex x)     == (vertex x :: LAS)++    test "emap h (edge e x y)    == edge (h e) x y" $ \(k :: S) e x y ->+        let h = (k*)+        in emap h (edge e x y)   == (edge (h e) x y :: LAS)++    test "emap h (overlay x y)   == overlay (emap h x) (emap h y)" $ \(k :: S) x y ->+        let h = (k*)+        in emap h (overlay x y)  == (overlay (emap h x) (emap h y) :: LAS)++    test "emap h (connect e x y) == connect (h e) (emap h x) (emap h y)" $ \(k :: S) (e :: S) x y ->+        let h = (k*)+        in emap h (connect e x y) == (connect (h e) (emap h x) (emap h y) :: LAS)++    test "emap id                == id" $ \x ->+          emap id x              == (id x :: LAS)++    test "emap g . emap h        == emap (g . h)" $ \(k :: S) (l :: S) x ->+        let h = (k*)+            g = (l*)+        in (emap g . emap h) x   == (emap (g . h) x :: LAS)++    testInduce t++    putStrLn "\n============ Labelled.AdjacencyMap.closure ============"+    test "closure empty         == empty" $+          closure empty         == (empty :: LAD)++    test "closure (vertex x)    == edge one x x" $ \x ->+          closure (vertex x)    == (edge one x x :: LAD)++    test "closure (edge e x x)  == edge one x x" $ \e x ->+          closure (edge e x x)  == (edge one x x :: LAD)++    test "closure (edge e x y)  == edges [(one,x,x), (e,x,y), (one,y,y)]" $ \e x y ->+          closure (edge e x y)  == (edges [(one,x,x), (e,x,y), (one,y,y)] :: LAD)++    test "closure               == reflexiveClosure . transitiveClosure" $ size10 $ \x ->+          closure (x :: LAD)    == (reflexiveClosure . transitiveClosure) x++    test "closure               == transitiveClosure . reflexiveClosure" $ size10 $ \x ->+          closure (x :: LAD)    == (transitiveClosure . reflexiveClosure) x++    test "closure . closure     == closure" $ size10 $ \x ->+         (closure . closure) x  == closure (x :: LAD)++    test "postSet x (closure y) == Set.fromList (reachable x y)" $ size10 $ \(x :: Int) (y :: LAD) ->+          postSet x (closure y) == Set.fromList (reachable x y)++    putStrLn "\n============ Labelled.AdjacencyMap.reflexiveClosure ============"+    test "reflexiveClosure empty              == empty" $+          reflexiveClosure empty              == (empty :: LAD)++    test "reflexiveClosure (vertex x)         == edge one x x" $ \x ->+          reflexiveClosure (vertex x)         == (edge one x x :: LAD)++    test "reflexiveClosure (edge e x x)       == edge one x x" $ \e x ->+          reflexiveClosure (edge e x x)       == (edge one x x :: LAD)++    test "reflexiveClosure (edge e x y)       == edges [(one,x,x), (e,x,y), (one,y,y)]" $ \e x y ->+          reflexiveClosure (edge e x y)       == (edges [(one,x,x), (e,x,y), (one,y,y)] :: LAD)++    test "reflexiveClosure . reflexiveClosure == reflexiveClosure" $ size10 $ \x ->+         (reflexiveClosure . reflexiveClosure) x == reflexiveClosure (x :: LAD)++    putStrLn "\n============ Labelled.AdjacencyMap.symmetricClosure ============"+    test "symmetricClosure empty              == empty" $+          symmetricClosure empty              == (empty :: LAD)++    test "symmetricClosure (vertex x)         == vertex x" $ \x ->+          symmetricClosure (vertex x)         == (vertex x :: LAD)++    test "symmetricClosure (edge e x y)       == edges [(e,x,y), (e,y,x)]" $ \e x y ->+          symmetricClosure (edge e x y)       == (edges [(e,x,y), (e,y,x)] :: LAD)++    test "symmetricClosure x                  == overlay x (transpose x)" $ \x ->+          symmetricClosure x                  == (overlay x (transpose x) :: LAD)++    test "symmetricClosure . symmetricClosure == symmetricClosure" $ size10 $ \x ->+         (symmetricClosure . symmetricClosure) x == symmetricClosure (x :: LAD)++    putStrLn "\n============ Labelled.AdjacencyMap.transitiveClosure ============"+    test "transitiveClosure empty               == empty" $+          transitiveClosure empty               == (empty :: LAD)++    test "transitiveClosure (vertex x)          == vertex x" $ \x ->+          transitiveClosure (vertex x)          == (vertex x :: LAD)++    test "transitiveClosure (edge e x y)        == edge e x y" $ \e x y ->+          transitiveClosure (edge e x y)        == (edge e x y :: LAD)++    test "transitiveClosure . transitiveClosure == transitiveClosure" $ size10 $ \x ->+         (transitiveClosure . transitiveClosure) x == transitiveClosure (x :: LAD)
+ test/Algebra/Graph/Test/Labelled/Graph.hs view
@@ -0,0 +1,465 @@+{-# LANGUAGE ViewPatterns #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Test.Labelled.Graph+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- Testsuite for "Algebra.Graph.Labelled.Graph".+-----------------------------------------------------------------------------+module Algebra.Graph.Test.Labelled.Graph (+    -- * Testsuite+    testLabelledGraph+    ) where++import Data.Monoid++import Algebra.Graph.Label+import Algebra.Graph.Labelled+import Algebra.Graph.Test+import Algebra.Graph.Test.Generic++import qualified Algebra.Graph.ToGraph as T+import qualified Data.Set              as Set++t :: Testsuite+t = testsuite "Labelled.Graph." (empty :: LAI)++type S = Sum Int+type D = Distance Int++type LAI = Graph Any Int+type LAS = Graph S   Int+type LAD = Graph D   Int++testLabelledGraph :: IO ()+testLabelledGraph = do+    putStrLn "\n============ Labelled.Graph.foldg ============"+    test "foldg empty     vertex        connect             == id" $ \(x :: LAS) ->+          foldg empty     vertex        connect x           == id x++    test "foldg empty     vertex        (fmap flip connect) == transpose" $ \(x :: LAS) ->+          foldg empty     vertex        (fmap flip connect) x == transpose x++    test "foldg 1         (const 1)     (const (+))         == size" $ \(x :: LAS) ->+          foldg 1         (const 1)     (const (+)) x       == size x++    test "foldg True      (const False) (const (&&))        == isEmpty" $ \(x :: LAS) ->+          foldg True      (const False) (const (&&)) x      == isEmpty x++    test "foldg False     (== x)        (const (||))        == hasVertex x" $ \x (y :: LAS) ->+          foldg False     (== x)        (const (||)) y      == hasVertex x y++    test "foldg Set.empty Set.singleton (const Set.union)   == vertexSet" $ \(x :: LAS) ->+          foldg Set.empty Set.singleton (const Set.union) x == vertexSet x++    testEmpty  t+    testVertex t++    putStrLn "\n============ Labelled.Graph.edge ============"+    test "edge e    x y              == connect e (vertex x) (vertex y)" $ \(e :: S) (x :: Int) y ->+          edge e    x y              == connect e (vertex x) (vertex y)++    test "edge zero x y              == vertices [x,y]" $ \(x :: Int) y ->+          edge (zero :: S) x y       == vertices [x,y]++    test "hasEdge   x y (edge e x y) == (e /= mempty)" $ \(e :: S) (x :: Int) y ->+          hasEdge   x y (edge e x y) == (e /= mempty)++    test "edgeLabel x y (edge e x y) == e" $ \(e :: S) (x :: Int) y ->+          edgeLabel x y (edge e x y) == e++    test "edgeCount     (edge e x y) == if e == mempty then 0 else 1" $ \(e :: S) (x :: Int) y ->+          T.edgeCount     (edge e x y) == if e == mempty then 0 else 1++    test "vertexCount   (edge e 1 1) == 1" $ \(e :: S) ->+          T.vertexCount   (edge e 1 (1 :: Int)) == 1++    test "vertexCount   (edge e 1 2) == 2" $ \(e :: S) ->+          T.vertexCount   (edge e 1 (2 :: Int)) == 2++    test "x -<e>- y                  == edge e x y" $ \(e :: S) (x :: Int) y ->+          x -<e>- y                  == edge e x y++    testOverlay t++    putStrLn ""+    test "edgeLabel x y $ overlay (edge e x y) (edge zero x y) == e" $ \(e :: S) (x :: Int) y ->+          edgeLabel x y (overlay (edge e x y) (edge zero x y)) == e++    test "edgeLabel x y $ overlay (edge e x y) (edge f    x y) == e <+> f" $ \(e :: S) f (x :: Int) y ->+          edgeLabel x y (overlay (edge e x y) (edge f    x y)) == e <+> f++    putStrLn ""+    test "edgeLabel 1 3 $ transitiveClosure (overlay (edge e 1 2) (edge one 2 3)) == e" $ \(e :: D) ->+          edgeLabel 1 3 (transitiveClosure (overlay (edge e 1 2) (edge one 2 (3 :: Int)))) == e++    test "edgeLabel 1 3 $ transitiveClosure (overlay (edge e 1 2) (edge f   2 3)) == e <.> f" $ \(e :: D) f ->+          edgeLabel 1 3 (transitiveClosure (overlay (edge e 1 2) (edge f   2 (3 :: Int))))== e <.> f++    putStrLn "\n============ Labelled.Graph.connect ============"+    test "isEmpty     (connect e x y) == isEmpty   x   && isEmpty   y" $ size10 $ \(e :: S) (x :: LAS) y ->+          isEmpty     (connect e x y) ==(isEmpty   x   && isEmpty   y)++    test "hasVertex z (connect e x y) == hasVertex z x || hasVertex z y" $ size10 $ \(e :: S) (x :: LAS) y z ->+          hasVertex z (connect e x y) ==(hasVertex z x || hasVertex z y)++    test "vertexCount (connect e x y) >= vertexCount x" $ size10 $ \(e :: S) (x :: LAS) y ->+          T.vertexCount (connect e x y) >= T.vertexCount x++    test "vertexCount (connect e x y) <= vertexCount x + vertexCount y" $ size10 $ \(e :: S) (x :: LAS) y ->+          T.vertexCount (connect e x y) <= T.vertexCount x + T.vertexCount y++    test "edgeCount   (connect e x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y" $ size10 $ \(e :: S) (x :: LAS) y ->+          T.edgeCount   (connect e x y) <= T.vertexCount x * T.vertexCount y + T.edgeCount x + T.edgeCount y++    test "vertexCount (connect e 1 2) == 2" $ \(e :: Any) ->+          T.vertexCount (connect e 1 (2 :: LAI)) == 2++    test "edgeCount   (connect e 1 2) == if e == zero then 0 else 1" $ \(e :: Any) ->+          T.edgeCount   (connect e 1 (2 :: LAI)) == if e == zero then 0 else 1++    testVertices t++    putStrLn "\n============ Labelled.Graph.edges ============"+    test "edges []        == empty" $+          edges []        == (empty :: LAS)++    test "edges [(e,x,y)] == edge e x y" $ \(e :: S) (x :: Int) y ->+          edges [(e,x,y)] == edge e x y++    test "edges           == overlays . map (\\(e, x, y) -> edge e x y)" $ \(es :: [(S, Int, Int)]) ->+          edges es        ==(overlays . map (\(e, x, y) -> edge e x y)) es++    testOverlays t++    putStrLn "\n============ Labelled.Graph.isSubgraphOf ============"+    test "isSubgraphOf empty      x     ==  True" $ \(x :: LAS) ->+          isSubgraphOf empty      x     ==  True++    test "isSubgraphOf (vertex x) empty ==  False" $ \(x :: Int) ->+          isSubgraphOf (vertex x)(empty :: LAS)==  False++    test "isSubgraphOf x y              ==> x <= y" $ \(x :: LAD) z ->+        let y = x + z -- Make sure we hit the precondition+        in isSubgraphOf x y             ==> x <= y++    putStrLn "\n============ Labelled.Graph.isEmpty ============"+    test "isEmpty empty                         == True" $+          isEmpty empty                         == True++    test "isEmpty (overlay empty empty)         == True" $+          isEmpty (overlay empty empty :: LAS)  == True++    test "isEmpty (vertex x)                    == False" $ \(x :: Int) ->+          isEmpty (vertex x)                    == False++    test "isEmpty (removeVertex x $ vertex x)   == True" $ \(x :: Int) ->+          isEmpty (removeVertex x $ vertex x)   == True++    test "isEmpty (removeEdge x y $ edge e x y) == False" $ \(e :: S) (x :: Int) y ->+          isEmpty (removeEdge x y $ edge e x y) == False++    testHasVertex t++    putStrLn "\n============ Labelled.Graph.hasEdge ============"+    test "hasEdge x y empty            == False" $ \(x :: Int) y ->+          hasEdge x y (empty :: LAS)   == False++    test "hasEdge x y (vertex z)       == False" $ \(x :: Int) y z ->+          hasEdge x y (vertex z :: LAS) == False++    test "hasEdge x y (edge e x y)     == (e /= zero)" $ \(e :: S) (x :: Int) y ->+          hasEdge x y (edge e x y)     == (e /= zero)++    test "hasEdge x y . removeEdge x y == const False" $ \x y (z :: LAS) ->+         (hasEdge x y . removeEdge x y) z == const False z++    test "hasEdge x y                  == not . null . filter (\\(_,ex,ey) -> ex == x && ey == y) . edgeList" $ \x y (z :: LAS) -> do+        (_, u, v) <- elements ((zero, x, y) : edgeList z)+        return $ hasEdge u v z         == (not . null . filter (\(_,ex,ey) -> ex == u && ey == v) . edgeList) z++    putStrLn "\n============ Labelled.Graph.edgeLabel ============"+    test "edgeLabel x y empty         == zero" $ \(x :: Int) y ->+          edgeLabel x y empty         == (zero :: S)++    test "edgeLabel x y (vertex z)    == zero" $ \(x :: Int) y z ->+          edgeLabel x y (vertex z)    == (zero :: S)++    test "edgeLabel x y (edge e x y)  == e" $ \(e :: S) (x :: Int) y ->+          edgeLabel x y (edge e x y)  == e++    test "edgeLabel s t (overlay x y) == edgeLabel s t x + edgeLabel s t y" $ \(x :: LAS) y -> do+        z <- arbitrary+        s <- elements ([z] ++ T.vertexList x ++ T.vertexList y)+        t <- elements ([z] ++ T.vertexList x ++ T.vertexList y)+        return $ edgeLabel s t (overlay x y) == edgeLabel s t x + edgeLabel s t y++    testVertexCount t++    putStrLn "\n============ Labelled.Graph.edgeCount ============"+    test "edgeCount empty        == 0" $+          T.edgeCount (empty :: LAS) == 0++    test "edgeCount (vertex x)   == 0" $ \(x :: Int) ->+          T.edgeCount (vertex x :: LAS) == 0++    test "edgeCount (edge e x y) == if e == zero then 0 else 1" $ \(e :: S) (x :: Int) y ->+          T.edgeCount (edge e x y) == if e == zero then 0 else 1++    test "edgeCount              == length . edgeList" $ \(x :: LAS) ->+          T.edgeCount x            == (length . edgeList) x++    testVertexList t++    putStrLn "\n============ Labelled.Graph.edgeList ============"+    test "edgeList empty        == []" $+          edgeList (empty :: LAS) == []++    test "edgeList (vertex x)   == []" $ \(x :: Int) ->+          edgeList (vertex x :: LAS) == []++    test "edgeList (edge e x y) == if e == zero then [] else [(e,x,y)]" $ \(e :: S) (x :: Int) y ->+          edgeList (edge e x y) == if e == zero then [] else [(e,x,y)]++    testVertexSet t++    putStrLn "\n============ Labelled.Graph.edgeSet ============"+    test "edgeSet empty        == Set.empty" $+          edgeSet (empty :: LAS) == Set.empty++    test "edgeSet (vertex x)   == Set.empty" $ \(x :: Int) ->+          edgeSet (vertex x :: LAS) == Set.empty++    test "edgeSet (edge e x y) == if e == zero then Set.empty else Set.singleton (e,x,y)" $ \(e :: S) (x :: Int) y ->+          edgeSet (edge e x y) == if e == zero then Set.empty else Set.singleton (e,x,y)++    putStrLn "\n============ Labelled.Graph.preSet ============"+    test "preSet x empty        == Set.empty" $ \x ->+          T.preSet x (empty :: LAS) == Set.empty++    test "preSet x (vertex x)   == Set.empty" $ \x ->+          T.preSet x (vertex x :: LAS) == Set.empty++    test "preSet 1 (edge e 1 2) == Set.empty" $ \e ->+          T.preSet 1 (edge e 1 2 :: LAS) == Set.empty++    test "preSet y (edge e x y) == if e == zero then Set.empty else Set.fromList [x]" $ \(e :: S) (x :: Int) y ->+          T.preSet y (edge e x y) == if e == zero then Set.empty else Set.fromList [x]++    putStrLn "\n============ Labelled.Graph.postSet ============"+    test "postSet x empty        == Set.empty" $ \x ->+          T.postSet x (empty :: LAS) == Set.empty++    test "postSet x (vertex x)   == Set.empty" $ \x ->+          T.postSet x (vertex x :: LAS) == Set.empty++    test "postSet x (edge e x y) == if e == zero then Set.empty else Set.fromList [y]" $ \(e :: S) (x :: Int) y ->+          T.postSet x (edge e x y) == if e == zero then Set.empty else Set.fromList [y]++    test "postSet 2 (edge e 1 2) == Set.empty" $ \e ->+          T.postSet 2 (edge e 1 2 :: LAS) == Set.empty++    putStrLn "\n============ Labelled.Graph.removeVertex ============"+    test "removeVertex x (vertex x)       == empty" $ \x ->+          removeVertex x (vertex x)       == (empty :: LAS)++    test "removeVertex 1 (vertex 2)       == vertex 2" $+          removeVertex 1 (vertex 2)       == (vertex 2 :: LAS)++    test "removeVertex x (edge e x x)     == empty" $ \(e :: S) (x :: Int) ->+          removeVertex x (edge e x x)     == empty++    test "removeVertex 1 (edge e 1 2)     == vertex 2" $ \(e :: S) ->+          removeVertex 1 (edge e 1 2)     == vertex (2 :: Int)++    test "removeVertex x . removeVertex x == removeVertex x" $ \x (y :: LAS) ->+         (removeVertex x . removeVertex x) y == removeVertex x y++    putStrLn "\n============ Labelled.Graph.removeEdge ============"+    test "removeEdge x y (edge e x y)     == vertices [x,y]" $ \(e :: S) (x :: Int) y ->+          removeEdge x y (edge e x y)     == vertices [x,y]++    test "removeEdge x y . removeEdge x y == removeEdge x y" $ \x y (z :: LAS) ->+         (removeEdge x y . removeEdge x y) z == removeEdge x y z++    test "removeEdge x y . removeVertex x == removeVertex x" $ \x y (z :: LAS) ->+         (removeEdge x y . removeVertex x) z == removeVertex x z++    test "removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2" $+          removeEdge 1 1 (1 * 1 * 2 * 2)  == (1 * 2 * 2 :: LAD)++    test "removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2" $+          removeEdge 1 2 (1 * 1 * 2 * 2)  == (1 * 1 + 2 * 2 :: LAD)++    putStrLn "\n============ Labelled.Graph.replaceVertex ============"+    test "replaceVertex x x            == id" $ \x y ->+          replaceVertex x x y          == (y :: LAS)++    test "replaceVertex x y (vertex x) == vertex y" $ \x y ->+          replaceVertex x y (vertex x) == (vertex y :: LAS)++    test "replaceVertex x y            == fmap (\\v -> if v == x then y else v)" $ \x y (z :: LAS) ->+          replaceVertex x y z          == fmap (\v -> if v == x then y else v) z++    putStrLn "\n============ Labelled.Graph.replaceEdge ============"+    test "replaceEdge e x y z                 == overlay (removeEdge x y z) (edge e x y)" $ \(e :: S) (x :: Int) y z ->+          replaceEdge e x y z                 == overlay (removeEdge x y z) (edge e x y)++    test "replaceEdge e x y (edge f x y)      == edge e x y" $ \(e :: S) f (x :: Int) y ->+          replaceEdge e x y (edge f x y)      == edge e x y++    test "edgeLabel x y (replaceEdge e x y z) == e" $ \(e :: S) (x :: Int) y z ->+          edgeLabel x y (replaceEdge e x y z) == e++    putStrLn "\n============ Labelled.Graph.transpose ============"+    test "transpose empty        == empty" $+          transpose empty        == (empty :: LAS)++    test "transpose (vertex x)   == vertex x" $ \x ->+          transpose (vertex x)   == (vertex x :: LAS)++    test "transpose (edge e x y) == edge e y x" $ \e x y ->+          transpose (edge e x y) == (edge e y x :: LAS)++    test "transpose . transpose == id" $ size10 $ \x ->+         (transpose . transpose) x == (x :: LAS)++    putStrLn "\n============ Labelled.Graph.fmap ============"+    test "fmap f empty        == empty" $ \(apply -> f) ->+          fmap f (empty :: LAS) == (empty :: LAS)++    test "fmap f (vertex x)   == vertex (f x)" $ \(apply -> f) x ->+          fmap f (vertex x :: LAS) == (vertex (f x) :: LAS)++    test "fmap f (edge e x y) == edge e (f x) (f y)" $ \(apply -> f) e x y ->+          fmap f (edge e x y :: LAS) == (edge e (f x) (f y) :: LAS)++    test "fmap id             == id" $ \x ->+          fmap id x           == (x :: LAS)++    test "fmap f . fmap g     == fmap (f . g)" $ \(apply -> f) (apply -> g) x ->+         ((fmap f :: LAS -> LAS) . fmap g) (x :: LAS)  == fmap (f . g) x++    -- TODO: We only test homomorphisms @h@ on @Sum Int@, which all happen to be+    -- just linear transformations: @h = (k*)@ for some @k :: Int@. These tests+    -- are therefore rather weak and do not cover the ruch space of possible+    -- monoid homomorphisms. How can we improve this?+    putStrLn "\n============ Labelled.Graph.emap ============"+    test "emap h empty           == empty" $ \(k :: S) ->+        let h = (k*)+        in emap h empty          == (empty :: LAS)++    test "emap h (vertex x)      == vertex x" $ \(k :: S) x ->+        let h = (k*)+        in emap h (vertex x)     == (vertex x :: LAS)++    test "emap h (edge e x y)    == edge (h e) x y" $ \(k :: S) e x y ->+        let h = (k*)+        in emap h (edge e x y)   == (edge (h e) x y :: LAS)++    test "emap h (overlay x y)   == overlay (emap h x) (emap h y)" $ \(k :: S) x y ->+        let h = (k*)+        in emap h (overlay x y)  == (overlay (emap h x) (emap h y) :: LAS)++    test "emap h (connect e x y) == connect (h e) (emap h x) (emap h y)" $ \(k :: S) (e :: S) x y ->+        let h = (k*)+        in emap h (connect e x y) == (connect (h e) (emap h x) (emap h y) :: LAS)++    test "emap id                == id" $ \x ->+          emap id x              == (id x :: LAS)++    test "emap g . emap h        == emap (g . h)" $ \(k :: S) (l :: S) x ->+        let h = (k*)+            g = (l*)+        in (emap g . emap h) x   == (emap (g . h) x :: LAS)++    testInduce t++    putStrLn "\n============ Labelled.Graph.closure ============"+    test "closure empty         == empty" $+          closure empty         == (empty :: LAD)++    test "closure (vertex x)    == edge one x x" $ \x ->+          closure (vertex x)    == (edge one x x :: LAD)++    test "closure (edge e x x)  == edge one x x" $ \e x ->+          closure (edge e x x)  == (edge one x x :: LAD)++    test "closure (edge e x y)  == edges [(one,x,x), (e,x,y), (one,y,y)]" $ \e x y ->+          closure (edge e x y)  == (edges [(one,x,x), (e,x,y), (one,y,y)] :: LAD)++    test "closure               == reflexiveClosure . transitiveClosure" $ size10 $ \x ->+          closure (x :: LAD)    == (reflexiveClosure . transitiveClosure) x++    test "closure               == transitiveClosure . reflexiveClosure" $ size10 $ \x ->+          closure (x :: LAD)    == (transitiveClosure . reflexiveClosure) x++    test "closure . closure     == closure" $ size10 $ \x ->+         (closure . closure) x  == closure (x :: LAD)++    test "postSet x (closure y) == Set.fromList (reachable x y)" $ size10 $ \(x :: Int) (y :: LAD) ->+          T.postSet x (closure y) == Set.fromList (T.reachable x y)++    putStrLn "\n============ Labelled.Graph.reflexiveClosure ============"+    test "reflexiveClosure empty              == empty" $+          reflexiveClosure empty              == (empty :: LAD)++    test "reflexiveClosure (vertex x)         == edge one x x" $ \x ->+          reflexiveClosure (vertex x)         == (edge one x x :: LAD)++    test "reflexiveClosure (edge e x x)       == edge one x x" $ \e x ->+          reflexiveClosure (edge e x x)       == (edge one x x :: LAD)++    test "reflexiveClosure (edge e x y)       == edges [(one,x,x), (e,x,y), (one,y,y)]" $ \e x y ->+          reflexiveClosure (edge e x y)       == (edges [(one,x,x), (e,x,y), (one,y,y)] :: LAD)++    test "reflexiveClosure . reflexiveClosure == reflexiveClosure" $ size10 $ \x ->+         (reflexiveClosure . reflexiveClosure) x == reflexiveClosure (x :: LAD)++    putStrLn "\n============ Labelled.Graph.symmetricClosure ============"+    test "symmetricClosure empty              == empty" $+          symmetricClosure empty              == (empty :: LAD)++    test "symmetricClosure (vertex x)         == vertex x" $ \x ->+          symmetricClosure (vertex x)         == (vertex x :: LAD)++    test "symmetricClosure (edge e x y)       == edges [(e,x,y), (e,y,x)]" $ \e x y ->+          symmetricClosure (edge e x y)       == (edges [(e,x,y), (e,y,x)] :: LAD)++    test "symmetricClosure x                  == overlay x (transpose x)" $ \x ->+          symmetricClosure x                  == (overlay x (transpose x) :: LAD)++    test "symmetricClosure . symmetricClosure == symmetricClosure" $ size10 $ \x ->+         (symmetricClosure . symmetricClosure) x == symmetricClosure (x :: LAD)++    putStrLn "\n============ Labelled.Graph.transitiveClosure ============"+    test "transitiveClosure empty               == empty" $+          transitiveClosure empty               == (empty :: LAD)++    test "transitiveClosure (vertex x)          == vertex x" $ \x ->+          transitiveClosure (vertex x)          == (vertex x :: LAD)++    test "transitiveClosure (edge e x y)        == edge e x y" $ \e x y ->+          transitiveClosure (edge e x y)        == (edge e x y :: LAD)++    test "transitiveClosure . transitiveClosure == transitiveClosure" $ size10 $ \x ->+         (transitiveClosure . transitiveClosure) x == transitiveClosure (x :: LAD)++    putStrLn "\n============ Labelled.Graph.context ============"+    test "context (const False) x                   == Nothing" $ \x ->+          context (const False) (x :: LAS)          == Nothing++    test "context (== 1)        (edge e 1 2)        == if e == zero then Just (Context [] []) else Just (Context []      [(e,2)])" $ \e ->+          context (== 1)        (edge e 1 2 :: LAS) == if e == zero then Just (Context [] []) else Just (Context []      [(e,2)])++    test "context (== 2)        (edge e 1 2)        == if e == zero then Just (Context [] []) else Just (Context [(e,1)] []     )" $ \e ->+          context (== 2)        (edge e 1 2 :: LAS) == if e == zero then Just (Context [] []) else Just (Context [(e,1)] []     )++    test "context (const True ) (edge e 1 2)        == if e == zero then Just (Context [] []) else Just (Context [(e,1)] [(e,2)])" $ \e ->+          context (const True ) (edge e 1 2 :: LAS) == if e == zero then Just (Context [] []) else Just (Context [(e,1)] [(e,2)])++    test "context (== 4)        (3 * 1 * 4 * 1 * 5) == Just (Context [(one,3), (one,1)] [(one,1), (one,5)])" $+          context (== 4)        (3 * 1 * 4 * 1 * 5 :: LAD) == Just (Context [(one,3), (one,1)] [(one,1), (one,5)])
+ test/Algebra/Graph/Test/NonEmpty/AdjacencyMap.hs view
@@ -0,0 +1,613 @@+{-# LANGUAGE CPP, OverloadedLists, ViewPatterns #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Test.NonEmpty.AdjacencyMap+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- Testsuite for "Algebra.Graph.NonEmpty.AdjacencyMap".+-----------------------------------------------------------------------------+module Algebra.Graph.Test.NonEmpty.AdjacencyMap (+    -- * Testsuite+    testNonEmptyAdjacencyMap+  ) where++import Prelude ()+import Prelude.Compat++#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup+#endif++import Control.Monad+import Data.Tree+import Data.Tuple++import Algebra.Graph.NonEmpty.AdjacencyMap+import Algebra.Graph.Test hiding (axioms, theorems)+import Algebra.Graph.ToGraph (toAdjacencyMap, reachable)++import qualified Algebra.Graph.AdjacencyMap          as AM+import qualified Algebra.Graph.NonEmpty.AdjacencyMap as NonEmpty+import qualified Data.List.NonEmpty                  as NonEmpty+import qualified Data.Set                            as Set++sizeLimit :: Testable prop => prop -> Property+sizeLimit = mapSize (min 10)++type G = NonEmpty.AdjacencyMap Int++axioms :: G -> G -> G -> Property+axioms x y z = conjoin+    [       x + y == y + x                      // "Overlay commutativity"+    , x + (y + z) == (x + y) + z                // "Overlay associativity"+    , x * (y * z) == (x * y) * z                // "Connect associativity"+    , x * (y + z) == x * y + x * z              // "Left distributivity"+    , (x + y) * z == x * z + y * z              // "Right distributivity"+    ,   x * y * z == x * y + x * z + y * z      // "Decomposition" ]++theorems :: G -> G -> Property+theorems x y = conjoin+    [         x + x == x                        // "Overlay idempotence"+    , x + y + x * y == x * y                    // "Absorption"+    ,         x * x == x * x * x                // "Connect saturation"+    ,             x <= x + y                    // "Overlay order"+    ,         x + y <= x * y                    // "Overlay-connect order" ]++testNonEmptyAdjacencyMap :: IO ()+testNonEmptyAdjacencyMap = do+    putStrLn "\n============ NonEmpty.AdjacencyMap ============"+    test "Axioms of non-empty graphs"   axioms+    test "Theorems of non-empty graphs" theorems++    putStrLn $ "\n============ Ord (NonEmpty.AdjacencyMap a) ============"+    test "vertex 1 <  vertex 2" $+          vertex 1 <  vertex (2 :: Int)++    test "vertex 3 <  edge 1 2" $+          vertex 3 <  edge 1 (2 :: Int)++    test "vertex 1 <  edge 1 1" $+          vertex 1 <  edge 1 (1 :: Int)++    test "edge 1 1 <  edge 1 2" $+          edge 1 1 <  edge 1 (2 :: Int)++    test "edge 1 2 <  edge 1 1 + edge 2 2" $+          edge 1 2 <  edge 1 1 + edge 2 (2 :: Int)++    test "edge 1 2 <  edge 1 3" $+          edge 1 2 <  edge 1 (3 :: Int)++    test "x        <= x + y" $ \(x :: G) y ->+          x        <= x + y++    test "x + y    <= x * y" $ \(x :: G) y ->+          x + y    <= x * y++    putStrLn $ "\n============ Show (NonEmpty.AdjacencyMap a) ============"+    test "show (1         :: AdjacencyMap Int) == \"vertex 1\"" $+          show (1         :: AdjacencyMap Int) == "vertex 1"++    test "show (1 + 2     :: AdjacencyMap Int) == \"vertices1 [1,2]\"" $+          show (1 + 2     :: AdjacencyMap Int) == "vertices1 [1,2]"++    test "show (1 * 2     :: AdjacencyMap Int) == \"edge 1 2\"" $+          show (1 * 2     :: AdjacencyMap Int) == "edge 1 2"++    test "show (1 * 2 * 3 :: AdjacencyMap Int) == \"edges1 [(1,2),(1,3),(2,3)]\"" $+          show (1 * 2 * 3 :: AdjacencyMap Int) == "edges1 [(1,2),(1,3),(2,3)]"++    test "show (1 * 2 + 3 :: AdjacencyMap Int) == \"overlay (vertex 3) (edge 1 2)\"" $+          show (1 * 2 + 3 :: AdjacencyMap Int) == "overlay (vertex 3) (edge 1 2)"++    test "show (vertex (-1)                             :: AdjacencyMap Int) == \"vertex (-1)\"" $+          show (vertex (-1)                             :: AdjacencyMap Int) == "vertex (-1)"++    test "show (vertex (-1) + vertex (-2)               :: AdjacencyMap Int) == \"vertices1 [-2,-1]\"" $+          show (vertex (-1) + vertex (-2)               :: AdjacencyMap Int) == "vertices1 [-2,-1]"++    test "show (vertex (-1) * vertex (-2)               :: AdjacencyMap Int) == \"edge (-1) (-2)\"" $+          show (vertex (-1) * vertex (-2)               :: AdjacencyMap Int) == "edge (-1) (-2)"++    test "show (vertex (-1) * vertex (-2) * vertex (-3) :: AdjacencyMap Int) == \"edges1 [(-2,-3),(-1,-3),(-1,-2)]\"" $+          show (vertex (-1) * vertex (-2) * vertex (-3) :: AdjacencyMap Int) == "edges1 [(-2,-3),(-1,-3),(-1,-2)]"++    test "show (vertex (-1) * vertex (-2) + vertex (-3) :: AdjacencyMap Int) == \"overlay (vertex (-3)) (edge (-1) (-2))\"" $+          show (vertex (-1) * vertex (-2) + vertex (-3) :: AdjacencyMap Int) == "overlay (vertex (-3)) (edge (-1) (-2))"++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.toNonEmpty ============"+    test "toNonEmpty empty              == Nothing" $+          toNonEmpty (AM.empty :: AM.AdjacencyMap Int) == Nothing++    test "toNonEmpty (toAdjacencyMap x) == Just (x :: NonEmpty.AdjacencyMap a)" $ \x ->+          toNonEmpty (toAdjacencyMap x) == Just (x :: G)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.vertex ============"+    test "hasVertex x (vertex x) == True" $ \(x :: Int) ->+          hasVertex x (vertex x) == True++    test "vertexCount (vertex x) == 1" $ \(x :: Int) ->+          vertexCount (vertex x) == 1++    test "edgeCount   (vertex x) == 0" $ \(x :: Int) ->+          edgeCount   (vertex x) == 0++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.edge ============"+    test "edge x y               == connect (vertex x) (vertex y)" $ \(x :: Int) y ->+          edge x y               == connect (vertex x) (vertex y)++    test "hasEdge x y (edge x y) == True" $ \(x :: Int) y ->+          hasEdge x y (edge x y) == True++    test "edgeCount   (edge x y) == 1" $ \(x :: Int) y ->+          edgeCount   (edge x y) == 1++    test "vertexCount (edge 1 1) == 1" $+          vertexCount (edge 1 1 :: G) == 1++    test "vertexCount (edge 1 2) == 2" $+          vertexCount (edge 1 2 :: G) == 2++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.overlay ============"+    test "hasVertex z (overlay x y) == hasVertex z x || hasVertex z y" $ \(x :: G) y z ->+          hasVertex z (overlay x y) == hasVertex z x || hasVertex z y++    test "vertexCount (overlay x y) >= vertexCount x" $ \(x :: G) y ->+          vertexCount (overlay x y) >= vertexCount x++    test "vertexCount (overlay x y) <= vertexCount x + vertexCount y" $ \(x :: G) y ->+          vertexCount (overlay x y) <= vertexCount x + vertexCount y++    test "edgeCount   (overlay x y) >= edgeCount x" $ \(x :: G) y ->+          edgeCount   (overlay x y) >= edgeCount x++    test "edgeCount   (overlay x y) <= edgeCount x   + edgeCount y" $ \(x :: G) y ->+          edgeCount   (overlay x y) <= edgeCount x   + edgeCount y++    test "vertexCount (overlay 1 2) == 2" $+          vertexCount (overlay 1 2 :: G) == 2++    test "edgeCount   (overlay 1 2) == 0" $+          edgeCount   (overlay 1 2 :: G) == 0++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.connect ============"+    test "hasVertex z (connect x y) == hasVertex z x || hasVertex z y" $ \(x :: G) y z ->+          hasVertex z (connect x y) == hasVertex z x || hasVertex z y++    test "vertexCount (connect x y) >= vertexCount x" $ \(x :: G) y ->+          vertexCount (connect x y) >= vertexCount x++    test "vertexCount (connect x y) <= vertexCount x + vertexCount y" $ \(x :: G) y ->+          vertexCount (connect x y) <= vertexCount x + vertexCount y++    test "edgeCount   (connect x y) >= edgeCount x" $ \(x :: G) y ->+          edgeCount   (connect x y) >= edgeCount x++    test "edgeCount   (connect x y) >= edgeCount y" $ \(x :: G) y ->+          edgeCount   (connect x y) >= edgeCount y++    test "edgeCount   (connect x y) >= vertexCount x * vertexCount y" $ \(x :: G) y ->+          edgeCount   (connect x y) >= vertexCount x * vertexCount y++    test "edgeCount   (connect x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y" $ \(x :: G) y ->+          edgeCount   (connect x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y++    test "vertexCount (connect 1 2) == 2" $+          vertexCount (connect 1 2 :: G) == 2++    test "edgeCount   (connect 1 2) == 1" $+          edgeCount   (connect 1 2 :: G) == 1++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.vertices1 ============"+    test "vertices1 [x]           == vertex x" $ \(x :: Int) ->+          vertices1 [x]           == vertex x++    test "hasVertex x . vertices1 == elem x" $ \(x :: Int) (xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (hasVertex x . vertices1) xs == elem x (NonEmpty.toList xs)++    test "vertexCount . vertices1 == length . nub" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexCount . vertices1) xs == (NonEmpty.length . NonEmpty.nub) xs++    test "vertexSet   . vertices1 == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexSet   . vertices1) xs == (Set.fromList . NonEmpty.toList) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.edges1 ============"+    test "edges1 [(x,y)]     == edge x y" $ \(x :: Int) y ->+          edges1 [(x,y)]     == edge x y++    test "edgeCount . edges1 == length . nub" $ \(xs' :: NonEmptyList (Int, Int)) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (edgeCount . edges1) xs == (NonEmpty.length . NonEmpty.nub) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.overlays1 ============"+    test "overlays1 [x]   == x" $ \(x :: G) ->+          overlays1 [x]   == x++    test "overlays1 [x,y] == overlay x y" $ \(x :: G) y ->+          overlays1 [x,y] == overlay x y++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.connects1 ============"+    test "connects1 [x]   == x" $ \(x :: G) ->+          connects1 [x]   == x++    test "connects1 [x,y] == connect x y" $ \(x :: G) y ->+          connects1 [x,y] == connect x y++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.isSubgraphOf ============"+    test "isSubgraphOf x             (overlay x y) ==  True" $ \(x :: G) y ->+          isSubgraphOf x             (overlay x y) ==  True++    test "isSubgraphOf (overlay x y) (connect x y) ==  True" $ \(x :: G) y ->+          isSubgraphOf (overlay x y) (connect x y) ==  True++    test "isSubgraphOf (path1 xs)    (circuit1 xs) ==  True" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in isSubgraphOf (path1 xs)    (circuit1 xs) == True++    test "isSubgraphOf x y                         ==> x <= y" $ \(x :: G) z ->+        let y = x + z -- Make sure we hit the precondition+        in isSubgraphOf x y                        ==> x <= y++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.hasVertex ============"+    test "hasVertex x (vertex x) == True" $ \(x :: Int) ->+          hasVertex x (vertex x) == True++    test "hasVertex 1 (vertex 2) == False" $+          hasVertex 1 (vertex 2 :: G) == False++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.hasEdge ============"+    test "hasEdge x y (vertex z)       == False" $ \(x :: Int) y z ->+          hasEdge x y (vertex z)       == False++    test "hasEdge x y (edge x y)       == True" $ \(x :: Int) y ->+          hasEdge x y (edge x y)       == True++    test "hasEdge x y . removeEdge x y == const False" $ \(x :: Int) y z ->+         (hasEdge x y . removeEdge x y) z == False++    test "hasEdge x y                  == elem (x,y) . edgeList" $ \(x :: Int) y z -> do+        (u, v) <- elements ((x, y) : edgeList z)+        return $ hasEdge u v z == elem (u, v) (edgeList z)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.vertexCount ============"+    test "vertexCount (vertex x) == 1" $ \(x :: Int) ->+          vertexCount (vertex x) == 1++    test "vertexCount x          >= 1" $ \(x :: G) ->+          vertexCount x          >= 1++    test "vertexCount            == length . vertexList1" $ \(x :: G) ->+          vertexCount x          == (NonEmpty.length . vertexList1) x++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.edgeCount ============"+    test "edgeCount (vertex x) == 0" $ \(x :: Int) ->+          edgeCount (vertex x) == 0++    test "edgeCount (edge x y) == 1" $ \(x :: Int) y ->+          edgeCount (edge x y) == 1++    test "edgeCount            == length . edgeList" $ \(x :: G) ->+          edgeCount x          == (length . edgeList) x++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.vertexList1 ============"+    test "vertexList1 (vertex x)  == [x]" $ \(x :: Int) ->+          vertexList1 (vertex x)  == [x]++    test "vertexList1 . vertices1 == nub . sort" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexList1 . vertices1) xs == (NonEmpty.nub . NonEmpty.sort) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.edgeList ============"+    test "edgeList (vertex x)     == []" $ \(x :: Int) ->+          edgeList (vertex x)     == []++    test "edgeList (edge x y)     == [(x,y)]" $ \(x :: Int) y ->+          edgeList (edge x y)     == [(x,y)]++    test "edgeList (star 2 [3,1]) == [(2,1), (2,3)]" $+          edgeList (star 2 [3,1]) == [(2,1), (2,3 :: Int)]++    test "edgeList . edges1       == nub . sort . toList" $ \(xs' :: NonEmptyList (Int, Int)) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (edgeList . edges1) xs   == (nubOrd . sort . NonEmpty.toList) xs++    test "edgeList . transpose    == sort . map swap . edgeList" $ \(x :: G) ->+         (edgeList . transpose) x == (sort . map swap . edgeList) x++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.vertexSet ============"+    test "vertexSet . vertex    == Set.singleton" $ \(x :: Int) ->+         (vertexSet . vertex) x == Set.singleton x++    test "vertexSet . vertices1 == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexSet . vertices1) xs == (Set.fromList . NonEmpty.toList) xs++    test "vertexSet . clique1   == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexSet . clique1) xs == (Set.fromList . NonEmpty.toList) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.edgeSet ============"+    test "edgeSet (vertex x) == Set.empty" $ \(x :: Int) ->+          edgeSet (vertex x) == Set.empty++    test "edgeSet (edge x y) == Set.singleton (x,y)" $ \(x :: Int) y ->+          edgeSet (edge x y) == Set.singleton (x,y)++    test "edgeSet . edges1   == Set.fromList . toList" $ \(xs' :: NonEmptyList (Int, Int)) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (edgeSet . edges1) xs == (Set.fromList . NonEmpty.toList) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.preSet ============"+    test "preSet x (vertex x) == Set.empty" $ \(x :: G) ->+          preSet x (vertex x) == Set.empty++    test "preSet 1 (edge 1 2) == Set.empty" $+          preSet 1 (edge 1 2 :: G) == Set.empty++    test "preSet y (edge x y) == Set.fromList [x]" $ \(x :: G) y ->+          preSet y (edge x y) == Set.fromList [x]++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.postSet ============"+    test "postSet x (vertex x) == Set.empty" $ \(x :: G) ->+          postSet x (vertex x) == Set.empty++    test "postSet x (edge x y) == Set.fromList [y]" $ \(x :: G) y ->+          postSet x (edge x y) == Set.fromList [y]++    test "postSet 2 (edge 1 2) == Set.empty" $+          postSet 2 (edge 1 2 :: G) == Set.empty++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.path1 ============"+    test "path1 [x]       == vertex x" $ \(x :: Int) ->+          path1 [x]       == vertex x++    test "path1 [x,y]     == edge x y" $ \(x :: Int) y ->+          path1 [x,y]     == edge x y++    test "path1 . reverse == transpose . path1" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (path1 . NonEmpty.reverse) xs == (transpose . path1) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.circuit1 ============"+    test "circuit1 [x]       == edge x x" $ \(x :: Int) ->+          circuit1 [x]       == edge x x++    test "circuit1 [x,y]     == edges1 [(x,y), (y,x)]" $ \(x :: Int) y ->+          circuit1 [x,y]     == edges1 [(x,y), (y,x)]++    test "circuit1 . reverse == transpose . circuit1" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (circuit1 . NonEmpty.reverse) xs == (transpose . circuit1) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.clique1 ============"+    test "clique1 [x]        == vertex x" $ \(x :: Int) ->+          clique1 [x]        == vertex x++    test "clique1 [x,y]      == edge x y" $ \(x :: Int) y ->+          clique1 [x,y]      == edge x y++    test "clique1 [x,y,z]    == edges1 [(x,y), (x,z), (y,z)]" $ \(x :: Int) y z ->+          clique1 [x,y,z]    == edges1 [(x,y), (x,z), (y,z)]++    test "clique1 (xs <> ys) == connect (clique1 xs) (clique1 ys)" $ \(xs' :: NonEmptyList Int) ys' ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+        in clique1 (xs <> ys)   == connect (clique1 xs) (clique1 ys)++    test "clique1 . reverse  == transpose . clique1" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (clique1 . NonEmpty.reverse) xs == (transpose . clique1) xs++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.biclique1 ============"+    test "biclique1 [x1,x2] [y1,y2] == edges1 [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]" $ \(x1 :: Int) x2 y1 y2 ->+          biclique1 [x1,x2] [y1,y2] == edges1 [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]++    test "biclique1 xs      ys      == connect (vertices1 xs) (vertices1 ys)" $ \(xs' :: NonEmptyList Int) ys' ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+        in biclique1 xs      ys      == connect (vertices1 xs) (vertices1 ys)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.star ============"+    test "star x []    == vertex x" $ \(x :: Int) ->+          star x []    == vertex x++    test "star x [y]   == edge x y" $ \(x :: Int) y ->+          star x [y]   == edge x y++    test "star x [y,z] == edges1 [(x,y), (x,z)]" $ \(x :: Int) y z ->+          star x [y,z] == edges1 [(x,y), (x,z)]++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.stars1 ============"+    test "stars1 [(x, [] )]               == vertex x" $ \(x :: Int) ->+          stars1 [(x, [] )]               == vertex x++    test "stars1 [(x, [y])]               == edge x y" $ \(x :: Int) y ->+          stars1 [(x, [y])]               == edge x y++    test "stars1 [(x, ys )]               == star x ys" $ \(x :: Int) ys ->+          stars1 [(x, ys )]               == star x ys++    test "stars1                          == overlays1 . fmap (uncurry star)" $ \(xs' :: NonEmptyList (Int, [Int])) ->+      let xs = NonEmpty.fromList (getNonEmpty xs')+      in  stars1 xs                       == overlays1 (fmap (uncurry star) xs)++    test "overlay (stars1 xs) (stars1 ys) == stars1 (xs <> ys)" $ \(xs' :: NonEmptyList (Int, [Int])) (ys' :: NonEmptyList (Int, [Int])) ->+      let xs = NonEmpty.fromList (getNonEmpty xs')+          ys = NonEmpty.fromList (getNonEmpty ys')+      in  overlay (stars1 xs) (stars1 ys) == stars1 (xs <> ys)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.tree ============"+    test "tree (Node x [])                                         == vertex x" $ \(x :: Int) ->+          tree (Node x [])                                         == vertex x++    test "tree (Node x [Node y [Node z []]])                       == path1 [x,y,z]" $ \(x :: Int) y z ->+          tree (Node x [Node y [Node z []]])                       == path1 [x,y,z]++    test "tree (Node x [Node y [], Node z []])                     == star x [y,z]" $ \(x :: Int) y z ->+          tree (Node x [Node y [], Node z []])                     == star x [y,z]++    test "tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == edges1 [(1,2), (1,3), (3,4), (3,5)]" $+          tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == edges1 [(1,2), (1,3), (3,4), (3,5::Int)]++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.removeVertex1 ============"+    test "removeVertex1 x (vertex x)          == Nothing" $ \(x :: Int) ->+          removeVertex1 x (vertex x)          == Nothing++    test "removeVertex1 1 (vertex 2)          == Just (vertex 2)" $+          removeVertex1 1 (vertex 2)          == Just (vertex 2 :: G)++    test "removeVertex1 x (edge x x)          == Nothing" $ \(x :: Int) ->+          removeVertex1 x (edge x x)          == Nothing++    test "removeVertex1 1 (edge 1 2)          == Just (vertex 2)" $+          removeVertex1 1 (edge 1 2)          == Just (vertex 2 :: G)++    test "removeVertex1 x >=> removeVertex1 x == removeVertex1 x" $ \(x :: Int) y ->+         (removeVertex1 x >=> removeVertex1 x) y == removeVertex1 x y++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.removeEdge ============"+    test "removeEdge x y (edge x y)       == vertices1 [x,y]" $ \(x :: Int) y ->+          removeEdge x y (edge x y)       == vertices1 [x,y]++    test "removeEdge x y . removeEdge x y == removeEdge x y" $ \(x :: Int) y z ->+         (removeEdge x y . removeEdge x y) z == removeEdge x y z++    test "removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2" $+          removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * (2 :: G)++    test "removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2" $+          removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * (2 :: G)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.replaceVertex ============"+    test "replaceVertex x x            == id" $ \(x :: Int) y ->+          replaceVertex x x y          == y++    test "replaceVertex x y (vertex x) == vertex y" $ \(x :: Int) y ->+          replaceVertex x y (vertex x) == vertex y++    test "replaceVertex x y            == mergeVertices (== x) y" $ \(x :: Int) y z ->+          replaceVertex x y z          == mergeVertices (== x) y z++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.mergeVertices ============"+    test "mergeVertices (const False) x    == id" $ \(x :: Int) y ->+          mergeVertices (const False) x y  == y++    test "mergeVertices (== x) y           == replaceVertex x y" $ \(x :: Int) y z ->+          mergeVertices (== x) y z         == replaceVertex x y z++    test "mergeVertices even 1 (0 * 2)     == 1 * 1" $+          mergeVertices even 1 (0 * 2)     == (1 * 1 :: G)++    test "mergeVertices odd  1 (3 + 4 * 5) == 4 * 1" $+          mergeVertices odd  1 (3 + 4 * 5) == (4 * 1 :: G)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.transpose ============"+    test "transpose (vertex x)  == vertex x" $ \(x :: Int) ->+          transpose (vertex x)  == vertex x++    test "transpose (edge x y)  == edge y x" $ \(x :: Int) y ->+          transpose (edge x y)  == edge y x++    test "transpose . transpose == id" $ \(x :: G) ->+         (transpose . transpose) x == x++    test "edgeList . transpose  == sort . map swap . edgeList" $ \(x :: G) ->+         (edgeList . transpose) x == (sort . map swap . edgeList) x++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.gmap ============"+    test "gmap f (vertex x) == vertex (f x)" $ \(apply -> f) (x :: Int) ->+          gmap f (vertex x) == vertex (f x :: Int)++    test "gmap f (edge x y) == edge (f x) (f y)" $ \(apply -> f) (x :: Int) y ->+          gmap f (edge x y) == edge (f x) (f y :: Int)++    test "gmap id           == id" $ \(x :: G) ->+          gmap id x         == x++    test "gmap f . gmap g   == gmap (f . g)" $ \(apply -> f) (apply -> g) (x :: G) ->+         (gmap f . gmap g) x == (gmap (f . (g :: Int -> Int)) x :: G)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.induce1 ============"+    test "induce1 (const True ) x == Just x" $ \(x :: G) ->+          induce1 (const True ) x == Just x++    test "induce1 (const False) x == Nothing" $ \(x :: G) ->+          induce1 (const False) x == Nothing++    test "induce1 (/= x)          == removeVertex1 x" $ \(x :: Int) y ->+          induce1 (/= x) y        == removeVertex1 x y++    test "induce1 p >=> induce1 q == induce1 (\\x -> p x && q x)" $ \(apply -> p) (apply -> q) (y :: G) ->+         (induce1 p >=> induce1 q) y == induce1 (\x -> p x && q x) y++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.closure ============"+    test "closure (vertex x)      == edge x x" $ \(x :: Int) ->+          closure (vertex x)      == edge x x++    test "closure (edge x x)      == edge x x" $ \(x :: Int) ->+          closure (edge x x)      == edge x x++    test "closure (edge x y)      == edges1 [(x,x), (x,y), (y,y)]" $ \(x :: Int) y ->+          closure (edge x y)      == edges1 [(x,x), (x,y), (y,y)]++    test "closure (path1 $ nub xs) == reflexiveClosure (clique1 $ nub xs)" $ \(xs :: NonEmptyList Int) ->+        let ys = NonEmpty.fromList (nubOrd $ getNonEmpty xs)+        in closure (path1 $ ys) == reflexiveClosure (clique1 $ ys)++    test "closure                 == reflexiveClosure . transitiveClosure" $ sizeLimit $ \(x :: G) ->+          closure x               == (reflexiveClosure . transitiveClosure) x++    test "closure                 == transitiveClosure . reflexiveClosure" $ sizeLimit $ \(x :: G) ->+          closure x               == (transitiveClosure . reflexiveClosure) x++    test "closure . closure       == closure" $ sizeLimit $ \(x :: G) ->+         (closure . closure) x    == closure x++    test "postSet x (closure y)   == Set.fromList (reachable x y)" $ sizeLimit $ \x (y :: G) ->+          postSet x (closure y)   == Set.fromList (reachable x y)++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.reflexiveClosure ============"+    test "reflexiveClosure (vertex x)         == edge x x" $ \(x :: Int) ->+          reflexiveClosure (vertex x)         == edge x x++    test "reflexiveClosure (edge x x)         == edge x x" $ \(x :: Int) ->+          reflexiveClosure (edge x x)         == edge x x++    test "reflexiveClosure (edge x y)         == edges1 [(x,x), (x,y), (y,y)]" $ \(x :: Int) y ->+          reflexiveClosure (edge x y)         == edges1 [(x,x), (x,y), (y,y)]++    test "reflexiveClosure . reflexiveClosure == reflexiveClosure" $ \(x :: G) ->+         (reflexiveClosure . reflexiveClosure) x == reflexiveClosure x++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.symmetricClosure ============"+    test "symmetricClosure (vertex x)         == vertex x" $ \(x :: Int) ->+          symmetricClosure (vertex x)         == vertex x++    test "symmetricClosure (edge x y)         == edges1 [(x,y), (y,x)]" $ \(x :: G) y ->+          symmetricClosure (edge x y)         == edges1 [(x,y), (y,x)]++    test "symmetricClosure x                  == overlay x (transpose x)" $ \(x :: G) ->+          symmetricClosure x                  == overlay x (transpose x)++    test "symmetricClosure . symmetricClosure == symmetricClosure" $ \(x :: G) ->+         (symmetricClosure . symmetricClosure) x == symmetricClosure x++    putStrLn $ "\n============ NonEmpty.AdjacencyMap.transitiveClosure ============"+    test "transitiveClosure (vertex x)          == vertex x" $ \(x :: Int) ->+          transitiveClosure (vertex x)          == vertex x++    test "transitiveClosure (edge x y)          == edge x y" $ \(x :: G) y ->+          transitiveClosure (edge x y)          == edge x y++    test "transitiveClosure (path1 $ nub xs)    == clique1 (nub $ xs)" $ \(xs :: NonEmptyList Int) ->+        let ys = NonEmpty.fromList (nubOrd $ getNonEmpty xs)+        in transitiveClosure (path1 ys) == clique1 ys++    test "transitiveClosure . transitiveClosure == transitiveClosure" $ sizeLimit $ \(x :: G) ->+         (transitiveClosure . transitiveClosure) x == transitiveClosure x
+ test/Algebra/Graph/Test/NonEmpty/Graph.hs view
@@ -0,0 +1,690 @@+{-# LANGUAGE CPP, OverloadedLists, ViewPatterns #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Test.NonEmpty.Graph+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- Testsuite for "Algebra.Graph.NonEmpty".+-----------------------------------------------------------------------------+module Algebra.Graph.Test.NonEmpty.Graph (+    -- * Testsuite+    testNonEmptyGraph+  ) where++import Prelude ()+import Prelude.Compat++#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup+#endif++import Control.Monad+import Data.Either+import Data.Maybe+import Data.Tree+import Data.Tuple++import Algebra.Graph.NonEmpty hiding (Graph)+import Algebra.Graph.Test hiding (axioms, theorems)+import Algebra.Graph.ToGraph (reachable, toGraph)++import qualified Algebra.Graph          as G+import qualified Algebra.Graph.NonEmpty as NonEmpty+import qualified Data.List.NonEmpty     as NonEmpty+import qualified Data.Set               as Set++type G = NonEmpty.Graph Int++axioms :: G -> G -> G -> Property+axioms x y z = conjoin+    [       x + y == y + x                      // "Overlay commutativity"+    , x + (y + z) == (x + y) + z                // "Overlay associativity"+    , x * (y * z) == (x * y) * z                // "Connect associativity"+    , x * (y + z) == x * y + x * z              // "Left distributivity"+    , (x + y) * z == x * z + y * z              // "Right distributivity"+    ,   x * y * z == x * y + x * z + y * z      // "Decomposition" ]++theorems :: G -> G -> Property+theorems x y = conjoin+    [         x + x == x                        // "Overlay idempotence"+    , x + y + x * y == x * y                    // "Absorption"+    ,         x * x == x * x * x                // "Connect saturation"+    ,             x <= x + y                    // "Overlay order"+    ,         x + y <= x * y                    // "Overlay-connect order" ]++testNonEmptyGraph :: IO ()+testNonEmptyGraph = do+    putStrLn "\n============ NonEmpty.Graph.============"+    test "Axioms of non-empty graphs"   axioms+    test "Theorems of non-empty graphs" theorems++    putStrLn $ "\n============ Ord (NonEmpty.Graph a) ============"+    test "vertex 1 <  vertex 2" $+          vertex 1 <  vertex (2 :: Int)++    test "vertex 3 <  edge 1 2" $+          vertex 3 <  edge 1 (2 :: Int)++    test "vertex 1 <  edge 1 1" $+          vertex 1 <  edge 1 (1 :: Int)++    test "edge 1 1 <  edge 1 2" $+          edge 1 1 <  edge 1 (2 :: Int)++    test "edge 1 2 <  edge 1 1 + edge 2 2" $+          edge 1 2 <  edge 1 1 + edge 2 (2 :: Int)++    test "edge 1 2 <  edge 1 3" $+          edge 1 2 <  edge 1 (3 :: Int)++    test "x        <= x + y" $ \(x :: G) y ->+          x        <= x + y++    test "x + y    <= x * y" $ \(x :: G) y ->+          x + y    <= x * y++    putStrLn $ "\n============ Functor (NonEmpty.Graph a) ============"+    test "fmap f (vertex x) == vertex (f x)" $ \(apply -> f) (x :: Int) ->+          fmap f (vertex x) == vertex (f x :: Int)++    test "fmap f (edge x y) == edge (f x) (f y)" $ \(apply -> f) (x :: Int) y ->+          fmap f (edge x y) == edge (f x) (f y :: Int)++    test "fmap id           == id" $ \(x :: G) ->+          fmap id x         == x++    test "fmap f . fmap g   == fmap (f . g)" $ \(apply -> f) (apply -> g) (x :: G) ->+         (fmap f . fmap g) x == (fmap (f . (g :: Int -> Int)) x :: G)++    putStrLn $ "\n============ Monad (NonEmpty.Graph a) ============"+    test "(vertex x >>= f)     == f x" $ \(apply -> f) (x :: Int) ->+          (vertex x >>= f)     == (f x :: G)++    test "(edge x y >>= f)     == connect (f x) (f y)" $ \(apply -> f) (x :: Int) y ->+          (edge x y >>= f)     == connect (f x) (f y :: G)++    test "(vertices1 xs >>= f) == overlays1 (fmap f xs)" $ mapSize (min 10) $ \(xs' :: NonEmptyList Int) (apply -> f) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertices1 xs >>= f) == (overlays1 (fmap f xs) :: G)++    test "(x >>= vertex)       == x" $ \(x :: G) ->+          (x >>= vertex)       == x++    test "((x >>= f) >>= g)    == (x >>= (\\y -> (f y) >>= g))" $ mapSize (min 10) $ \(x :: G) (apply -> f) (apply -> g) ->+          ((x >>= f) >>= g)    == (x >>= (\(y :: Int) -> (f y) >>= (g :: Int -> G)))++    putStrLn $ "\n============ NonEmpty.Graph.toNonEmpty ============"+    test "toNonEmpty empty       == Nothing" $+          toNonEmpty (G.empty :: G.Graph Int) == Nothing++    test "toNonEmpty (toGraph x) == Just (x :: NonEmpty.Graph a)" $ \x ->+          toNonEmpty (toGraph x) == Just (x :: G)++    putStrLn $ "\n============ NonEmpty.Graph.vertex ============"+    test "hasVertex x (vertex x) == True" $ \(x :: Int) ->+          hasVertex x (vertex x) == True++    test "vertexCount (vertex x) == 1" $ \(x :: Int) ->+          vertexCount (vertex x) == 1++    test "edgeCount   (vertex x) == 0" $ \(x :: Int) ->+          edgeCount   (vertex x) == 0++    test "size        (vertex x) == 1" $ \(x :: Int) ->+          size        (vertex x) == 1++    putStrLn $ "\n============ NonEmpty.Graph.edge ============"+    test "edge x y               == connect (vertex x) (vertex y)" $ \(x :: Int) y ->+          edge x y               == connect (vertex x) (vertex y)++    test "hasEdge x y (edge x y) == True" $ \(x :: Int) y ->+          hasEdge x y (edge x y) == True++    test "edgeCount   (edge x y) == 1" $ \(x :: Int) y ->+          edgeCount   (edge x y) == 1++    test "vertexCount (edge 1 1) == 1" $+          vertexCount (edge 1 1 :: G) == 1++    test "vertexCount (edge 1 2) == 2" $+          vertexCount (edge 1 2 :: G) == 2++    putStrLn $ "\n============ NonEmpty.Graph.overlay ============"+    test "hasVertex z (overlay x y) == hasVertex z x || hasVertex z y" $ \(x :: G) y z ->+          hasVertex z (overlay x y) == hasVertex z x || hasVertex z y++    test "vertexCount (overlay x y) >= vertexCount x" $ \(x :: G) y ->+          vertexCount (overlay x y) >= vertexCount x++    test "vertexCount (overlay x y) <= vertexCount x + vertexCount y" $ \(x :: G) y ->+          vertexCount (overlay x y) <= vertexCount x + vertexCount y++    test "edgeCount   (overlay x y) >= edgeCount x" $ \(x :: G) y ->+          edgeCount   (overlay x y) >= edgeCount x++    test "edgeCount   (overlay x y) <= edgeCount x   + edgeCount y" $ \(x :: G) y ->+          edgeCount   (overlay x y) <= edgeCount x   + edgeCount y++    test "size        (overlay x y) == size x        + size y" $ \(x :: G) y ->+          size        (overlay x y) == size x        + size y++    test "vertexCount (overlay 1 2) == 2" $+          vertexCount (overlay 1 2 :: G) == 2++    test "edgeCount   (overlay 1 2) == 0" $+          edgeCount   (overlay 1 2 :: G) == 0++    putStrLn $ "\n============ NonEmpty.Graph.overlay1 ============"+    test "               overlay1 empty x == x" $ \(x :: G) ->+                         overlay1 G.empty x == x++    test "x /= empty ==> overlay1 x     y == overlay (fromJust $ toNonEmpty x) y" $ \(x :: G.Graph Int) (y :: G) ->+          x /= G.empty ==> overlay1 x   y == overlay (fromJust $ toNonEmpty x) y+++    putStrLn $ "\n============ NonEmpty.Graph.connect ============"+    test "hasVertex z (connect x y) == hasVertex z x || hasVertex z y" $ \(x :: G) y z ->+          hasVertex z (connect x y) == hasVertex z x || hasVertex z y++    test "vertexCount (connect x y) >= vertexCount x" $ \(x :: G) y ->+          vertexCount (connect x y) >= vertexCount x++    test "vertexCount (connect x y) <= vertexCount x + vertexCount y" $ \(x :: G) y ->+          vertexCount (connect x y) <= vertexCount x + vertexCount y++    test "edgeCount   (connect x y) >= edgeCount x" $ \(x :: G) y ->+          edgeCount   (connect x y) >= edgeCount x++    test "edgeCount   (connect x y) >= edgeCount y" $ \(x :: G) y ->+          edgeCount   (connect x y) >= edgeCount y++    test "edgeCount   (connect x y) >= vertexCount x * vertexCount y" $ \(x :: G) y ->+          edgeCount   (connect x y) >= vertexCount x * vertexCount y++    test "edgeCount   (connect x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y" $ \(x :: G) y ->+          edgeCount   (connect x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y++    test "size        (connect x y) == size x        + size y" $ \(x :: G) y ->+          size        (connect x y) == size x        + size y++    test "vertexCount (connect 1 2) == 2" $+          vertexCount (connect 1 2 :: G) == 2++    test "edgeCount   (connect 1 2) == 1" $+          edgeCount   (connect 1 2 :: G) == 1++    putStrLn $ "\n============ NonEmpty.Graph.vertices1 ============"+    test "vertices1 [x]           == vertex x" $ \(x :: Int) ->+          vertices1 [x]           == vertex x++    test "hasVertex x . vertices1 == elem x" $ \(x :: Int) (xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (hasVertex x . vertices1) xs == elem x (NonEmpty.toList xs)++    test "vertexCount . vertices1 == length . nub" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexCount . vertices1) xs == (NonEmpty.length . NonEmpty.nub) xs++    test "vertexSet   . vertices1 == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexSet   . vertices1) xs == (Set.fromList . NonEmpty.toList) xs++    putStrLn $ "\n============ NonEmpty.Graph.edges1 ============"+    test "edges1 [(x,y)]     == edge x y" $ \(x :: Int) y ->+          edges1 [(x,y)]     == edge x y++    test "edgeCount . edges1 == length . nub" $ \(xs' :: NonEmptyList (Int, Int)) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (edgeCount . edges1) xs == (NonEmpty.length . NonEmpty.nub) xs++    putStrLn $ "\n============ NonEmpty.Graph.overlays1 ============"+    test "overlays1 [x]   == x" $ \(x :: G) ->+          overlays1 [x]   == x++    test "overlays1 [x,y] == overlay x y" $ \(x :: G) y ->+          overlays1 [x,y] == overlay x y++    putStrLn $ "\n============ NonEmpty.Graph.connects1 ============"+    test "connects1 [x]   == x" $ \(x :: G) ->+          connects1 [x]   == x++    test "connects1 [x,y] == connect x y" $ \(x :: G) y ->+          connects1 [x,y] == connect x y++    putStrLn $ "\n============ NonEmpty.Graph.foldg1 ============"+    test "foldg1 vertex    overlay connect        == id" $ \(x :: G) ->+          foldg1 vertex    overlay connect x      == id x++    test "foldg1 vertex    overlay (flip connect) == transpose" $ \(x :: G) ->+          foldg1 vertex    overlay (flip connect) x == transpose x++    test "foldg1 (const 1) (+)     (+)            == size" $ \(x :: G) ->+          foldg1 (const 1) (+)     (+) x          == size x++    test "foldg1 (== x)    (||)    (||)           == hasVertex x" $ \(x :: Int) y ->+          foldg1 (== x)    (||)    (||) y         == hasVertex x y++    putStrLn $ "\n============ NonEmpty.Graph.isSubgraphOf ============"+    test "isSubgraphOf x             (overlay x y) ==  True" $ \(x :: G) y ->+          isSubgraphOf x             (overlay x y) ==  True++    test "isSubgraphOf (overlay x y) (connect x y) ==  True" $ \(x :: G) y ->+          isSubgraphOf (overlay x y) (connect x y) ==  True++    test "isSubgraphOf (path1 xs)    (circuit1 xs) ==  True" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in isSubgraphOf (path1 xs)    (circuit1 xs) ==  True++    test "isSubgraphOf x y                         ==> x <= y" $ \(x :: G) z ->+        let y = x + z -- Make sure we hit the precondition+        in isSubgraphOf x y                        ==> x <= y++    putStrLn "\n============ NonEmpty.Graph.(===) ============"+    test "    x === x     == True" $ \(x :: G) ->+             (x === x)    == True++    test "x + y === x + y == True" $ \(x :: G) y ->+         (x + y === x + y) == True++    test "1 + 2 === 2 + 1 == False" $+         (1 + 2 === 2 + (1 :: G)) == False++    test "x + y === x * y == False" $ \(x :: G) y ->+         (x + y === x * y) == False++    putStrLn $ "\n============ NonEmpty.Graph.size ============"+    test "size (vertex x)    == 1" $ \(x :: Int) ->+          size (vertex x)    == 1++    test "size (overlay x y) == size x + size y" $ \(x :: G) y ->+          size (overlay x y) == size x + size y++    test "size (connect x y) == size x + size y" $ \(x :: G) y ->+          size (connect x y) == size x + size y++    test "size x             >= 1" $ \(x :: G) ->+          size x             >= 1++    test "size x             >= vertexCount x" $ \(x :: G) ->+          size x             >= vertexCount x++    putStrLn $ "\n============ NonEmpty.Graph.hasVertex ============"+    test "hasVertex x (vertex x) == True" $ \(x :: Int) ->+          hasVertex x (vertex x) == True++    test "hasVertex 1 (vertex 2) == False" $+          hasVertex 1 (vertex 2 :: G) == False++    putStrLn $ "\n============ NonEmpty.Graph.hasEdge ============"+    test "hasEdge x y (vertex z)       == False" $ \(x :: Int) y z ->+          hasEdge x y (vertex z)       == False++    test "hasEdge x y (edge x y)       == True" $ \(x :: Int) y ->+          hasEdge x y (edge x y)       == True++    test "hasEdge x y . removeEdge x y == const False" $ \(x :: Int) y z ->+         (hasEdge x y . removeEdge x y) z == False++    test "hasEdge x y                  == elem (x,y) . edgeList" $ \(x :: Int) y z -> do+        (u, v) <- elements ((x, y) : edgeList z)+        return $ hasEdge u v z == elem (u, v) (edgeList z)++    putStrLn $ "\n============ NonEmpty.Graph.vertexCount ============"+    test "vertexCount (vertex x) == 1" $ \(x :: Int) ->+          vertexCount (vertex x) == 1++    test "vertexCount x          >= 1" $ \(x :: G) ->+          vertexCount x          >= 1++    test "vertexCount            == length . vertexList1" $ \(x :: G) ->+          vertexCount x          == (NonEmpty.length . vertexList1) x++    putStrLn $ "\n============ NonEmpty.Graph.edgeCount ============"+    test "edgeCount (vertex x) == 0" $ \(x :: Int) ->+          edgeCount (vertex x) == 0++    test "edgeCount (edge x y) == 1" $ \(x :: Int) y ->+          edgeCount (edge x y) == 1++    test "edgeCount            == length . edgeList" $ \(x :: G) ->+          edgeCount x          == (length . edgeList) x++    putStrLn $ "\n============ NonEmpty.Graph.vertexList1 ============"+    test "vertexList1 (vertex x)  == [x]" $ \(x :: Int) ->+          vertexList1 (vertex x)  == [x]++    test "vertexList1 . vertices1 == nub . sort" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexList1 . vertices1) xs == (NonEmpty.nub . NonEmpty.sort) xs++    putStrLn $ "\n============ NonEmpty.Graph.edgeList ============"+    test "edgeList (vertex x)     == []" $ \(x :: Int) ->+          edgeList (vertex x)     == []++    test "edgeList (edge x y)     == [(x,y)]" $ \(x :: Int) y ->+          edgeList (edge x y)     == [(x,y)]++    test "edgeList (star 2 [3,1]) == [(2,1), (2,3)]" $+          edgeList (star 2 [3,1]) == [(2,1), (2,3 :: Int)]++    test "edgeList . edges1       == nub . sort . toList" $ \(xs' :: NonEmptyList (Int, Int)) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (edgeList . edges1) xs   == (nubOrd . sort . NonEmpty.toList) xs++    test "edgeList . transpose    == sort . map swap . edgeList" $ \(x :: G) ->+         (edgeList . transpose) x == (sort . map swap . edgeList) x++    putStrLn $ "\n============ NonEmpty.Graph.vertexSet ============"+    test "vertexSet . vertex    == Set.singleton" $ \(x :: Int) ->+         (vertexSet . vertex) x == Set.singleton x++    test "vertexSet . vertices1 == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexSet . vertices1) xs == (Set.fromList . NonEmpty.toList) xs++    test "vertexSet . clique1   == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (vertexSet . clique1) xs == (Set.fromList . NonEmpty.toList) xs++    putStrLn $ "\n============ NonEmpty.Graph.edgeSet ============"+    test "edgeSet (vertex x) == Set.empty" $ \(x :: Int) ->+          edgeSet (vertex x) == Set.empty++    test "edgeSet (edge x y) == Set.singleton (x,y)" $ \(x :: Int) y ->+          edgeSet (edge x y) == Set.singleton (x,y)++    test "edgeSet . edges1   == Set.fromList . toList" $ \(xs' :: NonEmptyList (Int, Int)) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (edgeSet . edges1) xs == (Set.fromList . NonEmpty.toList) xs++    putStrLn $ "\n============ NonEmpty.Graph.path1 ============"+    test "path1 [x]       == vertex x" $ \(x :: Int) ->+          path1 [x]       == vertex x++    test "path1 [x,y]     == edge x y" $ \(x :: Int) y ->+          path1 [x,y]     == edge x y++    test "path1 . reverse == transpose . path1" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (path1 . NonEmpty.reverse) xs == (transpose . path1) xs++    putStrLn $ "\n============ NonEmpty.Graph.circuit1 ============"+    test "circuit1 [x]       == edge x x" $ \(x :: Int) ->+          circuit1 [x]       == edge x x++    test "circuit1 [x,y]     == edges1 [(x,y), (y,x)]" $ \(x :: Int) y ->+          circuit1 [x,y]     == edges1 [(x,y), (y,x)]++    test "circuit1 . reverse == transpose . circuit1" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (circuit1 . NonEmpty.reverse) xs == (transpose . circuit1) xs++    putStrLn $ "\n============ NonEmpty.Graph.clique1 ============"+    test "clique1 [x]        == vertex x" $ \(x :: Int) ->+          clique1 [x]        == vertex x++    test "clique1 [x,y]      == edge x y" $ \(x :: Int) y ->+          clique1 [x,y]      == edge x y++    test "clique1 [x,y,z]    == edges1 [(x,y), (x,z), (y,z)]" $ \(x :: Int) y z ->+          clique1 [x,y,z]    == edges1 [(x,y), (x,z), (y,z)]++    test "clique1 (xs <> ys) == connect (clique1 xs) (clique1 ys)" $ \(xs' :: NonEmptyList Int) ys' ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+        in clique1 (xs <> ys)   == connect (clique1 xs) (clique1 ys)++    test "clique1 . reverse  == transpose . clique1" $ \(xs' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+        in (clique1 . NonEmpty.reverse) xs == (transpose . clique1) xs++    putStrLn $ "\n============ NonEmpty.Graph.biclique1 ============"+    test "biclique1 [x1,x2] [y1,y2] == edges1 [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]" $ \(x1 :: Int) x2 y1 y2 ->+          biclique1 [x1,x2] [y1,y2] == edges1 [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]++    test "biclique1 xs      ys      == connect (vertices1 xs) (vertices1 ys)" $ \(xs' :: NonEmptyList Int) ys' ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+        in biclique1 xs      ys      == connect (vertices1 xs) (vertices1 ys)++    putStrLn $ "\n============ NonEmpty.Graph.star ============"+    test "star x []    == vertex x" $ \(x :: Int) ->+          star x []    == vertex x++    test "star x [y]   == edge x y" $ \(x :: Int) y ->+          star x [y]   == edge x y++    test "star x [y,z] == edges1 [(x,y), (x,z)]" $ \(x :: Int) y z ->+          star x [y,z] == edges1 [(x,y), (x,z)]++    putStrLn $ "\n============ NonEmpty.Graph.stars1 ============"+    test "stars1 [(x, [] )]               == vertex x" $ \(x :: Int) ->+          stars1 [(x, [] )]               == vertex x++    test "stars1 [(x, [y])]               == edge x y" $ \(x :: Int) y ->+          stars1 [(x, [y])]               == edge x y++    test "stars1 [(x, ys )]               == star x ys" $ \(x :: Int) ys ->+          stars1 [(x, ys )]               == star x ys++    test "stars1                          == overlays1 . fmap (uncurry star)" $ \(xs' :: NonEmptyList (Int, [Int])) ->+      let xs = NonEmpty.fromList (getNonEmpty xs')+      in  stars1 xs                       == overlays1 (fmap (uncurry star) xs)++    test "overlay (stars1 xs) (stars1 ys) == stars1 (xs <> ys)" $ \(xs' :: NonEmptyList (Int, [Int])) (ys' :: NonEmptyList (Int, [Int])) ->+      let xs = NonEmpty.fromList (getNonEmpty xs')+          ys = NonEmpty.fromList (getNonEmpty ys')+      in  overlay (stars1 xs) (stars1 ys) == stars1 (xs <> ys)++    putStrLn $ "\n============ NonEmpty.Graph.tree ============"+    test "tree (Node x [])                                         == vertex x" $ \(x :: Int) ->+          tree (Node x [])                                         == vertex x++    test "tree (Node x [Node y [Node z []]])                       == path1 [x,y,z]" $ \(x :: Int) y z ->+          tree (Node x [Node y [Node z []]])                       == path1 [x,y,z]++    test "tree (Node x [Node y [], Node z []])                     == star x [y,z]" $ \(x :: Int) y z ->+          tree (Node x [Node y [], Node z []])                     == star x [y,z]++    test "tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == edges1 [(1,2), (1,3), (3,4), (3,5)]" $+          tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == edges1 [(1,2), (1,3), (3,4), (3,5::Int)]++    putStrLn $ "\n============ NonEmpty.Graph.mesh1 ============"+    test "mesh1 [x]     [y]        == vertex (x, y)" $ \(x :: Int) (y :: Int) ->+          mesh1 [x]     [y]        == vertex (x, y)++    test "mesh1 xs      ys         == box (path1 xs) (path1 ys)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+        in mesh1 xs      ys         == box (path1 xs) (path1 ys)++    test "mesh1 [1,2,3] ['a', 'b'] == <correct result>" $+          mesh1 [1,2,3] ['a', 'b'] == edges1 [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a'))+                                             , ((1,'b'),(2,'b')), ((2,'a'),(2,'b'))+                                             , ((2,'a'),(3,'a')), ((2,'b'),(3,'b'))+                                             , ((3,'a'),(3 :: Int,'b')) ]++    test "size (mesh xs ys)        == max 1 (3 * length xs * length ys - length xs - length ys -1)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+         in size (mesh1 xs ys) == max 1 (3 * length xs * length ys - length xs - length ys -1)++    putStrLn $ "\n============ NonEmpty.Graph.torus1 ============"+    test "torus1 [x]   [y]        == edge (x,y) (x,y)" $ \(x :: Int) (y :: Int) ->+          torus1 [x]   [y]        == edge (x,y) (x,y)++    test "torus1 xs    ys         == box (circuit1 xs) (circuit1 ys)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+        in torus1 xs    ys         == box (circuit1 xs) (circuit1 ys)++    test "torus1 [1,2] ['a', 'b'] == <correct result>" $+          torus1 [1,2] ['a', 'b'] == edges1 [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a'))+                                            , ((1,'b'),(1,'a')), ((1,'b'),(2,'b'))+                                            , ((2,'a'),(1,'a')), ((2,'a'),(2,'b'))+                                            , ((2,'b'),(1,'b')), ((2,'b'),(2 :: Int,'a')) ]++    test "size (torus1 xs ys)     == max 1 (3 * length xs * length ys)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->+        let xs = NonEmpty.fromList (getNonEmpty xs')+            ys = NonEmpty.fromList (getNonEmpty ys')+        in size (torus1 xs ys) == max 1 (3 * length xs * length ys)++    putStrLn $ "\n============ NonEmpty.Graph.removeVertex1 ============"+    test "removeVertex1 x (vertex x)          == Nothing" $ \(x :: Int) ->+          removeVertex1 x (vertex x)          == Nothing++    test "removeVertex1 1 (vertex 2)          == Just (vertex 2)" $+          removeVertex1 1 (vertex 2)          == Just (vertex 2 :: G)++    test "removeVertex1 x (edge x x)          == Nothing" $ \(x :: Int) ->+          removeVertex1 x (edge x x)          == Nothing++    test "removeVertex1 1 (edge 1 2)          == Just (vertex 2)" $+          removeVertex1 1 (edge 1 2)          == Just (vertex 2 :: G)++    test "removeVertex1 x >=> removeVertex1 x == removeVertex1 x" $ \(x :: Int) y ->+         (removeVertex1 x >=> removeVertex1 x) y == removeVertex1 x y++    putStrLn $ "\n============ NonEmpty.Graph.removeEdge ============"+    test "removeEdge x y (edge x y)       == vertices1 [x,y]" $ \(x :: Int) y ->+          removeEdge x y (edge x y)       == vertices1 [x,y]++    test "removeEdge x y . removeEdge x y == removeEdge x y" $ \(x :: Int) y z ->+         (removeEdge x y . removeEdge x y) z == removeEdge x y z++    test "removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2" $+          removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * (2 :: G)++    test "removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2" $+          removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * (2 :: G)++    test "size (removeEdge x y z)         <= 3 * size z" $ \(x :: Int) y z ->+          size (removeEdge x y z)         <= 3 * size z++    putStrLn $ "\n============ NonEmpty.Graph.replaceVertex ============"+    test "replaceVertex x x            == id" $ \(x :: Int) y ->+          replaceVertex x x y          == y++    test "replaceVertex x y (vertex x) == vertex y" $ \(x :: Int) y ->+          replaceVertex x y (vertex x) == vertex y++    test "replaceVertex x y            == mergeVertices (== x) y" $ \(x :: Int) y z ->+          replaceVertex x y z          == mergeVertices (== x) y z++    putStrLn $ "\n============ NonEmpty.Graph.mergeVertices ============"+    test "mergeVertices (const False) x    == id" $ \(x :: Int) y ->+          mergeVertices (const False) x y  == y++    test "mergeVertices (== x) y           == replaceVertex x y" $ \(x :: Int) y z ->+          mergeVertices (== x) y z         == replaceVertex x y z++    test "mergeVertices even 1 (0 * 2)     == 1 * 1" $+          mergeVertices even 1 (0 * 2)     == (1 * 1 :: G)++    test "mergeVertices odd  1 (3 + 4 * 5) == 4 * 1" $+          mergeVertices odd  1 (3 + 4 * 5) == (4 * 1 :: G)++    putStrLn $ "\n============ NonEmpty.Graph.splitVertex1 ============"+    test "splitVertex1 x [x]                 == id" $ \x (y :: G) ->+          splitVertex1 x [x] y               == y++    test "splitVertex1 x [y]                 == replaceVertex x y" $ \x y (z :: G) ->+          splitVertex1 x [y] z               == replaceVertex x y z++    test "splitVertex1 1 [0,1] $ 1 * (2 + 3) == (0 + 1) * (2 + 3)" $+          splitVertex1 1 [0,1] (1 * (2 + 3)) == (0 + 1) * (2 + 3 :: G)++    putStrLn $ "\n============ NonEmpty.Graph.transpose ============"+    test "transpose (vertex x)  == vertex x" $ \(x :: Int) ->+          transpose (vertex x)  == vertex x++    test "transpose (edge x y)  == edge y x" $ \(x :: Int) y ->+          transpose (edge x y)  == edge y x++    test "transpose . transpose == id" $ \(x :: G) ->+         (transpose . transpose) x == x++    test "transpose (box x y)   == box (transpose x) (transpose y)" $ mapSize (min 10) $ \(x :: G) (y :: G) ->+          transpose (box x y)   == box (transpose x) (transpose y)++    test "edgeList . transpose  == sort . map swap . edgeList" $ \(x :: G) ->+         (edgeList . transpose) x == (sort . map swap . edgeList) x++    putStrLn $ "\n============ NonEmpty.Graph.induce1 ============"+    test "induce1 (const True ) x == Just x" $ \(x :: G) ->+          induce1 (const True ) x == Just x++    test "induce1 (const False) x == Nothing" $ \(x :: G) ->+          induce1 (const False) x == Nothing++    test "induce1 (/= x)          == removeVertex1 x" $ \(x :: Int) y ->+          induce1 (/= x) y        == removeVertex1 x y++    test "induce1 p >=> induce1 q == induce1 (\\x -> p x && q x)" $ \(apply -> p) (apply -> q) (y :: G) ->+         (induce1 p >=> induce1 q) y == induce1 (\x -> p x && q x) y++    putStrLn $ "\n============ NonEmpty.Graph.simplify ============"+    test "simplify             ==  id" $ \(x :: G) ->+          simplify x           ==  x++    test "size (simplify x)    <=  size x" $ \(x :: G) ->+          size (simplify x)    <=  size x++    test "simplify 1           === 1" $+          simplify 1           === (1 :: G)++    test "simplify (1 + 1)     === 1" $+          simplify (1 + 1)     === (1 :: G)++    test "simplify (1 + 2 + 1) === 1 + 2" $+          simplify (1 + 2 + 1) === (1 + 2 :: G)++    test "simplify (1 * 1 * 1) === 1 * 1" $+          simplify (1 * 1 * 1) === (1 * 1 :: G)++    putStrLn "\n============ NonEmpty.Graph.sparsify ============"+    test "sort . reachable x       == sort . rights . reachable (Right x) . sparsify" $ \x (y :: G) ->+         (sort . reachable x) y    == (sort . rights . reachable (Right x) . sparsify) y++    test "vertexCount (sparsify x) <= vertexCount x + size x + 1" $ \(x :: G) ->+          vertexCount (sparsify x) <= vertexCount x + size x + 1++    test "edgeCount   (sparsify x) <= 3 * size x" $ \(x :: G) ->+          edgeCount   (sparsify x) <= 3 * size x++    test "size        (sparsify x) <= 3 * size x" $ \(x :: G) ->+          size        (sparsify x) <= 3 * size x++    putStrLn "\n============ NonEmpty.Graph.box ============"+    test "box (path1 [0,1]) (path1 ['a','b']) == <correct result>" $ mapSize (min 10) $+          box (path1 [0,1]) (path1 ['a','b']) == edges1 [ ((0,'a'), (0,'b'))+                                                        , ((0,'a'), (1,'a'))+                                                        , ((0,'b'), (1,'b'))+                                                        , ((1,'a'), (1::Int,'b')) ]++    let unit = fmap $ \(a, ()) -> a+        comm = fmap $ \(a,  b) -> (b, a)+    test "box x y                             ~~ box y x" $ mapSize (min 10) $ \(x :: G) (y :: G) ->+          comm (box x y)                      == box y x++    test "box x (overlay y z)                 == overlay (box x y) (box x z)" $ mapSize (min 10) $ \(x :: G) (y :: G) z ->+          box x (overlay y z)                 == overlay (box x y) (box x z)++    test "box x (vertex ())                   ~~ x" $ mapSize (min 10) $ \(x :: G) ->+     unit(box x (vertex ()))                  == x++    let assoc = fmap $ \(a, (b, c)) -> ((a, b), c)+    test "box x (box y z)                     ~~ box (box x y) z" $ mapSize (min 5) $ \(x :: G) (y :: G) (z :: G) ->+      assoc (box x (box y z))                 == box (box x y) z++    test "transpose   (box x y)               == box (transpose x) (transpose y)" $ mapSize (min 10) $ \(x :: G) (y :: G) ->+          transpose   (box x y)               == box (transpose x) (transpose y)++    test "vertexCount (box x y)               == vertexCount x * vertexCount y" $ mapSize (min 10) $ \(x :: G) (y :: G) ->+          vertexCount (box x y)               == vertexCount x * vertexCount y++    test "edgeCount   (box x y)               <= vertexCount x * edgeCount y + edgeCount x * vertexCount y" $ mapSize (min 10) $ \(x :: G) (y :: G) ->+          edgeCount   (box x y)               <= vertexCount x * edgeCount y + edgeCount x * vertexCount y
− test/Algebra/Graph/Test/NonEmptyGraph.hs
@@ -1,665 +0,0 @@-{-# LANGUAGE CPP, ViewPatterns #-}--------------------------------------------------------------------------------- |--- Module     : Algebra.Graph.Test.NonEmptyGraph--- Copyright  : (c) Andrey Mokhov 2016-2018--- License    : MIT (see the file LICENSE)--- Maintainer : andrey.mokhov@gmail.com--- Stability  : experimental------ Testsuite for "Algebra.Graph.NonEmpty".-------------------------------------------------------------------------------module Algebra.Graph.Test.NonEmptyGraph (-    -- * Testsuite-    testGraphNonEmpty-  ) where--import Prelude ()-import Prelude.Compat--#if !MIN_VERSION_base(4,11,0)-import Data.Semigroup-#endif--import Control.Monad-import Data.Either-import Data.List.NonEmpty (NonEmpty (..))-import Data.Maybe-import Data.Tree-import Data.Tuple--import Algebra.Graph.NonEmpty-import Algebra.Graph.Test hiding (axioms, theorems)-import Algebra.Graph.ToGraph (reachable, toGraph)--import qualified Algebra.Graph      as G-import qualified Data.List.NonEmpty as NonEmpty-import qualified Data.Set           as Set-import qualified Data.IntSet        as IntSet--type G = NonEmptyGraph Int--axioms :: G -> G -> G -> Property-axioms x y z = conjoin-    [       x + y == y + x                      // "Overlay commutativity"-    , x + (y + z) == (x + y) + z                // "Overlay associativity"-    , x * (y * z) == (x * y) * z                // "Connect associativity"-    , x * (y + z) == x * y + x * z              // "Left distributivity"-    , (x + y) * z == x * z + y * z              // "Right distributivity"-    ,   x * y * z == x * y + x * z + y * z      // "Decomposition" ]--theorems :: G -> G -> Property-theorems x y = conjoin-    [         x + x == x                        // "Overlay idempotence"-    , x + y + x * y == x * y                    // "Absorption"-    ,         x * x == x * x * x                // "Connect saturation"-    ,             x <= x + y                    // "Overlay order"-    ,         x + y <= x * y                    // "Overlay-connect order" ]-  where-    (<=) = isSubgraphOf-    infixl 4 <=--testGraphNonEmpty :: IO ()-testGraphNonEmpty = do-    putStrLn "\n============ Graph.NonEmpty ============"-    test "Axioms of non-empty graphs"   axioms-    test "Theorems of non-empty graphs" theorems--    putStrLn $ "\n============ Functor (NonEmptyGraph a) ============"-    test "fmap f (vertex x) == vertex (f x)" $ \(apply -> f) (x :: Int) ->-          fmap f (vertex x) == vertex (f x :: Int)--    test "fmap f (edge x y) == edge (f x) (f y)" $ \(apply -> f) (x :: Int) y ->-          fmap f (edge x y) == edge (f x) (f y :: Int)--    test "fmap id           == id" $ \(x :: G) ->-          fmap id x         == x--    test "fmap f . fmap g   == fmap (f . g)" $ \(apply -> f) (apply -> g) (x :: G) ->-         (fmap f . fmap g) x == (fmap (f . (g :: Int -> Int)) x :: G)--    putStrLn $ "\n============ Monad (NonEmptyGraph a) ============"-    test "(vertex x >>= f)     == f x" $ \(apply -> f) (x :: Int) ->-          (vertex x >>= f)     == (f x :: G)--    test "(edge x y >>= f)     == connect (f x) (f y)" $ \(apply -> f) (x :: Int) y ->-          (edge x y >>= f)     == connect (f x) (f y :: G)--    test "(vertices1 xs >>= f) == overlays1 (fmap f xs)" $ mapSize (min 10) $ \(xs' :: NonEmptyList Int) (apply -> f) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertices1 xs >>= f) == (overlays1 (fmap f xs) :: G)--    test "(x >>= vertex)       == x" $ \(x :: G) ->-          (x >>= vertex)       == x--    test "((x >>= f) >>= g)    == (x >>= (\\y -> (f y) >>= g))" $ mapSize (min 10) $ \(x :: G) (apply -> f) (apply -> g) ->-          ((x >>= f) >>= g)    == (x >>= (\(y :: Int) -> (f y) >>= (g :: Int -> G)))--    putStrLn $ "\n============ Graph.NonEmpty.toNonEmptyGraph ============"-    test "toNonEmptyGraph empty       == Nothing" $-          toNonEmptyGraph (G.empty :: G.Graph Int) == Nothing--    test "toNonEmptyGraph (toGraph x) == Just (x :: NonEmptyGraph a)" $ \x ->-          toNonEmptyGraph (toGraph x) == Just (x :: NonEmptyGraph Int)--    putStrLn $ "\n============ Graph.NonEmpty.vertex ============"-    test "hasVertex x (vertex x) == True" $ \(x :: Int) ->-          hasVertex x (vertex x) == True--    test "vertexCount (vertex x) == 1" $ \(x :: Int) ->-          vertexCount (vertex x) == 1--    test "edgeCount   (vertex x) == 0" $ \(x :: Int) ->-          edgeCount   (vertex x) == 0--    test "size        (vertex x) == 1" $ \(x :: Int) ->-          size        (vertex x) == 1--    putStrLn $ "\n============ Graph.NonEmpty.edge ============"-    test "edge x y               == connect (vertex x) (vertex y)" $ \(x :: Int) y ->-          edge x y               == connect (vertex x) (vertex y)--    test "hasEdge x y (edge x y) == True" $ \(x :: Int) y ->-          hasEdge x y (edge x y) == True--    test "edgeCount   (edge x y) == 1" $ \(x :: Int) y ->-          edgeCount   (edge x y) == 1--    test "vertexCount (edge 1 1) == 1" $-          vertexCount (edge 1 1 :: G) == 1--    test "vertexCount (edge 1 2) == 2" $-          vertexCount (edge 1 2 :: G) == 2--    putStrLn $ "\n============ Graph.NonEmpty.overlay ============"-    test "hasVertex z (overlay x y) == hasVertex z x || hasVertex z y" $ \(x :: G) y z ->-          hasVertex z (overlay x y) == hasVertex z x || hasVertex z y--    test "vertexCount (overlay x y) >= vertexCount x" $ \(x :: G) y ->-          vertexCount (overlay x y) >= vertexCount x--    test "vertexCount (overlay x y) <= vertexCount x + vertexCount y" $ \(x :: G) y ->-          vertexCount (overlay x y) <= vertexCount x + vertexCount y--    test "edgeCount   (overlay x y) >= edgeCount x" $ \(x :: G) y ->-          edgeCount   (overlay x y) >= edgeCount x--    test "edgeCount   (overlay x y) <= edgeCount x   + edgeCount y" $ \(x :: G) y ->-          edgeCount   (overlay x y) <= edgeCount x   + edgeCount y--    test "size        (overlay x y) == size x        + size y" $ \(x :: G) y ->-          size        (overlay x y) == size x        + size y--    test "vertexCount (overlay 1 2) == 2" $-          vertexCount (overlay 1 2 :: G) == 2--    test "edgeCount   (overlay 1 2) == 0" $-          edgeCount   (overlay 1 2 :: G) == 0--    putStrLn $ "\n============ Graph.NonEmpty.overlay1 ============"-    test "               overlay1 empty x == x" $ \(x :: G) ->-                         overlay1 G.empty x == x--    test "x /= empty ==> overlay1 x     y == overlay (fromJust $ toNonEmptyGraph x) y" $ \(x :: G.Graph Int) (y :: G) ->-          x /= G.empty ==> overlay1 x   y == overlay (fromJust $ toNonEmptyGraph x) y---    putStrLn $ "\n============ Graph.NonEmpty.connect ============"-    test "hasVertex z (connect x y) == hasVertex z x || hasVertex z y" $ \(x :: G) y z ->-          hasVertex z (connect x y) == hasVertex z x || hasVertex z y--    test "vertexCount (connect x y) >= vertexCount x" $ \(x :: G) y ->-          vertexCount (connect x y) >= vertexCount x--    test "vertexCount (connect x y) <= vertexCount x + vertexCount y" $ \(x :: G) y ->-          vertexCount (connect x y) <= vertexCount x + vertexCount y--    test "edgeCount   (connect x y) >= edgeCount x" $ \(x :: G) y ->-          edgeCount   (connect x y) >= edgeCount x--    test "edgeCount   (connect x y) >= edgeCount y" $ \(x :: G) y ->-          edgeCount   (connect x y) >= edgeCount y--    test "edgeCount   (connect x y) >= vertexCount x * vertexCount y" $ \(x :: G) y ->-          edgeCount   (connect x y) >= vertexCount x * vertexCount y--    test "edgeCount   (connect x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y" $ \(x :: G) y ->-          edgeCount   (connect x y) <= vertexCount x * vertexCount y + edgeCount x + edgeCount y--    test "size        (connect x y) == size x        + size y" $ \(x :: G) y ->-          size        (connect x y) == size x        + size y--    test "vertexCount (connect 1 2) == 2" $-          vertexCount (connect 1 2 :: G) == 2--    test "edgeCount   (connect 1 2) == 1" $-          edgeCount   (connect 1 2 :: G) == 1--    putStrLn $ "\n============ Graph.NonEmpty.vertices1 ============"-    test "vertices1 (x :| [])     == vertex x" $ \(x :: Int) ->-          vertices1 (x :| [])     == vertex x--    test "hasVertex x . vertices1 == elem x" $ \(x :: Int) (xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (hasVertex x . vertices1) xs == elem x (NonEmpty.toList xs)--    test "vertexCount . vertices1 == length . nub" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertexCount . vertices1) xs == (NonEmpty.length . NonEmpty.nub) xs--    test "vertexSet   . vertices1 == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertexSet   . vertices1) xs == (Set.fromList . NonEmpty.toList) xs--    putStrLn $ "\n============ Graph.NonEmpty.edges1 ============"-    test "edges1 ((x,y) :| []) == edge x y" $ \(x :: Int) y ->-          edges1 ((x,y) :| []) == edge x y--    test "edgeCount . edges1   == length . nub" $ \(xs' :: NonEmptyList (Int, Int)) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (edgeCount . edges1) xs == (NonEmpty.length . NonEmpty.nub) xs--    putStrLn $ "\n============ Graph.NonEmpty.overlays1 ============"-    test "overlays1 (x :| [] ) == x" $ \(x :: G) ->-          overlays1 (x :| [] ) == x--    test "overlays1 (x :| [y]) == overlay x y" $ \(x :: G) y ->-          overlays1 (x :| [y]) == overlay x y--    putStrLn $ "\n============ Graph.NonEmpty.connects1 ============"-    test "connects1 (x :| [] ) == x" $ \(x :: G) ->-          connects1 (x :| [] ) == x--    test "connects1 (x :| [y]) == connect x y" $ \(x :: G) y ->-          connects1 (x :| [y]) == connect x y--    putStrLn $ "\n============ Graph.NonEmpty.foldg1 ============"-    test "foldg1 (const 1) (+)  (+)  == size" $ \(x :: G) ->-          foldg1 (const 1) (+)  (+) x == size x--    test "foldg1 (==x)     (||) (||) == hasVertex x" $ \(x :: Int) y ->-          foldg1 (==x)     (||) (||) y == hasVertex x y--    putStrLn $ "\n============ Graph.NonEmpty.isSubgraphOf ============"-    test "isSubgraphOf x             (overlay x y) == True" $ \(x :: G) y ->-          isSubgraphOf x             (overlay x y) == True--    test "isSubgraphOf (overlay x y) (connect x y) == True" $ \(x :: G) y ->-          isSubgraphOf (overlay x y) (connect x y) == True--    test "isSubgraphOf (path1 xs)    (circuit1 xs) == True" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in isSubgraphOf (path1 xs)    (circuit1 xs) == True--    putStrLn "\n============ Graph.NonEmpty.(===) ============"-    test "    x === x      == True" $ \(x :: G) ->-             (x === x)     == True--    test "x + y === x + y  == True" $ \(x :: G) y ->-         (x + y === x + y) == True--    test "1 + 2 === 2 + 1  == False" $-         (1 + 2 === 2 + (1 :: G)) == False--    test "x + y === x * y  == False" $ \(x :: G) y ->-         (x + y === x * y) == False--    putStrLn $ "\n============ Graph.NonEmpty.size ============"-    test "size (vertex x)    == 1" $ \(x :: Int) ->-          size (vertex x)    == 1--    test "size (overlay x y) == size x + size y" $ \(x :: G) y ->-          size (overlay x y) == size x + size y--    test "size (connect x y) == size x + size y" $ \(x :: G) y ->-          size (connect x y) == size x + size y--    test "size x             >= 1" $ \(x :: G) ->-          size x             >= 1--    test "size x             >= vertexCount x" $ \(x :: G) ->-          size x             >= vertexCount x--    putStrLn $ "\n============ Graph.NonEmpty.hasVertex ============"-    test "hasVertex x (vertex x) == True" $ \(x :: Int) ->-          hasVertex x (vertex x) == True--    test "hasVertex 1 (vertex 2) == False" $-          hasVertex 1 (vertex 2 :: G) == False--    putStrLn $ "\n============ Graph.NonEmpty.hasEdge ============"-    test "hasEdge x y (vertex z)       == False" $ \(x :: Int) y z ->-          hasEdge x y (vertex z)       == False--    test "hasEdge x y (edge x y)       == True" $ \(x :: Int) y ->-          hasEdge x y (edge x y)       == True--    test "hasEdge x y . removeEdge x y == const False" $ \(x :: Int) y z ->-         (hasEdge x y . removeEdge x y) z == False--    test "hasEdge x y                  == elem (x,y) . edgeList" $ \(x :: Int) y z -> do-        (u, v) <- elements ((x, y) : edgeList z)-        return $ hasEdge u v z == elem (u, v) (edgeList z)--    putStrLn $ "\n============ Graph.NonEmpty.vertexCount ============"-    test "vertexCount (vertex x) == 1" $ \(x :: Int) ->-          vertexCount (vertex x) == 1--    test "vertexCount x          >= 1" $ \(x :: G) ->-          vertexCount x          >= 1--    test "vertexCount            == length . vertexList1" $ \(x :: G) ->-          vertexCount x          == (NonEmpty.length . vertexList1) x--    putStrLn $ "\n============ Graph.NonEmpty.edgeCount ============"-    test "edgeCount (vertex x) == 0" $ \(x :: Int) ->-          edgeCount (vertex x) == 0--    test "edgeCount (edge x y) == 1" $ \(x :: Int) y ->-          edgeCount (edge x y) == 1--    test "edgeCount            == length . edgeList" $ \(x :: G) ->-          edgeCount x          == (length . edgeList) x--    putStrLn $ "\n============ Graph.NonEmpty.vertexList1 ============"-    test "vertexList1 (vertex x)  == x :| []" $ \(x :: Int) ->-          vertexList1 (vertex x)  == x :| []--    test "vertexList1 . vertices1 == nub . sort" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertexList1 . vertices1) xs == (NonEmpty.nub . NonEmpty.sort) xs--    putStrLn $ "\n============ Graph.NonEmpty.edgeList ============"-    test "edgeList (vertex x)     == []" $ \(x :: Int) ->-          edgeList (vertex x)     == []--    test "edgeList (edge x y)     == [(x,y)]" $ \(x :: Int) y ->-          edgeList (edge x y)     == [(x,y)]--    test "edgeList (star 2 [3,1]) == [(2,1), (2,3)]" $-          edgeList (star 2 [3,1]) == [(2,1), (2,3 :: Int)]--    test "edgeList . edges1       == nub . sort . toList" $ \(xs' :: NonEmptyList (Int, Int)) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (edgeList . edges1) xs   == (nubOrd . sort . NonEmpty.toList) xs--    test "edgeList . transpose    == sort . map swap . edgeList" $ \(x :: G) ->-         (edgeList . transpose) x == (sort . map swap . edgeList) x--    putStrLn $ "\n============ Graph.NonEmpty.vertexSet ============"-    test "vertexSet . vertex    == Set.singleton" $ \(x :: Int) ->-         (vertexSet . vertex) x == Set.singleton x--    test "vertexSet . vertices1 == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertexSet . vertices1) xs == (Set.fromList . NonEmpty.toList) xs--    test "vertexSet . clique1   == Set.fromList . toList" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertexSet . clique1) xs == (Set.fromList . NonEmpty.toList) xs--    putStrLn $ "\n============ Graph.NonEmpty.vertexIntSet ============"-    test "vertexIntSet . vertex    == IntSet.singleton" $ \(x :: Int) ->-         (vertexIntSet . vertex) x == IntSet.singleton x--    test "vertexIntSet . vertices1 == IntSet.fromList . toList" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertexIntSet . vertices1) xs == (IntSet.fromList . NonEmpty.toList) xs--    test "vertexIntSet . clique1   == IntSet.fromList . toList" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (vertexIntSet . clique1) xs == (IntSet.fromList . NonEmpty.toList) xs--    putStrLn $ "\n============ Graph.NonEmpty.edgeSet ============"-    test "edgeSet (vertex x) == Set.empty" $ \(x :: Int) ->-          edgeSet (vertex x) == Set.empty--    test "edgeSet (edge x y) == Set.singleton (x,y)" $ \(x :: Int) y ->-          edgeSet (edge x y) == Set.singleton (x,y)--    test "edgeSet . edges1   == Set.fromList . toList" $ \(xs' :: NonEmptyList (Int, Int)) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (edgeSet . edges1) xs == (Set.fromList . NonEmpty.toList) xs--    putStrLn $ "\n============ Graph.NonEmpty.path1 ============"-    test "path1 (x :| [] ) == vertex x" $ \(x :: Int) ->-          path1 (x :| [] ) == vertex x--    test "path1 (x :| [y]) == edge x y" $ \(x :: Int) y ->-          path1 (x :| [y]) == edge x y--    test "path1 . reverse  == transpose . path1" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (path1 . NonEmpty.reverse) xs == (transpose . path1) xs--    putStrLn $ "\n============ Graph.NonEmpty.circuit1 ============"-    test "circuit1 (x :| [] ) == edge x x" $ \(x :: Int) ->-          circuit1 (x :| [] ) == edge x x--    test "circuit1 (x :| [y]) == edges1 ((x,y) :| [(y,x)])" $ \(x :: Int) y ->-          circuit1 (x :| [y]) == edges1 ((x,y) :| [(y,x)])--    test "circuit1 . reverse  == transpose . circuit1" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (circuit1 . NonEmpty.reverse) xs == (transpose . circuit1) xs--    putStrLn $ "\n============ Graph.NonEmpty.clique1 ============"-    test "clique1 (x :| []   ) == vertex x" $ \(x :: Int) ->-          clique1 (x :| []   ) == vertex x--    test "clique1 (x :| [y]  ) == edge x y" $ \(x :: Int) y ->-          clique1 (x :| [y]  ) == edge x y--    test "clique1 (x :| [y,z]) == edges1 ((x,y) :| [(x,z), (y,z)])" $ \(x :: Int) y z ->-          clique1 (x :| [y,z]) == edges1 ((x,y) :| [(x,z), (y,z)])--    test "clique1 (xs <> ys)   == connect (clique1 xs) (clique1 ys)" $ \(xs' :: NonEmptyList Int) ys' ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-            ys = NonEmpty.fromList (getNonEmpty ys')-        in clique1 (xs <> ys)   == connect (clique1 xs) (clique1 ys)--    test "clique1 . reverse    == transpose . clique1" $ \(xs' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-        in (clique1 . NonEmpty.reverse) xs == (transpose . clique1) xs--    putStrLn $ "\n============ Graph.NonEmpty.biclique1 ============"-    test "biclique1 (x1 :| [x2]) (y1 :| [y2]) == edges1 ((x1,y1) :| [(x1,y2), (x2,y1), (x2,y2)])" $ \(x1 :: Int) x2 y1 y2 ->-          biclique1 (x1 :| [x2]) (y1 :| [y2]) == edges1 ((x1,y1) :| [(x1,y2), (x2,y1), (x2,y2)])--    test "biclique1 xs            ys          == connect (vertices1 xs) (vertices1 ys)" $ \(xs' :: NonEmptyList Int) ys' ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-            ys = NonEmpty.fromList (getNonEmpty ys')-        in biclique1 xs            ys          == connect (vertices1 xs) (vertices1 ys)--    putStrLn $ "\n============ Graph.NonEmpty.star ============"-    test "star x []    == vertex x" $ \(x :: Int) ->-          star x []    == vertex x--    test "star x [y]   == edge x y" $ \(x :: Int) y ->-          star x [y]   == edge x y--    test "star x [y,z] == edges1 ((x,y) :| [(x,z)])" $ \(x :: Int) y z ->-          star x [y,z] == edges1 ((x,y) :| [(x,z)])--    putStrLn $ "\n============ Graph.NonEmpty.stars1 ============"-    test "stars1 ((x, [])  :| [])         == vertex x" $ \(x :: Int) ->-          stars1 ((x, [])  :| [])         == vertex x--    test "stars1 ((x, [y]) :| [])         == edge x y" $ \(x :: Int) y ->-          stars1 ((x, [y]) :| [])         == edge x y--    test "stars1 ((x, ys)  :| [])         == star x ys" $ \(x :: Int) ys ->-          stars1 ((x, ys)  :| [])         == star x ys--    test "stars1                          == overlays1 . fmap (uncurry star)" $ \(xs' :: NonEmptyList (Int, [Int])) ->-      let xs = NonEmpty.fromList (getNonEmpty xs')-      in  stars1 xs                       == overlays1 (fmap (uncurry star) xs)--    test "overlay (stars1 xs) (stars1 ys) == stars1 (xs <> ys)" $ \(xs' :: NonEmptyList (Int, [Int])) (ys' :: NonEmptyList (Int, [Int])) ->-      let xs = NonEmpty.fromList (getNonEmpty xs')-          ys = NonEmpty.fromList (getNonEmpty ys')-      in  overlay (stars1 xs) (stars1 ys) == stars1 (xs <> ys)--    putStrLn $ "\n============ Graph.NonEmpty.tree ============"-    test "tree (Node x [])                                         == vertex x" $ \(x :: Int) ->-          tree (Node x [])                                         == vertex x--    test "tree (Node x [Node y [Node z []]])                       == path1 (x :| [y,z])" $ \(x :: Int) y z ->-          tree (Node x [Node y [Node z []]])                       == path1 (x :| [y,z])--    test "tree (Node x [Node y [], Node z []])                     == star x [y,z]" $ \(x :: Int) y z ->-          tree (Node x [Node y [], Node z []])                     == star x [y,z]--    test "tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == edges1 ((1,2) :| [(1,3), (3,4), (3,5)])" $-          tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == edges1 ((1,2) :| [(1,3), (3,4), (3,5 :: Int)])--    putStrLn $ "\n============ Graph.NonEmpty.mesh1 ============"-    test "mesh1 (x :| [])    (y :| [])    == vertex (x, y)" $ \(x :: Int) (y :: Int) ->-          mesh1 (x :| [])    (y :| [])    == vertex (x, y)--    test "mesh1 xs           ys           == box (path1 xs) (path1 ys)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-            ys = NonEmpty.fromList (getNonEmpty ys')-        in mesh1 xs           ys           == box (path1 xs) (path1 ys)--    test "mesh1 (1 :| [2,3]) ('a' :| \"b\") == <correct result>" $-          mesh1 (1 :| [2,3]) ('a' :| "b") == edges1 (NonEmpty.fromList [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a'))-                                                                      , ((1,'b'),(2,'b')), ((2,'a'),(2,'b'))-                                                                      , ((2,'a'),(3,'a')), ((2,'b'),(3,'b'))-                                                                      , ((3,'a'),(3 :: Int,'b')) ])--    test "size (mesh xs ys)               == max 1 (3 * length xs * length ys - length xs - length ys -1)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-            ys = NonEmpty.fromList (getNonEmpty ys')-         in size (mesh1 xs ys) == max 1 (3 * length xs * length ys - length xs - length ys -1)--    putStrLn $ "\n============ Graph.NonEmpty.torus1 ============"-    test "torus1 (x :| [])  (y :| [])    == edge (x,y) (x,y)" $ \(x :: Int) (y :: Int) ->-          torus1 (x :| [])  (y :| [])    == edge (x,y) (x,y)--    test "torus1 xs         ys           == box (circuit1 xs) (circuit1 ys)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-            ys = NonEmpty.fromList (getNonEmpty ys')-        in torus1 xs         ys           == box (circuit1 xs) (circuit1 ys)--    test "torus1 (1 :| [2]) ('a' :| \"b\") == <correct result>" $-          torus1 (1 :| [2]) ('a' :| "b") == edges1 (NonEmpty.fromList [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a'))-                                                   , ((1,'b'),(1,'a')), ((1,'b'),(2,'b'))-                                                   , ((2,'a'),(1,'a')), ((2,'a'),(2,'b'))-                                                   , ((2,'b'),(1,'b')), ((2,'b'),(2 :: Int,'a')) ])--    test "size (torus1 xs ys)            == max 1 (3 * length xs * length ys)" $ \(xs' :: NonEmptyList Int) (ys' :: NonEmptyList Int) ->-        let xs = NonEmpty.fromList (getNonEmpty xs')-            ys = NonEmpty.fromList (getNonEmpty ys')-        in size (torus1 xs ys) == max 1 (3 * length xs * length ys)--    putStrLn $ "\n============ Graph.NonEmpty.removeVertex1 ============"-    test "removeVertex1 x (vertex x)          == Nothing" $ \(x :: Int) ->-          removeVertex1 x (vertex x)          == Nothing--    test "removeVertex1 1 (vertex 2)          == Just (vertex 2)" $-          removeVertex1 1 (vertex 2)          == Just (vertex 2 :: G)--    test "removeVertex1 x (edge x x)          == Nothing" $ \(x :: Int) ->-          removeVertex1 x (edge x x)          == Nothing--    test "removeVertex1 1 (edge 1 2)          == Just (vertex 2)" $-          removeVertex1 1 (edge 1 2)          == Just (vertex 2 :: G)--    test "removeVertex1 x >=> removeVertex1 x == removeVertex1 x" $ \(x :: Int) y ->-         (removeVertex1 x >=> removeVertex1 x) y == removeVertex1 x y--    putStrLn $ "\n============ Graph.NonEmpty.removeEdge ============"-    test "removeEdge x y (edge x y)       == vertices1 (x :| [y])" $ \(x :: Int) y ->-          removeEdge x y (edge x y)       == vertices1 (x :| [y])--    test "removeEdge x y . removeEdge x y == removeEdge x y" $ \(x :: Int) y z ->-         (removeEdge x y . removeEdge x y) z == removeEdge x y z--    test "removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * 2" $-          removeEdge 1 1 (1 * 1 * 2 * 2)  == 1 * 2 * (2 :: NonEmptyGraph Int)--    test "removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2" $-          removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * (2 :: NonEmptyGraph Int)--    test "size (removeEdge x y z)         <= 3 * size z" $ \(x :: Int) y z ->-          size (removeEdge x y z)         <= 3 * size z--    putStrLn $ "\n============ Graph.NonEmpty.replaceVertex ============"-    test "replaceVertex x x            == id" $ \(x :: Int) y ->-          replaceVertex x x y          == y--    test "replaceVertex x y (vertex x) == vertex y" $ \(x :: Int) y ->-          replaceVertex x y (vertex x) == vertex y--    test "replaceVertex x y            == mergeVertices (== x) y" $ \(x :: Int) y z ->-          replaceVertex x y z          == mergeVertices (== x) y z--    putStrLn $ "\n============ Graph.NonEmpty.mergeVertices ============"-    test "mergeVertices (const False) x    == id" $ \(x :: Int) y ->-          mergeVertices (const False) x y  == y--    test "mergeVertices (== x) y           == replaceVertex x y" $ \(x :: Int) y z ->-          mergeVertices (== x) y z         == replaceVertex x y z--    test "mergeVertices even 1 (0 * 2)     == 1 * 1" $-          mergeVertices even 1 (0 * 2)     == (1 * 1 :: G)--    test "mergeVertices odd  1 (3 + 4 * 5) == 4 * 1" $-          mergeVertices odd  1 (3 + 4 * 5) == (4 * 1 :: G)--    putStrLn $ "\n============ Graph.NonEmpty.splitVertex1 ============"-    test "splitVertex1 x (x :| [] )               == id" $ \x (y :: G) ->-          splitVertex1 x (x :| [] ) y             == y--    test "splitVertex1 x (y :| [] )               == replaceVertex x y" $ \x y (z :: G) ->-          splitVertex1 x (y :| [] ) z             == replaceVertex x y z--    test "splitVertex1 1 (0 :| [1]) $ 1 * (2 + 3) == (0 + 1) * (2 + 3)" $-          splitVertex1 1 (0 :| [1]) (1 * (2 + 3)) == (0 + 1) * (2 + 3 :: G)--    putStrLn $ "\n============ Graph.NonEmpty.transpose ============"-    test "transpose (vertex x)  == vertex x" $ \(x :: Int) ->-          transpose (vertex x)  == vertex x--    test "transpose (edge x y)  == edge y x" $ \(x :: Int) y ->-          transpose (edge x y)  == edge y x--    test "transpose . transpose == id" $ \(x :: G) ->-         (transpose . transpose) x == x--    test "transpose (box x y)   == box (transpose x) (transpose y)" $ mapSize (min 10) $ \(x :: G) (y :: G) ->-          transpose (box x y)   == box (transpose x) (transpose y)--    test "edgeList . transpose  == sort . map swap . edgeList" $ \(x :: G) ->-         (edgeList . transpose) x == (sort . map swap . edgeList) x--    putStrLn $ "\n============ Graph.NonEmpty.induce1 ============"-    test "induce1 (const True ) x == Just x" $ \(x :: G) ->-          induce1 (const True ) x == Just x--    test "induce1 (const False) x == Nothing" $ \(x :: G) ->-          induce1 (const False) x == Nothing--    test "induce1 (/= x)          == removeVertex1 x" $ \(x :: Int) y ->-          induce1 (/= x) y        == removeVertex1 x y--    test "induce1 p >=> induce1 q == induce1 (\\x -> p x && q x)" $ \(apply -> p) (apply -> q) (y :: G) ->-         (induce1 p >=> induce1 q) y == induce1 (\x -> p x && q x) y--    putStrLn $ "\n============ Graph.NonEmpty.simplify ============"-    test "simplify              == id" $ \(x :: G) ->-          simplify x            == x--    test "size (simplify x)     <= size x" $ \(x :: G) ->-          size (simplify x)     <= size x--    test "simplify 1           === 1" $-          simplify 1           === (1 :: G)--    test "simplify (1 + 1)     === 1" $-          simplify (1 + 1)     === (1 :: G)--    test "simplify (1 + 2 + 1) === 1 + 2" $-          simplify (1 + 2 + 1) === (1 + 2 :: G)--    test "simplify (1 * 1 * 1) === 1 * 1" $-          simplify (1 * 1 * 1) === (1 * 1 :: G)--    putStrLn "\n============ Graph.NonEmpty.box ============"-    let unit = fmap $ \(a, ()) -> a-        comm = fmap $ \(a,  b) -> (b, a)-    test "box x y               ~~ box y x" $ mapSize (min 10) $ \(x :: G) (y :: G) ->-          comm (box x y)        == box y x--    test "box x (overlay y z)   == overlay (box x y) (box x z)" $ mapSize (min 10) $ \(x :: G) (y :: G) z ->-          box x (overlay y z)   == overlay (box x y) (box x z)--    test "box x (vertex ())     ~~ x" $ mapSize (min 10) $ \(x :: G) ->-     unit(box x (vertex ()))    == x--    let assoc = fmap $ \(a, (b, c)) -> ((a, b), c)-    test "box x (box y z)       ~~ box (box x y) z" $ mapSize (min 5) $ \(x :: G) (y :: G) (z :: G) ->-      assoc (box x (box y z))   == box (box x y) z--    test "transpose   (box x y) == box (transpose x) (transpose y)" $ mapSize (min 10) $ \(x :: G) (y :: G) ->-          transpose   (box x y) == box (transpose x) (transpose y)--    test "vertexCount (box x y) == vertexCount x * vertexCount y" $ mapSize (min 10) $ \(x :: G) (y :: G) ->-          vertexCount (box x y) == vertexCount x * vertexCount y--    test "edgeCount   (box x y) <= vertexCount x * edgeCount y + edgeCount x * vertexCount y" $ mapSize (min 10) $ \(x :: G) (y :: G) ->-          edgeCount   (box x y) <= vertexCount x * edgeCount y + edgeCount x * vertexCount y--    putStrLn "\n============ Graph.NonEmpty.sparsify ============"-    test "sort . reachable x       == sort . rights . reachable (Right x) . sparsify" $ \x (y :: G) ->-         (sort . reachable x) y    == (sort . rights . reachable (Right x) . sparsify) y--    test "vertexCount (sparsify x) <= vertexCount x + size x + 1" $ \(x :: G) ->-          vertexCount (sparsify x) <= vertexCount x + size x + 1--    test "edgeCount   (sparsify x) <= 3 * size x" $ \(x :: G) ->-          edgeCount   (sparsify x) <= 3 * size x--    test "size        (sparsify x) <= 3 * size x" $ \(x :: G) ->-          size        (sparsify x) <= 3 * size x
test/Algebra/Graph/Test/Relation.hs view
@@ -30,13 +30,10 @@  type RI = Relation Int -sizeLimit :: Testable prop => prop -> Property-sizeLimit = mapSize (min 10)- testRelation :: IO () testRelation = do     putStrLn "\n============ Relation ============"-    test "Axioms of graphs" $ sizeLimit (axioms :: GraphTestsuite RI)+    test "Axioms of graphs" $ size10 (axioms :: GraphTestsuite RI)      test "Consistency of arbitraryRelation" $ \(m :: RI) ->         consistent m@@ -47,70 +44,14 @@     testToGraph         t     testGraphFamilies   t     testTransformations t--    putStrLn "\n============ Relation.compose ============"-    test "compose empty            x                == empty" $ \(x :: RI) ->-          compose empty            x                == empty--    test "compose x                empty            == empty" $ \(x :: RI) ->-          compose x                empty            == empty--    test "compose x                (compose y z)    == compose (compose x y) z" $ sizeLimit $ \(x :: RI) y z ->-          compose x                (compose y z)    == compose (compose x y) z--    test "compose (edge y z)       (edge x y)       == edge x z" $ \(x :: Int) y z ->-          compose (edge y z)       (edge x y)       == edge x z--    test "compose (path    [1..5]) (path    [1..5]) == edges [(1,3),(2,4),(3,5)]" $-          compose (path    [1..5]) (path    [1..5]) == edges [(1,3),(2,4),(3,5::Int)]--    test "compose (circuit [1..5]) (circuit [1..5]) == circuit [1,3,5,2,4]" $-          compose (circuit [1..5]) (circuit [1..5]) == circuit [1,3,5,2,4::Int]--    putStrLn "\n============ Relation.reflexiveClosure ============"-    test "reflexiveClosure empty      == empty" $-          reflexiveClosure empty      ==(empty :: RI)--    test "reflexiveClosure (vertex x) == edge x x" $ \(x :: Int) ->-          reflexiveClosure (vertex x) == edge x x--    putStrLn "\n============ Relation.symmetricClosure ============"--    test "symmetricClosure empty      == empty" $-          symmetricClosure empty      ==(empty :: RI)--    test "symmetricClosure (vertex x) == vertex x" $ \(x :: Int) ->-          symmetricClosure (vertex x) == vertex x--    test "symmetricClosure (edge x y) == edges [(x, y), (y, x)]" $ \(x :: Int) y ->-          symmetricClosure (edge x y) == edges [(x, y), (y, x)]--    putStrLn "\n============ Relation.transitiveClosure ============"-    test "transitiveClosure empty           == empty" $-          transitiveClosure empty           ==(empty :: RI)--    test "transitiveClosure (vertex x)      == vertex x" $ \(x :: Int) ->-          transitiveClosure (vertex x)      == vertex x--    test "transitiveClosure (path $ nub xs) == clique (nub $ xs)" $ \(xs :: [Int]) ->-          transitiveClosure (path $ nubOrd xs) == clique (nubOrd xs)--    putStrLn "\n============ Relation.preorderClosure ============"-    test "preorderClosure empty           == empty" $-          preorderClosure empty           ==(empty :: RI)--    test "preorderClosure (vertex x)      == edge x x" $ \(x :: Int) ->-          preorderClosure (vertex x)      == edge x x--    test "preorderClosure (path $ nub xs) == reflexiveClosure (clique $ nub xs)" $ \(xs :: [Int]) ->-          preorderClosure (path $ nubOrd xs) == reflexiveClosure (clique $ nubOrd xs)+    testRelational      t      putStrLn "\n============ ReflexiveRelation ============"-    test "Axioms of reflexive graphs" $ sizeLimit+    test "Axioms of reflexive graphs" $ size10         (reflexiveAxioms :: GraphTestsuite (ReflexiveRelation Int))      putStrLn "\n============ SymmetricRelation ============"-    test "Axioms of undirected graphs" $ sizeLimit+    test "Axioms of undirected graphs" $ size10         (undirectedAxioms :: GraphTestsuite (SymmetricRelation Int))      putStrLn "\n============ SymmetricRelation.neighbours ============"@@ -127,15 +68,15 @@           neighbours y (C.edge x y) == Set.fromList [x]      putStrLn "\n============ TransitiveRelation ============"-    test "Axioms of transitive graphs" $ sizeLimit+    test "Axioms of transitive graphs" $ size10         (transitiveAxioms :: GraphTestsuite (TransitiveRelation Int)) -    test "path xs == (clique xs :: TransitiveRelation Int)" $ sizeLimit $ \xs ->+    test "path xs == (clique xs :: TransitiveRelation Int)" $ size10 $ \xs ->           C.path xs == (C.clique xs :: TransitiveRelation Int)      putStrLn "\n============ PreorderRelation ============"-    test "Axioms of preorder graphs" $ sizeLimit+    test "Axioms of preorder graphs" $ size10         (preorderAxioms :: GraphTestsuite (PreorderRelation Int)) -    test "path xs == (clique xs :: PreorderRelation Int)" $ sizeLimit $ \xs ->+    test "path xs == (clique xs :: PreorderRelation Int)" $ size10 $ \xs ->           C.path xs == (C.clique xs :: PreorderRelation Int)
+ test/Algebra/Graph/Test/RewriteRules.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE TemplateHaskell #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Test.RewriteRules+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- Testsuite for "Algebra.Graph" rewrite rules.+-----------------------------------------------------------------------------+module Algebra.Graph.Test.RewriteRules where++import Data.Maybe (fromMaybe)++import Algebra.Graph hiding ((===))+import Algebra.Graph.Internal++import Test.Inspection++-- Naming convention: we use the suffix "R" to indicate the desired outcome of+-- rewrite rules, and suffices "1", "2", etc. to indicate initial expressions.++-- Testsuite for 'overlays' and 'connects'.+vertices1, verticesR :: [a] -> Graph a+vertices1 = overlays . map vertex+verticesR = fromMaybe Empty . foldr (maybeF Overlay . Vertex) Nothing++inspect $ 'vertices1 === 'verticesR++clique1, cliqueR :: [a] -> Graph a+clique1 = connects . map vertex+cliqueR = fromMaybe Empty . foldr (maybeF Connect . Vertex) Nothing++inspect $ 'clique1 === 'cliqueR++-- Testsuite for 'transpose'.+empty1, emptyR :: Graph a+empty1 = transpose Empty+emptyR = Empty++inspect $ 'empty1 === 'emptyR++vertex1, vertexR :: a -> Graph a+vertex1 = transpose . vertex+vertexR = Vertex++inspect $ 'vertex1 === 'vertexR++overlay1, overlayR :: Graph a -> Graph a -> Graph a+overlay1 x y = transpose (Overlay x y)+overlayR x y = Overlay (transpose x) (transpose y)++inspect $ 'overlay1 === 'overlayR++connect1, connectR :: Graph a -> Graph a -> Graph a+connect1 x y = transpose (Connect x y)+connectR x y = Connect (transpose y) (transpose x)++inspect $ 'connect1 === 'connectR++overlays1, overlaysR :: [Graph a] -> Graph a+overlays1 = transpose . overlays+overlaysR = overlays . map transpose++inspect $ 'overlays1 === 'overlaysR++connects1, connectsR :: [Graph a] -> Graph a+connects1 = transpose . connects+connectsR = fromMaybe Empty . foldr (maybeF (flip Connect) . transpose) Nothing++inspect $ 'connects1 === 'connectsR++vertices2 :: [a] -> Graph a+vertices2 = transpose . overlays . map vertex++inspect $ 'vertices2 === 'vertices1++-- Note that we currently have these three tests:+-- * vertices2 === vertices1+-- * vertices1 === verticesR+-- * vertices2 =/= verticesR+-- This non-transitivity is awkward, and feels like a bug in the inspection+-- testing library. See https://github.com/nomeata/inspection-testing/issues/23.+inspect $ 'vertices2 =/= 'verticesR++cliqueT1, cliqueTR :: [a] -> Graph a+cliqueT1 = transpose . connects . map vertex+cliqueTR = fromMaybe Empty . foldr (maybeF (flip Connect) . Vertex) Nothing++inspect $ 'cliqueT1 === 'cliqueTR++starT1, starTR :: a -> [a] -> Graph a+starT1 x = transpose . star x+starTR a [] = vertex a+starTR a xs = connect (vertices xs) (vertex a)++inspect $ 'starT1 === 'starTR
test/Main.hs view
@@ -1,10 +1,13 @@+import Algebra.Graph.Test.AdjacencyIntMap import Algebra.Graph.Test.AdjacencyMap+import Algebra.Graph.Test.NonEmpty.AdjacencyMap import Algebra.Graph.Test.Export import Algebra.Graph.Test.Fold import Algebra.Graph.Test.Graph-import Algebra.Graph.Test.AdjacencyIntMap+import Algebra.Graph.Test.NonEmpty.Graph import Algebra.Graph.Test.Internal-import Algebra.Graph.Test.NonEmptyGraph+import Algebra.Graph.Test.Labelled.AdjacencyMap+import Algebra.Graph.Test.Labelled.Graph import Algebra.Graph.Test.Relation import Data.Graph.Test.Typed @@ -15,7 +18,10 @@     testExport     testFold     testGraph-    testGraphNonEmpty     testInternal+    testLabelledAdjacencyMap+    testLabelledGraph+    testNonEmptyAdjacencyMap+    testNonEmptyGraph     testRelation     testTyped