// 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); }
// 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); }