24
Rewriting Engine for Process Algebras

Rewriting Engine for Process Algebras

Embed Size (px)

Citation preview

Page 1: Rewriting Engine for Process Algebras

Rewriting Engine for Process Algebras

Page 2: Rewriting Engine for Process Algebras

Plan

• Introduction to Process Algebras•Approaches to Process Algebra Engines•FreeACP: the rewriting engine

Page 3: Rewriting Engine for Process Algebras

Introduction to Process Algebras

Page 4: Rewriting Engine for Process Algebras

Process Algebras•Communicating sequential processes (CSP) – Tony Hoare, 1977•Calculus of communicating systems (CCS) – Robin Miller, 1980•Algebra of Communicating Processes (ACP) – Jan Bergstra and Jan Willem Klop, 1982

Page 5: Rewriting Engine for Process Algebras

ACP Axioms

Page 6: Rewriting Engine for Process Algebras

Example: GUI - Traditional approach

val firstButtonCallback: Event => Unit = e => { if (e.button == first) { eventSystem.deregister(firstButtonCallback ) eventSystem.deregister(secondButtonCallback)

atGuiThread { textField.text = "Hello World" } }}

Page 7: Rewriting Engine for Process Algebras

Example: GUI - Traditional approachval secondButtonCallback: Event => Unit = e => { if (e.button == second) { eventSystem.deregister(firstButtonCallback ) eventSystem.deregister(secondButtonCallback)

atGuiThread { textField.text = "Something Else" } }}

eventSystem.register(firstButtonCallback )eventSystem.register(secondButtonCallback)

Page 8: Rewriting Engine for Process Algebras

Example: GUI – ACP approach

button(first ) * setText(textField, "Hello World" ) +button(second) * setText(textField, "Something Else")

Page 9: Rewriting Engine for Process Algebras

Approaches to Process Algebra Engines

Page 10: Rewriting Engine for Process Algebras

SubScript: Actor-based implementation

Page 11: Rewriting Engine for Process Algebras

SubScript: Actor-based implementation

Page 12: Rewriting Engine for Process Algebras

FreeACP: Rewriting implementation1. ax + by // Initial expression2. εx + bx // a evaluated to success - ε3. εx // ε resolves the choice `+`4. x // x after empty action is the

// same as just x

Page 13: Rewriting Engine for Process Algebras

Rewriting Engine rules• Some PA axioms can be reflected in the engine via symbolic rewriting

of expressions, e.g.: εx = x; δx = δ.• Some PA expressions can’t be further reduced without performing a

computation, e.g.: ax, where a is an atomic action. The rules that need to perform a computation before execution are suspension rules.• To evaluate ax, one first need to evaluate a. a evaluates to either ε

or δ, and the expression is transformed to either εx or δx which can be reduced via symbolic rewriting.

Page 14: Rewriting Engine for Process Algebras

Rewriting Engine rules

Page 15: Rewriting Engine for Process Algebras

FreeACP Implementation

Page 16: Rewriting Engine for Process Algebras

Tree: a representation of a PA expression

trait Tree[S[_]]

case class Suspend [S[_]](a : S[Tree[S]]) extends Tree[S]case class Call [S[_]](t : () => Tree[S] ) extends Tree[S]case class Sequence[S[_]](ts: List[Tree[S]]) extends Tree[S]case class Choice [S[_]](ts: List[Tree[S]]) extends Tree[S]

trait Result[S[_]] extends Tree[S]case class Success[S[_]]() extends Result[S]case class Failure[S[_]]() extends Result[S]

case class Loop[S[_]]() extends Tree[S]

Page 17: Rewriting Engine for Process Algebras

