graph-rewriting 0.4.9 → 0.5
raw patch · 10 files changed
+137/−107 lines, 10 filesdep ~basedep ~containersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, containers
API changes (from Hackage documentation)
+ GraphRewriting.Pattern: amnesia :: Pattern n a -> Pattern n a
+ GraphRewriting.Pattern: instance Monad (Pattern n)
+ GraphRewriting.Pattern: instance MonadPlus (Pattern n)
+ GraphRewriting.Pattern: probe :: Pattern n a -> Pattern n Bool
+ GraphRewriting.Pattern: requireFailure :: Pattern n a -> Pattern n ()
- Data.View: adjust :: (View v n) => (v -> v) -> n -> n
+ Data.View: adjust :: View v n => (v -> v) -> n -> n
- Data.View: examine :: (View v n) => (v -> field) -> n -> field
+ Data.View: examine :: View v n => (v -> field) -> n -> field
- Data.View: inspect :: (View v n) => n -> v
+ Data.View: inspect :: View v n => n -> v
- Data.View: update :: (View v n) => v -> n -> n
+ Data.View: update :: View v n => v -> n -> n
- GraphRewriting.Graph.Read: adverseNodes :: (MonadReader (Graph n) m) => Node -> Port -> m [Node]
+ GraphRewriting.Graph.Read: adverseNodes :: MonadReader (Graph n) m => Node -> Port -> m [Node]
- GraphRewriting.Graph.Read: attachedNodes :: (MonadReader (Graph n) m) => Edge -> m [Node]
+ GraphRewriting.Graph.Read: attachedNodes :: MonadReader (Graph n) m => Edge -> m [Node]
- GraphRewriting.Graph.Read: readEdgeList :: (MonadReader (Graph n) m) => m [Edge]
+ GraphRewriting.Graph.Read: readEdgeList :: MonadReader (Graph n) m => m [Edge]
- GraphRewriting.Graph.Read: readNode :: (MonadReader (Graph n) m) => Node -> m n
+ GraphRewriting.Graph.Read: readNode :: MonadReader (Graph n) m => Node -> m n
- GraphRewriting.Graph.Read: readNodeList :: (MonadReader (Graph n) m) => m [Node]
+ GraphRewriting.Graph.Read: readNodeList :: MonadReader (Graph n) m => m [Node]
- GraphRewriting.Graph.Read: withNodes :: (MonadReader (Graph n) m) => (Node -> m a) -> m [a]
+ GraphRewriting.Graph.Read: withNodes :: MonadReader (Graph n) m => (Node -> m a) -> m [a]
- GraphRewriting.Graph.Write: deleteEdge :: (View [Port] n) => Edge -> Rewrite n [Edge]
+ GraphRewriting.Graph.Write: deleteEdge :: View [Port] n => Edge -> Rewrite n [Edge]
- GraphRewriting.Graph.Write: deleteNode :: (View [Port] n) => Node -> Rewrite n ()
+ GraphRewriting.Graph.Write: deleteNode :: View [Port] n => Node -> Rewrite n ()
- GraphRewriting.Graph.Write: mergeEdges :: (View [Port] n) => Edge -> Edge -> Rewrite n ()
+ GraphRewriting.Graph.Write: mergeEdges :: View [Port] n => Edge -> Edge -> Rewrite n ()
- GraphRewriting.Graph.Write: modifyNode :: (View [Port] n) => Node -> (n -> n) -> Rewrite n ()
+ GraphRewriting.Graph.Write: modifyNode :: View [Port] n => Node -> (n -> n) -> Rewrite n ()
- GraphRewriting.Graph.Write: newNode :: (View [Port] n) => n -> Rewrite n Node
+ GraphRewriting.Graph.Write: newNode :: View [Port] n => n -> Rewrite n Node
- GraphRewriting.Graph.Write: writeNode :: (View [Port] n) => Node -> n -> Rewrite n ()
+ GraphRewriting.Graph.Write: writeNode :: View [Port] n => Node -> n -> Rewrite n ()
- GraphRewriting.Graph.Write.Unsafe: adjustNode :: (View v n) => (v -> v) -> Node -> Rewrite n ()
+ GraphRewriting.Graph.Write.Unsafe: adjustNode :: View v n => (v -> v) -> Node -> Rewrite n ()
- GraphRewriting.Graph.Write.Unsafe: updateNode :: (View v n) => v -> Node -> Rewrite n ()
+ GraphRewriting.Graph.Write.Unsafe: updateNode :: View v n => v -> Node -> Rewrite n ()
- GraphRewriting.Pattern: edgeOf :: (View [Port] n) => Node -> Pattern n Edge
+ GraphRewriting.Pattern: edgeOf :: View [Port] n => Node -> Pattern n Edge
- GraphRewriting.Pattern: node :: (View v n) => Pattern n v
+ GraphRewriting.Pattern: node :: View v n => Pattern n v
- GraphRewriting.Pattern: nodeAt :: (View v n) => Edge -> Pattern n v
+ GraphRewriting.Pattern: nodeAt :: View v n => Edge -> Pattern n v
- GraphRewriting.Pattern: require :: (Monad m) => Bool -> m ()
+ GraphRewriting.Pattern: require :: Monad m => Bool -> m ()
- GraphRewriting.Pattern: requireM :: (Monad m) => m Bool -> m ()
+ GraphRewriting.Pattern: requireM :: Monad m => m Bool -> m ()
- GraphRewriting.Pattern.InteractionNet: principalPort :: (INet v) => v -> Int
+ GraphRewriting.Pattern.InteractionNet: principalPort :: INet v => v -> Int
- GraphRewriting.Rule: apply :: Rule n -> Rewrite n [Node]
+ GraphRewriting.Rule: apply :: Rule n -> Rewrite n ()
- GraphRewriting.Rule: erase :: (View [Port] n) => Rule n
+ GraphRewriting.Rule: erase :: View [Port] n => Rule n
- GraphRewriting.Rule: rewire :: (View [Port] n) => [[Edge]] -> Rule n
+ GraphRewriting.Rule: rewire :: View [Port] n => [[Edge]] -> Rule n
- GraphRewriting.Rule: rewrite :: (Match -> Rewrite n [Node]) -> Rule n
+ GraphRewriting.Rule: rewrite :: (Match -> Rewrite n a) -> Rule n
- GraphRewriting.Rule: type Rule n = Pattern n (Rewrite n [Node])
+ GraphRewriting.Rule: type Rule n = Pattern n (Rewrite n ())
Files
- Data/View.hs +1/−0
- GraphRewriting.hs +15/−13
- GraphRewriting/Graph/Internal.hs +1/−0
- GraphRewriting/Graph/Read.hs +2/−0
- GraphRewriting/Graph/Write.hs +1/−1
- GraphRewriting/Pattern.hs +51/−20
- GraphRewriting/Pattern/Internal.hs +10/−13
- GraphRewriting/Rule.hs +23/−31
- GraphRewriting/Rule/Internal.hs +2/−0
- graph-rewriting.cabal +31/−29
Data/View.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE UnicodeSyntax, MultiParamTypeClasses #-} -- | The multi-parameter type-class 'View' provides an abstraction @View v n@ of a type @n@ that exposes a value of type @v@. It allows both to 'inspect' and 'update' the value, while hiding the internal structure of the value type (@n@). module Data.View where
GraphRewriting.hs view
@@ -1,27 +1,29 @@--- | This is a monadic graph rewriting library for port (hyper)graphs with a strong emphasis on nodes. It aims primarily at making it as convenient as possible to specify graph rewriting systems in Haskell and to experiment with them. There are a few aspects of the design to be pointed out:+-- | This is a monadic graph rewriting library for port graphs with a strong emphasis on nodes. It aims primarily at making it as convenient as possible to specify graph rewriting systems in Haskell and to experiment with them. There are a few aspects of the design to be pointed out: ----- 1. The graph structure is essentially representated as a collection of nodes. The nodes have a user-defined type, where each node features a list of 'Port's to each of which an 'Edge' is attached. Edges are unlabeled and can not exist autonomously, i.e. each edge is connected to at least one port. Two ports are connected if (and only if) they share the same edge. What is particularly convenient is how these ports can be modeled as constructor fields of a user-defined node type.+-- 1. The port graph is actually a hypergraph, therefore if we speak of edges we are in fact referring hyperedges. ----- 2. An important abstraction used in this library is the multi-parameter type-class 'View'. It permits to expose a certain aspect of a node, allowing both to 'inspect' or 'update' it, while hiding the internal representation of the node. By that it is easy to specify the rewrite system in a way, that it can not only be applied to a graph with nodes of a fixed node type, but also to a 'Graph' with polymorphic node type @n@. The nodes merely have to /expose/ values of type @v@ by means of defining a @View v@ on @n@. The 'View' abstraction is also used to expose the nodes' ports (and therefore the graph structure) to this library.+-- 2. The graph structure is essentially representated as a collection of nodes. The nodes have a user-defined type, where each node features a list of 'Port's to each of which an 'Edge' is attached. Edges are unlabeled and can not exist autonomously, i.e. each edge is connected to at least one port. Each port is connetected to exactly one edge. Two ports are connected if (and only if) they share the same edge. What is particularly convenient is how these ports can be modeled as constructor fields of a user-defined node type. ----- 3. Rewrite 'Rule' are represented as 'Pattern's that return a 'Rewrite'. A 'Pattern' is a branching scrutinisation of the graph that returns a result for every possible matching position in the graph. A 'Rule' is essentially a 'Pattern' that returns a 'Rewrite'. A 'Rewrite' is a monadic modification of the graph structure. In a 'Rule' the 'Rewrite' part can conveniently use the variables bound in the 'Pattern' code.+-- 3. An important abstraction used in this library is the multi-parameter type-class 'View'. It permits to expose a certain aspect of a node, allowing both to 'inspect' or 'update' it, while hiding the internal representation of the node. By that it is easy to specify the rewrite system in a way, that it can not only be applied to a graph with nodes of a fixed node type, but also to a 'Graph' with polymorphic node type @n@. The nodes merely have to /expose/ values of type @v@ by means of defining a @View v@ on @n@. The 'View' abstraction is also used to expose the nodes' ports (and therefore the graph structure) to this library. ----- For an example of a simple rewrite system, see the graph-rewriting-ski package, an implementation of SKI combinators. Together with the graph-rewriting-layout and the graph-rewriting-gl packages it is easy to build a graphical and interactive application to experiment with your rewrite system.+-- 4. Rewrite 'Rule' are represented as 'Pattern's that return a 'Rewrite'. A 'Pattern' is a branching scrutinisation of the graph that returns a result for every possible matching position in the graph. A 'Rule' is essentially a 'Pattern' that returns a 'Rewrite'. A 'Rewrite' is a monadic modification of the graph structure. In a 'Rule' the 'Rewrite' part can conveniently use the variables bound in the 'Pattern' code. ----- What the library does not (yet) offer are combinators to define strategies, since the emphasis of the project was to create an interactive graph-rewriting tool where rules and rewriting positions are selected manually.+-- See the graph-rewriting-ski package for an example of a simple rewrite system. Together with the graph-rewriting-layout and the graph-rewriting-gl packages it is easy to build a graphical and interactive application to experiment with your rewrite system.+--+-- What the library does not (yet) offer combinators to define strategies, since the emphasis of the project was to create an interactive graph-rewriting tool where rules and rewriting positions are selected manually. module GraphRewriting- (-- | graph representation, 'Rewrite' monad- module GraphRewriting.Graph.Types,- -- | mapping over nodes, graph creation, applying a 'Rewrite' + (module GraphRewriting.Graph.Types,+ -- | graph representation, 'Rewrite' monad module GraphRewriting.Graph,- -- | monadic graph scrutinisation+ -- | mapping over nodes, graph creation, applying a 'Rewrite' module GraphRewriting.Graph.Read,- -- | monadic graph modification+ -- | monadic graph scrutinisation module GraphRewriting.Graph.Write,- -- | branching graph scrutinisation that keeps track of scrutinised nodes+ -- | monadic graph modification module GraphRewriting.Pattern,- -- | combine a 'Pattern' with a 'Rewrite' to obtain a rewrite rule+ -- | branching graph scrutinisation that keeps track of scrutinised nodes module GraphRewriting.Rule,+ -- | combine a 'Pattern' with a 'Rewrite' to obtain a rewrite rule module Data.View) where
GraphRewriting/Graph/Internal.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE UnicodeSyntax, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses, FlexibleContexts #-} module GraphRewriting.Graph.Internal where import Control.Monad.State
GraphRewriting/Graph/Read.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE UnicodeSyntax, FlexibleContexts, FlexibleInstances, TypeSynonymInstances, MultiParamTypeClasses #-}+ -- | Enquiry of the graph structure. Note: In this module the term "node" is often used synonymously to "node reference" and "node value". The two can easily distinguished by their type: the former has type 'Node' the latter usually 'n'. module GraphRewriting.Graph.Read (module GraphRewriting.Graph.Read, module GraphRewriting.Graph.Types, module Data.View)
GraphRewriting/Graph/Write.hs view
@@ -1,4 +1,4 @@--- | Functions for modifying the graph. Although the graph structure is entirely expressed by the graph's node collection, for better convenience and efficiency the graph representation also comprises a complementary node set, that has to be synchronised with the node collection. Therefore each of the functions below involves a test for whether the graph structure has been changed, and if so, measures are taken to ensure the graph remains consistent.+-- | Functions for modifying the graph. Although the graph structure is entirely expressed by the graph's node collection, for convenience and efficiency the graph representation also comprises a complementary collection of edges, that has to be synchronised with the node collection. Therefore each of the functions below involves a test for whether the graph structure has been changed, and if so, measures are taken to ensure the graph remains consistent. -- Invariants for graph consistency: -- - ∀n∊N ∀e∊E: n→e ⇔ e→n
GraphRewriting/Pattern.hs view
@@ -1,13 +1,28 @@--- | Patterns allow monadic scrutinisation of the graph (modifications are not possible) while keeping track of matched nodes. A 'Pattern' is interpreted by 'runPattern' that returns a result for each position in the graph where the pattern matches. It is allowed to 'fail' inside the 'Pattern' monad, indicating that the pattern does not match, which corresponds to conditional rewriting.+-- | Patterns allow monadic scrutinisation of the graph (modifications are not possible) while keeping track of matched nodes (history). A 'Pattern' is interpreted by 'runPattern' that returns a result for each position in the graph where the pattern matches. It is allowed to 'fail' inside the 'Pattern' monad, indicating that the pattern does not match, which corresponds to conditional rewriting. module GraphRewriting.Pattern (module GraphRewriting.Pattern, Pattern, Match) where import Prelude.Unicode-import GraphRewriting.Pattern.Internal+import GraphRewriting.Pattern.Internal -- (Pattern (..), Match, liftList, liftMatches) import GraphRewriting.Graph.Read import Control.Monad.Reader import Data.List (nub)+import Data.Set as Set (empty, insert, member) +instance Monad (Pattern n) where+ return x = Pattern $ \m → return ([],x)+ p >>= f = Pattern $ \m → do+ (m1,x) ← pattern p m+ (m2,y) ← pattern (f x) (m1 ⧺ m)+ return (m1 ⧺ m2, y)+ fail str = Pattern $ \m → lift []++instance MonadPlus (Pattern n) where+ mzero = fail "empty result list"+ mplus p q = Pattern $ \m → do+ g ← ask+ lift $ runReaderT (pattern p m) g ⧺ runReaderT (pattern q m) g+ -- | Apply a pattern on a graph returning a result for each matching position in the graph together with the matched nodes. runPattern ∷ Pattern n a → Graph n → [(Match,a)] runPattern p = runReaderT $ pattern p []@@ -20,11 +35,16 @@ -- combinators --------------------------------------------------------------- --- | probe a pattern returning the matches it has on the graph+-- | Probe whether a pattern matches somewhere on the graph. You might want to combine this with 'amnesia'.+probe ∷ Pattern n a → Pattern n Bool+probe p = liftM (not . null) (matches p)++-- | probe a pattern returning the matches it has on the graph. You might want to combine this with 'amnesia'. matches ∷ Pattern n a → Pattern n [Match] matches p = Pattern $ \m → do lma ← liftM (runReaderT $ pattern p m) ask- return ([], map fst lma)+ let matches = map fst lma+ return (nub $ concat matches, matches) -- | choice (<|>) ∷ Pattern n a → Pattern n a → Pattern n a@@ -35,22 +55,21 @@ anyOf [] = fail "anyOf []" anyOf xs = foldr1 (<|>) xs --- | 'fail' if given pattern succeeds, succeed if it fails.---requireFailure ∷ Pattern n a → Pattern n ()---requireFailure p = require . not =<< probe p---- TODO: Control.Monad.guard -- | conditional rewriting: 'fail' when predicate is not met require ∷ Monad m ⇒ Bool → m () require p = unless p $ fail "requirement not met" +-- | 'fail' if given pattern succeeds, succeed if it fails.+requireFailure ∷ Pattern n a → Pattern n ()+requireFailure p = do require . not =<< probe p+ -- | 'fail' when monadic predicate is not met requireM ∷ Monad m ⇒ m Bool → m () requireM p = p >>= require --- inspections that yield a list packed into a pattern match -----------------+-- some base patterns -------------------------------------------------------- --- | Lift a scrutinisation from 'Reader' to 'Pattern'. Attention: This does not contribute to returned 'Match'.+-- | Lift a scrutinisation from 'Reader' to 'Pattern' leaving the history unchanged. liftReader ∷ Reader (Graph n) a → Pattern n a liftReader r = Pattern $ \m → do x ← liftM (runReader r) ask@@ -58,7 +77,10 @@ -- | any node anywhere in the graph node ∷ View v n ⇒ Pattern n v-node = liftReader . inspectNode =<< liftMatches readNodeList+node = do+ n ← branch =<< liftReader readNodeList+ visit n+ liftReader $ inspectNode n -- | a reference to the lastly matched node previous ∷ Pattern n Node@@ -66,11 +88,11 @@ -- | any edge anywhere in the graph edge ∷ Pattern n Edge-edge = liftList readEdgeList+edge = branch =<< liftReader readEdgeList -- | node that is connected to given edge nodeAt ∷ View v n ⇒ Edge → Pattern n v-nodeAt e = liftReader . inspectNode =<< liftMatches (attachedNodes e)+nodeAt e = liftReader . inspectNode =<< branch =<< liftReader (attachedNodes e) -- | edge that is attached to given node edgeOf ∷ View [Port] n ⇒ Node → Pattern n Edge@@ -78,23 +100,29 @@ -- | node that is connected to the given node, but not that node itself neighbour ∷ (View [Port] n, View v n) ⇒ Node → Pattern n v-neighbour n = liftReader . inspectNode =<< liftMatches (neighbours n)+neighbour n = liftReader . inspectNode =<< branch =<< liftReader (neighbours n) -- | node that is connected to the given node, permitting the node itself relative ∷ (View [Port] n, View v n) ⇒ Node → Pattern n v-relative n = liftReader . inspectNode =<< liftMatches (relatives n)+relative n = liftReader . inspectNode =<< branch =<< liftReader (relatives n) -- | nodes connected to given port of the specified node, not including the node itself adverse ∷ (View [Port] n, View v n) ⇒ Port → Node → Pattern n v-adverse p n = liftReader . inspectNode =<< liftMatches (adverseNodes n p)+adverse p n = liftReader . inspectNode =<< branch =<< liftReader (adverseNodes n p) -- controlling history and future -------------------------------------------- +-- | Do not remember any of the nodes matched by the supplied pattern+amnesia ∷ Pattern n a → Pattern n a+amnesia p = Pattern $ \m → do+ (m',x) ← pattern p m+ return ([],x)+ -- | list of nodes matched until now with the most recent node in head position history ∷ Pattern n Match history = Pattern $ \m → return ([],m) --- | only match nodes in the next node pattern that have not been matched before+-- | only match nodes in the next pattern that have not been matched before nextFresh ∷ Pattern n a → Pattern n a nextFresh = restrictOverlap $ \hist (n:ns) → not (n ∈ hist) @@ -106,8 +134,11 @@ restrictOverlap ∷ (Match → Match → Bool) → Pattern n a → Pattern n a restrictOverlap c p = Pattern $ \m → do (m',x) ← pattern p m- if c m m' then return (m',x) else fail "requirement on history not met"+ require (c m m')+ return (m',x) -- | Nodes in the future may not be matched more than once. linear ∷ Pattern n a → Pattern n a-linear = restrictOverlap $ \hist future → length future ≡ length (nub future)+linear = restrictOverlap $ \hist future → isLinear Set.empty future where+ isLinear left [] = True+ isLinear left (r:rs) = not (r `Set.member` left) ∧ isLinear (r `Set.insert` left) rs
GraphRewriting/Pattern/Internal.hs view
@@ -1,33 +1,30 @@+{-# LANGUAGE UnicodeSyntax #-} module GraphRewriting.Pattern.Internal where -import Prelude.Unicode import GraphRewriting.Graph.Types import Control.Monad.Reader +-- | A pattern represents a graph scrutinisation that memorises all the scrutinised nodes during matching. newtype Pattern n a = Pattern {pattern ∷ Match → ReaderT (Graph n) [] (Match, a)} type Match = [Node] -instance Monad (Pattern n) where- return x = Pattern $ \m → return ([],x)- p >>= f = Pattern $ \m → do- (m1,x) ← pattern p m- (m2,y) ← pattern (f x) (m1 ⧺ m)- return (m1 ⧺ m2, y)- fail str = Pattern $ \m → lift []+-- | Something like an implicit monadic map+branch ∷ [a] → Pattern n a+branch xs = Pattern $ \m → lift [([],x) | x ← xs] -instance MonadPlus (Pattern n) where- mzero = fail "empty result list"- mplus p q = Pattern $ \m → do- g ← ask- lift $ runReaderT (pattern p m) g ⧺ runReaderT (pattern q m) g+visit ∷ Node → Pattern n ()+visit n = Pattern $ \m → lift [([n],())] +-- | From a graph scrutinisation returning a list of results make a 'Pattern' that branches on that list liftList ∷ Reader (Graph n) [a] → Pattern n a liftList r = Pattern $ \m → do xs ← liftM (runReader r) ask lift [([],x) | x ← xs] +-- | From a graph scrutinisation returning a list of nodes make a 'Pattern' that branches on these nodes.+-- For each branch the node matched is added to the history. liftMatches ∷ Reader (Graph n) [Node] → Pattern n Node liftMatches r = Pattern $ \m → do ns ← liftM (runReader r) ask
GraphRewriting/Rule.hs view
@@ -1,10 +1,10 @@--- | Rewrite rules are represented as nested monads: a 'Rule' is a 'Pattern' that returns a 'Rewrite' the latter directly defining the transformation of the graph. The 'Rewrite' itself is expected to return a list of newly created nodes.+{-# LANGUAGE UnicodeSyntax, TypeSynonymInstances, FlexibleInstances, MultiParamTypeClasses, FlexibleContexts #-}+-- | Rewrite rules are represented as nested monads: a 'Rule' is a 'Pattern' that returns a 'Rewrite' the latter directly defining the transformation of the graph. -- -- For rule construction a few functions a provided: The most basic one is 'rewrite'. But in most cases 'erase', 'rewire', and 'replace*' should be more convenient. These functions express rewrites that /replace/ the matched nodes of the 'Pattern', which comes quite close to the @L -> R@ form in which graph rewriting rules are usually expressed. module GraphRewriting.Rule where import Prelude.Unicode-import Data.Maybe (listToMaybe) import GraphRewriting.Graph import GraphRewriting.Graph.Internal (Port (Edge)) import GraphRewriting.Graph.Write@@ -17,30 +17,31 @@ -- | A rewriting rule is defined as a 'Pattern' that returns a 'Rewrite'-type Rule n = Pattern n (Rewrite n [Node])+type Rule n = Pattern n (Rewrite n ()) +-- | Apply rule at an arbitrary position if applicable+apply ∷ Rule n → Rewrite n ()+apply r = do+ contractions ← liftM (evalPattern r) ask+ when (not $ null contractions) (head contractions >> return ())+ -- rule construction --------------------------------------------------------- -- | primitive rule construction with the matched nodes of the left hand side as a parameter-rewrite ∷ (Match → Rewrite n [Node]) → Rule n-rewrite r = liftM r history+rewrite ∷ (Match → Rewrite n a) → Rule n+rewrite r = do+ h ← history+ return $ r h >> return () -- | constructs a rule that deletes all of the matched nodes from the graph erase ∷ View [Port] n ⇒ Rule n-erase = do- hist ← history- return $ do- mapM_ deleteNode $ nub hist- return []+erase = rewrite $ mapM_ deleteNode . nub -- | Constructs a rule from a list of rewirings. Each rewiring specifies a list of hyperedges that are to be merged into a single hyperedge. All matched nodes of the left-hand side are removed. rewire ∷ View [Port] n ⇒ [[Edge]] → Rule n-rewire ess = do- hist ← history- return $ do- mapM_ mergeEs $ joinEdges ess- mapM_ deleteNode $ nub hist- return []+rewire ess = rewrite $ \hist → do+ mapM_ mergeEs $ joinEdges ess+ mapM_ deleteNode $ nub hist data RHS v = Node v | Wire Edge Edge | Merge [Edge] @@ -48,15 +49,14 @@ replace ∷ (View [Port] n, View v n) ⇒ Int → ([Edge] → [RHS v]) → Rule n replace n rhs = do let vs = fst $ partition (replicate n $ Edge 0)- hist ← history- when (null hist ∧ not (null vs)) (fail "need at least one matching node to clone new nodes from")+ lhsNodes ← liftM nub history+ when (null lhsNodes ∧ not (null vs)) (fail "need at least one matching node to clone new nodes from") return $ do es ← replicateM n newEdge let (vs,ess) = partition es- ns ← zipWithM copyNode (cycle hist) vs+ zipWithM_ copyNode (cycle lhsNodes) vs mapM_ mergeEs $ joinEdges ess- mapM_ deleteNode $ nub hist- return ns+ mapM_ deleteNode lhsNodes where partition es = partitionEithers $ map splitRHS (rhs es) where splitRHS (Node v) = Left v splitRHS (Wire e1 e2) = Right [e1,e2]@@ -81,14 +81,10 @@ -- combinators --------------------------------------------------------------- -- | Apply two rules consecutively. Second rule is only applied if first one succeeds. Fails if (and only if) first rule fails.--- BUG: what if r2 deletes some of the nodes created in r1? Probably it's a bad idea, that the set of created nodes is returned by the rewrite at all. (>>>) ∷ Rule n → Rule n → Rule n r1 >>> r2 = do rw1 ← r1- return $ do- ns1 ← rw1- ns2 ← apply r2- return (ns1 ⧺ ns2)+ return $ rw1 >> apply r2 -- | Make a rule exhaustive, i.e. such that (when applied) it reduces redexes until no redexes are occur in the graph. exhaustive ∷ Rule n → Rule n@@ -97,9 +93,5 @@ -- | Make a rule parallel, i.e. such that (when applied) all current redexes are contracted one by one. Neither new redexes or destroyed redexes are reduced. everywhere ∷ Rule n → Rule n everywhere r = do- ms ← matches r+ ms ← amnesia $ matches r exhaustive $ restrictOverlap (\hist future → future ∈ ms) r---- | Apply rule at an arbitrary position if applicable-apply ∷ Rule n → Rewrite n [Node]-apply r = maybe (return []) snd . listToMaybe =<< liftM (runPattern r) ask
GraphRewriting/Rule/Internal.hs view
@@ -12,6 +12,8 @@ joinEdges ∷ [[Edge]] → [[Edge]] joinEdges = map (map Edge . Set.elems) . join . map (Set.fromList . map eKey) +-- The code below is essentially maintaining equivalence classes. TODO: use a library for that.+ -- | Join pairs of sets with a common element until all sets are disjoint. join ∷ [Set] → [Set] join = foldr join1 []
graph-rewriting.cabal view
@@ -1,5 +1,5 @@ Name: graph-rewriting-Version: 0.4.9+Version: 0.5 Copyright: (c) 2010, Jan Rochel License: BSD3 License-File: LICENSE@@ -9,33 +9,35 @@ Build-Type: Simple Synopsis: Monadic graph rewriting of hypergraphs with ports and multiedges Description:- This library provides a monadic EDSL to define your own graph rewrite system in Haskell. Once you have specified the signature of your graph and a set of rewrite rules, you can apply these rules on a graph to effect a graph transformation. The aim of this library is to make it as convenient as possible to define such a system and experiment with it and is not designed as a backend for high-performance computation.+ This library provides a monadic EDSL to define your own graph rewrite system in Haskell. Once you have specified the signature of your graph and a set of rewrite rules, you can apply these rules on a graph to effect a graph transformation. The aim of this library is to make it as convenient as possible to define such a system and experiment with it and is not designed as a backend for high-performance computation. Category: Graphs, Data Cabal-Version: >= 1.6-Build-Depends:- base >= 4 && < 4.3,- base-unicode-symbols >= 0.2 && < 0.3,- mtl >= 1.1 && < 1.2,- containers >= 0.3 && < 0.4-Exposed-Modules:- Data.View- GraphRewriting- GraphRewriting.Graph- GraphRewriting.Graph.Types- GraphRewriting.Graph.Read- GraphRewriting.Graph.Write- GraphRewriting.Graph.Write.Unsafe- GraphRewriting.Pattern- GraphRewriting.Pattern.InteractionNet- GraphRewriting.Rule-Other-Modules:- GraphRewriting.Graph.Internal- GraphRewriting.Pattern.Internal- GraphRewriting.Rule.Internal-Extensions:- UnicodeSyntax- FlexibleContexts- FlexibleInstances- TypeSynonymInstances- MultiParamTypeClasses-GHC-Options: -fno-warn-duplicate-exports -fwarn-unused-imports++Library+ Build-Depends:+ base >= 4 && < 4.4,+ base-unicode-symbols >= 0.2 && < 0.3,+ mtl >= 1.1 && < 1.2,+ containers >= 0.3 && < 0.5+ Exposed-Modules:+ Data.View+ GraphRewriting+ GraphRewriting.Graph+ GraphRewriting.Graph.Types+ GraphRewriting.Graph.Read+ GraphRewriting.Graph.Write+ GraphRewriting.Graph.Write.Unsafe+ GraphRewriting.Pattern+ GraphRewriting.Pattern.InteractionNet+ GraphRewriting.Rule+ Other-Modules:+ GraphRewriting.Graph.Internal+ GraphRewriting.Pattern.Internal+ GraphRewriting.Rule.Internal+ Extensions:+ UnicodeSyntax+ FlexibleContexts+ FlexibleInstances+ TypeSynonymInstances+ MultiParamTypeClasses+ GHC-Options: -fno-warn-duplicate-exports -fwarn-unused-imports