// Get a propositional formula and return its (raw) CNF form // addedVars: the names of the new variables introduced by the transformation private static ISet <ISet <string> > TseytinTransformation(FormulaNode formula, out ISet <string> addedVars) { ISet <ISet <string> > res = new HashSet <ISet <string> >(); ISet <TseytinBlock> blockSet = new HashSet <TseytinBlock>(); ticketMachine.Reset(); TseytinBlock top = GetTseytinBlocks(formula, blockSet); if (top == null) { // The formula is simply a variable - no Tseitin blocks required res.Add(new HashSet <string> { formula.GetName() }); } else { // Create a conjunction of all Tseitin blocks foreach (TseytinBlock block in blockSet) { res.UnionWith(TseytinBlockToCNF(block)); } // Add the requirement that the topmost formula is true ISet <string> topClause = new HashSet <string>(); topClause.Add(top.ticket.ToString()); res.Add(topClause); } addedVars = new HashSet <string>(); foreach (TseytinBlock block in blockSet) { addedVars.Add(block.ticket.ToString()); } // Force the TRUE variable to true res.Add(new HashSet <string> { FormulaNode.TRUE_LITERAL }); return(res); }
/* 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); }
// Get a PNF formula and return its QBCNF public static QBCNFormula ConvertToCNF(FormulaNode formula) { QBCNFormula res = new QBCNFormula(); FormulaNode node = formula; ISet <string> addedVars; res.quantifiers = new List <string>(); while (node.GetLogicOperator() == LogicOperator.EXISTS || node.GetLogicOperator() == LogicOperator.ALL) { if (node.GetLogicOperator() == LogicOperator.EXISTS) { res.quantifiers.Add("e" + node.GetName()); } else { res.quantifiers.Add("a" + node.GetName()); } node = node[0]; } if (res.quantifiers.Count != formula.GetVariables().Count) { throw new Exception("Non-quantified variables in formula!"); } res.propositional = TseytinTransformation(node, out addedVars); //Replace strings with numbers ISet <string> literals = res.GetLiterals(); Dictionary <string, string> changes = new Dictionary <string, string>(); foreach (string literal in literals) { int n; bool isNum = int.TryParse(literal, out n); if (!changes.ContainsKey(literal) & !isNum) { int ticket = ticketMachine.GetTicket(); if (literal[0] != '-') { changes.Add(literal, ticket.ToString()); changes.Add("-" + literal, (-ticket).ToString()); } else { changes.Add(literal, (-ticket).ToString()); changes.Add(literal.Substring(1), ticket.ToString()); } } } res.ReplaceLiterals(changes); // Quantify the Tseytin variables with EXISTS foreach (string var in addedVars) { res.quantifiers.Add("e" + var); } 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); }
/* Build a propositional formula representing the value of the given CTL * formula in this state */ public FormulaNode ValueOf(FormulaNode formula) { FormulaNode result, er; switch (formula.GetLogicOperator()) { case LogicOperator.VAR: case LogicOperator.EX: // literals and EX(...) formulas are considered positive elementary, // and so should correspond directly to a propositional variable if (formula.GetLogicOperator() == LogicOperator.VAR && formula.GetName() == FormulaNode.TRUE_LITERAL) { return(new FormulaNode(FormulaNode.TRUE_LITERAL)); } return(new FormulaNode(elementaryNames[formula])); case LogicOperator.AX: FormulaNode notBody = CTLUtils.nnfNegate(formula[0]); FormulaNode ex = new FormulaNode(LogicOperator.EX, notBody, null); FormulaNode exValue = ValueOf(ex); return(new FormulaNode(LogicOperator.NOT, exValue, null)); case LogicOperator.EU: result = ValueOf(new FormulaNode(LogicOperator.EX, formula, null)); result = new FormulaNode(LogicOperator.AND, ValueOf(formula[0]), result); result = new FormulaNode(LogicOperator.OR, ValueOf(formula[1]), result); return(result); case LogicOperator.AU: er = new FormulaNode(LogicOperator.ER, CTLUtils.nnfNegate(formula[0]), CTLUtils.nnfNegate(formula[1])); result = ValueOf(new FormulaNode(LogicOperator.EX, er, null)); result = new FormulaNode(LogicOperator.NOT, result, null); result = new FormulaNode(LogicOperator.AND, ValueOf(formula[0]), result); result = new FormulaNode(LogicOperator.OR, ValueOf(formula[1]), result); return(result); case LogicOperator.ER: result = ValueOf(new FormulaNode(LogicOperator.EX, formula, null)); result = new FormulaNode(LogicOperator.OR, ValueOf(formula[0]), result); result = new FormulaNode(LogicOperator.AND, ValueOf(formula[1]), result); return(result); case LogicOperator.AR: er = new FormulaNode(LogicOperator.EU, CTLUtils.nnfNegate(formula[0]), CTLUtils.nnfNegate(formula[1])); result = ValueOf(new FormulaNode(LogicOperator.EX, er, null)); result = new FormulaNode(LogicOperator.NOT, result, null); result = new FormulaNode(LogicOperator.OR, ValueOf(formula[0]), result); result = new FormulaNode(LogicOperator.AND, ValueOf(formula[1]), result); return(result); case LogicOperator.AND: case LogicOperator.OR: return(new FormulaNode(formula.GetLogicOperator(), ValueOf(formula[0]), ValueOf(formula[1]))); case LogicOperator.NOT: FormulaNode bodyVar; if (formula[0].GetLogicOperator() == LogicOperator.VAR && formula[0].GetName() == FormulaNode.TRUE_LITERAL) { bodyVar = new FormulaNode(FormulaNode.TRUE_LITERAL); } else if (!elementaryNames.ContainsKey(formula[0])) { throw new Exception("Argument to SymbolicState.valueOf must be contained in the closure, and in NNF form."); } else { bodyVar = new FormulaNode(elementaryNames[formula[0]]); } return(new FormulaNode(LogicOperator.NOT, bodyVar, null)); default: throw new NotImplementedException(); } }