{-# LANGUAGE UnicodeSyntax, FlexibleContexts #-} module Rules where import Prelude.Unicode import Graph import GraphRewriting.Rule as Rule import GraphRewriting.Pattern import GraphRewriting.Graph.Read import Control.Applicative import Data.Monoid.Unicode compileShare ∷ (View [Port] n, View NodeWW n) ⇒ Rule n compileShare = do Multiplexer {out = o, ins = is} ← node case is of [ ] → replace $ byNode Eraser {inp = o} [i] → rewire [[o,i]] ins → let (ins1, ins2) = splitAt (length ins `div` 2) ins in replace $ do (o1,o2) ← (,) <$> byEdge <*> byEdge byNode Duplicator {active = False, inp = o, out1 = o1, out2 = o2} byNode Multiplexer {out = o1, ins = ins1} byNode Multiplexer {out = o2, ins = ins2} beta ∷ (View [Port] n, View NodeWW n) ⇒ Rule n beta = do abs@Abstractor {} ← node app@Applicator {} ← nodeWith $ inp abs require (inp abs ≡ func app) rewire [[inp app, body abs], [arg app, var abs]] initDuplication ∷ (View [Port] n, View NodeWW n) ⇒ Rule n initDuplication = do dup@Duplicator {active = False} ← node abs@Abstractor {} ← nodeWith $ inp dup require $ inp abs ≡ inp dup replace $ do (b1,b2,v1,v2) ← (,,,) <$> byEdge <*> byEdge <*> byEdge <*> byEdge byNode abs {inp = out1 dup, body = b1, var = v1} byNode abs {inp = out2 dup, body = b2, var = v2} byNode Duplicator {out1 = b1, out2 = b2, inp = body abs, active = True} byNode Duplicator {out1 = v1, out2 = v2, inp = var abs, active = True} duplicateAbstractor ∷ (View [Port] n, View NodeWW n) ⇒ Rule n duplicateAbstractor = do dup@Duplicator {active = True} ← node abs@Abstractor {} ← nodeWith $ inp dup require $ body abs ≡ inp dup replace $ do (i1,i2,v1,v2) ← (,,,) <$> byEdge <*> byEdge <*> byEdge <*> byEdge byNode dup {inp = inp abs, out1 = i1, out2 = i2} byNode abs {inp = i1, body = out1 dup, var = v1} byNode abs {inp = i2, body = out2 dup, var = v2} byNode dup {out1 = v1, out2 = v2, inp = var abs} duplicateApplicator ∷ (View [Port] n, View NodeWW n) ⇒ Rule n duplicateApplicator = do dup@Duplicator {active = True} ← node app@Applicator {} ← nodeWith $ inp dup require $ inp dup ∈ [func app, arg app] if inp dup ≡ func app then do require $ func app ≡ inp dup replace $ do (i1,i2,a1,a2) ← (,,,) <$> byEdge <*> byEdge <*> byEdge <*> byEdge byNode dup {inp = inp app, out1 = i1, out2 = i2} byNode Applicator {inp = i1, func = out1 dup, arg = a1} byNode Applicator {inp = i2, func = out2 dup, arg = a2} byNode dup {out1 = a1, out2 = a2, inp = arg app} else do require $ arg app ≡ inp dup replace $ do (i1,i2,a1,a2) ← (,,,) <$> byEdge <*> byEdge <*> byEdge <*> byEdge byNode dup {inp = inp app, out1 = i1, out2 = i2} byNode Applicator {inp = i1, func = a1, arg = out1 dup} byNode Applicator {inp = i2, func = a2, arg = out2 dup} byNode dup {out1 = a1, out2 = a2, inp = func app} duplicateDuplicator ∷ (View [Port] n, View NodeWW n) ⇒ Rule n duplicateDuplicator = linear $ do dup1@Duplicator {active = True} ← node dup2@Duplicator {active = False} ← nodeWith $ inp dup1 require $ inp dup1 ≡ inp dup2 replace $ do (ll,lr,rl,rr) ← (,,,) <$> byEdge <*> byEdge <*> byEdge <*> byEdge byNode dup1 {inp = out1 dup2, out1 = ll, out2 = lr} byNode dup1 {inp = out2 dup2, out1 = rl, out2 = rr} byNode dup2 {inp = out1 dup1, out1 = ll, out2 = rl} byNode dup2 {inp = out2 dup1, out1 = lr, out2 = rr} duplicatePrimitive ∷ (View [Port] n, View NodeWW n) ⇒ Rule n duplicatePrimitive = do d@Duplicator {} ← node p@Primitive {} ← nodeWith $ inp d replace $ byNode p {inp = out1 d} ⊕ byNode p {inp = out2 d} duplicateEraser ∷ (View [Port] n, View NodeWW n) ⇒ Rule n duplicateEraser = do d@Duplicator {} ← node e@Eraser {} ← nodeWith $ inp d replace $ byNode Eraser {inp = out1 d} ⊕ byNode Eraser {inp = out2 d} annihilate ∷ (View [Port] n, View NodeWW n) ⇒ Rule n annihilate = linear $ do dup1@Duplicator {active = True} ← node dup2@Duplicator {active = True} ← nodeWith $ inp dup1 require $ inp dup1 ≡ inp dup2 rewire [[out1 dup1, out1 dup2], [out2 dup1, out2 dup2]] deactivate ∷ (View [Port] n, View NodeWW n) ⇒ Rule n deactivate = do dup@Duplicator {active = True} ← node replace $ byNode dup {active = False} eliminate ∷ (View [Port] n, View NodeWW n) ⇒ Rule n eliminate = do e@Eraser {} ← node d@Duplicator {out1 = o1, out2 = o2} ← neighbour =<< previous require $ inp e ∈ [o1, o2] if inp e ≡ o1 then rewire [[inp d, o2]] else rewire [[inp d, o1]] erase ∷ (View [Port] n, View NodeWW n) ⇒ Rule n erase = linear $ do e@Eraser {} ← node let abstractor = do a@Abstractor {} ← nodeWith $ inp e require $ inp a ≡ inp e replace $ byNode Eraser {inp = body a} ⊕ byNode Eraser {inp = var a} applicator = do a@Applicator {} ← nodeWith $ inp e require $ inp a ≡ inp e replace $ byNode Eraser {inp = func a} ⊕ byNode Eraser {inp = arg a} eraser = do Eraser {} ← nodeWith $ inp e Rule.erase abstractor <|> applicator <|> eraser applyPrimitive ∷ (View [Port] n, View NodeWW n) ⇒ Rule n applyPrimitive = linear $ do a@Applicator {} ← node f@Primitive {} ← nodeWith $ func a x@Primitive {} ← nodeWith $ arg a replace $ byNode Primitive {name = "(" ⧺ name f ⧺ " " ⧺ name x ⧺ ")", inp = inp a}