public static FormulaNode JoinTerms(LogicOperator op, List <FormulaNode> terms) { FormulaNode result; if (terms.Count == 0) { if (op == LogicOperator.AND) { return(new FormulaNode(FormulaNode.TRUE_LITERAL)); } if (op == LogicOperator.OR) { // Build FALSE as ~TRUE result = new FormulaNode(LogicOperator.NOT); result.SetChildren(new FormulaNode(FormulaNode.TRUE_LITERAL), null); return(result); } throw new Exception("Join with unsupported logic operator"); } if (terms.Count == 1) { return(terms[0]); } result = new FormulaNode(op, terms[0], terms[1]); foreach (var t in terms.GetRange(2, terms.Count - 2)) { result = new FormulaNode(op, result, t); } return(result); }
public static FormulaNode nnfNegate(FormulaNode formula) { FormulaNode result = new FormulaNode(LogicOperator.NOT); result.SetChildren(formula, null); return(result.NNF()); }
/* Generates a formula representing the fact that for <state> either * the eventuality is not promised or that if it is, then there * exists a fragment of <stateSet> rooted at <state> that has * a frontier node who satisfied the eventuallity */ private FormulaNode GenE(FormulaNode stateSet, SymbolicState state) { ComputeEUFragments(stateSet, state); List <FormulaNode> terms = new List <FormulaNode>(); foreach (var e in elementary) { if (e.GetLogicOperator() != LogicOperator.EX) { continue; } if (e[0].GetLogicOperator() != LogicOperator.EU) { continue; } FormulaNode notPromised = new FormulaNode(LogicOperator.NOT); notPromised.SetChildren(state.ValueOf(e), null); FormulaNode res = new FormulaNode(LogicOperator.OR); res.SetChildren(notPromised, new FormulaNode(LogicOperator.NOT)); res[1].SetChildren(state.ValueOf(e[0][0]), null); FormulaNode frag = fragEU[e[0]]; res = new FormulaNode(LogicOperator.OR, res, frag); terms.Add(res); } return(JoinTerms(LogicOperator.AND, terms)); }
public static FormulaNode CreateTestFormula() { FormulaNode result = new FormulaNode(LogicOperator.EX); result.SetChildren(null, new FormulaNode("b")); result = new FormulaNode(LogicOperator.EU); FormulaNode a = new FormulaNode(LogicOperator.AG); a.SetChildren(new FormulaNode("p"), null); result.SetChildren(a, new FormulaNode("q")); return(result); }
/* Replace the variables describing the state <from> with the ones that describe * state <to> */ public static FormulaNode Substitute(FormulaNode formula, SymbolicState from, SymbolicState to) { if (formula.GetLogicOperator() == LogicOperator.VAR) { if (from.nameToElementary.Keys.Contains(formula.GetName())) { // this variable represents an elementary formula var elementary = from.nameToElementary[formula.GetName()]; return(new FormulaNode(to.elementaryNames[elementary])); } else { return(new FormulaNode(formula.GetName())); } } if (formula.GetLogicOperator() == LogicOperator.ALL || formula.GetLogicOperator() == LogicOperator.EXISTS) { FormulaNode result = new FormulaNode(formula.GetLogicOperator()); if (from.nameToElementary.Keys.Contains(formula.GetName())) { // this variable represents an elementary formula var elementary = from.nameToElementary[formula.GetName()]; result.SetName(to.elementaryNames[elementary]); } else { result.SetName(formula.GetName()); } result.SetChildren(Substitute(formula[0], from, to), null); return(result); } FormulaNode res = new FormulaNode(formula.GetLogicOperator()); FormulaNode left = Substitute(formula[0], from, to); FormulaNode right = null; if (formula[1] != null) { right = Substitute(formula[1], from, to); } res.SetChildren(left, right); return(res); }
// replace ->, AF, AG, EF and EG with simpler operators public FormulaNode ImplementComplexOperators() { FormulaNode leftChild = null; FormulaNode rightChild = null; FormulaNode trueFormula = new FormulaNode(TRUE_LITERAL); FormulaNode falseFormula = new FormulaNode(LogicOperator.NOT, trueFormula, null); FormulaNode result; if (this[0] != null) { leftChild = this[0].ImplementComplexOperators(); } if (this[1] != null) { rightChild = this[1].ImplementComplexOperators(); } switch (logicOp) { // (a -> b) is (~a | b) case LogicOperator.IMP: FormulaNode left = new FormulaNode(LogicOperator.NOT, leftChild, null); return(new FormulaNode(LogicOperator.OR, left, rightChild)); // EF(f) is EU(TRUE, f) case LogicOperator.EF: return(new FormulaNode(LogicOperator.EU, trueFormula, leftChild)); // EG(f) is ER(FALSE, f) case LogicOperator.EG: return(new FormulaNode(LogicOperator.ER, falseFormula, leftChild)); // AF(f) is AU(TRUE, f) case LogicOperator.AF: return(new FormulaNode(LogicOperator.AU, trueFormula, leftChild)); // AG(f) is AU(FALSE, f) case LogicOperator.AG: return(new FormulaNode(LogicOperator.AR, falseFormula, leftChild)); default: result = new FormulaNode(logicOp, name); result.SetChildren(leftChild, rightChild); return(result); } }
// Change f[x] to f[x/x'] public FormulaNode Substitute(string original, string replacement) { if (this.logicOp == LogicOperator.VAR) { if (this.name == original) { return(new FormulaNode(replacement)); } else { return(new FormulaNode(this.name)); } } FormulaNode res = new FormulaNode(this.logicOp, this.name); if ((this.logicOp == LogicOperator.EXISTS || this.logicOp == LogicOperator.ALL) && (this.name == original)) { res.name = replacement; } FormulaNode left = null, right = null; if (this.childNodes[0] != null) { left = this.childNodes[0].Substitute(original, replacement); } if (this.childNodes[1] != null) { right = this.childNodes[1].Substitute(original, replacement); } res.SetChildren(left, right); return(res); }
/* Assumes the formula is in NNF form */ public static ISet <FormulaNode> elementaryFormulas(FormulaNode formula) { HashSet <FormulaNode> result = new HashSet <FormulaNode>(); switch (formula.GetLogicOperator()) { case LogicOperator.AU: case LogicOperator.AR: // AX(f) is elementary FormulaNode ax_f = new FormulaNode(LogicOperator.AX); ax_f.SetChildren(formula, null); result.Add(ax_f); result.Add(nnfNegate(ax_f)); result.UnionWith(elementaryFormulas(formula[0])); result.UnionWith(elementaryFormulas(formula[1])); break; case LogicOperator.EU: case LogicOperator.ER: // EX(f) is elementary FormulaNode ex_f = new FormulaNode(LogicOperator.EX); ex_f.SetChildren(formula, null); result.Add(ex_f); result.Add(nnfNegate(ex_f)); result.UnionWith(elementaryFormulas(formula[0])); result.UnionWith(elementaryFormulas(formula[1])); break; case LogicOperator.EX: case LogicOperator.AX: // the formula itself is elementary result.Add(formula); result.Add(nnfNegate(formula)); result.UnionWith(elementaryFormulas(formula[0])); break; case LogicOperator.OR: case LogicOperator.AND: result.UnionWith(elementaryFormulas(formula[0])); result.UnionWith(elementaryFormulas(formula[1])); break; case LogicOperator.NOT: Debug.Assert(formula[0].GetLogicOperator() == LogicOperator.VAR, "Input to elementaryFormulas must be in NNF form"); result.UnionWith(elementaryFormulas(formula[0])); break; case LogicOperator.VAR: if (formula.GetName() != FormulaNode.TRUE_LITERAL) { result.Add(formula); result.Add(nnfNegate(formula)); } break; default: throw new Exception("Not implemented"); } return(result); }
// Trnasfer the node to PNF (the formula is assumed to be in NNF) // We assume that the formula also has no temporal operators public FormulaNode PNF() { if (this.logicOp == LogicOperator.VAR) { return(new FormulaNode(this.name)); } FormulaNode res = null, left = null, right = null; ISet <string> leftSet, rightSet; string varname; if (this.logicOp == LogicOperator.NOT) { res = new FormulaNode(LogicOperator.NOT); res.SetChildren(new FormulaNode(this.childNodes[0].name), null); return(res); } if (this.logicOp == LogicOperator.EXISTS || this.logicOp == LogicOperator.ALL) { res = new FormulaNode(this.logicOp, this.name); res.SetChildren(this.childNodes[0].PNF(), null); return(res); } // Since we assume NNF, all NOT nodes are next to variables // Thus all of the remaining operators are binary left = this.childNodes[0].PNF(); right = this.childNodes[1].PNF(); leftSet = left.GetVariables(); rightSet = right.GetVariables(); if (this.logicOp == LogicOperator.AND || this.logicOp == LogicOperator.OR) { FormulaNode temp; if (left.logicOp == LogicOperator.EXISTS || left.logicOp == LogicOperator.ALL) { if (rightSet.Contains(left.name)) { varname = UniquePNFVariable(); left = left.Substitute(left.name, varname); } res = new FormulaNode(left.logicOp, left.name); temp = new FormulaNode(this.logicOp); temp.SetChildren(left.childNodes[0], right); res.SetChildren(temp.PNF(), null); } else if (right.logicOp == LogicOperator.EXISTS || right.logicOp == LogicOperator.ALL) { if (leftSet.Contains(right.name)) { varname = UniquePNFVariable(); right = right.Substitute(right.name, varname); } res = new FormulaNode(right.logicOp, right.name); temp = new FormulaNode(this.logicOp); temp.SetChildren(left, right.childNodes[0]); res.SetChildren(temp.PNF(), null); } else { res = new FormulaNode(this.logicOp); res.SetChildren(left, right); } } // For convenience, we get rid of "->" operators if (this.logicOp == LogicOperator.IMP) { res = new FormulaNode(LogicOperator.OR); res.SetChildren(new FormulaNode(LogicOperator.NOT), right); res.childNodes[0].SetChildren(left, null); res = res.NNF().PNF(); } return(res); }
// Transfer the node to NNF public FormulaNode NNF() { if (this.logicOp == LogicOperator.VAR) { return(new FormulaNode(this.name)); } FormulaNode res = null, left = null, right = null; if (this.logicOp != LogicOperator.NOT) { res = new FormulaNode(this.logicOp, this.name); if (this.childNodes[0] != null) { left = this.childNodes[0].NNF(); } if (this.childNodes[1] != null) { right = this.childNodes[1].NNF(); } res.SetChildren(left, right); return(res); } // If we reached here, our node is "~" and hence we should // rearrange the formula tree // We note that a "~" should be unary and hence it only // has a left child switch (this.childNodes[0].logicOp) { case LogicOperator.EXISTS: res = new FormulaNode(LogicOperator.ALL, this.childNodes[0].name); break; case LogicOperator.ALL: res = new FormulaNode(LogicOperator.EXISTS, this.childNodes[0].name); break; case LogicOperator.AND: res = new FormulaNode(LogicOperator.OR); break; case LogicOperator.OR: res = new FormulaNode(LogicOperator.AND); break; case LogicOperator.NOT: return(this.childNodes[0].childNodes[0].NNF()); case LogicOperator.IMP: // ~(a->b) == a & ~b res = new FormulaNode(LogicOperator.AND); left = this.childNodes[0].childNodes[0].NNF(); right = new FormulaNode(LogicOperator.NOT); right.SetChildren(this.childNodes[0].childNodes[1].NNF(), null); res.SetChildren(left, right.NNF()); return(res); case LogicOperator.EF: res = new FormulaNode(LogicOperator.AG); break; case LogicOperator.AF: res = new FormulaNode(LogicOperator.EG); break; case LogicOperator.EG: res = new FormulaNode(LogicOperator.AF); break; case LogicOperator.AG: res = new FormulaNode(LogicOperator.EF); break; case LogicOperator.AX: res = new FormulaNode(LogicOperator.EX); break; case LogicOperator.EX: res = new FormulaNode(LogicOperator.AX); break; case LogicOperator.EU: res = new FormulaNode(LogicOperator.AR); break; case LogicOperator.AU: res = new FormulaNode(LogicOperator.ER); break; case LogicOperator.ER: res = new FormulaNode(LogicOperator.AU); break; case LogicOperator.AR: res = new FormulaNode(LogicOperator.EU); break; case LogicOperator.VAR: res = new FormulaNode(LogicOperator.NOT); res.SetChildren(new FormulaNode(this.childNodes[0].name), null); return(res); default: res = null; break; } if (this.childNodes[0].childNodes[0] != null) { left = new FormulaNode(LogicOperator.NOT); left.SetChildren(this.childNodes[0].childNodes[0].NNF(), null); left = left.NNF(); } if (this.childNodes[0].childNodes[1] != null) { right = new FormulaNode(LogicOperator.NOT); right.SetChildren(this.childNodes[0].childNodes[1].NNF(), null); right = right.NNF(); } res.SetChildren(left, right); return(res); }
private static FormulaNode Parse(List <Token> tokens) { FormulaNode result = null; List <Token> rightSide = new List <Token>(); BinaryToken lastOp = null; // the input is a single token - must be an atom or an unparsed string if (tokens.Count == 1) { var tok = tokens[0] as LiteralToken; if (tok.type == TokenType.ATOM) { return(new FormulaNode(tok.value)); } return(Parse(ToplevelTokenize(tok.value))); } int minPrecedence = MAX_PRECEDENCE; for (int i = 0; i < tokens.Count; i++) { if (tokens[i] is BinaryToken) { var op = tokens[i] as BinaryToken; minPrecedence = Math.Min(minPrecedence, op.precedence); } } if (minPrecedence == MAX_PRECEDENCE) { // the input didn't contain any toplevel binary operators var opToken = tokens[0] as UnaryToken; result = new FormulaNode(opToken.logicOperator); var operand = Parse(tokens.GetRange(1, tokens.Count - 1)); if (untilOperators.Contains(opToken.logicOperator)) { result.SetChildren(operand[0], operand[1]); } else if (quanitifers.Contains(opToken.logicOperator)) { result.SetName(operand[0].GetName()); result.SetChildren(operand[1], null); } else { result.SetChildren(operand, null); } return(result); } // if we got here - split by lowest-precedence binary operator foreach (Token t in tokens) { if (t is BinaryToken) { var op = t as BinaryToken; if (op.precedence == minPrecedence) { if (result == null) { result = Parse(rightSide); } else { var leftSide = result; result = new FormulaNode(lastOp.logicOperator); result.SetChildren(leftSide, Parse(rightSide)); } rightSide = new List <Token>(); lastOp = op; continue; } } rightSide.Add(t); } if (rightSide.Count != 0) { var leftSide = result; result = new FormulaNode(lastOp.logicOperator); result.SetChildren(leftSide, Parse(rightSide)); } return(result); }