packages feed

algebraic-graphs 0.0.5 → 0.1.0

raw patch · 36 files changed

+2252/−515 lines, 36 filesdep +base-compatdep +base-orphansdep +deepseqdep ~QuickCheckdep ~arraydep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: base-compat, base-orphans, deepseq, semigroups

Dependency ranges changed: QuickCheck, array, base, containers

API changes (from Hackage documentation)

- Algebra.Graph: graph :: [a] -> [(a, a)] -> Graph a
- Algebra.Graph: instance Algebra.Graph.Class.Graph (Algebra.Graph.Piece a)
- Algebra.Graph.AdjacencyMap: graph :: Ord a => [a] -> [(a, a)] -> AdjacencyMap a
- Algebra.Graph.Class: graph :: Graph g => [Vertex g] -> [(Vertex g, Vertex g)] -> g
- Algebra.Graph.Fold: graph :: Graph g => [Vertex g] -> [(Vertex g, Vertex g)] -> g
- Algebra.Graph.Fold: instance Algebra.Graph.Class.Graph g => Algebra.Graph.Class.Graph (Algebra.Graph.Fold.Piece g)
- Algebra.Graph.HigherKinded.Class: graph :: Graph g => [a] -> [(a, a)] -> g a
- Algebra.Graph.IntAdjacencyMap: graph :: [Int] -> [(Int, Int)] -> IntAdjacencyMap
- Algebra.Graph.Relation: graph :: Ord a => [a] -> [(a, a)] -> Relation a
+ Algebra.Graph: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Algebra.Graph.Graph a)
+ Algebra.Graph: starTranspose :: a -> [a] -> Graph a
+ Algebra.Graph.AdjacencyMap: starTranspose :: Ord a => a -> [a] -> AdjacencyMap a
+ Algebra.Graph.Class: foldg :: ToGraph t => r -> (ToVertex t -> r) -> (r -> r -> r) -> (r -> r -> r) -> t -> r
+ Algebra.Graph.Class: instance Algebra.Graph.Class.Graph (Algebra.Graph.Class.G a)
+ Algebra.Graph.Class: starTranspose :: Graph g => Vertex g -> [Vertex g] -> g
+ Algebra.Graph.Fold: starTranspose :: Graph g => Vertex g -> [Vertex g] -> g
+ Algebra.Graph.HigherKinded.Class: starTranspose :: Graph g => a -> [a] -> g a
+ Algebra.Graph.IntAdjacencyMap: starTranspose :: Int -> [Int] -> IntAdjacencyMap
+ Algebra.Graph.Internal: Context :: [a] -> [a] -> Context a
+ Algebra.Graph.Internal: List :: (Endo [a]) -> List a
+ Algebra.Graph.Internal: [inputs] :: Context a -> [a]
+ Algebra.Graph.Internal: [outputs] :: Context a -> [a]
+ Algebra.Graph.Internal: context :: ToGraph g => (ToVertex g -> Bool) -> g -> Maybe (Context (ToVertex g))
+ Algebra.Graph.Internal: data Context a
+ Algebra.Graph.Internal: data Focus a
+ Algebra.Graph.Internal: focus :: ToGraph g => (ToVertex g -> Bool) -> g -> Focus (ToVertex g)
+ Algebra.Graph.Internal: instance Data.Foldable.Foldable Algebra.Graph.Internal.List
+ Algebra.Graph.Internal: instance Data.Semigroup.Semigroup (Algebra.Graph.Internal.List a)
+ Algebra.Graph.Internal: instance GHC.Base.Applicative Algebra.Graph.Internal.List
+ Algebra.Graph.Internal: instance GHC.Base.Functor Algebra.Graph.Internal.List
+ Algebra.Graph.Internal: instance GHC.Base.Monad Algebra.Graph.Internal.List
+ Algebra.Graph.Internal: instance GHC.Base.Monoid (Algebra.Graph.Internal.List a)
+ Algebra.Graph.Internal: instance GHC.Classes.Eq a => GHC.Classes.Eq (Algebra.Graph.Internal.List a)
+ Algebra.Graph.Internal: instance GHC.Classes.Ord a => GHC.Classes.Ord (Algebra.Graph.Internal.List a)
+ Algebra.Graph.Internal: instance GHC.Exts.IsList (Algebra.Graph.Internal.List a)
+ Algebra.Graph.Internal: instance GHC.Show.Show a => GHC.Show.Show (Algebra.Graph.Internal.List a)
+ Algebra.Graph.Internal: newtype List a
+ Algebra.Graph.NonEmpty: (===) :: Eq a => NonEmptyGraph a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: Connect :: (NonEmptyGraph a) -> (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: Overlay :: (NonEmptyGraph a) -> (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: Vertex :: a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: biclique1 :: NonEmpty a -> NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: box :: NonEmptyGraph a -> NonEmptyGraph b -> NonEmptyGraph (a, b)
+ Algebra.Graph.NonEmpty: circuit1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: clique1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: connect :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: connects1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: data NonEmptyGraph a
+ Algebra.Graph.NonEmpty: edge :: a -> a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: edgeCount :: Ord a => NonEmptyGraph a -> Int
+ Algebra.Graph.NonEmpty: edgeList :: Ord a => NonEmptyGraph a -> [(a, a)]
+ Algebra.Graph.NonEmpty: edgeSet :: Ord a => NonEmptyGraph a -> Set (a, a)
+ Algebra.Graph.NonEmpty: edges1 :: NonEmpty (a, a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: foldg1 :: (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> NonEmptyGraph a -> b
+ Algebra.Graph.NonEmpty: hasEdge :: Ord a => a -> a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: hasVertex :: Eq a => a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: induce1 :: (a -> Bool) -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)
+ Algebra.Graph.NonEmpty: infix 4 ===
+ Algebra.Graph.NonEmpty: instance Algebra.Graph.Class.ToGraph (Algebra.Graph.NonEmpty.NonEmptyGraph a)
+ Algebra.Graph.NonEmpty: instance Algebra.Graph.HigherKinded.Class.ToGraph Algebra.Graph.NonEmpty.NonEmptyGraph
+ 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: isSubgraphOf :: Ord a => NonEmptyGraph a -> NonEmptyGraph a -> Bool
+ Algebra.Graph.NonEmpty: mergeVertices :: (a -> Bool) -> a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: mesh1 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)
+ Algebra.Graph.NonEmpty: overlay :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: overlay1 :: Graph a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: overlays1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: path1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: removeEdge :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: removeVertex1 :: Eq a => a -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)
+ Algebra.Graph.NonEmpty: replaceVertex :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: simplify :: Ord a => NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: size :: NonEmptyGraph a -> Int
+ Algebra.Graph.NonEmpty: splitVertex1 :: Eq a => a -> NonEmpty a -> NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: star :: a -> [a] -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: starTranspose :: a -> [a] -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: toNonEmptyGraph :: Graph a -> Maybe (NonEmptyGraph a)
+ Algebra.Graph.NonEmpty: torus1 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)
+ Algebra.Graph.NonEmpty: transpose :: NonEmptyGraph a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: tree :: Tree a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: vertex :: a -> NonEmptyGraph a
+ Algebra.Graph.NonEmpty: vertexCount :: Ord a => NonEmptyGraph a -> Int
+ Algebra.Graph.NonEmpty: vertexIntSet :: NonEmptyGraph Int -> IntSet
+ Algebra.Graph.NonEmpty: vertexList1 :: Ord a => NonEmptyGraph a -> NonEmpty a
+ Algebra.Graph.NonEmpty: vertexSet :: Ord a => NonEmptyGraph a -> Set a
+ Algebra.Graph.NonEmpty: vertices1 :: NonEmpty a -> NonEmptyGraph a
+ Algebra.Graph.Relation: starTranspose :: Ord a => a -> [a] -> Relation a
- Algebra.Graph.Class: class Graph g where type Vertex g where {
+ Algebra.Graph.Class: class Graph g where {
- Algebra.Graph.Class: class ToGraph t where type ToVertex t where {
+ Algebra.Graph.Class: class ToGraph t where {
- Algebra.Graph.HigherKinded.Class: empty :: Alternative f => forall a. f a
+ Algebra.Graph.HigherKinded.Class: empty :: Alternative f => forall a. () => f a

Files

CHANGES.md view
@@ -1,5 +1,18 @@ # Change log
 
+## 0.1.0
+
+* Start complying with PVP.
+* #48: Add `starTranspose`.
+* #48: Add `foldg` to `ToGraph`.
+* #15: Optimise `removeEdge`.
+* #39: Factor out difference lists into `Algebra.Graph.Internal`.
+* #31: Add `Algebra.Graph.NonEmpty`.
+* #32: Remove smart constructor `graph`.
+* #27, #55: Support GHC versions 7.8.4, 7.10.3, 8.0.2, 8.2.2, 8.4.1.
+* #25: Add `NFData Graph` instance.
+* General improvements to code, documentation and tests.
+
 ## 0.0.5
 
 * Add `dfs`.
LICENSE view
@@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016-2017 Andrey Mokhov+Copyright (c) 2016-2018 Andrey Mokhov  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
algebraic-graphs.cabal view
@@ -1,16 +1,20 @@ name:          algebraic-graphs-version:       0.0.5+version:       0.1.0 synopsis:      A library for algebraic graph construction and transformation license:       MIT license-file:  LICENSE author:        Andrey Mokhov <andrey.mokhov@gmail.com>, github: @snowleopard maintainer:    Andrey Mokhov <andrey.mokhov@gmail.com>, github: @snowleopard-copyright:     Andrey Mokhov, 2016-2017+copyright:     Andrey Mokhov, 2016-2018 homepage:      https://github.com/snowleopard/alga category:      Algebra, Algorithms, Data Structures, Graphs build-type:    Simple cabal-version: >=1.18-tested-with:   GHC==8.0.2+tested-with:   GHC==7.8.4,+               GHC==7.10.3,+               GHC==8.0.2,+               GHC==8.2.2,+               GHC==8.4.1 stability:     experimental description:     <https://github.com/snowleopard/alga Alga> is a library for algebraic construction and@@ -36,8 +40,8 @@     that defines the Boehm-Berarducci encoding of algebraic graphs and provides additional     flexibility for polymorphic graph manipulation.     .-    This is an experimental library and the API will be unstable until version 1.0.0. Please-    consider contributing to the on-going+    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     <https://github.com/snowleopard/alga/issues discussions on the library API>.  extra-doc-files:@@ -60,6 +64,8 @@                         Algebra.Graph.HigherKinded.Class,                         Algebra.Graph.IntAdjacencyMap,                         Algebra.Graph.IntAdjacencyMap.Internal,+                        Algebra.Graph.Internal,+                        Algebra.Graph.NonEmpty,                         Algebra.Graph.Relation,                         Algebra.Graph.Relation.Internal,                         Algebra.Graph.Relation.InternalDerived,@@ -67,22 +73,29 @@                         Algebra.Graph.Relation.Reflexive,                         Algebra.Graph.Relation.Symmetric,                         Algebra.Graph.Relation.Transitive-    build-depends:      array      >= 0.5 && < 0.8,-                        base       >= 4.9 && < 5,-                        containers >= 0.5 && < 0.8+    build-depends:      array       >= 0.4     && < 0.6,+                        base        >= 4.7     && < 5,+                        base-compat >= 0.9.1   && < 0.10,+                        containers  >= 0.5.5.1 && < 0.8,+                        deepseq     >= 1.3.0.1 && < 1.5+    if !impl(ghc >= 8.0)+        build-depends:  semigroups  >= 0.18.3  && < 0.18.4     default-language:   Haskell2010     default-extensions: FlexibleContexts                         GeneralizedNewtypeDeriving                         ScopedTypeVariables                         TupleSections                         TypeFamilies-    other-extensions:   DeriveFoldable+    other-extensions:   CPP+                        DeriveFoldable                         DeriveFunctor                         DeriveTraversable                         OverloadedStrings                         RecordWildCards     GHC-options:        -Wall-                        -Wcompat+                        -fno-warn-name-shadowing+    if impl(ghc >= 8.0)+        GHC-options:    -Wcompat                         -Wincomplete-record-updates                         -Wincomplete-uni-patterns                         -Wredundant-constraints@@ -100,16 +113,24 @@                         Algebra.Graph.Test.Generic,                         Algebra.Graph.Test.Graph,                         Algebra.Graph.Test.IntAdjacencyMap,+                        Algebra.Graph.Test.Internal,+                        Algebra.Graph.Test.NonEmptyGraph,                         Algebra.Graph.Test.Relation     build-depends:      algebraic-graphs,-                        base       >= 4.9,-                        containers >= 0.5,-                        extra      >= 1.5,-                        QuickCheck >= 2.9+                        base         >= 4.7     && < 5,+                        base-compat  >= 0.9.1   && < 0.10,+                        base-orphans >= 0.5.4   && < 0.8,+                        containers   >= 0.5.5.1 && < 0.8,+                        extra        >= 1.5,+                        QuickCheck   >= 2.9     && < 2.11+    if !impl(ghc >= 8.0)+        build-depends:  semigroups   >= 0.18.3  && < 0.18.4     default-language:   Haskell2010     GHC-options:        -O2                         -Wall-                        -Wcompat+                        -fno-warn-name-shadowing+    if impl(ghc >= 8.0)+        GHC-options:    -Wcompat                         -Wincomplete-record-updates                         -Wincomplete-uni-patterns                         -Wredundant-constraints@@ -127,13 +148,16 @@     type:               exitcode-stdio-1.0     main-is:            Bench.hs     build-depends:      algebraic-graphs,-                        base       >= 4.9,-                        containers >= 0.5,-                        criterion  >= 1.1+                        base        >= 4.7     && < 5,+                        base-compat >= 0.9.1   && < 0.10,+                        containers  >= 0.5.5.1 && < 0.8,+                        criterion   >= 1.1     default-language:   Haskell2010     GHC-options:        -O2                         -Wall-                        -Wcompat+                        -fno-warn-name-shadowing+    if impl(ghc >= 8.0)+        GHC-options:    -Wcompat                         -Wincomplete-record-updates                         -Wincomplete-uni-patterns                         -Wredundant-constraints
bench/Bench.hs view
@@ -1,6 +1,9 @@+import Prelude ()+import Prelude.Compat+ import Criterion.Main import Data.Char-import Data.Foldable+import Data.Foldable (toList)  import Algebra.Graph.Class import Algebra.Graph.AdjacencyMap (AdjacencyMap, adjacencyMap)
src/Algebra/Graph.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -23,7 +23,6 @@      -- * Basic graph construction primitives     empty, vertex, edge, overlay, connect, vertices, edges, overlays, connects,-    graph,      -- * Graph folding     foldg,@@ -36,7 +35,8 @@     edgeList, vertexSet, vertexIntSet, edgeSet,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, tree, forest, mesh, torus, deBruijn,+    path, circuit, clique, biclique, star, starTranspose, tree, forest, mesh,+    torus, deBruijn,      -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, splitVertex,@@ -46,9 +46,15 @@     box   ) where +import Prelude ()+import Prelude.Compat+ import Control.Applicative (Alternative, (<|>))-import Control.Monad+import Control.DeepSeq (NFData (..))+import Control.Monad.Compat +import Algebra.Graph.Internal+ import qualified Algebra.Graph.AdjacencyMap       as AM import qualified Algebra.Graph.Class              as C import qualified Algebra.Graph.HigherKinded.Class as H@@ -57,7 +63,7 @@ import qualified Data.Set                         as Set import qualified Data.Tree                        as Tree -{-| The 'Graph' datatype is a deep embedding of the core graph construction+{-| The 'Graph' data type is a deep embedding of the core graph construction primitives 'empty', 'vertex', 'overlay' and 'connect'. We define a 'Num' instance as a convenient notation for working with graphs: @@ -106,8 +112,8 @@ 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-'Graph' expression. For example, if g is a 'Graph' then /n/, /m/ and /s/ can be-computed as follows:+'Graph' expression. For example, if @g@ is a 'Graph' then /n/, /m/ and /s/ can+be computed as follows:  @n == 'vertexCount' g m == 'edgeCount' g@@ -138,6 +144,12 @@              | Connect (Graph a) (Graph a)              deriving (Foldable, Functor, Show, Traversable) +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+ instance C.Graph (Graph a) where     type Vertex (Graph a) = a     empty   = empty@@ -147,7 +159,12 @@  instance C.ToGraph (Graph a) where     type ToVertex (Graph a) = a-    toGraph = foldg C.empty C.vertex C.overlay C.connect+    foldg e v o c = go+      where+        go Empty         = e+        go (Vertex  x  ) = v x+        go (Overlay x y) = o (go x) (go y)+        go (Connect x y) = c (go x) (go y)  instance H.ToGraph Graph where     toGraph = foldg H.empty H.vertex H.overlay H.connect@@ -202,7 +219,6 @@ -- @ -- 'isEmpty'     (vertex x) == False -- 'hasVertex' x (vertex x) == True--- 'hasVertex' 1 (vertex 2) == False -- 'vertexCount' (vertex x) == 1 -- 'edgeCount'   (vertex x) == 0 -- 'size'        (vertex x) == 1@@ -223,8 +239,8 @@ edge :: a -> a -> Graph a edge = H.edge --- | /Overlay/ two graphs. An alias for the constructor 'Overlay'. This is an--- idempotent, commutative and associative operation with the identity 'empty'.+-- | /Overlay/ two graphs. An alias for the constructor 'Overlay'. This is a+-- commutative, associative and idempotent operation with the identity 'empty'. -- Complexity: /O(1)/ time and memory, /O(s1 + s2)/ size. -- -- @@@ -242,8 +258,8 @@ overlay = Overlay  -- | /Connect/ two graphs. An alias for the constructor 'Connect'. This is an--- associative operation with the identity 'empty', which distributes over the--- overlay and obeys the decomposition axiom.+-- associative operation with the identity 'empty', which distributes over+-- 'overlay' and obeys the decomposition axiom. -- 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)/.@@ -298,6 +314,7 @@ -- overlays []        == 'empty' -- overlays [x]       == x -- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty' -- 'isEmpty' . overlays == 'all' 'isEmpty' -- @ overlays :: [Graph a] -> Graph a@@ -311,25 +328,12 @@ -- connects []        == 'empty' -- connects [x]       == x -- connects [x,y]     == 'connect' x y+-- connects           == 'foldr' 'connect' 'empty' -- 'isEmpty' . connects == 'all' 'isEmpty' -- @ connects :: [Graph a] -> Graph a connects = H.connects --- | Construct the graph from given lists of vertices /V/ and edges /E/.--- The resulting graph contains the vertices /V/ as well as all the vertices--- referred to by the edges /E/.--- Complexity: /O(|V| + |E|)/ time, memory and size.------ @--- graph []  []      == 'empty'--- graph [x] []      == 'vertex' x--- graph []  [(x,y)] == 'edge' x y--- graph vs  es      == 'overlay' ('vertices' vs) ('edges' es)--- @-graph :: [a] -> [(a, a)] -> Graph a-graph = H.graph- -- | 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, overlay and connect.@@ -345,12 +349,7 @@ -- foldg True  (const False) (&&)    (&&)           == 'isEmpty' -- @ foldg :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> b-foldg e v o c = go-  where-    go Empty         = e-    go (Vertex x)    = v x-    go (Overlay x y) = o (go x) (go y)-    go (Connect x y) = c (go x) (go y)+foldg = C.foldg  -- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the -- first graph is a /subgraph/ of the second.@@ -379,7 +378,7 @@ -- @ (===) :: Eq a => Graph a -> Graph a -> Bool Empty           === Empty           = True-(Vertex x)      === (Vertex y)      = x == y+(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@@ -420,6 +419,7 @@ -- @ -- 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 a -> Bool@@ -566,7 +566,7 @@ clique :: [a] -> Graph a clique = H.clique --- | The /biclique/ on a list of vertices.+-- | The /biclique/ on two lists of vertices. -- Complexity: /O(L1 + L2)/ time, memory and size, where /L1/ and /L2/ are the -- lengths of the given lists. --@@ -580,7 +580,7 @@ biclique :: [a] -> [a] -> Graph a biclique = H.biclique --- | The /star/ formed by a centre vertex and a list of leaves.+-- | The /star/ formed by a centre vertex connected to a list of leaves. -- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the -- given list. --@@ -588,11 +588,26 @@ -- star x []    == 'vertex' x -- star x [y]   == 'edge' x y -- star x [y,z] == 'edges' [(x,y), (x,z)]+-- star x ys    == 'connect' ('vertex' x) ('vertices' ys) -- @ star :: a -> [a] -> Graph a star = H.star --- | The /tree graph/ constructed from a given 'Tree' data structure.+-- | 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 :: a -> [a] -> Graph a+starTranspose = H.starTranspose++-- | The /tree graph/ constructed from a given 'Tree.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). --@@ -605,7 +620,7 @@ tree :: Tree.Tree a -> Graph a tree = H.tree --- | The /forest graph/ constructed from a given 'Forest' data structure.+-- | The /forest graph/ constructed from a given 'Tree.Forest' data structure. -- Complexity: /O(F)/ time, memory and size, where /F/ is the size of the -- given forest (i.e. the number of vertices in the forest). --@@ -651,7 +666,7 @@ -- | 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--- alphabet and /D/ is the dimention of the graph.+-- alphabet and /D/ is the dimension of the graph. -- -- @ --           deBruijn 0 xs               == 'edge' [] []@@ -672,52 +687,36 @@ -- -- @ -- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' x x)       == 'empty'+-- removeVertex 1 ('edge' 1 2)       == 'vertex' 2 -- removeVertex x . removeVertex x == removeVertex x -- @ removeVertex :: Eq a => a -> Graph a -> Graph a removeVertex = H.removeVertex  -- | Remove an edge from a given graph.--- Complexity: /O(s)/ time and memory. The worst case size complexity is /O(s^2)/,--- although in practice it is usually also linear /O(s)/.+-- Complexity: /O(s)/ time, memory and size. -- -- @ -- removeEdge x y ('edge' x y)       == 'vertices' [x, y] -- removeEdge x y . removeEdge x y == removeEdge x y--- removeEdge x y . 'Algebra.Graph.HigherKinded.Util.removeVertex' x == 'Algebra.Graph.HigherKinded.Util.removeVertex' x+-- 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+-- 'size' (removeEdge x y z)         <= 3 * 'size' z -- @ removeEdge :: Eq a => a -> a -> Graph a -> Graph a-removeEdge s t g = piece st where (_, _, st) = smash s t g--data Piece a = Piece { piece :: Graph a, intact :: Bool }--breakIf :: Bool -> Piece a -> Piece a-breakIf True  _ = Piece Empty False-breakIf False x = x--instance C.Graph (Piece a) where-    type Vertex (Piece a) = a-    empty       = Piece Empty True-    vertex x    = Piece (Vertex x) True-    overlay x y = Piece (nonTrivial Overlay (piece x) (piece y)) (intact x && intact y)-    connect x y = Piece (nonTrivial Connect (piece x) (piece y)) (intact x && intact y)--nonTrivial :: (Graph a -> Graph a -> Graph a) -> Graph a -> Graph a -> Graph a-nonTrivial _ Empty x = x-nonTrivial _ x Empty = x-nonTrivial f x y     = f x y--type Pieces a = (Piece a, Piece a, Piece a)+removeEdge s t = filterContext s (/=s) (/=t) -smash :: Eq a => a -> a -> Graph a -> Pieces a-smash s t = foldg C.empty v C.overlay c+-- TODO: Export+-- | 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-    v x = (breakIf (x == s) $ C.vertex x, breakIf (x == t) $ C.vertex x, C.vertex x)-    c x@(sx, tx, stx) y@(sy, ty, sty)-        | intact sx || intact ty = C.connect x y-        | otherwise = (C.connect sx sy, C.connect tx ty, C.connect sx sty `C.overlay` C.connect stx ty)+    go (Context is os) = overlays [ induce (/=s) g+                                  , starTranspose s (filter i is)+                                  , star          s (filter o os) ]  -- | 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.@@ -731,7 +730,7 @@ replaceVertex :: Eq a => a -> a -> Graph a -> Graph a replaceVertex = H.replaceVertex --- | Merge vertices satisfying a given predicate with a given vertex.+-- | 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. --@@ -766,14 +765,11 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- transpose . 'path'      == 'path'    . 'reverse'--- transpose . 'circuit'   == 'circuit' . 'reverse'--- transpose . 'clique'    == 'clique'  . 'reverse' -- transpose ('box' x y)   == 'box' (transpose x) (transpose y) -- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: Graph a -> Graph a-transpose = foldg empty vertex overlay (flip connect)+transpose = foldg Empty Vertex Overlay (flip Connect)  -- | Construct the /induced subgraph/ of a given graph by removing the -- vertices that do not satisfy a given predicate.@@ -781,14 +777,18 @@ -- /O(1)/ to be evaluated. -- -- @--- induce (const True)  x      == x+-- 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 a -> Graph a-induce = H.induce+induce p = foldg Empty (\x -> if p x then Vertex x else Empty) (k Overlay) (k Connect)+  where+    k _ x     Empty = x -- Constant folding to get rid of Empty leaves+    k _ Empty y     = y+    k f x     y     = f x y  -- | Simplify a graph expression. Semantically, this is the identity function, -- but it simplifies a given expression according to the laws of the algebra.
src/Algebra/Graph/AdjacencyMap.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.AdjacencyMap--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -22,7 +22,7 @@      -- * Basic graph construction primitives     empty, vertex, edge, overlay, connect, vertices, edges, overlays, connects,-    graph, fromAdjacencyList,+    fromAdjacencyList,      -- * Relations on graphs     isSubgraphOf,@@ -32,7 +32,7 @@     adjacencyList, vertexSet, edgeSet, postSet,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, tree, forest,+    path, circuit, clique, biclique, star, starTranspose, tree, forest,      -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, transpose, gmap, induce,@@ -71,7 +71,6 @@ -- @ -- 'isEmpty'     (vertex x) == False -- 'hasVertex' x (vertex x) == True--- 'hasVertex' 1 (vertex 2) == False -- 'vertexCount' (vertex x) == 1 -- 'edgeCount'   (vertex x) == 0 -- @@@ -91,7 +90,7 @@ edge :: Ord a => a -> a -> AdjacencyMap a edge = C.edge --- | /Overlay/ two graphs. This is an idempotent, commutative and associative+-- | /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. --@@ -109,7 +108,7 @@ overlay = C.overlay  -- | /Connect/ two graphs. This is an associative operation with the identity--- 'empty', which distributes over the overlay and obeys the decomposition axiom.+-- '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)/.@@ -162,6 +161,7 @@ -- overlays []        == 'empty' -- overlays [x]       == x -- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty' -- 'isEmpty' . overlays == 'all' 'isEmpty' -- @ overlays :: Ord a => [AdjacencyMap a] -> AdjacencyMap a@@ -174,25 +174,12 @@ -- connects []        == 'empty' -- connects [x]       == x -- connects [x,y]     == 'connect' x y+-- connects           == 'foldr' 'connect' 'empty' -- 'isEmpty' . connects == 'all' 'isEmpty' -- @ connects :: Ord a => [AdjacencyMap a] -> AdjacencyMap a connects = C.connects --- | Construct the graph from given lists of vertices /V/ and edges /E/.--- The resulting graph contains the vertices /V/ as well as all the vertices--- referred to by the edges /E/.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.------ @--- graph []  []      == 'empty'--- graph [x] []      == 'vertex' x--- graph []  [(x,y)] == 'edge' x y--- graph vs  es      == 'overlay' ('vertices' vs) ('edges' es)--- @-graph :: Ord a => [a] -> [(a, a)] -> AdjacencyMap a-graph vs es = overlay (vertices vs) (edges es)- -- | Construct a graph from an adjacency list. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. --@@ -243,6 +230,7 @@ -- @ -- 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 a -> Bool@@ -348,7 +336,7 @@ edgeSet :: Ord a => AdjacencyMap a -> Set (a, a) edgeSet = Map.foldrWithKey (\v es -> Set.union (Set.mapMonotonic (v,) es)) Set.empty . adjacencyMap --- | The /postset/ of a vertex is the set of its /direct successors/.+-- | The /postset/ (here 'postSet') of a vertex is the set of its /direct successors/. -- -- @ -- postSet x 'empty'      == Set.'Set.empty'@@ -397,7 +385,7 @@ clique :: Ord a => [a] -> AdjacencyMap a clique = C.clique --- | The /biclique/ on a list of vertices.+-- | The /biclique/ on two lists of vertices. -- Complexity: /O(n * log(n) + m)/ time and /O(n + m)/ memory. -- -- @@@ -416,17 +404,32 @@         | v `Set.member` x = y         | otherwise        = Set.empty --- | The /star/ formed by a centre vertex and a list of leaves.+-- | 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] == 'edges' [(x,y), (x,z)]+-- star x ys    == 'connect' ('vertex' x) ('vertices' ys) -- @ star :: Ord a => a -> [a] -> AdjacencyMap a star = C.star +-- | 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 :: Ord a => a -> [a] -> AdjacencyMap a+starTranspose = C.starTranspose+ -- | The /tree graph/ constructed from a given 'Tree' data structure. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. --@@ -456,6 +459,9 @@ -- -- @ -- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' x x)       == 'empty'+-- removeVertex 1 ('edge' 1 2)       == 'vertex' 2 -- removeVertex x . removeVertex x == removeVertex x -- @ removeVertex :: Ord a => a -> AdjacencyMap a -> AdjacencyMap a@@ -486,7 +492,7 @@ replaceVertex :: Ord a => a -> a -> AdjacencyMap a -> AdjacencyMap a replaceVertex u v = gmap $ \w -> if w == u then v else w --- | Merge vertices satisfying a given predicate with a given vertex.+-- | 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. --@@ -507,9 +513,6 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- transpose . 'path'      == 'path'    . 'reverse'--- transpose . 'circuit'   == 'circuit' . 'reverse'--- transpose . 'clique'    == 'clique'  . 'reverse' -- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: Ord a => AdjacencyMap a -> AdjacencyMap a@@ -539,7 +542,7 @@ -- be evaluated. -- -- @--- induce (const True)  x      == x+-- induce (const True ) x      == x -- induce (const False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x)
src/Algebra/Graph/AdjacencyMap/Internal.hs view
@@ -1,14 +1,14 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.AdjacencyMap.Internal--- Copyright  : (c) Andrey Mokhov 2016-2017+-- 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 adjacency maps. The API is unstable--- and unsafe. Where possible use non-internal module "Algebra.Graph.AdjacencyMap"--- instead.+-- and unsafe, and is exposed only for documentation. You should use the+-- non-internal module "Algebra.Graph.AdjacencyMap" instead. ----------------------------------------------------------------------------- module Algebra.Graph.AdjacencyMap.Internal (     -- * Adjacency map implementation@@ -18,6 +18,7 @@     GraphKL (..), mkGraphKL   ) where +import Data.List import Data.Map.Strict (Map, keysSet, fromSet) import Data.Set (Set) @@ -44,7 +45,7 @@ show (1 + 2     :: AdjacencyMap Int) == "vertices [1,2]" show (1 * 2     :: AdjacencyMap Int) == "edge 1 2" show (1 * 2 * 3 :: AdjacencyMap Int) == "edges [(1,2),(1,3),(2,3)]"-show (1 * 2 + 3 :: AdjacencyMap Int) == "graph [1,2,3] [(1,2)]"@+show (1 * 2 + 3 :: AdjacencyMap Int) == "overlay (vertex 3) (edge 1 2)"@  The 'Eq' instance satisfies all axioms of algebraic graphs: @@ -106,22 +107,22 @@  instance (Ord a, Show a) => Show (AdjacencyMap a) where     show (AM m _)-        | m == Map.empty = "empty"-        | es == []       = if Set.size vs > 1 then "vertices " ++ show (Set.toAscList vs)-                                              else "vertex "   ++ show v-        | vs == referred = if length es > 1 then "edges " ++ show es-                                            else "edge "  ++ show e ++ " " ++ show f-        | otherwise      = "graph " ++ show (Set.toAscList vs) ++ " " ++ show es+        | null vs    = "empty"+        | null es    = vshow vs+        | vs == used = eshow es+        | otherwise  = "overlay (" ++ vshow (vs \\ used) ++ ") (" ++ eshow es ++ ")"       where-        vs       = keysSet m-        es       = internalEdgeList m-        v        = head $ Set.toList vs-        (e, f)   = head es-        referred = referredToVertexSet m+        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+        used           = Set.toAscList (referredToVertexSet m)  instance Ord a => Graph (AdjacencyMap a) where     type Vertex (AdjacencyMap a) = a-    empty       = mkAM $ Map.empty+    empty       = mkAM   Map.empty     vertex x    = mkAM $ Map.singleton x Set.empty     overlay x y = mkAM $ Map.unionWith Set.union (adjacencyMap x) (adjacencyMap y)     connect x y = mkAM $ Map.unionsWith Set.union [ adjacencyMap x, adjacencyMap y,
src/Algebra/Graph/Class.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Class--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -38,18 +38,21 @@     Preorder,      -- * Basic graph construction primitives-    edge, vertices, overlays, connects, edges, graph,+    edge, vertices, overlays, connects, edges,      -- * Relations on graphs     isSubgraphOf,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, tree, forest,+    path, circuit, clique, biclique, star, starTranspose, tree, forest,      -- * Conversion between graph data types     ToGraph (..)   ) where +import Prelude ()+import Prelude.Compat+ import Data.Tree  {-|@@ -252,9 +255,12 @@ -- overlays []    == 'empty' -- overlays [x]   == x -- overlays [x,y] == 'overlay' x y+-- overlays       == 'foldr' 'overlay' 'empty' -- @ overlays :: Graph g => [g] -> g-overlays = foldr overlay empty+overlays []     = empty+overlays [x]    = x+overlays (x:xs) = x `overlay` overlays xs  -- | Connect a given list of graphs. -- Complexity: /O(L)/ time and memory, and /O(S)/ size, where /L/ is the length@@ -264,23 +270,12 @@ -- connects []    == 'empty' -- connects [x]   == x -- connects [x,y] == 'connect' x y+-- connects       == 'foldr' 'connect' 'empty' -- @ connects :: Graph g => [g] -> g-connects = foldr connect empty---- | Construct the graph from given lists of vertices /V/ and edges /E/.--- The resulting graph contains the vertices /V/ as well as all the vertices--- referred to by the edges /E/.--- Complexity: /O(|V| + |E|)/ time, memory and size.------ @--- graph []  []      == 'empty'--- graph [x] []      == 'vertex' x--- graph []  [(x,y)] == 'edge' x y--- graph vs  es      == 'overlay' ('vertices' vs) ('edges' es)--- @-graph :: Graph g => [Vertex g] -> [(Vertex g, Vertex g)] -> g-graph vs es = overlay (vertices vs) (edges es)+connects []     = empty+connects [x]    = x+connects (x:xs) = x `connect` connects xs  -- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the -- first graph is a /subgraph/ of the second. Here is the current implementation:@@ -311,9 +306,9 @@ -- path [x,y] == 'edge' x y -- @ path :: Graph g => [Vertex g] -> g-path []  = empty-path [x] = vertex x-path xs  = edges $ zip xs (tail xs)+path xs = case xs of []     -> empty+                     [x]    -> vertex x+                     (_:ys) -> edges (zip xs ys)  -- | The /circuit/ on a list of vertices. -- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the@@ -342,7 +337,7 @@ clique :: Graph g => [Vertex g] -> g clique = connects . map vertex --- | The /biclique/ on a list of vertices.+-- | The /biclique/ on two lists of vertices. -- Complexity: /O(L1 + L2)/ time, memory and size, where /L1/ and /L2/ are the -- lengths of the given lists. --@@ -354,9 +349,11 @@ -- biclique xs      ys      == 'connect' ('vertices' xs) ('vertices' ys) -- @ biclique :: Graph g => [Vertex g] -> [Vertex g] -> g+biclique xs [] = vertices xs+biclique [] ys = vertices ys biclique xs ys = connect (vertices xs) (vertices ys) --- | The /star/ formed by a centre vertex and a list of leaves.+-- | The /star/ formed by a centre vertex connected to a list of leaves. -- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the -- given list. --@@ -364,10 +361,27 @@ -- star x []    == 'vertex' x -- star x [y]   == 'edge' x y -- star x [y,z] == 'edges' [(x,y), (x,z)]+-- star x ys    == 'connect' ('vertex' x) ('vertices' ys) -- @ star :: Graph g => Vertex g -> [Vertex g] -> g+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).@@ -379,7 +393,9 @@ -- tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == 'edges' [(1,2), (1,3), (3,4), (3,5)] -- @ tree :: Graph g => Tree (Vertex g) -> g-tree (Node x f) = overlay (star x $ map rootLabel f) (forest f)+tree (Node x []) = vertex x+tree (Node x f ) = star x (map rootLabel f)+         `overlay` forest (filter (not . null . subForest) f)  -- | The /forest graph/ constructed from a given 'Forest' data structure. -- Complexity: /O(F)/ time, memory and size, where /F/ is the size of the@@ -403,6 +419,35 @@ --       toGraph (g     :: 'Algebra.Graph.Graph' a  ) :: 'Algebra.Graph.Graph' a       == g -- 'show' (toGraph (1 * 2 :: 'Algebra.Graph.Graph' Int) :: 'Algebra.Graph.Relation' Int) == "edge 1 2" -- @+--+-- The second method 'foldg' is used for generalised graph folding. It recursively+-- collapses a given data type by applying the provided graph construction+-- primitives. The order of arguments is: empty, vertex, overlay and connect,+-- and it is assumed that the functions satisfy the axioms of the algebra.+-- The following law establishes the relation between 'toGraph' and 'foldg':+--+-- @+-- toGraph == foldg 'empty' 'vertex' 'overlay' 'connect'+-- @ class ToGraph t where     type ToVertex t     toGraph :: (Graph g, Vertex g ~ ToVertex t) => t -> g+    toGraph = foldg empty vertex overlay connect+    foldg :: r -> (ToVertex t -> r) -> (r -> r -> r) -> (r -> r -> r) -> t -> r+    foldg e v o c = go . toGraph+      where+        go E       = e+        go (V x  ) = v x+        go (O x y) = o (go x) (go y)+        go (C x y) = c (go x) (go y)++-- TODO: Get rid of code duplication. Note: we do not use the data type Graph+-- here due to import cycle.+data G a = E | V a | O (G a) (G a) | C (G a) (G a)++instance Graph (G a) where+    type Vertex (G a) = a+    empty   = E+    vertex  = V+    overlay = O+    connect = C
src/Algebra/Graph/Export.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Export--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -11,9 +11,8 @@ -- 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 basic data types and functions for exporting graphs in--- textual and binary formats. "Algebra.Graph.Export.Dot" provides DOT-specific--- functionality.+-- This module defines basic functionality for exporting graphs in textual and+-- binary formats. "Algebra.Graph.Export.Dot" provides DOT-specific functions. ----------------------------------------------------------------------------- module Algebra.Graph.Export (     -- * Constructing and exporting documents@@ -26,19 +25,27 @@     export   ) where +import Prelude ()+import Prelude.Compat hiding (unlines)++import Data.Foldable (fold) import Data.Semigroup import Data.String hiding (unlines)-import Prelude hiding (unlines)  import Algebra.Graph.AdjacencyMap import Algebra.Graph.Class (ToGraph (..))+import Algebra.Graph.Internal --- | An abstract document type, where @s@ is the type of strings or words (text--- or binary). 'Doc' @s@ is a 'Monoid', therefore 'mempty' corresponds to the--- empty document and two documents can be concatenated with 'mappend' (or--- operator 'Data.Monoid.<>'). Note that most functions on 'Doc' @s@ require--- that the underlying type @s@ is also a 'Monoid'.-newtype Doc s = Doc (Endo [s]) deriving (Monoid, Semigroup)+-- | 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+-- 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.+newtype Doc s = Doc (List s) deriving (Monoid, Semigroup)  instance (Monoid s, Show s) => Show (Doc s) where     show = show . render@@ -52,32 +59,31 @@ instance IsString s => IsString (Doc s) where     fromString = literal . fromString --- | Construct a document comprising a single string or word. If @s@ is an+-- | 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). -- -- @--- literal "Hello, " <> literal "World!" == literal "Hello, World!"+-- 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 . Endo . (:)+literal = Doc . pure --- | Render a document as a single string or word. An inverse of the function--- 'literal'.+-- | Render the document as a single string. An inverse of the function 'literal'. -- -- @--- render ('literal' "al" <> 'literal' "ga") :: ('IsString' s, 'Monoid' s) => s--- render ('literal' "al" <> 'literal' "ga") == "alga"+-- render ('literal' "al" 'Data.Monoid.<>' 'literal' "ga") :: ('IsString' s, 'Monoid' s) => s+-- 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) = mconcat $ appEndo x []+render (Doc x) = fold x  -- | Concatenate two documents, separated by a single space, unless one of the -- documents is empty. The operator \<+\> is associative with identity 'mempty'.@@ -155,6 +161,6 @@ export :: (Ord a, ToGraph g, ToVertex g ~ a) => (a -> Doc s) -> (a -> a -> Doc s) -> g -> Doc s export vs es g = vDoc <> eDoc   where-    vDoc   = mconcat $ map (vs        ) (vertexList adjMap)+    vDoc   = mconcat $ map  vs          (vertexList adjMap)     eDoc   = mconcat $ map (uncurry es) (edgeList   adjMap)     adjMap = toGraph g
src/Algebra/Graph/Export/Dot.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Export.Dot--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -113,7 +113,7 @@ export Style {..} g = render $ header <> body <> "}\n"   where     header    = "digraph" <+> literal graphName <> "\n{\n"-             <> if preamble == mempty then mempty else (literal preamble <> "\n")+             <> if preamble == mempty then mempty else literal preamble <> "\n"     with x as = if null as            then mempty else line (x <+> attributes as)     line s    = indent 2 s <> "\n"     body      = ("graph" `with` graphAttributes)
src/Algebra/Graph/Fold.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Fold--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -24,7 +24,6 @@      -- * Basic graph construction primitives     empty, vertex, edge, overlay, connect, vertices, edges, overlays, connects,-    C.graph,      -- * Graph folding     foldg,@@ -37,8 +36,8 @@     edgeList, vertexSet, vertexIntSet, edgeSet,      -- * Standard families of graphs-    C.path, C.circuit, C.clique, C.biclique, C.star, C.tree, C.forest,-    mesh, torus, deBruijn,+    C.path, C.circuit, C.clique, C.biclique, C.star, C.starTranspose, C.tree,+    C.forest, mesh, torus, deBruijn,      -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, splitVertex,@@ -48,10 +47,15 @@     box   ) where +import Prelude ()+import Prelude.Compat+ import Control.Applicative hiding (empty)-import Control.Monad+import Control.Monad.Compat (MonadPlus (..), ap) import Data.Foldable +import Algebra.Graph.Internal+ import qualified Algebra.Graph.AdjacencyMap       as AM import qualified Algebra.Graph.Class              as C import qualified Algebra.Graph.HigherKinded.Class as H@@ -59,7 +63,7 @@ import qualified Data.IntSet                      as IntSet import qualified Data.Set                         as Set -{-| The 'Fold' datatype is the Boehm-Berarducci encoding of the core graph+{-| The 'Fold' data type is the Boehm-Berarducci encoding of the core graph construction primitives 'empty', 'vertex', 'overlay' and 'connect'. We define a 'Num' instance as a convenient notation for working with graphs: @@ -76,7 +80,7 @@ show (1 + 2     :: Fold Int) == "vertices [1,2]" show (1 * 2     :: Fold Int) == "edge 1 2" show (1 * 2 * 3 :: Fold Int) == "edges [(1,2),(1,3),(2,3)]"-show (1 * 2 + 3 :: Fold Int) == "graph [1,2,3] [(1,2)]"@+show (1 * 2 + 3 :: Fold Int) == "overlay (vertex 3) (edge 1 2)"@  The 'Eq' instance is currently implemented using the 'AM.AdjacencyMap' as the /canonical graph representation/ and satisfies all axioms of algebraic graphs:@@ -196,7 +200,7 @@  instance C.ToGraph (Fold a) where     type ToVertex (Fold a) = a-    toGraph = foldg C.empty C.vertex C.overlay C.connect+    foldg e v o c g = runFold g e v o c  instance H.ToGraph Fold where     toGraph = foldg H.empty H.vertex H.overlay H.connect@@ -220,7 +224,6 @@ -- @ -- 'isEmpty'     (vertex x) == False -- 'hasVertex' x (vertex x) == True--- 'hasVertex' 1 (vertex 2) == False -- 'vertexCount' (vertex x) == 1 -- 'edgeCount'   (vertex x) == 0 -- 'size'        (vertex x) == 1@@ -241,7 +244,7 @@ edge :: C.Graph g => C.Vertex g -> C.Vertex g -> g edge = C.edge --- | /Overlay/ two graphs. This is an idempotent, commutative and associative+-- | /Overlay/ two graphs. This is a commutative, associative and idempotent -- operation with the identity 'empty'. -- Complexity: /O(1)/ time and memory, /O(s1 + s2)/ size. --@@ -260,7 +263,7 @@ overlay = C.overlay  -- | /Connect/ two graphs. This is an associative operation with the identity--- 'empty', which distributes over the overlay and obeys the decomposition axiom.+-- 'empty', which distributes over 'overlay' and obeys the decomposition axiom. -- 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)/.@@ -315,6 +318,7 @@ -- overlays []        == 'empty' -- overlays [x]       == x -- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty' -- 'isEmpty' . overlays == 'all' 'isEmpty' -- @ overlays :: C.Graph g => [g] -> g@@ -328,6 +332,7 @@ -- connects []        == 'empty' -- connects [x]       == x -- connects [x,y]     == 'connect' x y+-- connects           == 'foldr' 'connect' 'empty' -- 'isEmpty' . connects == 'all' 'isEmpty' -- @ connects :: C.Graph g => [g] -> g@@ -348,7 +353,7 @@ -- foldg True  (const False) (&&)    (&&)           == 'isEmpty' -- @ 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+foldg = C.foldg  -- | Check if a graph is empty. A convenient alias for 'null'. -- Complexity: /O(s)/ time.@@ -384,6 +389,7 @@ -- @ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True+-- hasVertex 1 ('vertex' 2)       == False -- hasVertex x . 'removeVertex' x == const False -- @ hasVertex :: Eq a => a -> Fold a -> Bool@@ -402,35 +408,6 @@ hasEdge :: Ord a => a -> a -> Fold a -> Bool hasEdge = H.hasEdge -data Piece g = Piece { piece :: g, intact :: Bool, trivial :: Bool }--breakIf :: C.Graph g => Bool -> Piece g -> Piece g-breakIf True  _ = Piece C.empty False True-breakIf False x = x--instance C.Graph g => C.Graph (Piece g) where-    type Vertex (Piece g) = C.Vertex g-    empty       = Piece C.empty True True-    vertex x    = Piece (C.vertex x) True False-    overlay x y = Piece (nonTrivial C.overlay x y) (intact x && intact y) False-    connect x y = Piece (nonTrivial C.connect x y) (intact x && intact y) False--nonTrivial :: (g -> g -> g) -> Piece g -> Piece g -> g-nonTrivial f x y-    | trivial x = piece y-    | trivial y = piece x-    | otherwise = f (piece x) (piece y)--type Pieces a = (Piece a, Piece a, Piece a)--smash :: (Eq (C.Vertex g), C.Graph g) => C.Vertex g -> C.Vertex g -> Fold (C.Vertex g) -> Pieces g-smash s t = foldg C.empty v C.overlay c-  where-    v x = (breakIf (x == s) $ C.vertex x, breakIf (x == t) $ C.vertex x, C.vertex x)-    c x@(sx, tx, stx) y@(sy, ty, sty)-        | intact sx || intact ty = C.connect x y-        | otherwise = (C.connect sx sy, C.connect tx ty, C.connect sx sty `C.overlay` C.connect stx ty)- -- | The number of vertices in a graph. -- Complexity: /O(s * log(n))/ time. --@@ -551,7 +528,7 @@ -- | 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--- alphabet and /D/ is the dimention of the graph.+-- alphabet and /D/ is the dimension of the graph. -- -- @ --           deBruijn 0 xs               == 'edge' [] []@@ -577,14 +554,16 @@ -- -- @ -- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' x x)       == 'empty'+-- removeVertex 1 ('edge' 1 2)       == 'vertex' 2 -- removeVertex x . removeVertex x == removeVertex x -- @ removeVertex :: (Eq (C.Vertex g), C.Graph g) => C.Vertex g -> Fold (C.Vertex g) -> g removeVertex v = induce (/= v)  -- | Remove an edge from a given graph.--- Complexity: /O(s)/ time and memory. The worst case size complexity is /O(s^2)/,--- although in practice it is usually also linear /O(s)/.+-- Complexity: /O(s)/ time, memory and size. -- -- @ -- removeEdge x y ('edge' x y)       == 'vertices' [x, y]@@ -592,10 +571,21 @@ -- 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+-- 'size' (removeEdge x y z)         <= 3 * 'size' z -- @ removeEdge :: (Eq (C.Vertex g), C.Graph g) => C.Vertex g -> C.Vertex g -> Fold (C.Vertex g) -> g-removeEdge s t g = piece st where (_, _, st) = smash s t g+removeEdge s t = filterContext s (/=s) (/=t) +-- TODO: Export+-- | Filter vertices in a subgraph context.+filterContext :: (Eq (C.Vertex g), C.Graph g) => C.Vertex g -> (C.Vertex g -> Bool)+              -> (C.Vertex g -> Bool) -> Fold (C.Vertex g) -> g+filterContext s i o g = maybe (C.toGraph g) go $ context (==s) g+  where+    go (Context is os) = overlays [ induce (/=s) g+                                  , C.starTranspose s (filter i is)+                                  , C.star          s (filter o os) ]+ -- | The function @'replaceVertex' x y@ replaces vertex @x@ with vertex @y@ in a -- given graph expression. If @y@ already exists, @x@ and @y@ will be merged. -- Complexity: /O(s)/ time, memory and size.@@ -608,7 +598,7 @@ replaceVertex :: (Eq (C.Vertex g), C.Graph g) => C.Vertex g -> C.Vertex g -> Fold (C.Vertex g) -> g replaceVertex u v = gmap $ \w -> if w == u then v else w --- | Merge vertices satisfying a given predicate with a given vertex.+-- | 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. --@@ -643,9 +633,6 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- transpose . 'C.path'      == 'C.path'    . 'reverse'--- transpose . 'C.circuit'   == 'C.circuit' . 'reverse'--- transpose . 'C.clique'    == 'C.clique'  . 'reverse' -- transpose ('box' x y)   == 'box' (transpose x) (transpose y) -- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList' -- @@@ -687,14 +674,18 @@ -- /O(1)/ to be evaluated. -- -- @--- induce (const True)  x      == x+-- 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 :: C.Graph g => (C.Vertex g -> Bool) -> Fold (C.Vertex g) -> g-induce p g = bind g $ \v -> if p v then C.vertex v else C.empty+induce p = C.toGraph . foldg empty (\x -> if p x then vertex x else empty) (k overlay) (k connect)+  where+    k f x y | isEmpty x = y -- Constant folding to get rid of Empty leaves+            | isEmpty y = x+            | otherwise = f x y  -- | Simplify a graph expression. Semantically, this is the identity function, -- but it simplifies a given polymorphic graph expression according to the laws
src/Algebra/Graph/HigherKinded/Class.hs view
@@ -1,7 +1,8 @@+{-# LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.HigherKinded.Class--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -36,7 +37,7 @@     Preorder,      -- * Basic graph construction primitives-    edge, vertices, edges, overlays, connects, graph,+    edge, vertices, edges, overlays, connects,      -- * Relations on graphs     isSubgraphOf,@@ -45,7 +46,8 @@     isEmpty, hasVertex, hasEdge, vertexCount, vertexList, vertexSet, vertexIntSet,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, tree, forest, mesh, torus, deBruijn,+    path, circuit, clique, biclique, star, starTranspose, tree, forest, mesh,+    torus, deBruijn,      -- * Graph transformation     removeVertex, replaceVertex, mergeVertices, splitVertex, induce,@@ -58,9 +60,12 @@    ) where -import Control.Applicative (empty, (<|>))-import Control.Monad-import Data.Foldable+import Prelude ()+import Prelude.Compat++import Control.Applicative (Alternative(empty, (<|>)))+import Control.Monad.Compat (MonadPlus, msum, mfilter)+import Data.Foldable (toList) import Data.Tree  import qualified Data.IntSet as IntSet@@ -125,7 +130,11 @@ edges in the graph, and /s/ will denote the /size/ of the corresponding 'Graph' expression. -}-class (Traversable g, MonadPlus g) => Graph g where+class (Traversable g,+#if !MIN_VERSION_base(4,8,0)+  Alternative g,+#endif+  MonadPlus g) => Graph g where     -- | Connect two graphs.     connect :: g a -> g a -> g a @@ -224,10 +233,13 @@ -- overlays []        == 'empty' -- overlays [x]       == x -- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty' -- 'isEmpty' . overlays == 'all' 'isEmpty' -- @ overlays :: Graph g => [g a] -> g a-overlays = msum+overlays []     = empty+overlays [x]    = x+overlays (x:xs) = x `overlay` overlays xs  -- | Connect a given list of graphs. -- Complexity: /O(L)/ time and memory, and /O(S)/ size, where /L/ is the length@@ -237,24 +249,13 @@ -- connects []        == 'empty' -- connects [x]       == x -- connects [x,y]     == 'connect' x y+-- connects           == 'foldr' 'connect' 'empty' -- 'isEmpty' . connects == 'all' 'isEmpty' -- @ connects :: Graph g => [g a] -> g a-connects = foldr connect empty---- | Construct the graph from given lists of vertices /V/ and edges /E/.--- The resulting graph contains the vertices /V/ as well as all the vertices--- referred to by the edges /E/.--- Complexity: /O(|V| + |E|)/ time, memory and size.------ @--- graph []  []      == 'empty'--- graph [x] []      == 'vertex' x--- graph []  [(x,y)] == 'edge' x y--- graph vs  es      == 'overlay' ('vertices' vs) ('edges' es)--- @-graph :: Graph g => [a] -> [(a, a)] -> g a-graph vs es = overlay (vertices vs) (edges es)+connects []     = empty+connects [x]    = x+connects (x:xs) = x `connect` connects xs  -- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the -- first graph is a /subgraph/ of the second. Here is the current implementation:@@ -293,6 +294,7 @@ -- @ -- 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@@ -367,9 +369,9 @@ -- path [x,y] == 'edge' x y -- @ path :: Graph g => [a] -> g a-path []  = empty-path [x] = vertex x-path xs  = edges $ zip xs (tail xs)+path xs = case xs of []     -> empty+                     [x]    -> vertex x+                     (_:ys) -> edges (zip xs ys)  -- | The /circuit/ on a list of vertices. -- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the@@ -398,7 +400,7 @@ clique :: Graph g => [a] -> g a clique = connects . map vertex --- | The /biclique/ on a list of vertices.+-- | The /biclique/ on two lists of vertices. -- Complexity: /O(L1 + L2)/ time, memory and size, where /L1/ and /L2/ are the -- lengths of the given lists. --@@ -410,9 +412,11 @@ -- biclique xs      ys      == 'connect' ('vertices' xs) ('vertices' ys) -- @ biclique :: Graph g => [a] -> [a] -> g a+biclique xs [] = vertices xs+biclique [] ys = vertices ys biclique xs ys = connect (vertices xs) (vertices ys) --- | The /star/ formed by a centre vertex and a list of leaves.+-- | The /star/ formed by a centre vertex connected to a list of leaves. -- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the -- given list. --@@ -420,10 +424,27 @@ -- star x []    == 'vertex' x -- star x [y]   == 'edge' x y -- star x [y,z] == 'edges' [(x,y), (x,z)]+-- star x ys    == 'connect' ('vertex' x) ('vertices' ys) -- @ star :: Graph g => a -> [a] -> g a+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 => a -> [a] -> g a+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).@@ -435,7 +456,9 @@ -- tree (Node 1 [Node 2 [], Node 3 [Node 4 [], Node 5 []]]) == 'edges' [(1,2), (1,3), (3,4), (3,5)] -- @ tree :: Graph g => Tree a -> g a-tree (Node x f) = overlay (star x $ map rootLabel f) (forest f)+tree (Node x []) = vertex x+tree (Node x f ) = star x (map rootLabel f)+         `overlay` forest (filter (not . null . subForest) f)  -- | The /forest graph/ constructed from a given 'Forest' data structure. -- Complexity: /O(F)/ time, memory and size, where /F/ is the size of the@@ -483,7 +506,7 @@ -- | 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--- alphabet and /D/ is the dimention of the graph.+-- alphabet and /D/ is the dimension of the graph. -- -- @ --           deBruijn 0 xs               == 'edge' [] []@@ -492,7 +515,7 @@ --           deBruijn 2 "0"              == 'edge' "00" "00" --           deBruijn 2 "01"             == 'edges' [ ("00","00"), ("00","01"), ("01","10"), ("01","11") --                                                , ("10","00"), ("10","01"), ("11","10"), ("11","11") ]---           'transpose'   (deBruijn n xs) == 'fmap' 'reverse' $ deBruijn n xs+--           transpose   (deBruijn n xs) == 'fmap' 'reverse' $ deBruijn n xs --           'vertexCount' (deBruijn n xs) == ('length' $ 'Data.List.nub' xs)^n -- n > 0 ==> 'edgeCount'   (deBruijn n xs) == ('length' $ 'Data.List.nub' xs)^(n + 1) -- @@@ -510,7 +533,7 @@ -- /O(1)/ to be evaluated. -- -- @--- induce (const True)  x      == x+-- induce (const True ) x      == x -- induce (const False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x)@@ -524,6 +547,9 @@ -- -- @ -- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' x x)       == 'empty'+-- removeVertex 1 ('edge' 1 2)       == 'vertex' 2 -- removeVertex x . removeVertex x == removeVertex x -- @ removeVertex :: (Eq a, Graph g) => a -> g a -> g a@@ -541,7 +567,7 @@ replaceVertex :: (Eq a, Graph g) => a -> a -> g a -> g a replaceVertex u v = fmap $ \w -> if w == u then v else w --- | Merge vertices satisfying a given predicate with a given vertex.+-- | 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. --@@ -609,4 +635,3 @@ -- @ class ToGraph t where     toGraph :: Graph g => t a -> g a-
src/Algebra/Graph/IntAdjacencyMap.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.IntAdjacencyMap--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -22,7 +22,7 @@      -- * Basic graph construction primitives     empty, vertex, edge, overlay, connect, vertices, edges, overlays, connects,-    graph, fromAdjacencyList,+    fromAdjacencyList,      -- * Relations on graphs     isSubgraphOf,@@ -32,7 +32,7 @@     adjacencyList, vertexIntSet, edgeSet, postIntSet,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, tree, forest,+    path, circuit, clique, biclique, star, starTranspose, tree, forest,      -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, transpose, gmap, induce,@@ -72,7 +72,6 @@ -- @ -- 'isEmpty'     (vertex x) == False -- 'hasVertex' x (vertex x) == True--- 'hasVertex' 1 (vertex 2) == False -- 'vertexCount' (vertex x) == 1 -- 'edgeCount'   (vertex x) == 0 -- @@@ -92,7 +91,7 @@ edge :: Int -> Int -> IntAdjacencyMap edge = C.edge --- | /Overlay/ two graphs. This is an idempotent, commutative and associative+-- | /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. --@@ -110,7 +109,7 @@ overlay = C.overlay  -- | /Connect/ two graphs. This is an associative operation with the identity--- 'empty', which distributes over the overlay and obeys the decomposition axiom.+-- '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)/.@@ -163,6 +162,7 @@ -- overlays []        == 'empty' -- overlays [x]       == x -- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty' -- 'isEmpty' . overlays == 'all' 'isEmpty' -- @ overlays :: [IntAdjacencyMap] -> IntAdjacencyMap@@ -175,25 +175,12 @@ -- connects []        == 'empty' -- connects [x]       == x -- connects [x,y]     == 'connect' x y+-- connects           == 'foldr' 'connect' 'empty' -- 'isEmpty' . connects == 'all' 'isEmpty' -- @ connects :: [IntAdjacencyMap] -> IntAdjacencyMap connects = C.connects --- | Construct the graph from given lists of vertices /V/ and edges /E/.--- The resulting graph contains the vertices /V/ as well as all the vertices--- referred to by the edges /E/.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.------ @--- graph []  []      == 'empty'--- graph [x] []      == 'vertex' x--- graph []  [(x,y)] == 'edge' x y--- graph vs  es      == 'overlay' ('vertices' vs) ('edges' es)--- @-graph :: [Int] -> [(Int, Int)] -> IntAdjacencyMap-graph vs es = overlay (vertices vs) (edges es)- -- | Construct a graph from an adjacency list. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. --@@ -244,6 +231,7 @@ -- @ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True+-- hasVertex 1 ('vertex' 2)       == False -- hasVertex x . 'removeVertex' x == const False -- @ hasVertex :: Int -> IntAdjacencyMap -> Bool@@ -351,7 +339,7 @@   where     combine u es = Set.union (Set.fromAscList [ (u, v) | v <- IntSet.toAscList es ]) --- | The /postset/ of a vertex is the set of its /direct successors/.+-- | The /postset/ (here 'postIntSet') of a vertex is the set of its /direct successors/. -- -- @ -- postIntSet x 'empty'      == IntSet.'IntSet.empty'@@ -400,7 +388,7 @@ clique :: [Int] -> IntAdjacencyMap clique = C.clique --- | The /biclique/ on a list of vertices.+-- | The /biclique/ on two lists of vertices. -- Complexity: /O(n * log(n) + m)/ time and /O(n + m)/ memory. -- -- @@@ -419,17 +407,32 @@         | v `IntSet.member` x = y         | otherwise        = IntSet.empty --- | The /star/ formed by a centre vertex and a list of leaves.+-- | 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] == 'edges' [(x,y), (x,z)]+-- star x ys    == 'connect' ('vertex' x) ('vertices' ys) -- @ star :: Int -> [Int] -> IntAdjacencyMap star = C.star +-- | 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 :: Int -> [Int] -> IntAdjacencyMap+starTranspose = C.starTranspose+ -- | The /tree graph/ constructed from a given 'Tree' data structure. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. --@@ -459,6 +462,9 @@ -- -- @ -- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' x x)       == 'empty'+-- removeVertex 1 ('edge' 1 2)       == 'vertex' 2 -- removeVertex x . removeVertex x == removeVertex x -- @ removeVertex :: Int -> IntAdjacencyMap -> IntAdjacencyMap@@ -489,7 +495,7 @@ replaceVertex :: Int -> Int -> IntAdjacencyMap -> IntAdjacencyMap replaceVertex u v = gmap $ \w -> if w == u then v else w --- | Merge vertices satisfying a given predicate with a given vertex.+-- | 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. --@@ -510,9 +516,6 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- transpose . 'path'      == 'path'    . 'reverse'--- transpose . 'circuit'   == 'circuit' . 'reverse'--- transpose . 'clique'    == 'clique'  . 'reverse' -- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: IntAdjacencyMap -> IntAdjacencyMap@@ -542,7 +545,7 @@ -- be evaluated. -- -- @--- induce (const True)  x      == x+-- induce (const True ) x      == x -- induce (const False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x)
src/Algebra/Graph/IntAdjacencyMap/Internal.hs view
@@ -1,14 +1,14 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.IntAdjacencyMap.Internal--- Copyright  : (c) Andrey Mokhov 2016-2017+-- 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 adjacency maps. The API is unstable--- and unsafe. Where possible use non-internal module--- "Algebra.Graph.IntAdjacencyMap" instead.+-- and unsafe, and is exposed only for documentation. You should use the+-- non-internal module "Algebra.Graph.IntAdjacencyMap" instead. ----------------------------------------------------------------------------- module Algebra.Graph.IntAdjacencyMap.Internal (     -- * Adjacency map implementation@@ -20,6 +20,7 @@  import Data.IntMap.Strict (IntMap, keysSet, fromSet) import Data.IntSet (IntSet)+import Data.List  import Algebra.Graph.Class @@ -44,7 +45,7 @@ show (1 + 2     :: IntAdjacencyMap Int) == "vertices [1,2]" show (1 * 2     :: IntAdjacencyMap Int) == "edge 1 2" show (1 * 2 * 3 :: IntAdjacencyMap Int) == "edges [(1,2),(1,3),(2,3)]"-show (1 * 2 + 3 :: IntAdjacencyMap Int) == "graph [1,2,3] [(1,2)]"@+show (1 * 2 + 3 :: IntAdjacencyMap Int) == "overlay (vertex 3) (edge 1 2)"@  The 'Eq' instance satisfies all axioms of algebraic graphs: @@ -106,22 +107,22 @@  instance Show IntAdjacencyMap where     show (AM m _)-        | m == IntMap.empty = "empty"-        | es == []          = if IntSet.size vs > 1 then "vertices " ++ show (IntSet.toAscList vs)-                                                    else "vertex "   ++ show v-        | vs == referred    = if length es > 1 then "edges " ++ show es-                                               else "edge "  ++ show e ++ " " ++ show f-        | otherwise         = "graph " ++ show (IntSet.toAscList vs) ++ " " ++ show es+        | null vs    = "empty"+        | null es    = vshow vs+        | vs == used = eshow es+        | otherwise  = "overlay (" ++ vshow (vs \\ used) ++ ") (" ++ eshow es ++ ")"       where-        vs       = keysSet m-        es       = internalEdgeList m-        v        = head $ IntSet.toList vs-        (e, f)   = head es-        referred = referredToVertexSet m+        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+        used           = IntSet.toAscList (referredToVertexSet m)  instance Graph IntAdjacencyMap where     type Vertex IntAdjacencyMap = Int-    empty       = mkAM $ IntMap.empty+    empty       = mkAM   IntMap.empty     vertex x    = mkAM $ IntMap.singleton x IntSet.empty     overlay x y = mkAM $ IntMap.unionWith IntSet.union (adjacencyMap x) (adjacencyMap y)     connect x y = mkAM $ IntMap.unionsWith IntSet.union [ adjacencyMap x, adjacencyMap y,
+ src/Algebra/Graph/Internal.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Internal+-- 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 various internal utilities and data structures used+-- throughout the library, such as lists with fast concatenation. The API+-- is unstable and unsafe, and is exposed only for documentation.+-----------------------------------------------------------------------------+module Algebra.Graph.Internal (+    -- * General data structures+    List (..),++    -- * Data structures for graph traversal+    Focus, focus, Context (..), context+  ) where++import Prelude ()+import Prelude.Compat++import Data.Foldable+import Data.Semigroup++import Algebra.Graph.Class (ToGraph(..))++import qualified GHC.Exts as Exts++-- | An abstract list data type with /O(1)/ time concatenation (the current+-- implementation uses difference lists). Here @a@ is the type of list elements.+-- 'List' @a@ is a 'Monoid': 'mempty' corresponds to the empty list and two lists+-- can be concatenated with 'mappend' (or operator 'Data.Monoid.<>'). Singleton+-- lists can be constructed using the function 'pure' from the 'Applicative'+-- instance. 'List' @a@ is also an instance of 'IsList', therefore you can use+-- list literals, e.g. @[1,4]@ @::@ 'List' @Int@ is the same as 'pure' @1@+-- 'Data.Monoid.<>' 'pure' @4@; note that this requires the @OverloadedLists@+-- GHC extension. To extract plain Haskell lists you can use the 'toList'+-- function from the 'Foldable' instance.+newtype List a = List (Endo [a]) deriving (Monoid, Semigroup)++instance Show a => Show (List a) where+    show = show . toList++instance Eq a => Eq (List a) where+    x == y = toList x == toList y++instance Ord a => Ord (List a) where+    compare x y = compare (toList x) (toList y)++-- TODO: Add rewrite rules? fromList . toList == toList . fromList == id+instance Exts.IsList (List a) where+    type Item (List a) = a+    fromList        = List . Endo . (<>)+    toList (List x) = appEndo x []++instance Foldable List where+    foldMap f = foldMap f . Exts.toList+#if MIN_VERSION_base(4,8,0)+    toList    = Exts.toList+#endif++instance Functor List where+    fmap f = Exts.fromList . map f . toList++instance Applicative List where+    pure    = List . Endo . (:)+    f <*> x = Exts.fromList (toList f <*> toList x)++instance Monad List where+    return  = pure+    x >>= f = Exts.fromList (toList x >>= toList . f)++-- | Focus on the empty graph.+emptyFocus :: Focus 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 a+vertexFocus f x = Focus (f x) mempty mempty (pure x)++-- | Overlay two foci.+overlayFoci :: Focus a -> Focus a -> Focus a+overlayFoci x y = Focus (ok x || ok y) (is x <> is y) (os x <> os y) (vs x <> vs y)++-- | Connect two foci.+connectFoci :: Focus a -> Focus a -> Focus a+connectFoci x y = Focus (ok x || ok y) (xs <> is y) (os x <> ys) (vs x <> vs y)+  where+    xs = if ok y then vs x else is x+    ys = if ok x then vs y else os y++-- | 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 :: ToGraph g => (ToVertex g -> Bool) -> g -> Maybe (Context (ToVertex g))+context p g | ok f      = Just $ Context (toList $ is f) (toList $ os f)+            | otherwise = Nothing+  where+    f = focus p g++-- | 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 'Algebra.Graph.removeEdge' for a use-case example.+data Focus a = Focus+    { ok :: Bool     -- ^ True if focus on the specified subgraph is obtained.+    , is :: List a   -- ^ Inputs into the focused subgraph.+    , os :: List a   -- ^ Outputs out of the focused subgraph.+    , vs :: List a } -- ^ All vertices (leaves) of the graph expression.++-- | 'Focus' on a specified subgraph.+focus :: ToGraph g => (ToVertex g -> Bool) -> g -> Focus (ToVertex g)+focus f = foldg emptyFocus (vertexFocus f) overlayFoci connectFoci
+ src/Algebra/Graph/NonEmpty.hs view
@@ -0,0 +1,755 @@+{-# LANGUAGE CPP, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.NonEmpty+-- 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 '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'.+--+-----------------------------------------------------------------------------+module Algebra.Graph.NonEmpty (+    -- * Algebraic data type for non-empty graphs+    NonEmptyGraph (..), toNonEmptyGraph,++    -- * Basic graph construction primitives+    vertex, edge, overlay, overlay1, connect, vertices1, edges1, overlays1,+    connects1,++    -- * Graph folding+    foldg1,++    -- * Relations on graphs+    isSubgraphOf, (===),++    -- * Graph properties+    size, hasVertex, hasEdge, vertexCount, edgeCount, vertexList1, edgeList,+    vertexSet, vertexIntSet, edgeSet,++    -- * Standard families of graphs+    path1, circuit1, clique1, biclique1, star, starTranspose, tree, mesh1, torus1,++    -- * Graph transformation+    removeVertex1, removeEdge, replaceVertex, mergeVertices, splitVertex1,+    transpose, induce1, simplify,++    -- * Graph composition+    box+  ) where++import Prelude ()+import Prelude.Compat++#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup+#endif++import Control.DeepSeq (NFData (..))+import Control.Monad.Compat+import Data.List.NonEmpty (NonEmpty (..))++import Algebra.Graph.Internal++import qualified Algebra.Graph                    as G+import qualified Algebra.Graph.AdjacencyMap       as AM+import qualified Algebra.Graph.Class              as C+import qualified Algebra.Graph.HigherKinded.Class as H+import qualified Algebra.Graph.IntAdjacencyMap    as IAM+import qualified Algebra.Graph.Relation           as R+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.++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 that the 'signum' method of the 'Num' type class cannot be implemented.++The 'Eq' instance is currently implemented using the 'AM.AdjacencyMap' as the+/canonical graph representation/ and satisfies the following laws of algebraic+graphs:++    * 'overlay' is commutative, associative and idempotent:++        >       x + y == y + x+        > x + (y + z) == (x + y) + z+        >       x + x == x++    * 'connect' is associative:++        > x * (y * z) == (x * y) * z++    * 'connect' distributes over 'overlay':++        > x * (y + z) == x * y + x * z+        > (x + y) * z == x * z + y * z++    * 'connect' can be decomposed:++        > x * y * z == x * y + x * z + y * z++    * '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/ 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:++@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 '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.+-}+data NonEmptyGraph a = Vertex a+                     | Overlay (NonEmptyGraph a) (NonEmptyGraph a)+                     | Connect (NonEmptyGraph a) (NonEmptyGraph a)+                     deriving (Foldable, Functor, Show, Traversable)++instance NFData a => NFData (NonEmptyGraph 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 C.ToGraph (NonEmptyGraph a) where+    type ToVertex (NonEmptyGraph a) = a+    foldg _ = foldg1++instance H.ToGraph NonEmptyGraph where+    toGraph = foldg1 H.vertex H.overlay H.connect++instance Num a => Num (NonEmptyGraph a) where+    fromInteger = Vertex . fromInteger+    (+)         = Overlay+    (*)         = Connect+    signum      = error "NonEmptyGraph.signum cannot be implemented."+    abs         = id+    negate      = id++instance Ord a => Eq (NonEmptyGraph a) where+    x == y = C.toGraph x == (C.toGraph y :: AM.AdjacencyMap a)++instance Applicative NonEmptyGraph where+    pure  = Vertex+    (<*>) = ap++instance Monad NonEmptyGraph where+    return  = pure+    g >>= f = foldg1 f Overlay Connect g++-- | Convert a 'G.Graph' into 'NonEmptyGraph'. 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)+-- @+toNonEmptyGraph :: G.Graph a -> Maybe (NonEmptyGraph a)+toNonEmptyGraph = G.foldg Nothing (Just . Vertex) (go Overlay) (go Connect)+  where+    go _ Nothing  y        = y+    go _ x        Nothing  = x+    go f (Just x) (Just y) = Just (f x y)++-- | Construct the graph comprising /a single isolated vertex/. An alias for the+-- constructor 'Vertex'.+-- Complexity: /O(1)/ time, memory and size.+--+-- @+-- 'hasVertex' x (vertex x) == True+-- 'vertexCount' (vertex x) == 1+-- 'edgeCount'   (vertex x) == 0+-- 'size'        (vertex x) == 1+-- @+vertex :: a -> NonEmptyGraph a+vertex = Vertex++-- | Construct the graph comprising /a single edge/.+-- Complexity: /O(1)/ time, memory and size.+--+-- @+-- 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 :: a -> a -> NonEmptyGraph a+edge u v = connect (vertex u) (vertex v)++-- | /Overlay/ two graphs. An alias for the constructor 'Overlay'. This is a+-- commutative, associative and idempotent operation.+-- Complexity: /O(1)/ time and memory, /O(s1 + s2)/ size.+--+-- @+-- '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+-- 'size'        (overlay x y) == 'size' x        + 'size' y+-- 'vertexCount' (overlay 1 2) == 2+-- 'edgeCount'   (overlay 1 2) == 0+-- @+overlay :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a+overlay = 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'.+-- 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+-- @+overlay1 :: G.Graph a -> NonEmptyGraph a -> NonEmptyGraph a+overlay1 = maybe id overlay . toNonEmptyGraph++-- | /Connect/ two graphs. An alias for the constructor 'Connect'. This is an+-- associative operation, which distributes over 'overlay' and obeys the+-- decomposition axiom.+-- 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)/.+--+-- @+-- '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+-- 'size'        (connect x y) == 'size' x        + 'size' y+-- 'vertexCount' (connect 1 2) == 2+-- 'edgeCount'   (connect 1 2) == 1+-- @+connect :: NonEmptyGraph a -> NonEmptyGraph a -> NonEmptyGraph a+connect = Connect++-- | 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.+--+-- @+-- 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 = overlays1 . fmap vertex++-- | Construct the graph from a list of edges.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the+-- given list.+--+-- @+-- edges1 ((x,y) ':|' []) == 'edge' x y+-- 'edgeCount' . edges1   == 'Data.List.NonEmpty.length' . 'Data.List.NonEmpty.nub'+-- @+edges1 :: NonEmpty (a, a) -> NonEmptyGraph a+edges1 = overlays1 . fmap (uncurry edge)++-- | 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.+--+-- @+-- overlays1 (x ':|' [] ) == x+-- overlays1 (x ':|' [y]) == 'overlay' x y+-- @+overlays1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a+overlays1 (x :| xs) = case xs of []     -> x+                                 (y:ys) -> overlay x (overlays1 $ y :| ys)++-- | Connect 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.+--+-- @+-- connects1 (x ':|' [] ) == x+-- connects1 (x ':|' [y]) == 'connect' x y+-- @+connects1 :: NonEmpty (NonEmptyGraph a) -> NonEmptyGraph a+connects1 (x :| xs) = case xs of []     -> x+                                 (y:ys) -> connect x (connects1 $ y :| ys)++-- | Generalised graph folding: recursively collapse a 'NonEmptyGraph' 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 :: (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> NonEmptyGraph a -> b+foldg1 v o c = go+  where+    go (Vertex  x  ) = v x+    go (Overlay x y) = o (go x) (go y)+    go (Connect x y) = c (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 x             ('overlay' x y) == True+-- isSubgraphOf ('overlay' x y) ('connect' x y) == True+-- isSubgraphOf ('path1' xs)    ('circuit1' xs) == True+-- @+isSubgraphOf :: Ord a => NonEmptyGraph a -> NonEmptyGraph a -> Bool+isSubgraphOf x y = overlay x y == y++-- | Structural equality on graph expressions.+-- Complexity: /O(s)/ time.+--+-- @+--     x === x     == True+-- x + y === x + y == True+-- 1 + 2 === 2 + 1 == False+-- x + y === x * y == False+-- @+(===) :: Eq a => NonEmptyGraph a -> NonEmptyGraph 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++infix 4 ===++-- | The /size/ of a graph, i.e. the number of leaves of the expression.+-- Complexity: /O(s)/ time.+--+-- @+-- 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             >= 'vertexCount' x+-- @+size :: NonEmptyGraph a -> Int+size = foldg1 (const 1) (+) (+)++-- | Check if a graph contains a given vertex. A convenient alias for `elem`.+-- Complexity: /O(s)/ time.+--+-- @+-- hasVertex x ('vertex' x) == True+-- hasVertex 1 ('vertex' 2) == False+-- @+hasVertex :: Eq a => a -> NonEmptyGraph a -> Bool+hasVertex v = foldg1 (==v) (||) (||)++-- | Check if a graph contains a given edge.+-- Complexity: /O(s)/ 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 -> NonEmptyGraph a -> Bool+hasEdge u v = G.hasEdge u v . H.toGraph++-- | The number of vertices in a graph.+-- Complexity: /O(s * log(n))/ time.+--+-- @+-- vertexCount ('vertex' x) == 1+-- vertexCount x          >= 1+-- vertexCount            == 'length' . 'vertexList1'+-- @+vertexCount :: Ord a => NonEmptyGraph a -> Int+vertexCount = length . vertexList1++-- | The number of edges in a graph.+-- 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/.+--+-- @+-- edgeCount ('vertex' x) == 0+-- edgeCount ('edge' x y) == 1+-- edgeCount            == 'length' . 'edgeList'+-- @+edgeCount :: Ord a => NonEmptyGraph a -> Int+edgeCount = AM.edgeCount . C.toGraph++-- | The sorted list of vertices of a given graph.+-- Complexity: /O(s * log(n))/ time and /O(n)/ memory.+--+-- @+-- vertexList1 ('vertex' x)  == x ':|' []+-- vertexList1 . 'vertices1' == 'Data.List.NonEmpty.nub' . 'Data.List.NonEmpty.sort'+-- @+vertexList1 :: Ord a => NonEmptyGraph a -> NonEmpty a+vertexList1 = NonEmpty.fromList . G.vertexList . H.toGraph++-- | The sorted list of edges of a graph.+-- Complexity: /O(s + m * log(m))/ time and /O(m)/ memory. Note that the number of+-- edges /m/ of a graph can be quadratic with respect to the expression size /s/.+--+-- @+-- edgeList ('vertex' x)     == []+-- 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 :: Ord a => NonEmptyGraph a -> [(a, a)]+edgeList = AM.edgeList . C.toGraph++-- | The set of vertices of a given graph.+-- Complexity: /O(s * log(n))/ time and /O(n)/ 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 :: Ord a => NonEmptyGraph a -> Set.Set a+vertexSet = AM.vertexSet . C.toGraph++-- | 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+vertexIntSet = IAM.vertexIntSet . C.toGraph++-- | The set of edges of a given graph.+-- Complexity: /O(s * log(m))/ time and /O(m)/ memory.+--+-- @+-- edgeSet ('vertex' x) == Set.'Set.empty'+-- 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 = R.edgeSet . C.toGraph++-- | The /path/ on a list of vertices.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the+-- given list.+--+-- @+-- path1 (x ':|' [] ) == 'vertex' x+-- path1 (x ':|' [y]) == 'edge' x y+-- path1 . 'Data.List.NonEmpty.reverse'  == 'transpose' . path1+-- @+path1 :: NonEmpty a -> NonEmptyGraph a+path1 (x :| []    ) = vertex x+path1 (x :| (y:ys)) = edges1 ((x, y) :| zip (y:ys) ys)++-- | The /circuit/ on a list of vertices.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the+-- given list.+--+-- @+-- 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 (x :| xs) = path1 (x :| xs ++ [x])++-- | The /clique/ on a list of vertices.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the+-- 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 :: NonEmpty a -> NonEmptyGraph a+clique1 = connects1 . fmap vertex++-- | The /biclique/ on two lists of vertices.+-- Complexity: /O(L1 + L2)/ time, memory and size, where /L1/ and /L2/ are the+-- 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 :: NonEmpty a -> NonEmpty a -> NonEmptyGraph a+biclique1 xs ys = connect (vertices1 xs) (vertices1 ys)++-- | The /star/ formed by a centre vertex connected to a list of leaves.+-- Complexity: /O(L)/ time, memory and size, where /L/ is the length of the+-- given list.+--+-- @+-- star x []    == 'vertex' x+-- star x [y]   == 'edge' x y+-- star x [y,z] == 'edges1' ((x,y) ':|' [(x,z)])+-- @+star :: a -> [a] -> NonEmptyGraph a+star x []     = vertex x+star x (y:ys) = connect (vertex x) (vertices1 $ y :| 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] == 'edges1' ((y,x) ':|' [(z,x)])+-- starTranspose x ys    == 'transpose' ('star' x ys)+-- @+starTranspose :: a -> [a] -> NonEmptyGraph a+starTranspose x []     = vertex x+starTranspose x (y:ys) = connect (vertices1 $ y :| ys) (vertex x)++-- | The /tree graph/ constructed from a given 'Tree.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).+--+-- @+-- 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 :: Tree.Tree a -> NonEmptyGraph 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.+-- Complexity: /O(L1 * L2)/ time, memory and size, where /L1/ and /L2/ are the+-- 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 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)+mesh1 xs ys = path1 xs `box` path1 ys++-- | Construct a /torus graph/ from two lists of vertices.+-- Complexity: /O(L1 * L2)/ time, memory and size, where /L1/ and /L2/ are the+-- 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 :: NonEmpty a -> NonEmpty b -> NonEmptyGraph (a, b)+torus1 xs ys = circuit1 xs `box` circuit1 ys++-- | Remove a vertex from a given graph. Returns @Nothing@ if the resulting+-- graph is empty.+-- Complexity: /O(s)/ time, memory and size.+--+-- @+-- 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 '>=>' removeVertex1 x == removeVertex1 x+-- @+removeVertex1 :: Eq a => a -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)+removeVertex1 x = induce1 (/= x)++-- | 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 . 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+-- @+removeEdge :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a+removeEdge s t = filterContext s (/=s) (/=t)++-- TODO: Export+-- TODO: Here if @context (==s) g == Just ctx@ then we know for sure that+-- @induce1 (/=s) g == Just subgraph@. Can we exploit this?+filterContext :: Eq a => a -> (a -> Bool) -> (a -> Bool) -> NonEmptyGraph a -> NonEmptyGraph a+filterContext s i o g = maybe g go $ context (==s) g+  where+    go (Context is os) = G.induce (/=s) (C.toGraph g)  `overlay1`+                         starTranspose s (filter i is) `overlay` star s (filter o os)++-- | 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.+-- Complexity: /O(s)/ time, memory and size.+--+-- @+-- replaceVertex x x            == id+-- replaceVertex x y ('vertex' x) == 'vertex' y+-- replaceVertex x y            == 'mergeVertices' (== x) y+-- @+replaceVertex :: Eq a => a -> a -> NonEmptyGraph a -> NonEmptyGraph a+replaceVertex u v = fmap $ \w -> if w == u then v else w++-- | 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 (== x) y           == 'replaceVertex' x y+-- mergeVertices even 1 (0 * 2)     == 1 * 1+-- mergeVertices odd  1 (3 + 4 * 5) == 4 * 1+-- @+mergeVertices :: (a -> Bool) -> a -> NonEmptyGraph a -> NonEmptyGraph 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.+-- Complexity: /O(s + k * L)/ time, memory and size, where /k/ is the number of+-- occurrences of the vertex in the expression and /L/ is the length of the+-- given list.+--+-- @+-- splitVertex1 x (x ':|' [] )               == id+-- splitVertex1 x (y ':|' [] )               == 'replaceVertex' x y+-- splitVertex1 1 (0 ':|' [1]) $ 1 * (2 + 3) == (0 + 1) * (2 + 3)+-- @+splitVertex1 :: Eq a => a -> NonEmpty a -> NonEmptyGraph a -> NonEmptyGraph a+splitVertex1 v us g = g >>= \w -> if w == v then vertices1 us else vertex w++-- | Transpose a given graph.+-- Complexity: /O(s)/ time, memory and size.+--+-- @+-- transpose ('vertex' x)  == 'vertex' x+-- 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'+-- @+transpose :: NonEmptyGraph a -> NonEmptyGraph a+transpose = foldg1 vertex overlay (flip connect)++-- | Construct the /induced subgraph/ of a given graph by removing the+-- vertices that do not satisfy a given predicate. Returns @Nothing@ if the+-- resulting graph is empty.+-- Complexity: /O(s)/ time, memory and size, 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 '>=>' induce1 q == induce1 (\\x -> p x && q x)+-- @+induce1 :: (a -> Bool) -> NonEmptyGraph a -> Maybe (NonEmptyGraph a)+induce1 p = toNonEmptyGraph . G.induce p . C.toGraph++-- | Simplify a graph expression. Semantically, this is the identity function,+-- but it simplifies a given expression according to the laws of the algebra.+-- The function does not compute the simplest possible expression,+-- but uses heuristics to obtain useful simplifications in reasonable time.+-- Complexity: the function performs /O(s)/ graph comparisons. It is guaranteed+-- that the size of the result does not exceed the size of the given expression.+--+-- @+-- 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+-- @+simplify :: Ord a => NonEmptyGraph a -> NonEmptyGraph a+simplify = foldg1 Vertex (simple Overlay) (simple Connect)++simple :: Eq g => (g -> g -> g) -> g -> g -> g+simple op x y+    | x == z    = x+    | y == z    = y+    | otherwise = z+  where+    z = op x 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.+--+-- @+-- 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\')) ])+-- @+-- Up to an isomorphism between the resulting vertex types, this operation+-- is /commutative/, /associative/, /distributes/ over 'overlay', and has+-- singleton graphs as /identities/. 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+-- 'transpose'   (box x y) == box ('transpose' x) ('transpose' y)+-- '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 x y = overlays1 xs `overlay` overlays1 ys+  where+    xs = fmap (\b -> fmap (,b) x) $ toNonEmpty y+    ys = fmap (\a -> fmap (a,) y) $ toNonEmpty x++-- Shall we export this? I suggest to wait for Foldable1 type class instead.+toNonEmpty :: NonEmptyGraph a -> NonEmpty a+toNonEmpty = foldg1 (:| []) (<>) (<>)
src/Algebra/Graph/Relation.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -20,7 +20,7 @@      -- * Basic graph construction primitives     empty, vertex, edge, overlay, connect, vertices, edges, overlays, connects,-    graph, fromAdjacencyList,+    fromAdjacencyList,      -- * Relations on graphs     isSubgraphOf,@@ -30,7 +30,7 @@     vertexSet, vertexIntSet, edgeSet, preSet, postSet,      -- * Standard families of graphs-    path, circuit, clique, biclique, star, tree, forest,+    path, circuit, clique, biclique, star, starTranspose, tree, forest,      -- * Graph transformation     removeVertex, removeEdge, replaceVertex, mergeVertices, transpose, gmap, induce,@@ -39,6 +39,9 @@     compose, reflexiveClosure, symmetricClosure, transitiveClosure, preorderClosure   ) where +import Prelude ()+import Prelude.Compat+ import Data.Tuple  import Algebra.Graph.Relation.Internal@@ -66,7 +69,6 @@ -- @ -- 'isEmpty'     (vertex x) == False -- 'hasVertex' x (vertex x) == True--- 'hasVertex' 1 (vertex 2) == False -- 'vertexCount' (vertex x) == 1 -- 'edgeCount'   (vertex x) == 0 -- @@@ -86,7 +88,7 @@ edge :: Ord a => a -> a -> Relation a edge = C.edge --- | /Overlay/ two graphs. This is an idempotent, commutative and associative+-- | /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. --@@ -104,7 +106,7 @@ overlay = C.overlay  -- | /Connect/ two graphs. This is an associative operation with the identity--- 'empty', which distributes over the overlay and obeys the decomposition axiom.+-- '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)/.@@ -156,6 +158,7 @@ -- overlays []        == 'empty' -- overlays [x]       == x -- overlays [x,y]     == 'overlay' x y+-- overlays           == 'foldr' 'overlay' 'empty' -- 'isEmpty' . overlays == 'all' 'isEmpty' -- @ overlays :: Ord a => [Relation a] -> Relation a@@ -168,25 +171,12 @@ -- connects []        == 'empty' -- connects [x]       == x -- connects [x,y]     == 'connect' x y+-- connects           == 'foldr' 'connect' 'empty' -- 'isEmpty' . connects == 'all' 'isEmpty' -- @ connects :: Ord a => [Relation a] -> Relation a connects = C.connects --- | Construct the graph from given lists of vertices /V/ and edges /E/.--- The resulting graph contains the vertices /V/ as well as all the vertices--- referred to by the edges /E/.--- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory.------ @--- graph []  []      == 'empty'--- graph [x] []      == 'vertex' x--- graph []  [(x,y)] == 'edge' x y--- graph vs  es      == 'overlay' ('vertices' vs) ('edges' es)--- @-graph :: Ord a => [a] -> [(a, a)] -> Relation a-graph = C.graph- -- | Construct a graph from an adjacency list. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. --@@ -199,7 +189,7 @@ fromAdjacencyList :: Ord a => [(a, [a])] -> Relation a fromAdjacencyList as = Relation (Set.fromList vs) (Set.fromList es)   where-    vs = concatMap (\(x, ys) -> x : ys) as+    vs = concatMap (uncurry (:)) as     es = [ (x, y) | (x, ys) <- as, y <- ys ]  -- | The 'isSubgraphOf' function takes two graphs and returns 'True' if the@@ -235,6 +225,7 @@ -- @ -- hasVertex x 'empty'            == False -- hasVertex x ('vertex' x)       == True+-- hasVertex 1 ('vertex' 2)       == False -- hasVertex x . 'removeVertex' x == const False -- @ hasVertex :: Ord a => a -> Relation a -> Bool@@ -338,7 +329,7 @@ edgeSet :: Relation a -> Set.Set (a, a) edgeSet = relation --- | The /preset/ of an element @x@ is the set of elements that are related to+-- | The /preset/ (here 'preSet') of an element @x@ is the set of elements that are related to -- it on the /left/, i.e. @preSet x == { a | aRx }@. In the context of directed -- graphs, this corresponds to the set of /direct predecessors/ of vertex @x@. -- Complexity: /O(n + m)/ time and /O(n)/ memory.@@ -352,7 +343,7 @@ preSet :: Ord a => a -> Relation a -> Set.Set a preSet x = Set.mapMonotonic fst . Set.filter ((== x) . snd) . relation --- | The /postset/ of an element @x@ is the set of elements that are related to+-- | The /postset/ (here 'postSet') of an element @x@ is the set of elements that are related to -- it on the /right/, i.e. @postSet x == { a | xRa }@. In the context of directed -- graphs, this corresponds to the set of /direct successors/ of vertex @x@. -- Complexity: /O(n + m)/ time and /O(n)/ memory.@@ -404,7 +395,7 @@ clique :: Ord a => [a] -> Relation a clique = C.clique --- | The /biclique/ on a list of vertices.+-- | The /biclique/ on two lists of vertices. -- Complexity: /O(n * log(n) + m)/ time and /O(n + m)/ memory. -- -- @@@ -420,18 +411,33 @@     x = Set.fromList xs     y = Set.fromList ys --- | The /star/ formed by a centre vertex and a list of leaves.+-- | 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] == 'edges' [(x,y), (x,z)]+-- star x ys    == 'connect' ('vertex' x) ('vertices' ys) -- @ star :: Ord a => a -> [a] -> Relation a star = C.star --- | The /tree graph/ constructed from a given 'Tree' data structure.+-- | 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 :: Ord a => a -> [a] -> Relation a+starTranspose = C.starTranspose++-- | The /tree graph/ constructed from a given 'Tree.Tree' data structure. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. -- -- @@@ -443,7 +449,7 @@ tree :: Ord a => Tree.Tree a -> Relation a tree = C.tree --- | The /forest graph/ constructed from a given 'Forest' data structure.+-- | The /forest graph/ constructed from a given 'Tree.Forest' data structure. -- Complexity: /O((n + m) * log(n))/ time and /O(n + m)/ memory. -- -- @@@ -460,6 +466,9 @@ -- -- @ -- removeVertex x ('vertex' x)       == 'empty'+-- removeVertex 1 ('vertex' 2)       == 'vertex' 2+-- removeVertex x ('edge' x x)       == 'empty'+-- removeVertex 1 ('edge' 1 2)       == 'vertex' 2 -- removeVertex x . removeVertex x == removeVertex x -- @ removeVertex :: Ord a => a -> Relation a -> Relation a@@ -492,7 +501,7 @@ replaceVertex :: Ord a => a -> a -> Relation a -> Relation a replaceVertex u v = gmap $ \w -> if w == u then v else w --- | Merge vertices satisfying a given predicate with a given vertex.+-- | 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. --@@ -513,9 +522,6 @@ -- transpose ('vertex' x)  == 'vertex' x -- transpose ('edge' x y)  == 'edge' y x -- transpose . transpose == id--- transpose . 'path'      == 'path'    . 'reverse'--- transpose . 'circuit'   == 'circuit' . 'reverse'--- transpose . 'clique'    == 'clique'  . 'reverse' -- 'edgeList' . transpose  == 'Data.List.sort' . map 'Data.Tuple.swap' . 'edgeList' -- @ transpose :: Ord a => Relation a -> Relation a@@ -542,7 +548,7 @@ -- be evaluated. -- -- @--- induce (const True)  x      == x+-- induce (const True ) x      == x -- induce (const False) x      == 'empty' -- induce (/= x)               == 'removeVertex' x -- induce p . induce q         == induce (\\x -> p x && q x)@@ -593,7 +599,7 @@ -- symmetricClosure ('edge' x y) == 'edges' [(x, y), (y, x)] -- @ symmetricClosure :: Ord a => Relation a -> Relation a-symmetricClosure (Relation d r) = Relation d $ r `Set.union` (Set.map swap r)+symmetricClosure (Relation d r) = Relation d $ r `Set.union` Set.map swap r  -- | Compute the /transitive closure/ of a 'Relation'. -- Complexity: /O(n * m * log(n) * log(m))/ time.
src/Algebra/Graph/Relation/Internal.hs view
@@ -1,14 +1,14 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation.Internal--- Copyright  : (c) Andrey Mokhov 2016-2017+-- 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 the 'Relation' data type. The API--- is unstable and unsafe. Where possible use the non-internal module--- "Algebra.Graph.Relation" instead.+-- is unstable and unsafe, and is exposed only for documentation. You should+-- use the non-internal module "Algebra.Graph.Relation" instead. ----------------------------------------------------------------------------- module Algebra.Graph.Relation.Internal (     -- * Binary relation implementation@@ -37,7 +37,7 @@ show (1 + 2     :: Relation Int) == "vertices [1,2]" show (1 * 2     :: Relation Int) == "edge 1 2" show (1 * 2 * 3 :: Relation Int) == "edges [(1,2),(1,3),(2,3)]"-show (1 * 2 + 3 :: Relation Int) == "graph [1,2,3] [(1,2)]"@+show (1 * 2 + 3 :: Relation Int) == "overlay (vertex 3) (edge 1 2)"@  The 'Eq' instance satisfies all axioms of algebraic graphs: @@ -90,18 +90,17 @@  instance (Ord a, Show a) => Show (Relation a) where     show (Relation d r)-        | vs == []      = "empty"-        | es == []      = if Set.size d > 1 then "vertices " ++ show vs-                                            else "vertex "   ++ show v-        | d == referred = if Set.size r > 1 then "edges " ++ show es-                                            else "edge "  ++ show e ++ " " ++ show f-        | otherwise     = "graph " ++ show vs ++ " " ++ show es+        | 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) ++ ")"       where-        vs       = Set.toAscList d-        es       = Set.toAscList r-        v        = head vs-        (e, f)   = head es-        referred = referredToVertexSet r+        vshow [x]      = "vertex "   ++ show x+        vshow xs       = "vertices " ++ show xs+        eshow [(x, y)] = "edge "     ++ show x ++ " " ++ show y+        eshow xs       = "edges "    ++ show xs+        used           = referredToVertexSet r  instance Ord a => Graph (Relation a) where     type Vertex (Relation a) = a@@ -125,7 +124,7 @@  instance ToGraph (Relation a) where     type ToVertex (Relation a) = a-    toGraph (Relation d r) = graph (Set.toList d) (Set.toList r)+    toGraph (Relation d r) = vertices (Set.toList d) `overlay` edges (Set.toList r)  -- | Check if the internal representation of a relation is consistent, i.e. if all -- pairs of elements in the 'relation' refer to existing elements in the 'domain'.
src/Algebra/Graph/Relation/InternalDerived.hs view
@@ -1,16 +1,16 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation.InternalDerived--- Copyright  : (c) Andrey Mokhov 2016-2017+-- 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 derived binary relation data types.--- The API is unstable and unsafe. Where possible use the non-internal modules--- "Algebra.Graph.Relation.Reflexive", "Algebra.Graph.Relation.Symmetric",--- "Algebra.Graph.Relation.Transitive" and "Algebra.Graph.Relation.Preorder"--- instead.+-- The API is unstable and unsafe, and is exposed only for documentation. You+-- should use the non-internal modules "Algebra.Graph.Relation.Reflexive",+-- "Algebra.Graph.Relation.Symmetric", "Algebra.Graph.Relation.Transitive" and+-- "Algebra.Graph.Relation.Preorder" instead. ----------------------------------------------------------------------------- module Algebra.Graph.Relation.InternalDerived (     -- * Implementation of derived binary relations
src/Algebra/Graph/Relation/Preorder.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation.Preorder--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental
src/Algebra/Graph/Relation/Reflexive.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation.Reflexive--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental
src/Algebra/Graph/Relation/Symmetric.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation.Symmetric--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental
src/Algebra/Graph/Relation/Transitive.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Relation.Transitive--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental
test/Algebra/Graph/Test.hs view
@@ -5,7 +5,7 @@     module Test.QuickCheck,     module Test.QuickCheck.Function, -    GraphTestsuite, axioms, theorems, undirectedAxioms, reflexiveAxioms,+    GraphTestsuite, (//), axioms, theorems, undirectedAxioms, reflexiveAxioms,     transitiveAxioms, preorderAxioms, test,     ) where @@ -47,9 +47,9 @@ infixl 6 + infixl 7 * -type GraphTestsuite g = (Eq g, Graph g) => g -> g -> g -> Property+type GraphTestsuite g = g -> g -> g -> Property -axioms :: GraphTestsuite g+axioms :: (Eq g, Graph g) => GraphTestsuite g axioms x y z = conjoin     [       x + y == y + x                      // "Overlay commutativity"     , x + (y + z) == (x + y) + z                // "Overlay associativity"@@ -60,7 +60,7 @@     , (x + y) * z == x * z + y * z              // "Right distributivity"     ,   x * y * z == x * y + x * z + y * z      // "Decomposition" ] -theorems :: GraphTestsuite g+theorems :: (Eq g, Graph g) => GraphTestsuite g theorems x y z = conjoin     [     x + empty == x                        // "Overlay identity"     ,         x + x == x                        // "Overlay idempotence"@@ -72,23 +72,23 @@     ,             x <= x + y                    // "Overlay order"     ,         x + y <= x * y                    // "Overlay-connect order" ] -undirectedAxioms :: GraphTestsuite g+undirectedAxioms :: (Eq g, Graph g) => GraphTestsuite g undirectedAxioms x y z = conjoin     [ axioms x y z     , x * y == y * x                            // "Connect commutativity" ] -reflexiveAxioms :: (Arbitrary (Vertex g), Show (Vertex g)) => GraphTestsuite g+reflexiveAxioms :: (Eq g, Graph g, Arbitrary (Vertex g), Show (Vertex g)) => GraphTestsuite g reflexiveAxioms x y z = conjoin     [ axioms x y z     , forAll arbitrary (\v -> vertex v `asTypeOf` x == vertex v * vertex v)                                                 // "Vertex self-loop" ] -transitiveAxioms :: GraphTestsuite g+transitiveAxioms :: (Eq g, Graph g) => GraphTestsuite g transitiveAxioms x y z = conjoin     [ axioms x y z     , y == empty || x * y * z == x * y + y * z  // "Closure" ] -preorderAxioms :: (Arbitrary (Vertex g), Show (Vertex g)) => GraphTestsuite g+preorderAxioms :: (Eq g, Graph g, Arbitrary (Vertex g), Show (Vertex g)) => GraphTestsuite g preorderAxioms x y z = conjoin     [ axioms x y z     , forAll arbitrary (\v -> vertex v `asTypeOf` x == vertex v * vertex v)
test/Algebra/Graph/Test/API.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.API--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -18,9 +18,10 @@ import Data.Set (Set) import Data.Tree -import Algebra.Graph.Class+import Algebra.Graph.Class hiding (toGraph)  import qualified Algebra.Graph.AdjacencyMap    as AdjacencyMap+import qualified Algebra.Graph.Class           as Class import qualified Algebra.Graph.Fold            as Fold import qualified Algebra.Graph                 as Graph import qualified Algebra.Graph.IntAdjacencyMap as IntAdjacencyMap@@ -39,10 +40,10 @@     overlays          = notImplemented     connects          :: [g] -> g     connects          = notImplemented-    graph             :: [Vertex g] -> [(Vertex g, Vertex g)] -> g-    graph             = notImplemented     fromAdjacencyList :: [(Vertex g, [Vertex g])] -> g     fromAdjacencyList = notImplemented+    toGraph           :: (Graph h, Vertex g ~ Vertex h) => g -> h+    toGraph           = notImplemented     foldg             :: r -> (Vertex g -> r) -> (r -> r -> r) -> (r -> r -> r) -> g -> r     foldg             = notImplemented     isSubgraphOf      :: g -> g -> Bool@@ -89,6 +90,8 @@     biclique          = notImplemented     star              :: Vertex g -> [Vertex g] -> g     star              = notImplemented+    starTranspose     :: Vertex g -> [Vertex g] -> g+    starTranspose     = notImplemented     tree              :: Tree (Vertex g) -> g     tree              = notImplemented     forest            :: Forest (Vertex g) -> g@@ -141,7 +144,6 @@     edges             = AdjacencyMap.edges     overlays          = AdjacencyMap.overlays     connects          = AdjacencyMap.connects-    graph             = AdjacencyMap.graph     fromAdjacencyList = AdjacencyMap.fromAdjacencyList     isSubgraphOf      = AdjacencyMap.isSubgraphOf     isEmpty           = AdjacencyMap.isEmpty@@ -161,6 +163,7 @@     clique            = AdjacencyMap.clique     biclique          = AdjacencyMap.biclique     star              = AdjacencyMap.star+    starTranspose     = AdjacencyMap.starTranspose     tree              = AdjacencyMap.tree     forest            = AdjacencyMap.forest     removeVertex      = AdjacencyMap.removeVertex@@ -182,7 +185,7 @@     edges         = Fold.edges     overlays      = Fold.overlays     connects      = Fold.connects-    graph         = Fold.graph+    toGraph       = Class.toGraph     foldg         = Fold.foldg     isSubgraphOf  = Fold.isSubgraphOf     isEmpty       = Fold.isEmpty@@ -201,6 +204,7 @@     clique        = Fold.clique     biclique      = Fold.biclique     star          = Fold.star+    starTranspose = Fold.starTranspose     tree          = Fold.tree     forest        = Fold.forest     mesh          = Fold.mesh@@ -224,7 +228,7 @@     edges         = Graph.edges     overlays      = Graph.overlays     connects      = Graph.connects-    graph         = Graph.graph+    toGraph       = Class.toGraph     foldg         = Graph.foldg     isSubgraphOf  = Graph.isSubgraphOf     (===)         = (Graph.===)@@ -244,6 +248,7 @@     clique        = Graph.clique     biclique      = Graph.biclique     star          = Graph.star+    starTranspose = Graph.starTranspose     tree          = Graph.tree     forest        = Graph.forest     mesh          = Graph.mesh@@ -267,7 +272,6 @@     edges             = IntAdjacencyMap.edges     overlays          = IntAdjacencyMap.overlays     connects          = IntAdjacencyMap.connects-    graph             = IntAdjacencyMap.graph     fromAdjacencyList = IntAdjacencyMap.fromAdjacencyList     isSubgraphOf      = IntAdjacencyMap.isSubgraphOf     isEmpty           = IntAdjacencyMap.isEmpty@@ -287,6 +291,7 @@     clique            = IntAdjacencyMap.clique     biclique          = IntAdjacencyMap.biclique     star              = IntAdjacencyMap.star+    starTranspose     = IntAdjacencyMap.starTranspose     tree              = IntAdjacencyMap.tree     forest            = IntAdjacencyMap.forest     removeVertex      = IntAdjacencyMap.removeVertex@@ -308,7 +313,6 @@     edges             = Relation.edges     overlays          = Relation.overlays     connects          = Relation.connects-    graph             = Relation.graph     fromAdjacencyList = Relation.fromAdjacencyList     isSubgraphOf      = Relation.isSubgraphOf     isEmpty           = Relation.isEmpty@@ -320,7 +324,7 @@     edgeList          = Relation.edgeList     preSet            = Relation.preSet     postSet           = Relation.postSet-    adjacencyList     = AdjacencyMap.adjacencyList . toGraph+    adjacencyList     = AdjacencyMap.adjacencyList . Class.toGraph     vertexSet         = Relation.vertexSet     vertexIntSet      = IntSet.fromAscList . Set.toAscList . Relation.vertexSet     edgeSet           = Relation.edgeSet@@ -329,6 +333,7 @@     clique            = Relation.clique     biclique          = Relation.biclique     star              = Relation.star+    starTranspose     = Relation.starTranspose     tree              = Relation.tree     forest            = Relation.forest     removeVertex      = Relation.removeVertex
test/Algebra/Graph/Test/AdjacencyMap.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.AdjacencyMap--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -29,7 +29,7 @@ testAdjacencyMap :: IO () testAdjacencyMap = do     putStrLn "\n============ AdjacencyMap ============"-    test "Axioms of graphs" $ (axioms :: GraphTestsuite AI)+    test "Axioms of graphs" (axioms :: GraphTestsuite AI)      test "Consistency of arbitraryAdjacencyMap" $ \(m :: AI) ->         consistent m
test/Algebra/Graph/Test/Arbitrary.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.Arbitrary--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -14,6 +14,9 @@     arbitraryGraph, arbitraryRelation, arbitraryAdjacencyMap, arbitraryIntAdjacencyMap   ) where +import Prelude ()+import Prelude.Compat+ import Control.Monad import Data.Tree import Test.QuickCheck@@ -26,9 +29,10 @@ import Algebra.Graph.Relation.Internal import Algebra.Graph.Relation.InternalDerived -import qualified Algebra.Graph.Class           as C import qualified Algebra.Graph.AdjacencyMap    as AdjacencyMap+import qualified Algebra.Graph.Class           as C import qualified Algebra.Graph.IntAdjacencyMap as IntAdjacencyMap+import qualified Algebra.Graph.NonEmpty        as NE import qualified Algebra.Graph.Relation        as Relation  -- | Generate an arbitrary 'Graph' value of a specified size.@@ -39,8 +43,8 @@     expr 1 = C.vertex <$> arbitrary     expr n = do         left <- choose (0, n)-        oneof [ C.overlay <$> (expr left) <*> (expr $ n - left)-              , C.connect <$> (expr left) <*> (expr $ n - left) ]+        oneof [ C.overlay <$> expr left <*> expr (n - left)+              , C.connect <$> expr left <*> expr (n - left) ]  instance Arbitrary a => Arbitrary (Graph a) where     arbitrary = arbitraryGraph@@ -51,6 +55,26 @@                         ++ [Overlay x' y' | (x', y') <- shrink (x, y) ]     shrink (Connect x y) = [Empty, x, y, Overlay x y]                         ++ [Connect x' y' | (x', y') <- shrink (x, y) ]++-- | Generate an arbitrary 'NonEmptyGraph' value of a specified size.+arbitraryNonEmptyGraph :: Arbitrary a => Gen (NE.NonEmptyGraph a)+arbitraryNonEmptyGraph = sized expr+  where+    expr 0 = NE.vertex <$> arbitrary -- can't generate non-empty graph of size 0+    expr 1 = NE.vertex <$> arbitrary+    expr n = do+        left <- choose (1, n)+        oneof [ NE.overlay <$> expr left <*> expr (n - left)+              , NE.connect <$> expr left <*> expr (n - left) ]++instance Arbitrary a => Arbitrary (NE.NonEmptyGraph a) where+    arbitrary = arbitraryNonEmptyGraph++    shrink (NE.Vertex    _) = []+    shrink (NE.Overlay x y) = [x, y]+                           ++ [NE.Overlay x' y' | (x', y') <- shrink (x, y) ]+    shrink (NE.Connect x y) = [x, y, NE.Overlay x y]+                           ++ [NE.Connect x' y' | (x', y') <- shrink (x, y) ]  -- | Generate an arbitrary 'Relation'. arbitraryRelation :: (Arbitrary a, Ord a) => Gen (Relation a)
test/Algebra/Graph/Test/Export.hs view
@@ -1,8 +1,8 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP, OverloadedStrings #-} ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.Export--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -14,9 +14,13 @@     testExport   ) where -import Prelude-import Data.Monoid+import Prelude ()+import Prelude.Compat +#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup+#endif+ import Algebra.Graph (Graph, circuit) import Algebra.Graph.Export hiding (unlines) import Algebra.Graph.Export.Dot (Attribute (..))@@ -79,7 +83,7 @@      putStrLn "\n============ Export.indent ============"     test "indent 0        == id" $ \(x :: String) ->-         (indent 0) (literal x) == literal x+          indent 0 (literal x) == literal x      test "indent 1 mempty == \" \"" $           indent 1 mempty == (" " :: Doc String)
test/Algebra/Graph/Test/Fold.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.Fold--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -29,11 +29,11 @@ testFold :: IO () testFold = do     putStrLn "\n============ Fold ============"-    test "Axioms of graphs"   $ (axioms   :: GraphTestsuite F)+    test "Axioms of graphs" (axioms :: GraphTestsuite F)      testShow            t     testBasicPrimitives t-    testFoldg           h+    testToGraph         h     testIsSubgraphOf    t     testSize            t     testProperties      t@@ -53,9 +53,9 @@     test "mesh xs     ys   == box (path xs) (path ys)" $ \(xs :: [Int]) (ys :: [Int]) ->           mesh xs     ys   == (box (path xs) (path ys) :: Fold (Int, Int)) -    test ("mesh [1..3] \"ab\" == <correct result>") $-         (mesh [1..3] "ab" :: Fold (Int, Char)) == edges [ ((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')) ]+    test "mesh [1..3] \"ab\" == <correct result>" $+         (mesh [1..3]  "ab" :: Fold (Int, Char)) == edges [ ((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')) ]      putStrLn "\n============ Fold.torus ============"     test "torus xs    []   == empty" $ \xs ->@@ -70,9 +70,9 @@     test "torus xs    ys   == box (circuit xs) (circuit ys)" $ \(xs :: [Int]) (ys :: [Int]) ->           torus xs    ys   == (box (circuit xs) (circuit ys) :: Fold (Int, Int)) -    test ("torus [1,2] \"ab\" == <correct result>") $-         (torus [1,2] "ab" :: Fold (Int, Char)) == edges [ ((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')) ]+    test "torus [1,2] \"ab\" == <correct result>" $+         (torus [1,2]  "ab" :: Fold (Int, Char)) == edges [ ((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')) ]      putStrLn "\n============ Fold.deBruijn ============"     test "          deBruijn 0 xs               == edge [] []" $ \(xs :: [Int]) ->@@ -107,21 +107,21 @@     putStrLn "\n============ Fold.box ============"     let unit = fmap $ \(a, ()) -> a         comm = fmap $ \(a,  b) -> (b, a)-    test "box x y             ~~ box y x" $ mapSize (min 10) $ \(x :: F) (y :: F) ->-          comm (box x y)      == (box y x :: Fold (Int, Int))+    test "box x y               ~~ box y x" $ mapSize (min 10) $ \(x :: F) (y :: F) ->+          comm (box x y)        == (box y x :: Fold (Int, Int)) -    test "box x (overlay y z) == overlay (box x y) (box x z)" $ mapSize (min 10) $ \(x :: F) (y :: F) z ->-          box x (overlay y z) == (overlay (box x y) (box x z) :: Fold (Int, Int))+    test "box x (overlay y z)   == overlay (box x y) (box x z)" $ mapSize (min 10) $ \(x :: F) (y :: F) z ->+          box x (overlay y z)   == (overlay (box x y) (box x z) :: Fold (Int, Int)) -    test "box x (vertex ())   ~~ x" $ mapSize (min 10) $ \(x :: F) ->-     unit(box x (vertex ()))  == x+    test "box x (vertex ())     ~~ x" $ mapSize (min 10) $ \(x :: F) ->+     unit(box x (vertex ()))    == x -    test "box x empty         ~~ empty" $ mapSize (min 10) $ \(x :: F) ->-     unit(box x empty)        == empty+    test "box x empty           ~~ empty" $ mapSize (min 10) $ \(x :: F) ->+     unit(box x empty)          == empty      let assoc = fmap $ \(a, (b, c)) -> ((a, b), c)-    test "box x (box y z)     ~~ box (box x y) z" $ mapSize (min 10) $ \(x :: F) (y :: F) (z :: F) ->-      assoc (box x (box y z)) == (box (box x y) z :: Fold ((Int, Int), Int))+    test "box x (box y z)       ~~ box (box x y) z" $ mapSize (min 10) $ \(x :: F) (y :: F) (z :: F) ->+      assoc (box x (box y z))   == (box (box x y) z :: Fold ((Int, Int), Int))      test "transpose   (box x y) == box (transpose x) (transpose y)" $ mapSize (min 10) $ \(x :: F) (y :: F) ->           transpose   (box x y) == (box (transpose x) (transpose y) :: Fold (Int, Int))
test/Algebra/Graph/Test/Generic.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.Generic--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -12,20 +12,27 @@ module Algebra.Graph.Test.Generic (     -- * Generic tests     Testsuite, testsuite, HTestsuite, hTestsuite, testShow, testFromAdjacencyList,-    testBasicPrimitives, testFoldg, testIsSubgraphOf, testSize, testProperties,+    testBasicPrimitives, testToGraph, testIsSubgraphOf, testSize, testProperties,     testAdjacencyList, testPreSet, testPostSet, testPostIntSet, testGraphFamilies,     testTransformations, testDfsForest, testDfsForestFrom, testDfs, testTopSort,     testIsTopSort, testSplitVertex, testBind, testSimplify   ) where -import Data.Foldable-import Data.List (nub, sort)+import Prelude ()+import Prelude.Compat++import Control.Monad (when)+import Data.Orphans ()++import Data.Foldable (toList)+import Data.List (nub) import Data.Tree import Data.Tuple  import Algebra.Graph.Class (Graph (..)) import Algebra.Graph.Test import Algebra.Graph.Test.API+import Algebra.Graph.Relation (Relation)  import qualified Data.Set    as Set import qualified Data.IntSet as IntSet@@ -56,8 +63,7 @@                               , testVertices                               , testEdges                               , testOverlays-                              , testConnects-                              , testGraph ]+                              , testConnects ]  testProperties :: Testsuite -> IO () testProperties = mconcat [ testIsEmpty@@ -77,6 +83,7 @@                             , testClique                             , testBiclique                             , testStar+                            , testStarTranspose                             , testTree                             , testForest ] @@ -92,23 +99,23 @@ testShow :: Testsuite -> IO () testShow (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "Show ============"-    test "show (empty     :: IntAdjacencyMap) == \"empty\"" $-          show % empty                        == "empty"+    test "show (empty    ) == \"empty\"" $+          show % empty     ==  "empty" -    test "show (1         :: IntAdjacencyMap) == \"vertex 1\"" $-          show % 1                            == "vertex 1"+    test "show (1        ) == \"vertex 1\"" $+          show % 1         ==  "vertex 1" -    test "show (1 + 2     :: IntAdjacencyMap) == \"vertices [1,2]\"" $-          show % (1 + 2)                      == "vertices [1,2]"+    test "show (1 + 2    ) == \"vertices [1,2]\"" $+          show % (1 + 2)   ==  "vertices [1,2]" -    test "show (1 * 2     :: IntAdjacencyMap) == \"edge 1 2\"" $-          show % (1 * 2)                      == "edge 1 2"+    test "show (1 * 2    ) == \"edge 1 2\"" $+          show % (1 * 2)   ==  "edge 1 2" -    test "show (1 * 2 * 3 :: IntAdjacencyMap) == \"edges [(1,2),(1,3),(2,3)]\"" $-          show % (1 * 2 * 3)                  == "edges [(1,2),(1,3),(2,3)]"+    test "show (1 * 2 * 3) == \"edges [(1,2),(1,3),(2,3)]\"" $+          show % (1 * 2 * 3) == "edges [(1,2),(1,3),(2,3)]" -    test "show (1 * 2 + 3 :: IntAdjacencyMap) == \"graph [1,2,3] [(1,2)]\"" $-          show % (1 * 2 + 3)                  == "graph [1,2,3] [(1,2)]"+    test "show (1 * 2 + 3) == \"overlay (vertex 3) (edge 1 2)\"" $+          show % (1 * 2 + 3) == "overlay (vertex 3) (edge 1 2)"  testEmpty :: Testsuite -> IO () testEmpty (Testsuite prefix (%)) = do@@ -134,9 +141,6 @@     test "hasVertex x (vertex x) == True" $ \x ->           hasVertex x % vertex x == True -    test "hasVertex 1 (vertex 2) == False" $-          hasVertex 1 % vertex 2 == False-     test "vertexCount (vertex x) == 1" $ \x ->           vertexCount % vertex x == 1 @@ -147,46 +151,46 @@ testEdge (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "edge ============"     test "edge x y               == connect (vertex x) (vertex y)" $ \x y ->-          edge x y               == connect (vertex x) % (vertex y)+          edge x y               == connect (vertex x) % vertex y      test "hasEdge x y (edge x y) == True" $ \x y ->-          hasEdge x y % (edge x y) == True+          hasEdge x y % edge x y == True      test "edgeCount   (edge x y) == 1" $ \x y ->-          edgeCount % (edge x y) == 1+          edgeCount %  edge x y  == 1      test "vertexCount (edge 1 1) == 1" $-          vertexCount % (edge 1 1) == 1+          vertexCount % edge 1 1 == 1      test "vertexCount (edge 1 2) == 2" $-          vertexCount % (edge 1 2) == 2+          vertexCount % edge 1 2 == 2  testOverlay :: Testsuite -> IO () testOverlay (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "overlay ============"     test "isEmpty     (overlay x y) == isEmpty   x   && isEmpty   y" $ \x y ->-          isEmpty   % (overlay x y) == (isEmpty   x   && isEmpty   y)+          isEmpty   %  overlay x y  == (isEmpty  x   && isEmpty   y)      test "hasVertex z (overlay x y) == hasVertex z x || hasVertex z y" $ \x y z ->-          hasVertex z % (overlay x y) == (hasVertex z x || hasVertex z y)+          hasVertex z % overlay x y == (hasVertex z x || hasVertex z y)      test "vertexCount (overlay x y) >= vertexCount x" $ \x y ->-          vertexCount % (overlay x y) >= vertexCount x+          vertexCount % overlay x y >= vertexCount x      test "vertexCount (overlay x y) <= vertexCount x + vertexCount y" $ \x y ->-          vertexCount % (overlay x y) <= vertexCount x + vertexCount y+          vertexCount % overlay x y <= vertexCount x + vertexCount y      test "edgeCount   (overlay x y) >= edgeCount x" $ \x y ->-          edgeCount % (overlay x y) >= edgeCount x+          edgeCount %  overlay x y  >= edgeCount x      test "edgeCount   (overlay x y) <= edgeCount x   + edgeCount y" $ \x y ->-          edgeCount % (overlay x y) <= edgeCount x   + edgeCount y+          edgeCount %  overlay x y  <= edgeCount x   + edgeCount y      test "vertexCount (overlay 1 2) == 2" $-          vertexCount % (overlay 1 2) == 2+          vertexCount % overlay 1 2 == 2      test "edgeCount   (overlay 1 2) == 0" $-          edgeCount % (overlay 1 2) == 0+          edgeCount %  overlay 1 2  == 0  testConnect :: Testsuite -> IO () testConnect (Testsuite prefix (%)) = do@@ -263,6 +267,9 @@     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 ->+          overlays xs        == id % foldr overlay empty xs+     test "isEmpty . overlays == all isEmpty" $ mapSize (min 10) $ \xs ->           isEmpty % overlays xs == all isEmpty xs @@ -278,24 +285,12 @@     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 ->+          connects xs        == id % foldr connect empty xs+     test "isEmpty . connects == all isEmpty" $ mapSize (min 10) $ \xs ->           isEmpty % connects xs == all isEmpty xs -testGraph :: Testsuite -> IO ()-testGraph (Testsuite prefix (%)) = do-    putStrLn $ "\n============ " ++ prefix ++ "graph ============"-    test "graph []  []      == empty" $-          graph []  []      == id % empty--    test "graph [x] []      == vertex x" $ \x ->-          graph [x] []      == id % vertex x--    test "graph []  [(x,y)] == edge x y" $ \x y ->-          graph []  [(x,y)] == id % edge x y--    test "graph vs  es      == overlay (vertices vs) (edges es)" $ \vs es ->-          graph vs  es      == overlay (vertices vs) % edges es- testFromAdjacencyList :: Testsuite -> IO () testFromAdjacencyList (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "fromAdjacencyList ============"@@ -314,8 +309,18 @@     test "overlay (fromAdjacencyList xs) (fromAdjacencyList ys) == fromAdjacencyList (xs ++ ys)" $ \xs ys ->           overlay (fromAdjacencyList xs) % fromAdjacencyList ys == fromAdjacencyList (xs ++ ys) -testFoldg :: HTestsuite -> IO ()-testFoldg (HTestsuite prefix (%)) = do+testToGraph :: HTestsuite -> IO ()+testToGraph (HTestsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "toGraph ============"+    test "      toGraph (g     :: Graph a  ) :: Graph a       == g" $ \g ->+                toGraph % g                                   == g++    test "show (toGraph (1 * 2 :: Graph Int) :: Relation Int) == \"edge 1 2\"" $+          show (toGraph % (1 * 2)            :: Relation Int) == "edge 1 2"++    test "\ntoGraph == foldg empty vertex overlay connect" $ \x ->+          toGraph % x == id % foldg empty vertex overlay connect x+     putStrLn $ "\n============ " ++ prefix ++ "foldg ============"     test "foldg empty vertex        overlay connect        == id" $ \x ->           foldg empty vertex        overlay connect x      == id % x@@ -399,8 +404,11 @@           hasVertex x % empty          == False      test "hasVertex x (vertex x)       == True" $ \x ->-          hasVertex x % vertex x     == True+          hasVertex x % vertex x       == True +    test "hasVertex 1 (vertex 2)       == False" $+          hasVertex 1 % vertex 2       == False+     test "hasVertex x . removeVertex x == const False" $ \x y ->          (hasVertex x . removeVertex x) y == const False % y @@ -625,7 +633,7 @@           clique [x,y,z]    == id % edges [(x,y), (x,z), (y,z)]      test "clique (xs ++ ys) == connect (clique xs) (clique ys)" $ \xs ys ->-          clique (xs ++ ys) == connect (clique xs) % (clique ys)+          clique (xs ++ ys) == connect (clique xs) % clique ys  testBiclique :: Testsuite -> IO () testBiclique (Testsuite prefix (%)) = do@@ -639,11 +647,11 @@     test "biclique []      [y]     == vertex y" $ \y ->           biclique []      [y]     == id % vertex y -    test "biclique [x1,x2] [y1,y2] == edges [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]" $ \(x1) x2 y1 y2 ->+    test "biclique [x1,x2] [y1,y2] == edges [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]" $ \x1 x2 y1 y2 ->           biclique [x1,x2] [y1,y2] == id % edges [(x1,y1), (x1,y2), (x2,y1), (x2,y2)]      test "biclique xs      ys      == connect (vertices xs) (vertices ys)" $ \xs ys ->-          biclique xs      ys      == connect (vertices xs) % (vertices ys)+          biclique xs      ys      == connect (vertices xs) % vertices ys  testStar :: Testsuite -> IO () testStar (Testsuite prefix (%)) = do@@ -657,6 +665,27 @@     test "star x [y,z] == edges [(x,y), (x,z)]" $ \x y z ->           star x [y,z] == id % edges [(x,y), (x,z)] +    test "star x ys    == connect (vertex x) (vertices ys)" $ \x ys ->+          star x ys    == connect (vertex x) % (vertices ys)++testStarTranspose :: Testsuite -> IO ()+testStarTranspose (Testsuite prefix (%)) = do+    putStrLn $ "\n============ " ++ prefix ++ "starTranspose ============"+    test "starTranspose x []    == vertex x" $ \x ->+          starTranspose x []    == id % vertex x++    test "starTranspose x [y]   == edge y x" $ \x y ->+          starTranspose x [y]   == id % edge y x++    test "starTranspose x [y,z] == edges [(y,x), (z,x)]" $ \x y z ->+          starTranspose x [y,z] == id % edges [(y,x), (z,x)]++    test "starTranspose x ys    == connect (vertices ys) (vertex x)" $ \x ys ->+          starTranspose x ys    == connect (vertices ys) % (vertex x)++    test "starTranspose x ys    == transpose (star x ys)" $ \x ys ->+          starTranspose x ys    == transpose % (star x ys)+ testTree :: Testsuite -> IO () testTree (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "tree ============"@@ -685,7 +714,7 @@           forest [Node 1 [Node 2 [], Node 3 []], Node 4 [Node 5 []]] == id % edges [(1,2), (1,3), (4,5)]      test "forest                                                     == overlays . map tree" $ \x ->-         (forest x)                                                  == id % (overlays . map tree) x+          forest x                                                   == id % (overlays . map tree) x  testRemoveVertex :: Testsuite -> IO () testRemoveVertex (Testsuite prefix (%)) = do@@ -693,6 +722,15 @@     test "removeVertex x (vertex x)       == empty" $ \x ->           removeVertex x % vertex x       == empty +    test "removeVertex 1 (vertex 2)       == vertex 2" $+          removeVertex 1 % (vertex 2)     == vertex 2++    test "removeVertex x (edge x x)       == empty" $ \x ->+          removeVertex x % (edge x x)     == empty++    test "removeVertex 1 (edge 1 2)       == vertex 2" $+          removeVertex 1 % (edge 1 2)     == vertex 2+     test "removeVertex x . removeVertex x == removeVertex x" $ \x y ->          (removeVertex x . removeVertex x) y == removeVertex x % y @@ -714,6 +752,11 @@     test "removeEdge 1 2 (1 * 1 * 2 * 2)  == 1 * 1 + 2 * 2" $           removeEdge 1 2 % (1 * 1 * 2 * 2) == 1 * 1 + 2 * 2 +    -- TODO: Ouch. Generic tests are becoming awkward. We need a better way.+    when (prefix == "Fold." || prefix == "Graph.") $ do+        test "size (removeEdge x y z)         <= 3 * size z" $ \x y z ->+              size % (removeEdge x y z)       <= 3 * size z+ testReplaceVertex :: Testsuite -> IO () testReplaceVertex (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "replaceVertex ============"@@ -748,25 +791,16 @@           transpose % empty     == empty      test "transpose (vertex x)  == vertex x" $ \x ->-          transpose % (vertex x) == vertex x+          transpose % vertex x  == vertex x      test "transpose (edge x y)  == edge y x" $ \x y ->-          transpose % (edge x y) == edge y x+          transpose % edge x y  == edge y x -    test "transpose . transpose == id" $ \x ->+    test "transpose . transpose == id" $ mapSize (min 10) $ \x ->          (transpose . transpose) % x == x -    test "transpose . path      == path    . reverse" $ \xs ->-          transpose % (path xs) == (path . reverse) xs--    test "transpose . circuit   == circuit . reverse" $ \xs ->-          transpose % (circuit xs) == (circuit . reverse) xs--    test "transpose . clique    == clique  . reverse" $ \xs ->-          transpose % (clique xs) == (clique . reverse) xs-     test "edgeList . transpose  == sort . map swap . edgeList" $ \x ->-          edgeList % (transpose x) == (sort . map swap . edgeList) x+          edgeList % transpose x == (sort . map swap . edgeList) x  testGmap :: Testsuite -> IO () testGmap (Testsuite prefix (%)) = do@@ -789,8 +823,8 @@ testInduce :: Testsuite -> IO () testInduce (Testsuite prefix (%)) = do     putStrLn $ "\n============ " ++ prefix ++ "induce ============"-    test "induce (const True)  x      == x" $ \x ->-          induce (const True) % x     == x+    test "induce (const True ) x      == x" $ \x ->+          induce (const True ) % x    == x      test "induce (const False) x      == empty" $ \x ->           induce (const False) % x    == empty@@ -829,7 +863,7 @@           bind (vertex x) f    == id % f x      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)+          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) ->           bind (vertices xs) f == id % overlays (map f xs)@@ -869,10 +903,10 @@           isSubgraphOf (forest $ dfsForest x) % x == True      test "dfsForest . forest . dfsForest        == dfsForest" $ \x ->-          dfsForest % (forest $ dfsForest x)    == dfsForest % x+          dfsForest % forest (dfsForest x)      == dfsForest % x      test "dfsForest (vertices vs)               == map (\\v -> Node v []) (nub $ sort vs)" $ \vs ->-          dfsForest % (vertices vs)             == map (\v -> Node v []) (nub $ sort vs)+          dfsForest % vertices vs               == map (\v -> Node v []) (nub $ sort vs)      test "dfsForest $ 3 * (1 + 4) * (1 + 5)     == <correct result>" $           dfsForest % (3 * (1 + 4) * (1 + 5))   == [ Node { rootLabel = 1@@ -907,7 +941,7 @@           dfsForestFrom (vertexList x) % x             == dfsForest % x      test "dfsForestFrom vs             (vertices vs)   == map (\\v -> Node v []) (nub vs)" $ \vs ->-          dfsForestFrom vs           % (vertices vs)   == map (\v -> Node v []) (nub vs)+          dfsForestFrom vs           %  vertices vs    == map (\v -> Node v []) (nub vs)      test "dfsForestFrom []             x               == []" $ \x ->           dfsForestFrom []           % x               == []
test/Algebra/Graph/Test/Graph.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.Graph--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -24,16 +24,16 @@ h :: HTestsuite h = hTestsuite "Graph." empty -type G  = Graph Int+type G = Graph Int  testGraph :: IO () testGraph = do     putStrLn "\n============ Graph ============"-    test "Axioms of graphs"   $ (axioms   :: GraphTestsuite G)-    test "Theorems of graphs" $ (theorems :: GraphTestsuite G)+    test "Axioms of graphs"   (axioms   :: GraphTestsuite G)+    test "Theorems of graphs" (theorems :: GraphTestsuite G)      testBasicPrimitives t-    testFoldg           h+    testToGraph         h     testIsSubgraphOf    t     testSize            t     testProperties      t@@ -69,8 +69,8 @@     test "mesh xs     ys   == box (path xs) (path ys)" $ \(xs :: [Int]) (ys :: [Int]) ->           mesh xs     ys   == box (path xs) (path ys) -    test ("mesh [1..3] \"ab\" == <correct result>") $-         mesh [1..3] "ab"  == edges [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a')), ((1,'b'),(2,'b')), ((2,'a'),(2,'b'))+    test "mesh [1..3] \"ab\" == <correct result>" $+          mesh [1..3]  "ab"  == edges [ ((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')) ]      putStrLn "\n============ Graph.torus ============"@@ -86,9 +86,9 @@     test "torus xs    ys   == box (circuit xs) (circuit ys)" $ \(xs :: [Int]) (ys :: [Int]) ->           torus xs    ys   == box (circuit xs) (circuit ys) -    test ("torus [1,2] \"ab\" == <correct result>") $-         torus [1,2] "ab"  == edges [ ((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 "torus [1,2] \"ab\" == <correct result>" $+          torus [1,2]  "ab"  == edges [ ((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')) ]      putStrLn "\n============ Graph.deBruijn ============"     test "          deBruijn 0 xs               == edge [] []" $ \(xs :: [Int]) ->@@ -108,7 +108,7 @@                                                          , ("10","00"), ("10","01"), ("11","10"), ("11","11") ]      test "          transpose   (deBruijn n xs) == fmap reverse $ deBruijn n xs" $ mapSize (min 5) $ \(NonNegative n) (xs :: [Int]) ->-                    transpose   (deBruijn n xs) == (fmap reverse $ deBruijn n xs)+                    transpose   (deBruijn n xs) == fmap reverse (deBruijn n xs)      test "          vertexCount (deBruijn n xs) == (length $ nub xs)^n" $ mapSize (min 5) $ \(NonNegative n) (xs :: [Int]) ->                     vertexCount (deBruijn n xs) == (length $ nubOrd xs)^n
test/Algebra/Graph/Test/IntAdjacencyMap.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.IntAdjacencyMap--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -27,7 +27,7 @@ testIntAdjacencyMap :: IO () testIntAdjacencyMap = do     putStrLn "\n============ IntAdjacencyMap ============"-    test "Axioms of graphs" $ (axioms :: GraphTestsuite IntAdjacencyMap)+    test "Axioms of graphs" (axioms :: GraphTestsuite IntAdjacencyMap)      test "Consistency of arbitraryAdjacencyMap" $ \m ->         consistent m
+ test/Algebra/Graph/Test/Internal.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE CPP, OverloadedLists #-}+-----------------------------------------------------------------------------+-- |+-- Module     : Algebra.Graph.Test.Internal+-- Copyright  : (c) Andrey Mokhov 2016-2018+-- License    : MIT (see the file LICENSE)+-- Maintainer : andrey.mokhov@gmail.com+-- Stability  : experimental+--+-- Testsuite for "Algebra.Graph.Internal".+-----------------------------------------------------------------------------+module Algebra.Graph.Test.Internal (+    -- * Testsuite+    testInternal+  ) where++import Prelude ()+import Prelude.Compat++#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup+#endif++import Control.Applicative (pure)++import Algebra.Graph.Internal+import Algebra.Graph.Test++testInternal :: IO ()+testInternal = do+    putStrLn "\n============ Internal.List ============"+    test "pure 1 <> pure 4 == [1, 4]" $+          pure 1 <> pure 4 == ([1, 4] :: List Int)
+ test/Algebra/Graph/Test/NonEmptyGraph.hs view
@@ -0,0 +1,635 @@+{-# 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.List.NonEmpty (NonEmpty (..))+import Data.Maybe+import Data.Tree+import Data.Tuple++import Algebra.Graph.NonEmpty+import Algebra.Graph.Test hiding (axioms, theorems)++import qualified Algebra.Graph       as G+import qualified Algebra.Graph.Class as C+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 (C.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.starTranspose ============"+    test "starTranspose x []    == vertex x" $ \(x :: Int) ->+          starTranspose x []    == vertex x++    test "starTranspose x [y]   == edge y x" $ \(x :: Int) y ->+          starTranspose x [y]   == edge y x++    test "starTranspose x [y,z] == edges1 ((y,x) :| [(z,x)])" $ \(x :: Int) y z ->+          starTranspose x [y,z] == edges1 ((y,x) :| [(z,x)])++    test "starTranspose x ys    == transpose (star x ys)" $ \(x :: Int) ys ->+          starTranspose x ys    == transpose (star x 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')) ])++    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')) ])++    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
test/Algebra/Graph/Test/Relation.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module     : Algebra.Graph.Test.Relation--- Copyright  : (c) Andrey Mokhov 2016-2017+-- Copyright  : (c) Andrey Mokhov 2016-2018 -- License    : MIT (see the file LICENSE) -- Maintainer : andrey.mokhov@gmail.com -- Stability  : experimental@@ -36,7 +36,7 @@ testRelation :: IO () testRelation = do     putStrLn "\n============ Relation ============"-    test "Axioms of graphs" $ sizeLimit $ (axioms :: GraphTestsuite RI)+    test "Axioms of graphs" $ sizeLimit (axioms :: GraphTestsuite RI)      test "Consistency of arbitraryRelation" $ \(m :: RI) ->         consistent m@@ -100,7 +100,7 @@           transitiveClosure (vertex x)      == vertex x      test "transitiveClosure (path $ nub xs) == clique (nub $ xs)" $ \(xs :: [Int]) ->-          transitiveClosure (path $ nubOrd xs) == clique (nubOrd $ xs)+          transitiveClosure (path $ nubOrd xs) == clique (nubOrd xs)      putStrLn "\n============ Relation.preorderClosure ============"     test "preorderClosure empty           == empty" $@@ -122,7 +122,7 @@      putStrLn "\n============ SymmetricRelation.neighbours ============"     test "neighbours x empty      == Set.empty" $ \(x :: Int) ->-          neighbours x C.empty      == Set.empty+          neighbours x C.empty    == Set.empty      test "neighbours x (vertex x) == Set.empty" $ \(x :: Int) ->           neighbours x (C.vertex x) == Set.empty
test/Main.hs view
@@ -3,6 +3,8 @@ import Algebra.Graph.Test.Fold import Algebra.Graph.Test.Graph import Algebra.Graph.Test.IntAdjacencyMap+import Algebra.Graph.Test.Internal+import Algebra.Graph.Test.NonEmptyGraph import Algebra.Graph.Test.Relation  main :: IO ()@@ -11,5 +13,7 @@     testExport     testFold     testGraph+    testGraphNonEmpty     testIntAdjacencyMap+    testInternal     testRelation