Symbolic rewriting rulesdef rewrite: PartialFunction[Tree[S], Tree[S]] = _ match { // Sequence case Sequence(Nil ) => Success() case Sequence(Sequence(a) :: x) => Sequence(a ++ x) case Sequence(Call(t) :: x) => Sequence(t() :: x) case Sequence(Success() :: x) => Sequence(x) case Sequence(Failure() :: x) => Failure() // To be continued…

Page 18: Rewriting Engine for Process Algebras

Symbolic rewriting rules // Choice case Choice(Nil) => Failure() case Choice (Choice(x) :: y) => Choice(x ++ y) case Sequence(Choice(x) :: y) => Choice(x.map { t => Sequence(t :: y) }) case Choice(x) if x.contains(Success()) => Success() case Choice(x) if x.contains(Failure()) => Choice(x.filter(_ != Failure())) case Choice(x) if x.exists(!resume.isDefinedAt(_)) => Choice(x.map { case a if !resume.isDefinedAt(a) => rewrite.apply(a) case a => a })}

Page 19: Rewriting Engine for Process Algebras

Suspension rulesimplicit val F: Functor[S]

def resume: PartialFunction[ Tree[S], List[S[Tree[S]]] ] = _ match { // Atom case Suspend(r: S[Tree[S]]) => List(r) // Sequence case Sequence(Suspend(r: S[Tree[S]]) :: x) => List( F.map(r) { rs => Sequence(rs :: x) } )

// Choice case Choice(x @ _ :: _) if x.forall(resume.isDefinedAt) => x.flatMap(resume)}

Page 20: Rewriting Engine for Process Algebras

Executiondef run(debug: Boolean = false)(implicit C: Comonad[S], SG: MonoidK[S]): Result[S] = runM(new (S ~> S) { override def apply[A](x: S[A]): S[A] = x }, debug)

def runM[G[_]: Suspended, Functor](f: S ~> G) (implicit G: Comonad[G], M: MonoidK[G]): Result[G] = { @annotation.tailrec def loop(t: Tree[S]): Result[G] = t match { case _: Success[S] => Success[G]() case _: Failure[S] => Failure[G]() case t => loop ({ if (!resume.isDefinedAt(t)) rewrite.apply(t) else Comonad[G].extract { Foldable[List].combineAll( resume.apply(t).map(f.apply[Tree[S]]) )(M.algebra[Tree[S]]) } }) } loop(this, steps) }

Page 21: Rewriting Engine for Process Algebras

LanguageT: a free S[_]trait LanguageT[+T]case class Atom(a: () => Unit) extends LanguageT[Result[LanguageT]]case class MapLanguage[A, B](t1: LanguageT[A], f : A => B) extends LanguageT[B]case class SuspendedLanguage[A](x: () => A) extends LanguageT[A]

object LanguageT { type Language = Tree[LanguageT]

def atom(a: => Unit): Language = Suspend[LanguageT](Atom( () => a )) def call(t: => Language): Language = Call[LanguageT] { () => t }

def ε = Success[LanguageT]() def δ = Failure[LanguageT]()}

Page 22: Rewriting Engine for Process Algebras

Compiler for LanguageTdef defaultCompiler[F[_]](implicit F: Functor[F], S: Suspended[F]): PartialCompiler[F] = mainCompiler => new (LanguageT ~> OptionK[F, ?]) { override def apply[A](x: LanguageT[A]): Option[F[A]] = ({ case Atom(s) => S.suspend { try { s(); Success[LanguageT]().asInstanceOf[A] } // TODO: Casts catch { case t: Throwable => Failure[LanguageT]().asInstanceOf[A] } }

case MapLanguage(t1, f) => F.map(mainCompiler(t1))(f) case SuspendedLanguage(x) => S(x) }: PartialFunction[LanguageT[A], F[A]]).lift.apply(x) }

Page 23: Rewriting Engine for Process Algebras

Current state of FreeACP• Supports sequence “*”, choice “+”• Extensibility due to the free S[_] (GUI example available for Scala

Swing)• Inherent Limitations

• Centralization of the coordination logic• Expressions’ size influences runtime complexity: certain rules require the engine

to traverse the entire list of operator’s children each time rewriting is done.

• Inspired by the implementation of the Free Monad• https://github.com/anatoliykmetyuk/free-acp• http://subscript-lang.org/

Page 24: Rewriting Engine for Process Algebras

Q&A