packages feed

algebraic-graphs-0.8: test/Algebra/Graph/Test/RewriteRules.hs

{-# LANGUAGE TemplateHaskell #-}
-----------------------------------------------------------------------------
-- |
-- Module     : Algebra.Graph.Test.RewriteRules
-- Copyright  : (c) Andrey Mokhov 2016-2025
-- License    : MIT (see the file LICENSE)
-- Maintainer : andrey.mokhov@gmail.com
-- Stability  : experimental
--
-- Testsuite for "Algebra.Graph" rewrite rules.
-----------------------------------------------------------------------------
module Algebra.Graph.Test.RewriteRules where

import Data.Maybe (fromMaybe)

import qualified Algebra.Graph.AdjacencyMap as AM
import qualified Data.Set                   as Set

import Algebra.Graph hiding ((===))
import Algebra.Graph.Internal

import GHC.Base (build)

import Test.Inspection

type Build  a = forall b. (a -> b -> b) -> b -> b
type Buildg a = forall b. b -> (a -> b) -> (b -> b ->b ) -> (b -> b-> b) -> b

{- We suffix various values using the following convention:

   * "R": the desired outcome of a rewrite rule
   * "C": the "good consumer" property
   * "P": the "good producer" property
   * "I": inlining
   * "T": specialisation for a type
-}

-- 'foldg'
emptyI, emptyIR :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> b
emptyI  e v o c = foldg e v o c Empty
emptyIR e _ _ _ = e

inspect $ 'emptyI === 'emptyIR

vertexI, vertexIR :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> a -> b
vertexI  e v o c x = foldg e v o c (Vertex x)
vertexIR _ v _ _ x = v x

inspect $ 'vertexI === 'vertexIR

overlayI, overlayIR ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> Graph a -> b
overlayI  e v o c x y = foldg e v o c (Overlay x y)
overlayIR e v o c x y = o (foldg e v o c x) (foldg e v o c y)

inspect $ 'overlayI === 'overlayIR

connectI, connectIR ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> Graph a -> b
connectI  e v o c x y = foldg e v o c (Connect x y)
connectIR e v o c x y = c (foldg e v o c x) (foldg e v o c y)

inspect $ 'connectI === 'connectIR

-- overlays
overlaysC :: Build (Graph a) -> Graph a
overlaysC xs = overlays (build xs)

inspect $ 'overlaysC `hasNoType` ''[]

overlaysP, overlaysPR ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> [Graph a] -> b
overlaysP  e v o c xs = foldg e v o c (overlays xs)
overlaysPR e v o c xs = fromMaybe e (foldr (maybeF o . foldg e v o c) Nothing xs)

inspect $ 'overlaysP === 'overlaysPR

-- vertices
verticesCP :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Build a -> b
verticesCP e v o c xs = foldg e v o c (vertices (build xs))

inspect $ 'verticesCP `hasNoType` ''[]
inspect $ 'verticesCP `hasNoType` ''Graph

-- connects
connectsC :: Build (Graph a) -> Graph a
connectsC xs = connects (build xs)

inspect $ 'connectsC `hasNoType` ''[]

connectsP, connectsPR ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> [Graph a] -> b
connectsP  e v o c xs = foldg e v o c (connects xs)
connectsPR e v o c xs = fromMaybe e (foldr (maybeF c . foldg e v o c) Nothing xs)

inspect $ 'connectsP === 'connectsPR

-- isSubgraphOf
isSubgraphOfC :: Ord a => Buildg a -> Buildg a -> Bool
isSubgraphOfC x y = isSubgraphOf (buildg x) (buildg y)

inspect $ 'isSubgraphOfC `hasNoType` ''Graph

-- clique
cliqueCP :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Build a -> b
cliqueCP e v o c xs = foldg e v o c (clique (build xs))

inspect $ 'cliqueCP `hasNoType` ''[]
inspect $ 'cliqueCP `hasNoType` ''Graph

-- edges
edgesCP :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Build (a,a) -> b
edgesCP e v o c xs = foldg e v o c (edges (build xs))

inspect $ 'edgesCP `hasNoType` ''[]
inspect $ 'edgesCP `hasNoType` ''Graph

-- star
starCP :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> a -> Build a -> b
starCP e v o c x xs = foldg e v o c (star x (build xs))

inspect $ 'starCP `hasNoType` ''[]
inspect $ 'starCP `hasNoType` ''Graph

-- fmap
fmapCP ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> (c -> a) -> Buildg c -> b
fmapCP  e v o c f g = foldg e v o c (fmap f (buildg g))

inspect $ 'fmapCP `hasNoType` ''Graph

-- bind
bindC, bindCR :: (a -> Graph b) -> Buildg a -> Graph b
bindC  f g = (buildg g) >>= f
bindCR f g = g Empty (\x -> f x) Overlay Connect

inspect $ 'bindC === 'bindCR

bindP, bindPR ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> (c -> Graph a) -> Graph c -> b
bindP  e v o c f g = foldg e v o c (g >>= f)
bindPR e v o c f g = foldg e (foldg e v o c . f) o c g

inspect $ 'bindP === 'bindPR

-- ap
apC, apCR :: Buildg (a -> b) -> Graph a -> Graph b
apC  f x = buildg f <*> x
apCR f x = f Empty (\v -> foldg Empty (Vertex . v) Overlay Connect x) Overlay Connect

inspect $ 'apC === 'apCR

apP, apPR ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph (c -> a) -> Graph c -> b
apP  e v o c f x = foldg e v o c (f <*> x)
apPR e v o c f x =
  foldg e (\w -> foldg e (v . w) o c x) o c f

inspect $ 'apP === 'apPR

-- eq
eqC :: Ord a => Buildg a -> Buildg a -> Bool
eqC x y = buildg x == buildg y

inspect $ 'eqC `hasNoType` ''Graph

eqT :: Graph Int -> Graph Int -> Bool
eqT x y = x == y

inspect $ 'eqT `hasNoType` ''AM.AdjacencyMap

-- ord
ordC :: Ord a => Buildg a -> Buildg a -> Ordering
ordC x y = compare (buildg x) (buildg y)

inspect $ 'ordC `hasNoType` ''Graph

ordT :: Graph Int -> Graph Int -> Ordering
ordT x y = compare x y

inspect $ 'ordT  `hasNoType` ''AM.AdjacencyMap

-- isEmpty
isEmptyC :: Buildg a -> Bool
isEmptyC g = isEmpty (buildg g)

inspect $ 'isEmptyC `hasNoType` ''Graph

-- size
sizeC :: Buildg a -> Int
sizeC g = size (buildg g)

inspect $ 'sizeC `hasNoType` ''Graph

-- vertexSet
vertexSetC :: Ord a => Buildg a -> Set.Set a
vertexSetC g = vertexSet (buildg g)

inspect $ 'vertexSetC `hasNoType` ''Graph

-- vertexCount
vertexCountC :: Ord a => Buildg a -> Int
vertexCountC g = vertexCount (buildg g)

inspect $ 'vertexSetC `hasNoType` ''Graph

vertexCountT :: Graph Int -> Int
vertexCountT g = vertexCount g

inspect $ 'vertexCountT  `hasNoType` ''Set.Set

-- edgeCount
edgeCountC :: Ord a => Buildg a -> Int
edgeCountC g = edgeCount (buildg g)

inspect $ 'edgeCountC `hasNoType` ''Graph

edgeCountT :: Graph Int -> Int
edgeCountT g = edgeCount g

inspect $ 'edgeCountT `hasNoType` ''Set.Set

-- vertexList
vertexListCP :: Ord a => (a -> b -> b) -> b -> Buildg a -> b
vertexListCP k c g = foldr k c (vertexList (buildg g))

inspect $ 'vertexListCP `hasNoType` ''Graph
inspect $ 'vertexListCP `hasNoType` ''[]

vertexListT :: Graph Int -> [Int]
vertexListT g = vertexList g

inspect $ 'vertexListT `hasNoType` ''Set.Set

-- edgeSet
edgeSetC :: Ord a => Buildg a -> Set.Set (a,a)
edgeSetC g = edgeSet (buildg g)

inspect $ 'edgeSetC `hasNoType` ''Graph

edgeSetT :: Graph Int -> Set.Set (Int,Int)
edgeSetT g = edgeSet g

inspect $ 'vertexListT `hasNoType` ''AM.AdjacencyMap

-- edgeList
edgeListCP :: Ord a => ((a,a) -> b -> b) -> b -> Buildg a -> b
edgeListCP k c g = foldr k c (edgeList (buildg g))

inspect $ 'edgeListCP `hasNoType` ''Graph
inspect $ 'edgeListCP `hasNoType` ''[]

edgeListT :: Graph Int -> [(Int,Int)]
edgeListT g = edgeList g

inspect $ 'edgeListT `hasNoType` ''AM.AdjacencyMap

-- hasVertex
hasVertexC :: Eq a => a -> Buildg a -> Bool
hasVertexC x g = hasVertex x (buildg g)

inspect $ 'hasVertexC `hasNoType` ''Graph

-- hasEdge
hasEdgeC :: Eq a => a -> a -> Buildg a -> Bool
hasEdgeC x y g = hasEdge x y (buildg g)

inspect $ 'hasEdgeC `hasNoType` ''Graph

-- adjacencyList
adjacencyListC :: Ord a => Buildg a -> [(a, [a])]
adjacencyListC g = adjacencyList (buildg g)

inspect $ 'adjacencyListC `hasNoType` ''Graph

-- path
pathP :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> [a] -> b
pathP e v o c xs = foldg e v o c (path xs)

inspect $ 'pathP `hasNoType` ''Graph

-- circuit
circuitP :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> [a] -> b
circuitP e v o c xs = foldg e v o c (circuit xs)

inspect $ 'circuitP `hasNoType` ''Graph

-- biclique
bicliqueCP :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Build a -> Build a -> b
bicliqueCP e v o c xs ys = foldg e v o c (biclique (build xs) (build ys))

inspect $ 'bicliqueCP `hasNoType` ''[]
inspect $ 'bicliqueCP `hasNoType` ''Graph

-- replaceVertex
replaceVertexCP :: Eq a => a -> a ->
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Buildg a -> b
replaceVertexCP u v e v' o c g =
  foldg e v' o c (replaceVertex u v (buildg g))

inspect $ 'replaceVertexCP `hasNoType` ''Graph

-- mergeVertices
mergeVerticesCP :: (a -> Bool) -> a ->
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Buildg a -> b
mergeVerticesCP p v e v' o c g =
  foldg e v' o c (mergeVertices p v (buildg g))

inspect $ 'mergeVerticesCP `hasNoType` ''Graph

-- splitVertex
splitVertexCP :: Eq a => a -> Build a ->
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Buildg a -> b
splitVertexCP x us e v o c g = foldg e v o c (splitVertex x (build us) (buildg g))

inspect $ 'splitVertexCP `hasNoType` ''[]
inspect $ 'splitVertexCP `hasNoType` ''Graph

-- transpose
transposeCP ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Buildg a -> b
transposeCP e v o c g = foldg e v o c (transpose (buildg g))

inspect $ 'transposeCP `hasNoType` ''Graph

-- simplify
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

simplifyC, simplifyCR :: Ord a => Buildg a -> Graph a
simplifyC  g = simplify (buildg g)
simplifyCR g = g Empty Vertex (simple Overlay) (simple Connect)

inspect $ 'simplifyC === 'simplifyCR

-- compose
composeCP :: Ord a => b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Buildg a -> Buildg a -> b
composeCP e v o c x y = foldg e v o c $ compose (buildg x) (buildg y)

inspect $ 'composeCP `hasNoType` ''Graph

-- induce
induceCP ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> (a -> Bool) -> Buildg a -> b
induceCP e v o c p g = foldg e v o c (induce p (buildg g))

inspect $ 'induceCP `hasNoType` ''Graph

-- induceJust
induceJustCP ::
  b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Buildg (Maybe a) -> b
induceJustCP e v o c g = foldg e v o c (induceJust (buildg g))

inspect $ 'induceJustCP `hasNoType` ''Graph

-- context
contextC :: (a -> Bool) -> Buildg a -> Maybe (Context a)
contextC p g = context p (buildg g)

inspect $ 'contextC `hasNoType` ''Graph