/** * Author: Christoph Hillebold <c.hillebold@student.tugraz.at> */ package at.iaik.suraq.main; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import at.iaik.suraq.sexp.Token; import at.iaik.suraq.smtlib.SMTLibObject; import at.iaik.suraq.smtlib.formula.AndFormula; import at.iaik.suraq.smtlib.formula.ArrayVariable; import at.iaik.suraq.smtlib.formula.DomainVariable; import at.iaik.suraq.smtlib.formula.Formula; import at.iaik.suraq.smtlib.formula.FunctionMacro; import at.iaik.suraq.smtlib.formula.NotFormula; import at.iaik.suraq.smtlib.formula.OrFormula; import at.iaik.suraq.smtlib.formula.PropositionalVariable; import at.iaik.suraq.smtlib.formula.UninterpretedFunction; /** * Helps encoding a Formula to QBF-Format * * @author chillebold * */ public class QBFEncoder { private static boolean _isActive = false; /** * Optional comment for QBF-Inputfile */ private String comment = null; /** * Number of variables */ protected int varcounter = 1; /** * Number of clauses (lines in QBF) */ protected int clauses = 0; /** * cache for the unique variable-integer replacements */ protected final Map<String, Integer> mapping = new HashMap<String, Integer>(); /** * Empty public constructor */ public QBFEncoder() { // } // List<PropositionalVariable> controlSignals = // logicParser.getControlVariables() public String encode(Formula formula, Set<Token> noDependenceVars, List<PropositionalVariable> controlSignals, Set<PropositionalVariable> tseitinEncoding) { // see http://www.qbflib.org/qdimacs.html for format mapping.clear(); clauses = 0; varcounter = 1; StringBuilder sb = new StringBuilder(); // check if the formula is in CNF if (!checkFormulaReady(formula)) throw new RuntimeException( "Formula not ready for QBF Encoding (AND)."); AndFormula top = (AndFormula) formula; for (Formula innerFormula : top.getConjuncts()) { if (!(innerFormula instanceof OrFormula)) throw new RuntimeException( "Formula not ready for QBF Encoding (OR)."); OrFormula inner = (OrFormula) innerFormula; for (Formula disjunctElem : inner.getDisjuncts()) { boolean not = disjunctElem instanceof NotFormula; Formula var = (disjunctElem instanceof NotFormula) ? ((NotFormula) disjunctElem) .getNegatedFormula() : disjunctElem; if (var == null || !(var instanceof PropositionalVariable)) throw new RuntimeException( "Formula not ready for QBF Encoding (PropVar/Not)."); PropositionalVariable prop = (PropositionalVariable) var; int varID = encodeVar(prop.getVarName()); if (not) // negative values for negated vars varID *= -1; sb = sb.append(varID + " "); } sb = sb.append("0\n"); clauses++; } StringBuilder header = makeQuantors(formula, noDependenceVars, controlSignals, tseitinEncoding); return header.append(sb.toString()).toString(); } /** * generates the quantors and returns a StringBuilder * * @param formula * @param noDependenceVars * @param controlSignals * @param tseitinEncoding * @return */ protected StringBuilder makeQuantors(Formula formula, Set<Token> noDependenceVars, List<PropositionalVariable> controlSignals, Set<PropositionalVariable> tseitinEncoding) { // A ... for all // E ... exists // A inputs E control A no_dependence E tseitin // Assumption: // inputs is everything that is not control, no_dependence, tseitin StringBuilder header = new StringBuilder(); if (comment != null) header = header.append("c " + comment + "\n"); header = header.append("p cnf " + (varcounter - 1) + " " + clauses + "\n"); // input vars Set<PropositionalVariable> inputVars = new HashSet<PropositionalVariable>(); formula.getPropositionalVariables(inputVars, new HashSet<SMTLibObject>()); inputVars.removeAll(controlSignals); inputVars.removeAll(tseitinEncoding); header = header.append("a "); for (PropositionalVariable var : inputVars) { if (!noDependenceVars.contains(Token.generate(var.getVarName()))) header = header.append(encodeVar(var.getVarName()) + " "); } header = header.append("0\n"); // control signals header = header.append("e "); for (PropositionalVariable var : controlSignals) { header = header.append(encodeVar(var.getVarName()) + " "); } header = header.append("0\n"); // no dependence vars header = header.append("a "); for (Token var : noDependenceVars) { header = header.append(encodeVar(var.toString()) + " "); } header = header.append("0\n"); // no dependence vars header = header.append("e "); for (PropositionalVariable var : tseitinEncoding) { header = header.append(encodeVar(var.getVarName()) + " "); } header = header.append("0\n"); return header; } /** * returns an unique Integer replacement for each variable * * @param varname * @return */ protected Integer encodeVar(String varname) { if (mapping.containsKey(varname)) { return mapping.get(varname); } int varID = varcounter++; mapping.put(varname, varID); return varID; } /** * Checks if the given Formula does not contain any Arrays, DomainVariables, * FunctionMacros, UF and if the first layer formula is an AndFormula * * @param formula * @return */ public boolean checkFormulaReady(Formula formula) { if (!QBFEncoder._isActive) { System.err.println("QBFEncoder: QBFEncoder is inactive!"); return false; } Set<ArrayVariable> arrayVars = new HashSet<ArrayVariable>(); formula.getArrayVariables(arrayVars, new HashSet<SMTLibObject>()); if (!arrayVars.isEmpty()) { System.err.println("QBFEncoder: There are Arrays in the Formula!"); return false; } Set<DomainVariable> domainVars = new HashSet<DomainVariable>(); formula.getDomainVariables(domainVars, new HashSet<SMTLibObject>()); if (!domainVars.isEmpty()) { System.err .println("QBFEncoder: There are DomainVariables in the Formula!"); return false; } Set<FunctionMacro> macros = new HashSet<FunctionMacro>(); formula.getFunctionMacros(macros, new HashSet<SMTLibObject>()); if (!macros.isEmpty()) { System.err .println("QBFEncoder: There are FunctionMacros in the Formula!"); return false; } Set<UninterpretedFunction> ufs = new HashSet<UninterpretedFunction>(); formula.getUninterpretedFunctions(ufs, new HashSet<SMTLibObject>()); if (!ufs.isEmpty()) { System.err .println("QBFEncoder: There are UninterpretedFunctions in the Formula!"); return false; } if (!(formula instanceof AndFormula)) { System.err.println("QBFEncoder: The Formula must be in CNF!"); System.err.println("The Formula is type of " + formula.getClass()); return false; } return true; } public static void setActive(boolean isActive) { QBFEncoder._isActive = isActive; } public static boolean isActive() { return QBFEncoder._isActive; } public String getComment() { return comment; } /** * You can also set null if you don't want comments * * @param comment */ public void setComment(String comment) { this.comment = comment; } }