Commit 14b736c7 authored by Christian Müller's avatar Christian Müller

leaders

parent 2c08691d
...@@ -32,7 +32,7 @@ object MainLTL extends App with LazyLogging { ...@@ -32,7 +32,7 @@ object MainLTL extends App with LazyLogging {
logger.info("Embedding FOLTL formula in LTL") logger.info("Embedding FOLTL formula in LTL")
val (agents, res) = FOTransformers.eliminateExistentials(prop) val (agents, res) = FOTransformers.eliminateExistentials(prop)
val universe = agents.map(_.withType()).mkString(", ") val universe = agents.map(_.withType).mkString(", ")
logger.info(s"Using universe $universe") logger.info(s"Using universe $universe")
if (agents.groupBy(_.typ).exists(_._2.size > MAX_AGENTS)) { if (agents.groupBy(_.typ).exists(_._2.size > MAX_AGENTS)) {
......
...@@ -18,10 +18,10 @@ object Preconditions extends LazyLogging { ...@@ -18,10 +18,10 @@ object Preconditions extends LazyLogging {
for (s <- b.steps) yield { for (s <- b.steps) yield {
val first = s.tuple.head val first = s.tuple.head
val inner = if (first.typ == spec.target.params.head.typ) { val inner = if (first.typ == spec.target.params.head.typ) {
val inf = Fun(INFNAME, List(b.agents.head))
if (properties.stubborn) { if (properties.stubborn) {
choice.in(T1) choice.in(T1)
} else { } else {
val inf = Fun(INFNAME, List(b.agents.head))
Or(And(Neg(inf.in(T1)), choice.in(T1)), And(inf.in(T1), choice)) Or(And(Neg(inf.in(T1)), choice.in(T1)), And(inf.in(T1), choice))
} }
} else { } else {
...@@ -34,16 +34,23 @@ object Preconditions extends LazyLogging { ...@@ -34,16 +34,23 @@ object Preconditions extends LazyLogging {
b.steps b.steps
} }
val newsteps = for ( val newb = b.updateSteps(guardfix)
// for causality, add informedness updates
if (properties.stubborn) {
List(newb)
} else {
val newsteps = for (
stmt <- b.steps stmt <- b.steps
if spec.causals.map(_.typ).contains(stmt.tuple.head.typ) || if spec.causals.map(_.typ).contains(stmt.tuple.head.typ) ||
stmt.tuple.head.typ == spec.target.params.head.typ) yield { stmt.tuple.head.typ == spec.target.params.head.typ) yield {
val fun = Fun(stmt.fun, stmt.tuple) val fun = Fun(stmt.fun, stmt.tuple)
// TODO // TODO
val guard = Neg(Equiv(fun.in(T1), fun.in(T2))) val guard = Neg(Equiv(fun.in(T1), fun.in(T2)))
ForallBlock(stmt.tuple, List(Add(guard, INFNAME, List(stmt.tuple.head)))) ForallBlock(stmt.tuple, List(Add(guard, INFNAME, List(stmt.tuple.head))))
}
newb :: newsteps
} }
b :: newsteps
} }
// For oracly blocks, remove O from guard and add to ForallMay choice predicate // For oracly blocks, remove O from guard and add to ForallMay choice predicate
...@@ -54,7 +61,7 @@ object Preconditions extends LazyLogging { ...@@ -54,7 +61,7 @@ object Preconditions extends LazyLogging {
def findOracle(f: Formula) = { def findOracle(f: Formula) = {
f.collect { f.collect {
case f: Fun if (f.isOracle()) => List(f.name) case f: Fun if f.isOracle => List(f.name)
} }
} }
val oracles = findOracle(stmt.guard) val oracles = findOracle(stmt.guard)
...@@ -68,10 +75,10 @@ object Preconditions extends LazyLogging { ...@@ -68,10 +75,10 @@ object Preconditions extends LazyLogging {
def fixguard(f: Formula, choice:Fun) = { def fixguard(f: Formula, choice:Fun) = {
val nooracles = f.everywhere { val nooracles = f.everywhere {
case f: Fun if f.isOracle() => True case f: Fun if f.isOracle => True
} }
val decl = spec.declass.getOrElse(b.pred.get, (List(), False))._2 val decl = spec.declass.getOrElse(name, (List(), False))._2
// FIXME: substitutions? // FIXME: substitutions?
// FIXME: decl in T2? // FIXME: decl in T2?
And(nooracles, Or(And(decl.in(T1), choice.in(T1)), And(Neg(decl.in(T1)), choice))) And(nooracles, Or(And(decl.in(T1), choice.in(T1)), And(Neg(decl.in(T1)), choice)))
...@@ -86,7 +93,7 @@ object Preconditions extends LazyLogging { ...@@ -86,7 +93,7 @@ object Preconditions extends LazyLogging {
} else b } else b
} }
def subst(f: Formula, updates: List[(String, (List[FOLTL.Var], FOLTL.Formula))], b: SimpleBlock) = { def subst(f: Formula, updates: List[(String, (List[FOLTL.Var], FOLTL.Formula))], b: SimpleBlock): Formula = {
updates.foldRight(f)((update, f) => { updates.foldRight(f)((update, f) => {
val (repname, (vars, form)) = update val (repname, (vars, form)) = update
...@@ -105,7 +112,7 @@ object Preconditions extends LazyLogging { ...@@ -105,7 +112,7 @@ object Preconditions extends LazyLogging {
}) })
} }
def getUpdate(s:Statement, choice:Option[Fun], spec:NISpec, properties:InvProperties) = { def getUpdate(s:Statement, spec:NISpec, properties:InvProperties): Formula = {
val frees = s.guard.freeVars -- s.tuple.toSet -- spec.constants val frees = s.guard.freeVars -- s.tuple.toSet -- spec.constants
...@@ -120,12 +127,12 @@ object Preconditions extends LazyLogging { ...@@ -120,12 +127,12 @@ object Preconditions extends LazyLogging {
form form
} }
def elaborate(block: SimpleBlock, spec:NISpec, properties:InvProperties) = { def elaborate(block: SimpleBlock, spec:NISpec, properties:InvProperties): List[SimpleBlock] = {
val stepOne = if (!properties.stubborn) elaborateSteps(block, spec, properties) else List(block) val stepOne = elaborateSteps(block, spec, properties)
stepOne map { b => elaborateOraclyBlock(b, spec) } stepOne map { b => elaborateOraclyBlock(b, spec) }
} }
def weakestPrecondition(post: Formula, outerb: SimpleBlock, spec: NISpec, properties: InvProperties) = { def weakestPrecondition(post: Formula, outerb: SimpleBlock, spec: NISpec, properties: InvProperties): Formula = {
// TODO: Make 2-trace elaboration optional // TODO: Make 2-trace elaboration optional
...@@ -138,11 +145,11 @@ object Preconditions extends LazyLogging { ...@@ -138,11 +145,11 @@ object Preconditions extends LazyLogging {
precond precond
} }
private def weakestPreconditionSingle(f: Formula, b: SimpleBlock, spec: NISpec, properties: InvProperties) = { private def weakestPreconditionSingle(f: Formula, b:SimpleBlock, spec: NISpec, properties: InvProperties) = {
val updates = for (s <- b.steps) yield { val updates = for (s <- b.steps) yield {
s.fun -> (s.tuple, { s.fun -> (s.tuple, {
getUpdate(s, b, spec, properties) getUpdate(s, spec, properties)
}) })
} }
...@@ -152,18 +159,20 @@ object Preconditions extends LazyLogging { ...@@ -152,18 +159,20 @@ object Preconditions extends LazyLogging {
// TODO: have we proven this correct? // TODO: have we proven this correct?
val removed = FOTransformers.eliminateDoubleQuantifiers(replaced) val removed = FOTransformers.eliminateDoubleQuantifiers(replaced)
if (Utils.DEBUG_MODE) { if (Utils.DEBUG_MODE) {
if (FormulaFunctions.collectQuantifiers(removed) != FormulaFunctions.collectQuantifiers(replaced)) { val neg1 = replaced.toNegNf
logger.warn(s"Removed a quantifier:\nBefore: ${replaced}\nAfter:$removed") val neg2 = removed.toNegNf
if (FormulaFunctions.collectQuantifiers(neg1) != FormulaFunctions.collectQuantifiers(neg2)) {
logger.warn(s"Would have removed a quantifier:\nBefore: ${neg1}\nAfter: $neg2")
} }
} }
removed replaced
} }
def abstractedPrecondition(f: Formula, b: SimpleBlock, spec: NISpec, properties: InvProperties, untouched: Set[String]) = { def abstractedPrecondition(f: Formula, b: SimpleBlock, spec: NISpec, properties: InvProperties, untouched: Set[String]): Formula = {
val precond = weakestPrecondition(f, b, spec, properties) val precond = weakestPrecondition(f, b, spec, properties)
// Assume untoucheds empty // Assume untouched predicates empty
val untouchedprecond = precond.assumeEmpty(untouched.toList) val untouchedprecond = precond.assumeEmpty(untouched.toList)
val z3simpednewinv = Z3BSFO.simplifyBS(untouchedprecond) val z3simpednewinv = Z3BSFO.simplifyBS(untouchedprecond)
...@@ -179,7 +188,7 @@ object Preconditions extends LazyLogging { ...@@ -179,7 +188,7 @@ object Preconditions extends LazyLogging {
// Abstract away inner existentials // Abstract away inner existentials
val universalinv = if (removedannotations.toNegNf.hasSubFormula { val universalinv = if (removedannotations.toNegNf.hasSubFormula {
case e:Exists => true case _:Exists => true
}) { }) {
FOTransformers.abstractExistentials(removedannotations) FOTransformers.abstractExistentials(removedannotations)
} else { } else {
......
...@@ -5,8 +5,7 @@ import de.tum.workflows.foltl.FOLTL._ ...@@ -5,8 +5,7 @@ import de.tum.workflows.foltl.FOLTL._
import java.io.File import java.io.File
import java.io.PrintWriter import java.io.PrintWriter
import de.tum.workflows.toz3.InvariantChecker import de.tum.workflows.toz3.{InvProperties, InvariantChecker, Z3BSFO}
import de.tum.workflows.toz3.InvProperties
import com.typesafe.scalalogging.LazyLogging import com.typesafe.scalalogging.LazyLogging
import de.tum.workflows.MainInvariantsInference.logger import de.tum.workflows.MainInvariantsInference.logger
...@@ -74,13 +73,18 @@ object Utils extends LazyLogging { ...@@ -74,13 +73,18 @@ object Utils extends LazyLogging {
val basename = name.split("/").last val basename = name.split("/").last
val filenames = s"${basename}_$model${if (desc.isEmpty()) "" else s"_$desc"}" val filenames = s"${basename}_$model${if (desc.isEmpty()) "" else s"_$desc"}"
// do not blow up the formula with auxilliary elimination
val (res, graph, labelling, provens, dot, time) = val (res, graph, labelling, provens, dot, time) =
InvariantChecker.checkInvariantFPLabelling(spec, inv, properties) InvariantChecker.checkInvariantFPLabelling(spec, inv, properties)
logger.info(s"Invariant was ${inv}") logger.info(s"Invariant was ${inv}")
logger.info(s"Invariant was ${if (res) "" else "not "}proven (took $time ms)\n") logger.info(s"Invariant was ${if (res) "" else "not "}proven (took $time ms)\n")
if (!res) {
val headinv = labelling.last(graph.nodes.head)
val satq = And(spec.always, Neg(headinv))
logger.info(s"Initial state violating the invariant: ${Z3BSFO.debugmodelBS(satq)}")
}
for ((s, i) <- dot.zipWithIndex) { for ((s, i) <- dot.zipWithIndex) {
Utils.write(name,s"${filenames}_$i.dot", s) Utils.write(name,s"${filenames}_$i.dot", s)
} }
......
...@@ -76,15 +76,16 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging ...@@ -76,15 +76,16 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging
val preds = allpredicates(list) val preds = allpredicates(list)
// Filter to just the first // Filter to just the first
val filtered = preds groupBy (_.name) map (_._2.head) toSet val filtered = preds.groupBy(_.name).map(_._2.head).toSet
val oracles = filtered.filter(_.isOracle()) val oracles = filtered.filter(_.isOracle)
val bs = filtered.filter(_.isB()) val constinputs = filtered.filter(_.isConstInput)
val rels = filtered -- oracles -- bs val bs = filtered.filter(_.isB)
Signature(oracles, bs, rels) val rels = filtered -- oracles -- constinputs -- bs
Signature(oracles, constinputs, bs, rels)
} }
def typeMap(typedvars: List[Var]) = { def typeMap(typedvars: List[Var]) = {
typedvars.map(v => v.name -> v.typ) toMap typedvars.map(v => v.name -> v.typ).toMap
} }
def inferType(typemap: Map[String, String], v:Var) = { def inferType(typemap: Map[String, String], v:Var) = {
...@@ -136,13 +137,15 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging ...@@ -136,13 +137,15 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging
def TUPLE = "(" ~> repsep(TYPEDVAR, ",") <~ ")" def TUPLE = "(" ~> repsep(TYPEDVAR, ",") <~ ")"
def FUN = VAR ~ TUPLE ^^ { case f ~ tup => Fun(f.name, tup) } def FUN = VAR ~ TUPLE ^^ { case f ~ tup => Fun(f.name, tup) }
def EQ = (VAR <~ "=") ~ VAR ^^ { case v1 ~ v2 => Equal(v1, v2) } | (VAR <~ "≠") ~ VAR ^^ { case v1 ~ v2 => Neg(Equal(v1, v2)) }
def EQUIV = "(" ~> (SIMPLETERM <~ "<->") ~ (TERM <~ ")") ^^ { case t1 ~ t2 => Equiv(t1, t2) }
def EXISTS = "∃" ~> (repsep(TYPEDVAR, ",") <~ ("."?)) ~ TERM ^^ { case vs ~ t => Exists(vs, t) } def EXISTS = "∃" ~> (repsep(TYPEDVAR, ",") <~ ("."?)) ~ TERM ^^ { case vs ~ t => Exists(vs, t) }
def FORALL = "∀" ~> (repsep(TYPEDVAR, ",") <~ ("."?)) ~ TERM ^^ { case vs ~ t => Forall(vs, t) } def FORALL = "∀" ~> (repsep(TYPEDVAR, ",") <~ ("."?)) ~ TERM ^^ { case vs ~ t => Forall(vs, t) }
def QUANTIFIER = EXISTS | FORALL def QUANTIFIER:PackratParser[Formula] = EXISTS | FORALL
def SIMPLETERM = (tt | ff | FUN) def SIMPLETERM = tt | ff | FUN | EQ
lazy val TERM:PackratParser[Formula] = (AND | OR | IMPLIES | NEG | SIMPLETERM | GLOBALLY | FINALLY | QUANTIFIER) lazy val TERM:PackratParser[Formula] = AND | OR | IMPLIES | NEG | SIMPLETERM | GLOBALLY | FINALLY | QUANTIFIER | EQUIV
def ADD = TERM ~ ("→" | "->") ~ VAR ~ "+=" ~ TUPLE ^^ { case guard ~ _ ~ fun ~ _ ~ tup => Add(guard, fun.name, tup) } def ADD = TERM ~ ("→" | "->") ~ VAR ~ "+=" ~ TUPLE ^^ { case guard ~ _ ~ fun ~ _ ~ tup => Add(guard, fun.name, tup) }
def REM = TERM ~ ("→" | "->") ~ VAR ~ "-=" ~ TUPLE ^^ { case guard ~ _ ~ fun ~ _ ~ tup => Remove(guard, fun.name, tup) } def REM = TERM ~ ("→" | "->") ~ VAR ~ "-=" ~ TUPLE ^^ { case guard ~ _ ~ fun ~ _ ~ tup => Remove(guard, fun.name, tup) }
...@@ -154,7 +157,8 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging ...@@ -154,7 +157,8 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging
def BLOCK = "forall" ~> ("may"?) ~ repsep(TYPEDVAR, ",") ~ (STMT+) ^? ({ def BLOCK = "forall" ~> ("may"?) ~ repsep(TYPEDVAR, ",") ~ (STMT+) ^? ({
// all free variables contained // all free variables contained
case may ~ vars ~ stmts if validblock(vars, stmts) => { case may ~ vars ~ stmts if validblock(vars, stmts) => {
val typemap = typeMap(vars) // add quantified variables to typemap
val typemap = typeMap(vars ++ stmts.flatMap(_.guard.boundVars))
val typedstmts = stmts map (inferTypes(typemap, _)) val typedstmts = stmts map (inferTypes(typemap, _))
if (may.isEmpty) { if (may.isEmpty) {
ForallBlock(vars, typedstmts) ForallBlock(vars, typedstmts)
...@@ -186,7 +190,7 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging ...@@ -186,7 +190,7 @@ object WorkflowParser extends RegexParsers with PackratParsers with LazyLogging
(("Declassify" ~> DECLASS)?) ~ (("Declassify" ~> DECLASS)?) ~
("Target" ~> FUN) ~ ("Target" ~> FUN) ~
(("Causality" ~> repsep(TYPEDVAR, ","))?) ^^ { (("Causality" ~> repsep(TYPEDVAR, ","))?) ^^ {
case _ ~ w ~ decl ~ tar ~ causals => NISpec(w, toMap(decl.toList), tar, causals.getOrElse(List())) case _ ~ w ~ decl ~ tar ~ causals => NISpec(w, toMap(decl.toList), True, tar, causals.getOrElse(List()))
} }
def toMap(list:List[(Fun, Formula)]):Map[String, (List[Var], Formula)] = { def toMap(list:List[(Fun, Formula)]):Map[String, (List[Var], Formula)] = {
......
...@@ -11,8 +11,8 @@ object Signature { ...@@ -11,8 +11,8 @@ object Signature {
} }
case class Workflow(sig: Signature, steps: List[Block]) { case class Workflow(sig: Signature, steps: List[Block]) {
override def toString() = steps.mkString("\n") override def toString(): String = steps.mkString("\n")
lazy val isomitting = { lazy val isomitting: Boolean = {
steps.exists(_.isomitting) steps.exists(_.isomitting)
} }
} }
...@@ -24,18 +24,8 @@ trait Spec { ...@@ -24,18 +24,8 @@ trait Spec {
def w: Workflow def w: Workflow
} }
case class InvSpec(w: Workflow, always: Formula, invariant: Formula) extends Spec { case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], always: Formula, target: Fun, causals:List[Var]) extends Spec with LazyLogging {
override def toString = { override def toString: String = {
s"Spec\nWorkflow:\n$w\nAlways:$always\nInvariant:$invariant"
}
def toNISpec() = {
NISpec(w, Map(), Fun("NOTHING", List()), List())
}
}
case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], target: Fun, causals:List[Var]) extends Spec with LazyLogging {
override def toString = {
s"NISpec\nWorkflow:\n$w\nDeclass:$declass\nTarget:$target" s"NISpec\nWorkflow:\n$w\nDeclass:$declass\nTarget:$target"
} }
...@@ -47,7 +37,7 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], targe ...@@ -47,7 +37,7 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], targe
// TODO: How to check for more constants? // TODO: How to check for more constants?
} }
def checkSanity() = { def checkSanity(): Boolean = {
var sane = true var sane = true
// TODO: check all types // TODO: check all types
...@@ -65,18 +55,18 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], targe ...@@ -65,18 +55,18 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], targe
// Oracle only positive // Oracle only positive
val f = stmt.guard.toNegNf val f = stmt.guard.toNegNf
val noneg = !f.hasSubFormula { val noneg = !f.hasSubFormula {
case Neg(f:Fun) if f.isOracle() => true case Neg(f:Fun) if f.isOracle => true
} }
if (!noneg) { if (!noneg) {
logger.error(s"Found negated oracle in guard for statement $stmt") logger.error(s"Found negated oracle in guard for statement $stmt")
} }
val allvars = !(f hasSubFormula { // val allvars = !(f hasSubFormula {
case f:Fun if f.isOracle && f.params != frees => true // case f:Fun if f.isOracle && f.params != frees => true
}) // })
if (!allvars) { // if (!allvars) {
logger.error(s"Found oracle with wrong parameters in statement $stmt") // logger.error(s"Found oracle with wrong parameters in statement $stmt")
} // }
noneg && allvars noneg // && allvars
} }
// check same relation only updated once per block // check same relation only updated once per block
...@@ -103,9 +93,13 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], targe ...@@ -103,9 +93,13 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], targe
sane &&= isSane(w.steps) sane &&= isSane(w.steps)
sane sane
} }
def addKnowledge(k:Formula) = {
NISpec(w, declass, And.make(always, k), target, causals)
}
} }
object NISpec { object NISpec {
val EMPTY = NISpec(Workflow.EMPTY, Map(), Fun("NOTHING", List()), List()) val EMPTY = NISpec(Workflow.EMPTY, Map(), True, Fun("NOTHING", List()), List())
} }
abstract sealed class Block { abstract sealed class Block {
...@@ -113,13 +107,15 @@ abstract sealed class Block { ...@@ -113,13 +107,15 @@ abstract sealed class Block {
} }
abstract sealed class SimpleBlock extends Block { abstract sealed class SimpleBlock extends Block {
type This >: this.type <: SimpleBlock
def agents: List[Var] def agents: List[Var]
def steps: List[Statement] def steps: List[Statement]
def may: Boolean def may: Boolean
def pred: Option[String] def pred: Option[String]
def updateSteps(s:List[Statement]) def updateSteps(s:List[Statement]):This
override def isomitting = { override def isomitting: Boolean = {
// a simple block is omitting, if there exists a statement where not all agents appear in the tuple // a simple block is omitting, if there exists a statement where not all agents appear in the tuple
steps.exists(s => agents.exists(a => !s.tuple.contains(a))) steps.exists(s => agents.exists(a => !s.tuple.contains(a)))
} }
...@@ -128,11 +124,11 @@ abstract sealed class SimpleBlock extends Block { ...@@ -128,11 +124,11 @@ abstract sealed class SimpleBlock extends Block {
// before transformation // before transformation
val before = steps.exists(s => { val before = steps.exists(s => {
s.guard.hasSubFormula { s.guard.hasSubFormula {
case f:Fun => f.isOracle() case f:Fun => f.isOracle
} }
}) })
// after transformation // after transformation
val after = pred.exists(name => Fun(name, agents).isOracle()) val after = pred.exists(name => Fun(name, agents).isOracle)
before || after before || after
} }
...@@ -150,50 +146,56 @@ abstract sealed class SimpleBlock extends Block { ...@@ -150,50 +146,56 @@ abstract sealed class SimpleBlock extends Block {
} }
abstract class Statement { abstract class Statement {
type This >: this.type <: Statement
def guard: Formula def guard: Formula
def fun: String def fun: String
def tuple: List[Var] def tuple: List[Var]
def updateGuard(newguard: Formula) def updateGuard(newguard: Formula): This
lazy val freeVars = guard.freeVars ++ tuple lazy val freeVars: Set[Var] = guard.freeVars ++ tuple
} }
case class Add(guard: Formula, fun: String, tuple: List[Var]) extends Statement { case class Add(guard: Formula, fun: String, tuple: List[Var]) extends Statement {
override def toString() = guard + " → " + fun + " += " + tuple.mkString("(", ",", ")") + ";" type This = Add
override def toString(): String = guard + " → " + fun + " += " + tuple.mkString("(", ",", ")") + ";"
override def updateGuard(newguard: Formula) = Add(newguard, fun, tuple) override def updateGuard(newguard: Formula) = Add(newguard, fun, tuple)
} }
case class Remove(guard: Formula, fun: String, tuple: List[Var]) extends Statement { case class Remove(guard: Formula, fun: String, tuple: List[Var]) extends Statement {
override def toString() = guard + " → " + fun + " -= " + tuple.mkString("(", ",", ")") + ";" type This = Remove
override def toString(): String = guard + " → " + fun + " -= " + tuple.mkString("(", ",", ")") + ";"
override def updateGuard(newguard: Formula) = Remove(newguard, fun, tuple) override def updateGuard(newguard: Formula) = Remove(newguard, fun, tuple)
} }
case class ForallBlock(agents: List[Var], steps: List[Statement]) extends SimpleBlock { case class ForallBlock(agents: List[Var], steps: List[Statement]) extends SimpleBlock {
type This = ForallBlock
val may = false val may = false
override def toString() = "forall " + agents.map(_.withType).mkString(",") + steps.mkString("\n ", "\n ", "")
override def pred() = None override def pred() = None
override def toString(): String = "forall " + agents.map(_.withType).mkString(",") + steps.mkString("\n ", "\n ", "")
override def updateSteps(newsteps: List[Statement]) = ForallBlock(agents, newsteps) override def updateSteps(newsteps: List[Statement]) = ForallBlock(agents, newsteps)
} }
case class ForallMayBlock(agents: List[Var], choice: String, steps: List[Statement]) extends SimpleBlock { case class ForallMayBlock(agents: List[Var], choice: String, steps: List[Statement]) extends SimpleBlock {
type This = ForallMayBlock
val may = true val may = true
override def toString() = "forall " + agents.map(_.withType).mkString(",") + " may (" + pred + ")" + steps.mkString("\n ", "\n ", "")
override def pred() = Some(choice) override def pred() = Some(choice)
override def toString(): String = "forall " + agents.map(_.withType).mkString(",") + " may (" + pred + ")" + steps.mkString("\n ", "\n ", "")
override def updateSteps(newsteps: List[Statement]) = ForallMayBlock(agents, choice, newsteps) override def updateSteps(newsteps: List[Statement]) = ForallMayBlock(agents, choice, newsteps)
} }
case class Loop(steps: List[Block]) extends Block { case class Loop(steps: List[Block]) extends Block {
override def toString() = { override def toString(): String = {
// indentation // indentation
"loop(*)\n" + Utils.indentLines(steps.mkString("\n")) "loop(*)\n" + Utils.indentLines(steps.mkString("\n"))
} }
override def isomitting = { override def isomitting: Boolean = {
steps.exists(_.isomitting) steps.exists(_.isomitting)
} }
} }
case class NondetChoice(left: List[Block], right: List[Block]) extends Block { case class NondetChoice(left: List[Block], right: List[Block]) extends Block {
override def toString() = { override def toString(): String = {
"choose {\n" + Utils.indentLines(left.mkString("\n")) + "\n} {\n" + Utils.indentLines(right.mkString("\n")) + "\n}\n" "choose {\n" + Utils.indentLines(left.mkString("\n")) + "\n} {\n" + Utils.indentLines(right.mkString("\n")) + "\n}\n"
} }
override def isomitting = { override def isomitting: Boolean = {
left.exists(_.isomitting) || right.exists(_.isomitting) left.exists(_.isomitting) || right.exists(_.isomitting)
} }
} }
package de.tum.workflows.foltl package de.tum.workflows.foltl
import de.tum.workflows.Utils import de.tum.workflows.Utils
import de.tum.workflows.foltl.FOLTL.FunFromVar
import de.tum.workflows.foltl.FOLTL.FunFromVar.getVars
import scala.annotation.tailrec import scala.util.matching.Regex
//import de.tum.workflows.foltl.TermFunctions._ //import de.tum.workflows.foltl.TermFunctions._
...@@ -37,7 +35,7 @@ object FOLTL { ...@@ -37,7 +35,7 @@ object FOLTL {
lazy val bracketed: String = this match { lazy val bracketed: String = this match {
case _: BinOp => "(" + this + ")" case _: BinOp => "(" + this + ")"
case _ => this.toString() case _ => this.toString
} }
// single arrow is for maps // single arrow is for maps
...@@ -80,15 +78,15 @@ object FOLTL { ...@@ -80,15 +78,15 @@ object FOLTL {
val DEFAULT_TYPE = "T" val DEFAULT_TYPE = "T"
} }
case class Var(name: String, typ: String = Var.DEFAULT_TYPE) extends Formula { case class Var(name: String, typ: String = Var.DEFAULT_TYPE) extends Formula {
override def toString() = s"$name" override def toString = s"$name"
def withType() = s"$name:$typ" def withType = s"$name:$typ"
} }
object Fun { object Fun {
def apply(name: String, params: List[Var]): Fun = Fun(name, None, params) def apply(name: String, params: List[Var]): Fun = Fun(name, None, params)
} }
object FunNameFromVar { object FunNameFromVar {
val PredicateNoParam = "([a-zA-Z0-9]+)(#([a-zA-Z0-9]+))?".r val PredicateNoParam: Regex = "([a-zA-Z0-9]+)(#([a-zA-Z0-9]+))?".r
def unapply(s: String): Option[(String, Option[String])] = { def unapply(s: String): Option[(String, Option[String])] = {
s match { s match {
...@@ -99,15 +97,15 @@ object FOLTL { ...@@ -99,15 +97,15 @@ object FOLTL {
} }
} }
object FunFromVar { object FunFromVar {
val Predicate = "([a-zA-Z0-9]+)(#([a-zA-Z0-9]+))?((_[a-zA-Z0-9]+#[a-zA-Z0-9]+)*)".r val Predicate: Regex = "([a-zA-Z0-9]+)(#([a-zA-Z0-9]+))?((_[a-zA-Z0-9]+#[a-zA-Z0-9]+)*)".r
def getVars(s: String) = { def getVars(s: String): List[Var] = {
val split = s split ("_") val split = s split "_"
if (split.length > 1) { if (split.length > 1) {
split.drop(1).map(str => {