/** * Author: Georg Hofferek <georg.hofferek@iaik.tugraz.at> */ package at.iaik.suraq.main; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.math.BigInteger; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import at.iaik.suraq.exceptions.ParseError; import at.iaik.suraq.exceptions.SuraqException; import at.iaik.suraq.parser.FormulaParser; import at.iaik.suraq.parser.LogicParser; import at.iaik.suraq.parser.ProofParser; import at.iaik.suraq.parser.SExpParser; import at.iaik.suraq.parser.TseitinParser; import at.iaik.suraq.parser.VeriTParser; import at.iaik.suraq.proof.VeritProof; import at.iaik.suraq.proof.VeritProofNode; import at.iaik.suraq.resProof.ResNode; import at.iaik.suraq.resProof.ResProof; import at.iaik.suraq.sexp.SExpression; import at.iaik.suraq.sexp.SExpressionConstants; import at.iaik.suraq.sexp.Token; import at.iaik.suraq.smtlib.SMTLibObject; import at.iaik.suraq.smtlib.TransformedZ3Proof; import at.iaik.suraq.smtlib.Z3Proof; import at.iaik.suraq.smtlib.formula.AndFormula; import at.iaik.suraq.smtlib.formula.ArrayVariable; import at.iaik.suraq.smtlib.formula.DomainEq; import at.iaik.suraq.smtlib.formula.DomainTerm; import at.iaik.suraq.smtlib.formula.DomainVariable; import at.iaik.suraq.smtlib.formula.Formula; import at.iaik.suraq.smtlib.formula.FormulaTerm; import at.iaik.suraq.smtlib.formula.FunctionMacro; import at.iaik.suraq.smtlib.formula.ImpliesFormula; import at.iaik.suraq.smtlib.formula.NotFormula; import at.iaik.suraq.smtlib.formula.OrFormula; import at.iaik.suraq.smtlib.formula.PropositionalConstant; import at.iaik.suraq.smtlib.formula.PropositionalTerm; import at.iaik.suraq.smtlib.formula.PropositionalVariable; import at.iaik.suraq.smtlib.formula.Term; import at.iaik.suraq.smtlib.formula.UninterpretedFunction; import at.iaik.suraq.smtsolver.SMTSolver; import at.iaik.suraq.smtsolver.VeriTSolver; import at.iaik.suraq.smtsolver.z3; import at.iaik.suraq.util.BenchmarkTimer; import at.iaik.suraq.util.DebugHelper; import at.iaik.suraq.util.FormulaSimplifier; import at.iaik.suraq.util.Timer; import at.iaik.suraq.util.Util; /** * * This is the main class of the Suraq project. Control flow will start here. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class Suraq implements Runnable { public static final BenchmarkTimer extTimer = new BenchmarkTimer(); /** * Timer for overall execution */ private Timer overallTimer = new Timer(); /** * The parser that holds the data of the main formula from which to * synthesize. */ private LogicParser logicParser; /** * The special variable that is used for reducing array properties to finite * conjunctions. */ private DomainVariable lambda; // /** // * The expressions that will be written to the output. // */ // private List<SExpression> outputExpressions; /** * Maps each noDependenceVar to a list of its copies. */ private Map<Token, List<Term>> noDependenceVarsCopies; /** * Maps each noDependenceFunction to a list of its copies. */ private Map<Token, List<UninterpretedFunction>> noDependenceFunctionsCopies; /** * Mapping variable names to their type. */ private Map<Token, SExpression> varTypes; /** * Stores whether or not any (serious) errors occurred. */ private boolean noErrors = true; /** * stores the declaration part of the smt description */ private String declarationStr = ""; /** * Stores the encoding from Tseitin variables to their formulas. */ private Map<PropositionalVariable, Formula> tseitinEncoding = new HashMap<PropositionalVariable, Formula>(); /** * stores the assert partitions of the smt description */ // TODO: REMOVE, use assertPartitionFormulas @Deprecated private List<SExpression> assertPartitionList = new ArrayList<SExpression>(); /** * stores the main formula */ private Formula mainFormula = null; /** * stores all present propositional variables */ private Set<PropositionalVariable> propositionalVars = new HashSet<PropositionalVariable>(); /** * stores all present domain variables */ private Set<DomainVariable> domainVars = new HashSet<DomainVariable>(); /** * stores all present array variables */ private Set<ArrayVariable> arrayVars = new HashSet<ArrayVariable>(); /** * stores all present uninterpreted functions */ private Set<UninterpretedFunction> uninterpretedFunctions = new HashSet<UninterpretedFunction>(); /** * Constraints for variables newly introduced during reductions. */ private Set<Formula> constraints = new HashSet<Formula>(); /** * stores the assert partition formula for each assert partition */ private TreeMap<Integer, Formula> assertPartitionFormulas = new TreeMap<Integer, Formula>(); private VeritProof veritProof = null; private Set<Token> noDependenceVars; /** * Stores the Tseitin-encoded partitions. */ private TreeMap<Integer, Formula> tseitinPartitions = new TreeMap<Integer, Formula>(); /** * Constructs a new <code>Suraq</code>. */ public Suraq(String[] args) { try { SuraqOptions.initialize(args); } catch (SuraqException exc) { System.err .println("Error in parsing options. Unparseable options will be overriden by defaults. Details follow."); exc.printStackTrace(); } } /** * Checks whether everything was successful. * * @return <code>false</code> if there were errors, <code>true</code> * otherwise. */ public boolean success() { return noErrors; } /** * This is the main entry point into the program. * * @param args * command-line arguments */ public static void main(String[] args) { try { Suraq.extTimer.start(); Suraq.extTimer.stopReset("start"); Suraq suraq = new Suraq(args); suraq.run(); } catch (Throwable exc) { Util.printMemoryInformation(); Util.printToSystemOutWithWallClockTimePrefix("Program ended with an Exception"); System.err.println("ERROR: Uncaught exception!"); System.err.println("Message:" + exc.getMessage() == null ? "<null>" : exc.getMessage()); exc.printStackTrace(); System.exit(-1); } System.exit(0); } private void parseInput() { SuraqOptions options = SuraqOptions.getInstance(); File sourceFile = new File(options.getInput()); Util.printToSystemOutWithWallClockTimePrefix("Starting to read " + sourceFile.getPath() + " ..."); SExpParser sExpParser = null; try { sExpParser = new SExpParser(sourceFile); } catch (FileNotFoundException exc) { System.err.println("ERROR: File " + sourceFile.getPath() + " not found!"); noErrors = false; throw new RuntimeException(exc); } catch (IOException exc) { System.err.println("ERROR: Could not read from file " + sourceFile.getPath()); noErrors = false; throw new RuntimeException(exc); } Timer sExpParseTimer = new Timer(); sExpParseTimer.start(); try { sExpParser.parse(); assert (sExpParser.wasParsingSuccessfull()); } catch (ParseError exc) { handleParseError(exc); noErrors = false; throw new RuntimeException(exc); } finally { sExpParseTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("S-Expression parsing took " + sExpParseTimer); } logicParser = new LogicParser(sExpParser.getRootExpr()); sExpParser = null; // Allow this to be garbage collected Timer logicParseTimer = new Timer(); try { logicParseTimer.start(); logicParser.parse(); assert (logicParser.wasParsingSuccessfull()); } catch (ParseError exc) { handleParseError(exc); noErrors = false; throw new RuntimeException(exc); } finally { logicParseTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Logic parsing took " + logicParseTimer); } // Parsing complete if (options.isVerbose()) Util.printToSystemOutWithWallClockTimePrefix("Parsing completed successfully!"); } /** * Input transformations as they are used in non-iterative mode * * @param sourceFile * @return */ private void inputTransformations(File sourceFile) { DebugHelper.getInstance().setFolder(sourceFile.getPath() + "_out/"); SuraqOptions options = SuraqOptions.getInstance(); Suraq.extTimer.stopReset("<inputTransformations>"); parseInput(); try { mainFormula = doMainWork(); } catch (SuraqException exc) { noErrors = false; if (exc.getMessage() != null) System.err.println(exc.getMessage()); } // build function and variable lists for parser if (mainFormula == null) { // abort (workaround not to crash for QBF-Enc) return; } Util.printToSystemOutWithWallClockTimePrefix(" build function and variable lists for parser"); propositionalVars.clear(); mainFormula.getPropositionalVariables(propositionalVars, new HashSet<SMTLibObject>()); domainVars.clear(); mainFormula.getDomainVariables(domainVars, new HashSet<SMTLibObject>()); arrayVars.clear(); mainFormula.getArrayVariables(arrayVars, new HashSet<SMTLibObject>()); uninterpretedFunctions.clear(); mainFormula.getUninterpretedFunctions(uninterpretedFunctions, new HashSet<SMTLibObject>()); for (Map.Entry<Token, List<Term>> varList : noDependenceVarsCopies .entrySet()) { assert (varList.getValue() != null); assert (varList.getValue().size() > 0); Term first = varList.getValue().get(0); if (first instanceof DomainVariable) for (Term var : varList.getValue()) domainVars.add((DomainVariable) var); if (first instanceof PropositionalVariable) for (Term var : varList.getValue()) propositionalVars.add((PropositionalVariable) var); if (first instanceof ArrayVariable) for (Term var : varList.getValue()) arrayVars.add((ArrayVariable) var); } for (Map.Entry<Token, List<UninterpretedFunction>> functionList : noDependenceFunctionsCopies .entrySet()) uninterpretedFunctions.addAll(functionList.getValue()); // debug // try { // Util.printToSystemOutWithWallClockTimePrefix(" Saving Debugfile ./debug_nodepvar.txt"); // File debugFile1 = new File("./debug_nodepvar.txt"); // FileWriter fstream = new FileWriter(debugFile1); // fstream.write(mainFormula.toString()); // fstream.close(); // } catch (Exception ex) { // ex.printStackTrace(); // } if (options.getDumpSMTQueryFile() != null) { dumpSMTQuery(options.getDumpSMTQueryFile()); } Util.printToSystemOutWithWallClockTimePrefix(" Simplifying assert-partitions and tseitin-cnf encoding..."); Timer allPartitionsTimer = new Timer(); allPartitionsTimer.start(); boolean activetseitin = true; if (activetseitin) { Suraq.extTimer.stopReset("before tseitin"); if (options.getTseitinType() == SuraqOptions.TSEITIN_WITHOUT_Z3) { Util.printToSystemOutWithWallClockTimePrefix(" Performing tseitin encoding without Z3..."); performTseitinEncodingWithoutZ3(); } else { Util.printToSystemOutWithWallClockTimePrefix(" Performing tseitin encoding with Z3..."); performTseitinEncodingWithZ3(); } Suraq.extTimer.stopReset("after tseitin"); // DebugHelper.getInstance().stringtoFile(tseitinPartitions.toString(), // "tseitin-all.txt"); allPartitionsTimer.end(); Util.printToSystemOutWithWallClockTimePrefix(" All partitions done. (" + allPartitionsTimer + ")"); Suraq.extTimer .stopReset("after buildSMTDescriptionFromTseitinPartitions"); } Suraq.extTimer.stopReset("</inputTransformations>"); } /** * Performs the tseitin encoding for each partition. Therefore it uses the * Z3 solver. Adds the encoding for each tseitin variable in the * <code>tseitinEncoding</code> map and returns the new encoded partitions. * * @return the tseitin encoded partitions * */ @Deprecated private void performTseitinEncodingWithZ3() { int count = 1; Timer onePartitionTimer = new Timer(); Timer timer2 = new Timer(); z3 z3 = (at.iaik.suraq.smtsolver.z3) SMTSolver.create( SMTSolver.z3_type, SuraqOptions.getZ3_4Path()); for (Integer partition : assertPartitionFormulas.keySet()) { Formula assertPartition = assertPartitionFormulas.get(partition); onePartitionTimer.reset(); onePartitionTimer.start(); Util.printToSystemOutWithWallClockTimePrefix(" Encoding partition " + count + "..."); timer2.end(); Util.printToSystemOutWithWallClockTimePrefix("T1: " + timer2); timer2.reset(); timer2.start(); String smtStr = buildSMTDescriptionForTseitinEncoding( declarationStr, assertPartition.toString()); timer2.end(); Util.printToSystemOutWithWallClockTimePrefix("T2: " + timer2); timer2.reset(); timer2.start(); String tseitingStr = z3.solve2(smtStr); timer2.end(); Util.printToSystemOutWithWallClockTimePrefix("T3: " + timer2); timer2.reset(); timer2.start(); TseitinParser parser = parseTseitinStr(tseitingStr, count); timer2.end(); Util.printToSystemOutWithWallClockTimePrefix("T4: " + timer2); timer2.reset(); timer2.start(); Formula partitionFormula = parser.getRootFormula(); timer2.end(); Util.printToSystemOutWithWallClockTimePrefix("T5: " + timer2); timer2.reset(); timer2.start(); tseitinPartitions.put(partition, partitionFormula); timer2.end(); Util.printToSystemOutWithWallClockTimePrefix("T6: " + timer2); timer2.reset(); timer2.start(); if (SuraqOptions.getInstance().getCheckTseitin()) { Util.printToSystemOutWithWallClockTimePrefix(" test if tseitin encoding is correct..."); if (!Util.checkFormulaImplication(partitionFormula, assertPartitionFormulas.get(count))) throw new RuntimeException("Tseitin encoding incorrect."); Util.printToSystemOutWithWallClockTimePrefix(" ...test finished"); } timer2.end(); Util.printToSystemOutWithWallClockTimePrefix("T7: " + timer2); timer2.reset(); timer2.start(); onePartitionTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + onePartitionTimer + ")"); count++; } } /** * Performs the tseitin encoding for each partition. This method does not * use the Z3 solver. Adds the encoding for each tseitin variable in the * <code>tseitinEncoding</code> map and returns the new encoded partitions. * * @return the tseitin encoded partitions * */ private void performTseitinEncodingWithoutZ3() { Timer onePartitionTimer = new Timer(); // SMTSolver z3 = SMTSolver.create(SMTSolver.z3_type, // SuraqOptions.getZ3_4Path()); for (int count = 1; count <= assertPartitionFormulas.size(); count++) { onePartitionTimer.reset(); onePartitionTimer.start(); Util.printToSystemOutWithWallClockTimePrefix(" Encoding partition " + count + " of " + assertPartitionFormulas.size() + "..."); Formula partitionFormula = assertPartitionFormulas.get(count); // simplify assert partition // String smtStr = ""; // smtStr += SExpressionConstants.SET_LOGIC_QF_UF.toString(); // smtStr += SExpressionConstants.SET_OPTION_PRODUCE_MODELS_TRUE // .toString(); // smtStr += SExpressionConstants.DECLARE_SORT_VALUE.toString(); // smtStr += declarationStr; // smtStr += "(assert " + partitionFormula.toString() + " )"; // smtStr += "(apply (then (! simplify :elim-and true) skip))"; // smtStr += SExpressionConstants.EXIT.toString(); // // String simpleSmtStr = z3.solve2(smtStr); Formula simplifiedPartitionFormula = simplifyWithZ3(partitionFormula); assert (Util.checkEquivalenceOfFormulas(partitionFormula, simplifiedPartitionFormula)); partitionFormula = simplifiedPartitionFormula; Util.printToSystemOutWithWallClockTimePrefix("Done simplifying."); // TseitinParser parser = parseTseitinStr(simpleSmtStr, count); // Util.printToSystemOutWithWallClockTimePrefix("Done parsing simplified partition"); // assert (parser.getTseitinVariables().size() == 0); // partitionFormula = parser.getRootFormula(); // apply tseitin encoding List<OrFormula> clauses = new ArrayList<OrFormula>(); Map<PropositionalVariable, Formula> encoding = new HashMap<PropositionalVariable, Formula>(); Map<Formula, PropositionalVariable> done = new HashMap<Formula, PropositionalVariable>(); // also changes the partitionFormula Formula tseitinVar = partitionFormula.tseitinEncode(clauses, encoding, done, count); Util.printToSystemOutWithWallClockTimePrefix("Done encoding."); assert (Util.isLiteral(tseitinVar)); tseitinEncoding.putAll(encoding); if (tseitinVar instanceof PropositionalVariable) tseitinEncoding.put((PropositionalVariable) tseitinVar, partitionFormula); List<Formula> disjuncts = new ArrayList<Formula>(); disjuncts.add(tseitinVar); clauses.add(OrFormula.generate(disjuncts)); Formula encodedPartitionFormula = AndFormula.generate(clauses); // DebugHelper.getInstance().formulaToFile(encodedPartitionFormula, // "debug-tseitin-encoding.txt"); if (SuraqOptions.getInstance().getCheckTseitin()) { Util.printToSystemOutWithWallClockTimePrefix(" test if tseitin encoding is correct..."); if (!Util.checkFormulaImplication(encodedPartitionFormula, assertPartitionFormulas.get(count))) throw new RuntimeException("Tseitin encoding incorrect."); Util.printToSystemOutWithWallClockTimePrefix(" ...test finished"); } onePartitionTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + onePartitionTimer + ")"); tseitinPartitions.put(count, encodedPartitionFormula); } } private Map<PropositionalVariable, Formula> proofTransformationAndInterpolation( List<PropositionalVariable> controlVars) { Timer timer = new Timer(); Map<Integer, Formula> literalMap = new HashMap<Integer, Formula>(); Set<VeritProofNode> leaves = null; Map<VeritProofNode, VeritProofNode> replacements = null; LogicParser newLogicParser = null; if (SuraqOptions.getInstance().getUseThisPropProofFile() == null) { // assert (proof.checkProof()); Util.printToSystemOutWithWallClockTimePrefix(" Splitting uncolorable leaves in veriT proof..."); timer.start(); replacements = veritProof.splitUncolorableLeaves(); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); Util.printToSystemOutWithWallClockTimePrefix(" Obtaining new propositional ResProof based on new leaves..."); // Use the getLeaves() method of the root, in order to avoid // getting the leaves of the colorable subproofs as well! leaves = veritProof.getRoot().getLeaves(); // Now the original veritProof is no longer need. Let it be garbage // collected. Util.printToSystemOutWithWallClockTimePrefix(" Killing reference to original veriT proof."); veritProof = null; // Hint to the garbage collector: System.gc(); timer.start(); } else { Util.printToSystemOutWithWallClockTimePrefix("Using propositional proof from file: " + SuraqOptions.getInstance().getUseThisPropProofFile()); Set<PropositionalVariable> propVars = new HashSet<PropositionalVariable>(); Set<DomainVariable> domainVars = new HashSet<DomainVariable>(); Set<UninterpretedFunction> functions = new HashSet<UninterpretedFunction>(); propVars.addAll(logicParser.getBoolVariables()); propVars.addAll(tseitinEncoding.keySet()); domainVars.addAll(logicParser.getDomainVariables()); functions.addAll(logicParser.getFunctions()); for (Formula constraint : constraints) { constraint.getDomainVariables(domainVars, new HashSet<SMTLibObject>()); } for (ArrayVariable arrayVar : logicParser.getArrayVariables()) { functions.add(UninterpretedFunction.create( arrayVar.getVarName(), 1, SExpressionConstants.VALUE_TYPE)); } for (Token nodepVar : noDependenceVarsCopies.keySet()) { for (Term term : noDependenceVarsCopies.get(nodepVar)) { if (term instanceof DomainVariable) domainVars.add((DomainVariable) term); if (term instanceof PropositionalVariable) propVars.add((PropositionalVariable) term); } } for (Token functionName : noDependenceFunctionsCopies.keySet()) { for (UninterpretedFunction function : noDependenceFunctionsCopies .get(functionName)) functions.add(function); } newLogicParser = new LogicParser(propVars, domainVars, functions); } ResProof resProof = null; try { resProof = ResProof.create(leaves, replacements, literalMap, newLogicParser); } catch (IOException exc) { System.out.println("IOException during creation of resProof"); throw new RuntimeException(exc); } assert (resProof != null); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); Util.printToSystemOutWithWallClockTimePrefix("Dumping resProof."); resProof.dumpProof("resProof.txt"); Util.printToSystemOutWithWallClockTimePrefix("Done"); Util.printToSystemOutWithWallClockTimePrefix("Size of ResProof: " + Util.largeNumberFormatter.format(resProof.size())); System.gc(); Util.printMemoryInformation(); Util.printToSystemOutWithWallClockTimePrefix(" Processing resolution proof..."); timer.start(); // Util.printToSystemOutWithWallClockTimePrefix(" Checking resolution proof."); // assert(resProof.checkProof(false)); // Util.printToSystemOutWithWallClockTimePrefix(" Done."); Util.printToSystemOutWithWallClockTimePrefix(" Making it local first."); boolean checkResult = resProof.makeLocalFirst(true, false, false); assert (checkResult); Util.printToSystemOutWithWallClockTimePrefix(" Done."); Util.printToSystemOutWithWallClockTimePrefix("Size of ResProof: " + Util.largeNumberFormatter.format(resProof.size())); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); Util.printToSystemOutWithWallClockTimePrefix(" Recovering."); Map<ResNode, TransformedZ3Proof> cache = new HashMap<ResNode, TransformedZ3Proof>(); TransformedZ3Proof recoveredProof = new TransformedZ3Proof( resProof.getRoot(), literalMap, cache); // create ITE-tree for every control signal Util.printToSystemOutWithWallClockTimePrefix(" Compute interpolants..."); timer.start(); Map<PropositionalVariable, Formula> iteTrees = recoveredProof .createITETrees(controlVars, tseitinEncoding); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); return iteTrees; } @SuppressWarnings("unused") @Deprecated private Map<PropositionalVariable, Formula> proofTransformationAndInterpolation( Z3Proof rootProof, List<PropositionalVariable> controlVars) { Timer timer = new Timer(); // assert (rootProof.checkZ3ProofNodeRecursive); // try { // File prooffile = new File("proofTemp.txt"); // FileWriter fstream = new FileWriter(prooffile); // BufferedWriter proofFilewriter = new BufferedWriter(fstream); // proofFilewriter.write(rootProof.prettyPrint()); // proofFilewriter.close(); // } catch (IOException exc) { // System.err.println("Error while writing to proof file."); // exc.printStackTrace(); // noErrors = false; // } printProofStats(rootProof); Util.printToSystemOutWithWallClockTimePrefix(" Computing parent nodes..."); timer.start(); rootProof.computeParents(); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); // assert (rootProof.checkZ3ProofNodeRecursive()); dealWithBadLiteralHypotheses(rootProof); printProofStats(rootProof); // timer.start(); // int all_nodes_size = rootProof.allNodes().size(); // timer.end(); // Util.printToSystemOutWithWallClockTimePrefix(" All nodes size: " + // all_nodes_size); // Util.printToSystemOutWithWallClockTimePrefix(" (computed in " + // timer + ")"); // Util.printToSystemOutWithWallClockTimePrefix(" Local lemmas to assertions..."); // timer.start(); // rootProof.localLemmasToAssertions(); // timer.end(); // Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + // ")"); // timer.reset(); // // assert (rootProof.checkZ3ProofNodeRecursive()); // timer.start(); // Util.printToSystemOutWithWallClockTimePrefix(" Proof DAG size: " + // rootProof.size(false)); // timer.end(); // Util.printToSystemOutWithWallClockTimePrefix(" Size computed in " // + timer); // timer.reset(); // timer.start(); // Util.printToSystemOutWithWallClockTimePrefix(" Proof size after unwinding DAG: " // + rootProof.size(true)); // timer.end(); // Util.printToSystemOutWithWallClockTimePrefix(" Size computed in " // + timer); // timer.reset(); // Util.printToSystemOutWithWallClockTimePrefix(); Util.printToSystemOutWithWallClockTimePrefix(" Remove local sub-proofs..."); timer.start(); rootProof.removeLocalSubProofs(); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); // assert (rootProof.checkZ3ProofNodeRecursive()); printProofStats(rootProof); // Util.printToSystemOutWithWallClockTimePrefix("Num Instances: " + // Z3Proof.numInstances()); Util.printToSystemOutWithWallClockTimePrefix(" Conversion to transformed z3 proof..."); timer.start(); TransformedZ3Proof transformedZ3Proof = TransformedZ3Proof .convertToTransformedZ3Proof(rootProof); rootProof = null; // Allow this to be garbage collected timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); printProofStats(transformedZ3Proof); /* * Util.printToSystemOutWithWallClockTimePrefix("Num Instances: " + * Z3Proof.numInstances()); try { File smtfile = new * File("proofTemp.txt"); FileWriter fstream = new FileWriter(smtfile); * BufferedWriter smtfilewriter = new BufferedWriter(fstream); * rootProof.resetMarks(); smtfilewriter.write(rootProof.prettyPrint()); * smtfilewriter.close(); } catch (IOException exc) { * System.err.println("Error while writing to smtfile."); * exc.printStackTrace(); noErrors = false; } */ // assert (transformedZ3Proof.checkZ3ProofNodeRecursive()); Util.printToSystemOutWithWallClockTimePrefix(" To local proof..."); timer.start(); transformedZ3Proof.toLocalProof(); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); // assert (transformedZ3Proof.checkZ3ProofNodeRecursive()); assert (transformedZ3Proof.isLocal()); printProofStats(transformedZ3Proof); // System.out // .println("----Check:" // + transformedZ3Proof // .checkLeafsAgainstOriginalFormula(this.assertPartitionFormulas)); Util.printToSystemOutWithWallClockTimePrefix(" To resolution proof..."); timer.start(); transformedZ3Proof.toResolutionProof(); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); printProofStats(transformedZ3Proof); // System.out // .println("----Check:" // + transformedZ3Proof // .checkLeafsAgainstOriginalFormula(this.assertPartitionFormulas)); // START: ASHUTOSH code Util.printToSystemOutWithWallClockTimePrefix(" To resolution proof format..."); timer.start(); ResProof resolutionProof = Util .createResolutionProof(transformedZ3Proof); transformedZ3Proof = null; // Allow this to be garbage collected timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); Util.printToSystemOutWithWallClockTimePrefix(" Check and transform resolution proof..."); timer.start(); // resolutionProof.dumpProof(); resolutionProof.checkProof(false); resolutionProof.rmDoubleLits(); resolutionProof.checkProof(false); resolutionProof.deLocalizeProof(); resolutionProof.checkProof(false); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); // END: ASHUTOSH code // Transform back into Z3Proof format Util.printToSystemOutWithWallClockTimePrefix(" Recover resolution proof..."); timer.start(); TransformedZ3Proof recoveredProof = new TransformedZ3Proof( resolutionProof.getRoot(), Util.getLiteralMap(), null); resolutionProof = null; // Allow this to be garbage collected timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); printProofStats(recoveredProof); // System.out // .println("----Check:" // + recoveredProof // .checkLeafsAgainstOriginalFormula(this.assertPartitionFormulas)); // create ITE-tree for every control signal Util.printToSystemOutWithWallClockTimePrefix(" Compute interpolants..."); timer.start(); Map<PropositionalVariable, Formula> iteTrees = recoveredProof .createITETrees(controlVars, tseitinEncoding); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); return iteTrees; } /** * @param rootProof */ @Deprecated private void dealWithBadLiteralHypotheses(Z3Proof rootProof) { Timer timer = new Timer(); timer.start(); Util.printToSystemOutWithWallClockTimePrefix(" Starting to deal with bad-literal hypotheses..."); // Find all bad literal hypotheses Set<Z3Proof> leafs = rootProof.allLeafs(); Set<Z3Proof> badLiteralHypotheses = new HashSet<Z3Proof>(leafs.size()); for (Z3Proof leaf : leafs) { if (leaf.getProofType().equals(SExpressionConstants.ASSERTED)) continue; if (leaf.getProofType().equals(SExpressionConstants.COMMUTATIVITY)) continue; assert (leaf.getProofType().equals(SExpressionConstants.HYPOTHESIS)); assert (Util.isLiteral(leaf.getConsequent())); if (Util.containsBadLiteral(leaf.getConsequent() .transformToConsequentsForm())) badLiteralHypotheses.add(leaf); } leafs = null; // Allow this to be garbage collected Util.printToSystemOutWithWallClockTimePrefix(" Found " + badLiteralHypotheses.size() + " bad-literal hypotheses. Current timer: " + timer); Set<Formula> badLiterals = new HashSet<Formula>(); for (Z3Proof badLiteralHypothesis : badLiteralHypotheses) badLiterals.add(badLiteralHypothesis.getConsequent()); Util.printToSystemOutWithWallClockTimePrefix(" These consist of " + badLiterals.size() + " different bad literals."); Util.printToSystemOutWithWallClockTimePrefix(" Now looking for IFF nodes for all these formulas. Current timer: " + timer); int foundCounter = 0; int literalCount = 0; for (Formula badLiteral : badLiterals) { Set<Z3Proof> iffNodes = rootProof.findIffNodes(badLiteral); Util.printToSystemOutWithWallClockTimePrefix(" Literal " + ++literalCount + ": " + Util.formulaToStringWithoutNewlines(badLiteral)); Util.printToSystemOutWithWallClockTimePrefix(" Found " + iffNodes.size() + " IFF nodes. Current timer: " + timer); Set<Z3Proof> unconditionalIffNodes = new HashSet<Z3Proof>( iffNodes.size()); boolean found = false; for (Z3Proof iffNode : iffNodes) { Set<Z3Proof> iffNodeHypotheses = iffNode.getHypotheses(); if (iffNodeHypotheses.isEmpty()) { unconditionalIffNodes.add(iffNode); found = true; break; } else { Util.printToSystemOutWithWallClockTimePrefix(" Found " + iffNodeHypotheses.size() + " hypotheses for IFF node. Size: " + iffNode.size()); if (iffNodeHypotheses.size() == 3) assert (iffNodeHypotheses.size() == 3); } } if (found) { Util.printToSystemOutWithWallClockTimePrefix(" Unconditional node found. Current timer: " + timer); foundCounter++; } else { Util.printToSystemOutWithWallClockTimePrefix(" NO unconditional node found. Current timer: " + timer); } } Util.printToSystemOutWithWallClockTimePrefix(" Found unconditional nodes for " + foundCounter + " literals, out of " + badLiterals.size() + " literals in total. Current timer: " + timer); assert (foundCounter == badLiterals.size()); // Deal with each bad literal hypothesis for (Z3Proof badLiteralHypothesis : badLiteralHypotheses) { Timer oneHypTimer = new Timer(); oneHypTimer.start(); assert (badLiteralHypothesis != null); oneHypTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Update complete. (" + oneHypTimer + ")"); System.out.println(); } timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done with all bad-literal hypotheses. (Overall time: " + timer + ")"); } /** * Run synthesis in iterative mode. * * @throws SuraqException */ private void runIterative() throws SuraqException { assert (VeriTSolver.isActive()); SuraqOptions options = SuraqOptions.getInstance(); File sourceFile = new File(options.getInput()); Util.printMemoryInformation(); Util.printToSystemOutWithWallClockTimePrefix("start input transformations"); Timer inputTransformationTimer = new Timer(); parseInput(); inputTransformationTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("finished input transformations in " + inputTransformationTimer + ".\n"); Util.printMemoryInformation(); mainFormula = performFormulaReductions(); List<PropositionalVariable> controlVariables = logicParser .getControlVariables(); Map<PropositionalVariable, Formula> interpolants = new HashMap<PropositionalVariable, Formula>( 2 * controlVariables.size()); int numControlSignals = controlVariables.size(); Util.printToSystemOutWithWallClockTimePrefix("Starting iterative interpolant computation"); // Main loop where one interpolant per iteration is computed for (int count = 0; count < numControlSignals; count++) { Util.printToSystemOutWithWallClockTimePrefix("##########################################"); Util.printToSystemOutWithWallClockTimePrefix("Iteration " + (count + 1)); Util.printToSystemOutWithWallClockTimePrefix("Computing witness function for signal '" + controlVariables.get(0) + "'."); Util.printToSystemOutWithWallClockTimePrefix("Preparing output expressions..."); prepareOutputExpressions(mainFormula, controlVariables); Util.printToSystemOutWithWallClockTimePrefix("Done."); Util.printToSystemOutWithWallClockTimePrefix(" build function and variable lists for parser"); propositionalVars.clear(); mainFormula.getPropositionalVariables(propositionalVars, new HashSet<SMTLibObject>()); domainVars.clear(); mainFormula.getDomainVariables(domainVars, new HashSet<SMTLibObject>()); arrayVars.clear(); mainFormula.getArrayVariables(arrayVars, new HashSet<SMTLibObject>()); uninterpretedFunctions.clear(); mainFormula.getUninterpretedFunctions(uninterpretedFunctions, new HashSet<SMTLibObject>()); for (Map.Entry<Token, List<Term>> varList : noDependenceVarsCopies .entrySet()) { assert (varList.getValue() != null); assert (varList.getValue().size() > 0); Term first = varList.getValue().get(0); if (first instanceof DomainVariable) for (Term var : varList.getValue()) domainVars.add((DomainVariable) var); if (first instanceof PropositionalVariable) for (Term var : varList.getValue()) propositionalVars.add((PropositionalVariable) var); if (first instanceof ArrayVariable) for (Term var : varList.getValue()) arrayVars.add((ArrayVariable) var); } for (Map.Entry<Token, List<UninterpretedFunction>> functionList : noDependenceFunctionsCopies .entrySet()) uninterpretedFunctions.addAll(functionList.getValue()); if (options.getTseitinType() == SuraqOptions.TSEITIN_WITHOUT_Z3) { Util.printToSystemOutWithWallClockTimePrefix(" Performing tseitin encoding without Z3..."); performTseitinEncodingWithoutZ3(); } else { Util.printToSystemOutWithWallClockTimePrefix(" Performing tseitin encoding with Z3..."); performTseitinEncodingWithZ3(); } Util.printToSystemOutWithWallClockTimePrefix(" All partitions done."); BufferedReader proofReader; Util.printToSystemOutWithWallClockTimePrefix("start proof calculation."); Timer proofcalculationTimer = new Timer(); proofcalculationTimer.start(); List<Formula> tseitinPartitionsList = new ArrayList<Formula>( tseitinPartitions.size()); for (Integer key : tseitinPartitions.keySet()) tseitinPartitionsList.add(tseitinPartitions.get(key)); VeriTSolver veriT = new VeriTSolver(); Timer veritTimer = new Timer(); veritTimer.start(); veriT.solve(tseitinPartitionsList); veritTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("VeriTSolver returned!"); Util.printToSystemOutWithWallClockTimePrefix("Solving and proof production took " + veritTimer.toString() + "."); try { proofReader = veriT.getStream(); } catch (FileNotFoundException exc) { throw new RuntimeException(exc); } VeriTParser veriTParser; veriTParser = new VeriTParser(proofReader, mainFormula, tseitinEncoding.keySet(), noDependenceVarsCopies.values(), noDependenceFunctionsCopies); Util.printMemoryInformation(); if (!options.getCheckProofWhileParsing()) { VeritProof.setCheckProofEnabled(false); VeritProofNode.setCheckProofNodesEnabled(false); } Util.printToSystemOutWithWallClockTimePrefix("start to parse proof."); Timer parseTimer = new Timer(); parseTimer.start(); veriTParser.parse(); parseTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Done parsing. (Took " + parseTimer.toString() + ")"); veritProof = veriTParser.getProof(); assert (veritProof != null); Util.printToSystemOutWithWallClockTimePrefix("Proof size: " + Util.largeNumberFormatter.format(veritProof.size())); veritProof.removeUnreachableNodes(); Util.printToSystemOutWithWallClockTimePrefix("Proof size (after removing unreachable nodes): " + Util.largeNumberFormatter.format(veritProof.size())); assert (veritProof.checkProof()); assert (veritProof.hasNoBadLiterals()); Util.printToSystemOutWithWallClockTimePrefix("Starting to interpolate even vs. odd partitions."); Timer interpolationTimer = new Timer(); interpolationTimer.start(); Formula interpolant = veritProof .interpolateEvenVsOddPartitions(tseitinPartitions); interpolationTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Done interpolation. (Took " + interpolationTimer.toString() + ")"); Util.printToSystemOutWithWallClockTimePrefix("Backsubsituting Tseitin encoding."); Map<Token, Term> substitutionsMap = new HashMap<Token, Term>(); for (PropositionalVariable tseitinVar : tseitinEncoding.keySet()) substitutionsMap.put(Token.generate(tseitinVar.getVarName()), FormulaTerm.create(tseitinEncoding.get(tseitinVar))); Util.printToSystemOutWithWallClockTimePrefix("Done."); Map<SMTLibObject, SMTLibObject> done = new HashMap<SMTLibObject, SMTLibObject>(); interpolant = interpolant.substituteFormula(substitutionsMap, done); // interpolant = simplifyWithZ3(interpolant); FormulaSimplifier simplifier = new FormulaSimplifier(interpolant); try { simplifier.simplify(); } catch (IOException exc) { throw new RuntimeException( "Could not simplify interpolant due to IOException", exc); } assert (simplifier.checkSimplification()); interpolant = simplifier.getSimplifiedFormula(); assert (Util.checkInterpolant(interpolant, assertPartitionFormulas)); Util.printToSystemOutWithWallClockTimePrefix("Resubstituting..."); PropositionalVariable currentSignal = controlVariables.remove(0); // // DEBUG // File interpolantFile = new File(currentSignal.getVarName() // .toString() + ".smt2"); // try { // FileWriter fwriter = new FileWriter(interpolantFile); // Util.printToSystemOutWithWallClockTimePrefix("Writing interpolant to " // + interpolantFile.toString()); // BufferedWriter writer = new BufferedWriter(fwriter); // Util.writeFormulaUsingLetExpressions(interpolant, writer); // writer.close(); // fwriter.close(); // } catch (IOException exc) { // Util.printToSystemOutWithWallClockTimePrefix("Could not write interpolant to file."); // exc.printStackTrace(); // } // // END DEBUG interpolants.put(currentSignal, interpolant); Map<Token, PropositionalTerm> substMap = new TreeMap<Token, PropositionalTerm>(); substMap.put(Token.generate(currentSignal.getVarName()), FormulaTerm.create(interpolant)); done.clear(); mainFormula = mainFormula.substituteFormula(substMap, done); boolean assertsEnabled = false; assert (assertsEnabled = true) == true; // Intentional side // effect!!! if (count == numControlSignals - 1 && assertsEnabled) { // This was the last control signal. // mainFormula should now be UNSAT. Util.printToSystemOutWithWallClockTimePrefix("Checking if negation of main formula is UNSAT"); if (!Util.checkUnsat(NotFormula.create(mainFormula))) { noErrors = false; Util.printToSystemOutWithWallClockTimePrefix("ERROR! negation of mainFormula was not UNSAT!"); } else Util.printToSystemOutWithWallClockTimePrefix("OK! negation of mainFormula is UNSAT."); } assertPartitionFormulas.clear(); tseitinPartitions.clear(); tseitinEncoding.clear(); declarationStr = ""; } // Done with iterative interpolation Util.printToSystemOutWithWallClockTimePrefix("Starting back-substitution"); for (PropositionalVariable key : interpolants.keySet()) { assert (interpolants.get(key) != null); Formula interpolant = (Formula) interpolants.get(key) .uninterpretedFunctionsBackToArrayReads( new HashSet<ArrayVariable>( logicParser.getArrayVariables()), new HashMap<SMTLibObject, SMTLibObject>()); interpolants.put(key, interpolant); } // write output file try { Util.printToSystemOutWithWallClockTimePrefix(" Writing output to file " + options.getOutput()); FileWriter fstream = new FileWriter(options.getOutput()); BufferedWriter writer = new BufferedWriter(fstream); createOutputFile(sourceFile, interpolants, writer); writer.close(); fstream.close(); } catch (IOException exc) { Util.printToSystemOutWithWallClockTimePrefix("Error while writing to output file: " + options.getOutput()); exc.printStackTrace(); noErrors = false; } overallTimer.stop(); // Don't include check time into overall time if (options.isCheckResult()) { Util.printToSystemOutWithWallClockTimePrefix("Starting to check results with z3..."); Timer checkTimer = new Timer(); checkTimer.start(); SMTSolver z3 = SMTSolver.create(SMTSolver.z3_type, "lib/z3/bin/z3"); z3.solve(new File(options.getOutput())); switch (z3.getState()) { case SMTSolver.UNSAT: Util.printToSystemOutWithWallClockTimePrefix("SUCCESSFULLY MODEL-CHECKED RESULTS WITH Z3! :-)"); break; case SMTSolver.SAT: noErrors = false; Util.printToSystemOutWithWallClockTimePrefix("ERROR: Z3 tells us SAT. Implementation of control signal is not correct"); break; default: noErrors = false; Util.printToSystemOutWithWallClockTimePrefix("Z3 OUTCOME ----> UNKNOWN! CHECK ERROR STREAM."); } checkTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Check finished in " + checkTimer); } Util.printToSystemOutWithWallClockTimePrefix(" done!"); // All done :-) printEnd(noErrors, overallTimer); // System.err.println(Suraq.extTimer); return; } /** * @param formula * @return */ private Formula simplifyWithZ3(Formula formula) { z3 z3 = (at.iaik.suraq.smtsolver.z3) SMTSolver.create( SMTSolver.z3_type, SuraqOptions.getZ3_4Path()); Timer timer = new Timer(); timer.start(); Util.printToSystemOutWithWallClockTimePrefix("Simplifying formula."); BufferedReader simpliefiedFormulaReader = z3.simplify(formula); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Done. (Took " + timer.toString() + ")"); Util.printToSystemOutWithWallClockTimePrefix("Starting parsing."); try { Set<ArrayVariable> aVars = new HashSet<ArrayVariable>(); formula.getArrayVariables(aVars, new HashSet<SMTLibObject>()); Set<PropositionalVariable> pVars = new HashSet<PropositionalVariable>(); Set<DomainVariable> dVars = new HashSet<DomainVariable>(); Set<UninterpretedFunction> ufs = new HashSet<UninterpretedFunction>(); Set<SMTLibObject> done = new HashSet<SMTLibObject>(); formula.getPropositionalVariables(pVars, done); done.clear(); formula.getDomainVariables(dVars, done); done.clear(); formula.getUninterpretedFunctions(ufs, done); done.clear(); FormulaParser parser = new FormulaParser(pVars, dVars, aVars, ufs, simpliefiedFormulaReader); Util.printToSystemOutWithWallClockTimePrefix("Finished parsing SExpressions. Starting to parse formula."); parser.parse(); Formula result = parser.getParsedFormula(); Util.printToSystemOutWithWallClockTimePrefix("Done."); return result; } catch (ParseError exc) { System.out.println("Parser error."); throw new RuntimeException(exc); } catch (IOException exc) { System.out.println("IOException."); throw new RuntimeException(exc); } } /** * @see java.lang.Runnable#run() */ @Override public void run() { overallTimer.start(); printWelcome(); SuraqOptions options = SuraqOptions.getInstance(); if (options.getIterativeInterpolation() == true) { Util.printToSystemOutWithWallClockTimePrefix("Running in iterative mode..."); VeriTSolver.setActive(true); try { runIterative(); } catch (SuraqException exc) { throw new RuntimeException(exc); } return; } if (options.getSolver().toLowerCase().equals("z3")) { VeriTSolver.setActive(false); } else if (options.getSolver().toLowerCase().equals("verit")) { VeriTSolver.setActive(true); } else { Util.printToSystemOutWithWallClockTimePrefix("WARNING: Unknown solver \"" + options.getSolver() + "\" selected. Using veriT per default."); VeriTSolver.setActive(true); } if (VeriTSolver.isActive()) { runWithVeriT(); return; // IMPORTANT: Any reference to veriT below is deprecated. // When using veriT, everything is done in runWithVeriT. // The following usage of veriT in this method is just // left-over code, that should now be unreachable. } assert (!VeriTSolver.isActive()); assert (options.getSolver().toLowerCase().equals("z3")); throw new RuntimeException("Only veriT solver currently supported!"); } /** * Main control flow when using veriT. */ private void runWithVeriT() { assert (VeriTSolver.isActive()); SuraqOptions options = SuraqOptions.getInstance(); File sourceFile = new File(options.getInput()); List<PropositionalVariable> controlVariables = null; Map<PropositionalVariable, Formula> iteTrees = null; Util.printMemoryInformation(); Util.printToSystemOutWithWallClockTimePrefix("start input transformations"); Timer inputTransformationTimer = new Timer(); inputTransformationTimer.start(); inputTransformations(sourceFile); controlVariables = logicParser.getControlVariables(); inputTransformationTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("finished input transformations in " + inputTransformationTimer + ".\n"); Util.printMemoryInformation(); if (options.getUseThisPropProofFile() == null) { String providedProofFile = options.getUseThisProofFile(); Timer veritTimer = new Timer(); veritTimer.start(); BufferedReader proofReader; if (providedProofFile == null) { Util.printToSystemOutWithWallClockTimePrefix("start proof calculation."); Timer proofcalculationTimer = new Timer(); proofcalculationTimer.start(); List<Formula> tseitinPartitionsList = new ArrayList<Formula>( tseitinPartitions.size()); for (Integer key : tseitinPartitions.keySet()) tseitinPartitionsList.add(tseitinPartitions.get(key)); VeriTSolver veriT = new VeriTSolver(); veriT.solve(tseitinPartitionsList); Util.printToSystemOutWithWallClockTimePrefix("VeriTSolver returned!"); veritTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Solving and proof production took " + veritTimer.toString() + "."); try { proofReader = veriT.getStream(); } catch (FileNotFoundException exc) { throw new RuntimeException(exc); } } else { try { proofReader = new BufferedReader(new FileReader( providedProofFile)); Util.printToSystemOutWithWallClockTimePrefix("[INFO] Using the following proof file, instead of calling the solver: " + providedProofFile); } catch (FileNotFoundException exc) { System.out.println("Proof file not found: " + providedProofFile); throw new RuntimeException(exc); } } VeriTParser veriTParser; veriTParser = new VeriTParser(proofReader, mainFormula, tseitinEncoding.keySet(), noDependenceVarsCopies.values(), noDependenceFunctionsCopies); Util.printMemoryInformation(); if (!options.getCheckProofWhileParsing()) { VeritProof.setCheckProofEnabled(false); VeritProofNode.setCheckProofNodesEnabled(false); } Util.printToSystemOutWithWallClockTimePrefix("start to parse proof."); Timer parseTimer = new Timer(); parseTimer.start(); veriTParser.parse(); parseTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Done parsing. (Took " + parseTimer.toString() + ")"); veritProof = veriTParser.getProof(); assert (veritProof != null); Util.printToSystemOutWithWallClockTimePrefix("Proof size: " + Util.largeNumberFormatter.format(veritProof.size())); veritProof.removeUnreachableNodes(); Util.printToSystemOutWithWallClockTimePrefix("Proof size (after removing unreachable nodes): " + Util.largeNumberFormatter.format(veritProof.size())); assert (veritProof.checkProof()); assert (veritProof.hasNoBadLiterals()); } if (options.getUseThisPropProofFile() == null) { assert (veritProof != null); VeritProof.setCheckProofEnabled(true); VeritProofNode.setCheckProofNodesEnabled(true); Util.printMemoryInformation(); } iteTrees = proofTransformationAndInterpolation(controlVariables); Util.printToSystemOutWithWallClockTimePrefix("Starting back-substitution"); for (PropositionalVariable key : iteTrees.keySet()) { assert (iteTrees.get(key) != null); Formula iteTree = iteTrees.get(key); iteTree = simplifyWithZ3(iteTree); iteTree = (Formula) iteTree .uninterpretedFunctionsBackToArrayReads( new HashSet<ArrayVariable>(logicParser .getArrayVariables()), new HashMap<SMTLibObject, SMTLibObject>()); iteTrees.put(key, iteTree); } // write output file try { Util.printToSystemOutWithWallClockTimePrefix(" Writing output to file " + options.getOutput()); FileWriter fstream = new FileWriter(options.getOutput()); BufferedWriter writer = new BufferedWriter(fstream); createOutputFile(sourceFile, iteTrees, writer); writer.close(); fstream.close(); } catch (IOException exc) { Util.printToSystemOutWithWallClockTimePrefix("Error while writing to output file: " + options.getOutput()); exc.printStackTrace(); noErrors = false; } overallTimer.stop(); // Don't count time to check results. if (options.isCheckResult()) { Util.printToSystemOutWithWallClockTimePrefix("Starting to check results with z3..."); Timer checkTimer = new Timer(); checkTimer.start(); SMTSolver z3 = SMTSolver.create(SMTSolver.z3_type, "lib/z3/bin/z3"); z3.solve(new File(options.getOutput())); switch (z3.getState()) { case SMTSolver.UNSAT: Util.printToSystemOutWithWallClockTimePrefix("SUCCESSFULLY MODEL-CHECKED RESULTS WITH Z3! :-)"); break; case SMTSolver.SAT: noErrors = false; Util.printToSystemOutWithWallClockTimePrefix("ERROR: Z3 tells us SAT. Implementation of control signal is not correct"); break; default: noErrors = false; Util.printToSystemOutWithWallClockTimePrefix("Z3 OUTCOME ----> UNKNOWN! CHECK ERROR STREAM."); } checkTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix("Check finished in " + checkTimer); } Util.printToSystemOutWithWallClockTimePrefix(" done!"); // All done :-) printEnd(noErrors, overallTimer); // System.err.println(Suraq.extTimer); return; } /** * Forms the file which represents the final result of suraq. The * interpolation result for each control signal is inserted in the original * input file, and forms the result. * * @param interpolationFormulas * Map which contains the interpolation for each control signal * @param writer * the writer to write to * @return the string from the union of the input file and * control-signal-interpolations. * @throws IOException * */ private void createOutputFile(File sourceFile, Map<PropositionalVariable, Formula> interpolations, Writer writer) throws IOException { SExpParser sExpParser = null; try { sExpParser = new SExpParser(sourceFile); } catch (FileNotFoundException exc) { System.err.println("ERROR: File " + sourceFile.getPath() + " not found!"); noErrors = false; return; } catch (IOException exc) { System.err.println("ERROR: Could not read from file " + sourceFile.getPath()); noErrors = false; return; } try { sExpParser.parse(); assert (sExpParser.wasParsingSuccessfull()); } catch (ParseError exc) { handleParseError(exc); noErrors = false; return; } SExpression rootExp = sExpParser.getRootExpr(); ArrayList<SExpression> children = new ArrayList<SExpression>( rootExp.getChildren()); rootExp.replaceChild(SExpressionConstants.SET_LOGIC_QF_AUFLIA, 0); rootExp.addChild(SExpressionConstants.DECLARE_SORT_VALUE, 1); int count = 1; SExpression lastDeclare = null; for (SExpression child : children) { // if (child.toString().contains("declare-fun")) { // String newChild = child.toString().replace("Control", "Bool") // .replace(":no_dependence", " "); // newChild = newChild.replace("\n\n", "\n"); // // rootExp.replaceChild(SExpression.fromString(newChild), count); // lastDeclare = rootExp.getChildren().get(count); // } child.changeControlAndNoDepDefs(); if (child.isDeclareFun()) lastDeclare = rootExp.getChildren().get(count); // negate assert formulas if (child.isAssert()) { assert (child.getChildren().size() == 2); SExpression assertFormula = child.getChildren().get(1); SExpression negatedAssertFormula = new SExpression( SExpressionConstants.NOT, assertFormula); SExpression negatedAssert = new SExpression( SExpressionConstants.ASSERT, negatedAssertFormula); rootExp.replaceChild(negatedAssert, count); } count++; } // Add constraints for new variables insertConstraintDeclarations(rootExp, lastDeclare); SExpression constraintExp = new SExpression( SExpressionConstants.ASSERT, AndFormula .generate(new ArrayList<Formula>(this.constraints)) .uninterpretedFunctionsBackToArrayReads( new HashSet<ArrayVariable>( logicParser.getArrayVariables()), new HashMap<SMTLibObject, SMTLibObject>()) .toSmtlibV2()); rootExp.addChild(constraintExp); for (SExpression child : rootExp.getChildren()) child.writeTo(writer); // add new assert formulas for each control signal for (Map.Entry<PropositionalVariable, Formula> entry : interpolations .entrySet()) { PropositionalVariable controlSignal = entry.getKey(); Formula controlFormula = entry.getValue(); writer.write("(assert (= "); writer.write(controlSignal.toString()); writer.write(" \n"); Util.writeFormulaUsingLetExpressions(controlFormula, writer); writer.write("\n))"); } writer.write(SExpressionConstants.CHECK_SAT.toString()); } /** * @param rootExp * @param lastDeclare */ private void insertConstraintDeclarations(SExpression rootExp, SExpression lastDeclare) { assert (constraints != null); SExpression currentLast = lastDeclare; if (constraints.isEmpty()) return; assert (constraints.size() > 0); AndFormula constraint = AndFormula.generate(new ArrayList<Formula>( constraints)); // Adding declare-fun for array variables Set<ArrayVariable> localArrayVars = new HashSet<ArrayVariable>(); constraint.getArrayVariables(localArrayVars, new HashSet<SMTLibObject>()); localArrayVars.removeAll(this.logicParser.getArrayVariables()); for (ArrayVariable var : localArrayVars) { SExpression declare = SExpression.makeDeclareFun( Token.generate(var.getVarName()), SExpressionConstants.ARRAY_TYPE, 0); rootExp.insertChildAfter(declare, currentLast); currentLast = declare; } // Adding declare-fun for domain variables Set<DomainVariable> localDomainVars = new HashSet<DomainVariable>(); constraint.getDomainVariables(localDomainVars, new HashSet<SMTLibObject>()); localDomainVars.removeAll(this.logicParser.getDomainVariables()); for (DomainVariable var : localDomainVars) { SExpression declare = SExpression.makeDeclareFun( Token.generate(var.getVarName()), SExpressionConstants.VALUE_TYPE, 0); rootExp.insertChildAfter(declare, currentLast); currentLast = declare; } // Adding declare-fun for propositional variables Set<PropositionalVariable> localPropositionalVars = new HashSet<PropositionalVariable>(); constraint.getPropositionalVariables(localPropositionalVars, new HashSet<SMTLibObject>()); localPropositionalVars.removeAll(this.logicParser.getBoolVariables()); localPropositionalVars .removeAll(this.logicParser.getControlVariables()); for (PropositionalVariable var : localPropositionalVars) { SExpression declare = SExpression.makeDeclareFun( Token.generate(var.getVarName()), SExpressionConstants.BOOL_TYPE, 0); rootExp.insertChildAfter(declare, currentLast); currentLast = declare; } } /** * Parses <code>tseitinStr</code> into a formula. * * @param tseitinStr * output string of the z3 after applying tseitin encoding * @param partition * the partition of the tseitin string * @return the parser that parsed the formula. * */ private TseitinParser parseTseitinStr(String tseitinStr, int partition) { SExpParser sExpParser = new SExpParser(tseitinStr); try { sExpParser.parse(); assert (sExpParser.wasParsingSuccessfull()); } catch (ParseError exc) { handleParseError(exc); throw new RuntimeException( "S-Expression parse error. Cannot continue.", exc); } SExpression rootExp = sExpParser.getRootExpr(); TseitinParser tseitinParser = new TseitinParser(rootExp, domainVars, propositionalVars, arrayVars, uninterpretedFunctions, partition); try { tseitinParser.parse(); assert (tseitinParser.wasParsingSuccessfull()); } catch (ParseError exc) { handleParseError(exc); throw new RuntimeException( "Tseitin encoding parse error. Cannot continue.", exc); } tseitinEncoding.putAll(tseitinParser.getTseitinEncoding()); return tseitinParser; } /** * Creates an SMT Description from the tseitin assert partitions. Adds * entries in the <code>tseitinEncoding</code> map, for each tseitin * variable the corresponding formula. * * @param declarationStr * declarations of the SMT Description * @param tseitinAssertPartitions * tseitin assert partitions * @return SMT description to proof * */ @SuppressWarnings("unused") @Deprecated private String buildSMTDescriptionFromTseitinPartitions( String declarationStr, Map<Integer, Formula> tseitinPartitions) { StringBuilder smtStr = new StringBuilder(); smtStr.append(SExpressionConstants.SET_LOGIC_QF_UF.toString()); if (!VeriTSolver.isActive()) { smtStr.append(SExpressionConstants.AUTO_CONFIG_FALSE.toString()); smtStr.append(SExpressionConstants.PROOF_MODE_2.toString()); smtStr.append(SExpressionConstants.SET_OPTION_PROPAGATE_BOOLEANS_FALSE .toString()); smtStr.append(SExpressionConstants.SET_OPTION_PROPAGATE_VALUES_FALSE .toString()); } smtStr.append(SExpressionConstants.DECLARE_SORT_VALUE.toString()); smtStr.append(declarationStr); // declarations for tseitin variables for (PropositionalVariable var : tseitinEncoding.keySet()) smtStr.append(SExpression.makeDeclareFun( Token.generate(var.getVarName()), SExpressionConstants.BOOL_TYPE, 0)); for (int count : tseitinPartitions.keySet()) { Formula tseitinPartition = tseitinPartitions.get(count); smtStr.append("(assert " + tseitinPartition.toString() + ")"); } smtStr.append(SExpressionConstants.CHECK_SAT.toString()); if (!VeriTSolver.isActive()) smtStr.append(SExpressionConstants.GET_PROOF.toString()); smtStr.append(SExpressionConstants.EXIT.toString()); return smtStr.toString(); } @SuppressWarnings("unused") @Deprecated private String buildSMTDescriptionWithoutTsetin(String declarationStr) { StringBuffer smtStr = new StringBuffer(); smtStr.append(SExpressionConstants.SET_LOGIC_QF_UF.toString()); if (!VeriTSolver.isActive()) smtStr.append(SExpressionConstants.AUTO_CONFIG_FALSE.toString()); smtStr.append(SExpressionConstants.PROOF_MODE_2.toString()); if (!VeriTSolver.isActive()) smtStr.append(SExpressionConstants.SET_OPTION_PROPAGATE_BOOLEANS_FALSE .toString()); smtStr.append(SExpressionConstants.SET_OPTION_PROPAGATE_VALUES_FALSE .toString()); // if(!VeriTSolver.isActive()) smtStr.append(SExpressionConstants.DECLARE_SORT_VALUE.toString()); smtStr.append(declarationStr); for (SExpression assertPartition : assertPartitionList) { // smtStr.append("(assert " + assertPartition + ")"); smtStr.append(assertPartition); } smtStr.append(SExpressionConstants.CHECK_SAT.toString()); if (!VeriTSolver.isActive()) { // ??? } smtStr.append(SExpressionConstants.GET_PROOF.toString()); smtStr.append(SExpressionConstants.EXIT.toString()); return smtStr.toString(); } /** * Creates an SMT Description from the simplified assert partitions. * * @param declarationStr * declarations of the SMT Description * @param simplifiedAssertPartitions * simplified assert partitions * @return SMT description to proof * */ @SuppressWarnings("unused") @Deprecated private String buildProofSMTDescription(String declarationStr, List<String> simplifiedAssertPartitions) { String smtStr = ""; smtStr += SExpressionConstants.SET_LOGIC_QF_UF.toString(); smtStr += SExpressionConstants.AUTO_CONFIG_FALSE.toString(); smtStr += SExpressionConstants.PROOF_MODE_2.toString(); smtStr += SExpressionConstants.SET_OPTION_PROPAGATE_BOOLEANS_FALSE .toString(); smtStr += SExpressionConstants.SET_OPTION_PROPAGATE_VALUES_FALSE .toString(); smtStr += SExpressionConstants.DECLARE_SORT_VALUE.toString(); smtStr += declarationStr; // create assert partition for every simplified partition for (String partition : simplifiedAssertPartitions) { SExpression expr = new SExpression(Token.generate("assert"), SExpression.fromString(partition)); smtStr += expr.toString(); } smtStr += SExpressionConstants.CHECK_SAT.toString(); smtStr += SExpressionConstants.GET_PROOF.toString(); smtStr += SExpressionConstants.EXIT.toString(); return smtStr; } /** * Creates an SMT description for an tseitin-cnf operation * * @param declarationStr * declarations of the SMT description * @param assertPartition * partition to be transformed by tseitin-encoding * @return SMT description of tseitin-encoding operation * */ private String buildSMTDescriptionForTseitinEncoding(String declarationStr, String assertPartition) { String smtStr = ""; smtStr += SExpressionConstants.SET_LOGIC_QF_UF.toString(); smtStr += SExpressionConstants.SET_OPTION_PRODUCE_MODELS_TRUE .toString(); smtStr += SExpressionConstants.DECLARE_SORT_VALUE.toString(); smtStr += declarationStr; smtStr += assertPartition; smtStr += SExpressionConstants.APPLY_TSEITIN.toString(); smtStr += SExpressionConstants.EXIT.toString(); return smtStr; } /** * Takes the main formula from <code>logicParser</code> and performs the * reductions on it (arrays, ITEs, ...) * * @return the reduced formula. */ private Formula performFormulaReductions() throws SuraqException { Suraq.extTimer.stopReset("<doMainWork>"); Timer timer = new Timer(); Formula formula = logicParser.getMainFormula(); // Output statistics List<ArrayVariable> arrayVars2 = logicParser.getArrayVariables(); List<DomainVariable> domainVars = logicParser.getDomainVariables(); List<PropositionalVariable> propVars = logicParser.getBoolVariables(); List<Token> nodepVars = logicParser.getNoDependenceVariables(); int numDepvars = 0; for (ArrayVariable var : arrayVars2) { if (!nodepVars.contains(Token.generate(var.getVarName()))) numDepvars++; } for (DomainVariable var : domainVars) { if (!nodepVars.contains(Token.generate(var.getVarName()))) numDepvars++; } for (PropositionalVariable var : propVars) { if (!nodepVars.contains(Token.generate(var.getVarName()))) numDepvars++; } Util.printToSystemOutWithWallClockTimePrefix("[INFO] The following number refer to variables DECLARED in the input file."); Util.printToSystemOutWithWallClockTimePrefix("[INFO] They are not necessarily actually USED in the formula."); Util.printToSystemOutWithWallClockTimePrefix("Number of variables on which the controllers CAN depend: " + numDepvars); Util.printToSystemOutWithWallClockTimePrefix("Number of variables on which the controllers CANNOT depend: " + nodepVars.size()); Util.printToSystemOutWithWallClockTimePrefix("Number of (all) array variables: " + arrayVars2.size()); Set<UninterpretedFunction> ufs = new HashSet<UninterpretedFunction>(); formula.getUninterpretedFunctions(ufs, new HashSet<SMTLibObject>()); int numUfs = 0; int numUps = 0; for (UninterpretedFunction function : ufs) { if (function.getType().equals(SExpressionConstants.BOOL_TYPE)) numUps++; if (function.getType().equals(SExpressionConstants.VALUE_TYPE)) numUfs++; } Util.printToSystemOutWithWallClockTimePrefix("Number of uninterpreted functions: " + numUfs); Util.printToSystemOutWithWallClockTimePrefix("Number of uninterpreted predicates: " + numUps); // Util.writeFormulaToFile(formula, "afterNothing.smt2", false, false); // // DEBUG // Flattening formula, because macros cause problems when // replacing arrays with uninterpreted functions // (functions cannot be macro parameters) Util.printToSystemOutWithWallClockTimePrefix(" Flattening formula..."); timer.start(); formula = formula.flatten(); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // Util.writeFormulaToFile(formula, "afterFlatten.smt2", false, false); // // DEBUG BigInteger treeSize = formula.size(true, new HashMap<Formula, BigInteger>()); BigInteger dagSize = formula.size(false, new HashMap<Formula, BigInteger>()); Util.printToSystemOutWithWallClockTimePrefix("Formula DAG size: " + dagSize.toString()); Util.printToSystemOutWithWallClockTimePrefix("Formula tree size: " + treeSize.toString()); Set<FunctionMacro> macros = new HashSet<FunctionMacro>(); formula.getFunctionMacros(macros, new HashSet<SMTLibObject>()); assert (macros.isEmpty()); noDependenceVars = new HashSet<Token>( logicParser.getNoDependenceVariables()); Set<Formula> constraints = new HashSet<Formula>(); Util.printToSystemOutWithWallClockTimePrefix(" Removing array ITEs..."); timer.reset(); timer.start(); formula = formula .removeArrayITE(formula, noDependenceVars, constraints); if (constraints.size() > 0) { List<Formula> constraintsList = new ArrayList<Formula>(); constraintsList.addAll(constraints); AndFormula arrayIteConstraints = AndFormula .generate(constraintsList); formula = ImpliesFormula.create(arrayIteConstraints, formula); storeConstraints(constraints, noDependenceVars); constraints.clear(); } timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // Util.writeFormulaToFile(formula, "afterRemoveArrayITE.smt2", false, // false); // DEBUG Util.printToSystemOutWithWallClockTimePrefix(" Making array reads simple..."); timer.reset(); timer.start(); formula = formula.makeArrayReadsSimple(formula, constraints, noDependenceVars); if (constraints.size() > 0) { List<Formula> constraintsList = new ArrayList<Formula>(); constraintsList.addAll(constraints); AndFormula arrayReadConstraints = AndFormula .generate(constraintsList); formula = ImpliesFormula.create(arrayReadConstraints, formula); storeConstraints(constraints, noDependenceVars); constraints.clear(); } timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // Util.writeFormulaToFile(formula, "afterMakeReadsSimple.smt2", false, // false); // DEBUG Util.printToSystemOutWithWallClockTimePrefix(" Removing array writes..."); timer.reset(); timer.start(); formula = formula.removeArrayWrites(formula, constraints, noDependenceVars); if (constraints.size() > 0) { List<Formula> constraintsList = new ArrayList<Formula>(); constraintsList.addAll(constraints); AndFormula arrayWriteConstraints = AndFormula .generate(constraintsList); formula = ImpliesFormula.create(arrayWriteConstraints, formula); storeConstraints(constraints, noDependenceVars); constraints.clear(); } timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // Util.writeFormulaToFile(formula, "afterRemoveArrayWrites.smt2", // false, // false); // DEBUG Suraq.extTimer.stopReset("after removin array reads + writes"); Util.printToSystemOutWithWallClockTimePrefix(" Removing array equalities..."); timer.reset(); timer.start(); formula = formula.removeArrayEqualities(); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // Util.writeFormulaToFile(formula, "afterRemoveArrayEq.smt2", false, // false); // DEBUG Suraq.extTimer.stopReset("after removing array equalities"); Set<DomainTerm> indexSet = formula.getIndexSet(); lambda = DomainVariable.create(Util.freshVarNameCached(formula, "lambda")); List<Formula> lambdaDisequalities = new ArrayList<Formula>(); for (DomainTerm index : indexSet) { List<DomainTerm> domainTerms = new ArrayList<DomainTerm>(2); domainTerms.add(lambda); domainTerms.add(index); lambdaDisequalities.add(DomainEq.create(domainTerms, false)); } Formula lambdaConstraints = AndFormula.generate(lambdaDisequalities); indexSet.add(lambda); noDependenceVars.add(Token.generate(lambda.getVarName())); Util.printToSystemOutWithWallClockTimePrefix(" Converting array properties to finite conjunctions..."); timer.reset(); timer.start(); formula = formula.arrayPropertiesToFiniteConjunctions(indexSet); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); formula = ImpliesFormula.create(lambdaConstraints, formula); // Util.writeFormulaToFile(formula, "aftertoArrayProp.smt2", false, // false); // DEBUG Set<Token> currentDependenceArrayVariables = new HashSet<Token>(); Set<ArrayVariable> arrayVars = new HashSet<ArrayVariable>(); formula.getArrayVariables(arrayVars, new HashSet<SMTLibObject>()); for (ArrayVariable var : arrayVars) if (!noDependenceVars.contains(Token.generate(var.getVarName()))) currentDependenceArrayVariables.add(Token.generate(var .getVarName())); Util.printToSystemOutWithWallClockTimePrefix(" Converting array reads to uninterpreted function calls..."); timer.reset(); timer.start(); formula = formula.arrayReadsToUninterpretedFunctions(noDependenceVars); noDependenceVars.removeAll(currentDependenceArrayVariables); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // Util.writeFormulaToFile(formula, "afterArrayToUF.smt2", false, true); // // DEBUG Suraq.extTimer.stopReset("after Array Reads to UF"); // ///////////////////////////////////////////////// // Perform Ackermann // ///////////////////////////////////////////////// Util.printToSystemOutWithWallClockTimePrefix(" Perform Ackermann's Reduction..."); timer.reset(); timer.start(); Ackermann ackermann = new Ackermann(); formula = ackermann.performAckermann(formula, noDependenceVars); timer.end(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // DebugHelper.getInstance().formulaToFile(formula, // "./debug_ackermann.txt"); Suraq.extTimer.stopReset("after Ackermann"); // ///////////////////////////////////////////////// // Reduction of var1 = ITE(cond, var2, var3) // to var1 = itevar & ITE(cond, itevar=var2, itevar=var3) Util.printToSystemOutWithWallClockTimePrefix(" Perform ITE Reduction..."); timer.reset(); timer.start(); ITEEquationReduction itered = new ITEEquationReduction(); formula = itered.perform(formula, noDependenceVars); storeConstraints(itered.getConstraints(), noDependenceVars); timer.end(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); // DebugHelper.getInstance().formulaToFile(formula, "./debug_ite.txt"); Suraq.extTimer.stopReset("after ITE equality trans"); // ///////////////////////////////////////////////// // Perform Graph Based Reduction // ///////////////////////////////////////////////// Util.printToSystemOutWithWallClockTimePrefix(" Perform Graph-Based Reduction..."); timer.reset(); timer.start(); GraphReduction graphReduction = new GraphReduction(); try { formula = graphReduction.perform(formula, noDependenceVars); } catch (Exception ex) { ex.printStackTrace(); } timer.end(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); Suraq.extTimer.stopReset("after Graph reduction"); // ///////////////////////////////////////////////// // DebugHelper.getInstance().formulaToFile(formula, // "./debug_graph.txt"); List<PropositionalVariable> controlSignals = logicParser .getControlVariables(); // ///////////////////////////////////////////////// // TSEITIN-Encoding + QBF Encoding // ///////////////////////////////////////////////// boolean qbfsolver = QBFEncoder.isActive(); if (qbfsolver) { // debug: // formula = NotFormula.create(formula); TseitinEncoding tseitin = new TseitinEncoding(); formula = tseitin.performTseitinEncodingWithoutZ3(formula); DebugHelper.getInstance().formulaToFile(formula, "./debug_tseitin.txt"); QBFEncoder qbfEncoder = new QBFEncoder(); String qbf = qbfEncoder.encode(formula, noDependenceVars, controlSignals, tseitin.getPropositionalVariables()); DebugHelper.getInstance().stringtoFile(qbf, "./debug_qbf.txt"); QBFSolver qbfSolver = new QBFSolver(); qbfSolver.solve(qbf); // int state = qbfSolver.getState(); // if(state == QBFSolver.SAT) System.err .println("System.exit(0) in Suraq.java(2104) because of QBF."); Suraq.extTimer.stopReset("after QBF enc"); System.exit(0); return null; } System.err.println(Suraq.extTimer); return formula; } /** * Expands the given formula for the given <code>controlSignals</code> and * the nodepvars in the field <code>noDependenceVars</code>. * * Initializes the fields <code>declarationStr</code> and * <code>outputExpressions</code>. * * @param formula * @param controlSignals * @throws SuraqException */ private void prepareOutputExpressions(Formula formula, List<PropositionalVariable> controlSignals) throws SuraqException { Timer timer = new Timer(); Util.printToSystemOutWithWallClockTimePrefix(" Writing declarations..."); timer.reset(); timer.start(); writeDeclarationsAndDefinitions(formula, noDependenceVars, controlSignals.size()); timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); writeAssertPartitions(formula, noDependenceVars, controlSignals); Suraq.extTimer.stopReset("</doMainWork>"); } /** * Performs the main work. * * @return * * @throws SuraqException * if something goes wrong */ private Formula doMainWork() throws SuraqException { Formula formula = performFormulaReductions(); List<PropositionalVariable> controlSignals = logicParser .getControlVariables(); if (controlSignals.size() > 30) { throw new SuraqException( "Current implementation cannot handle more than 30 control signals."); } prepareOutputExpressions(formula, logicParser.getControlVariables()); return formula; } /** * Stores all equality constraints in the given set to the * <code>constraints</code> field. Ignores non-equality formulas (i.e., * array properties). Also ignores constraints that contain * noDependenceVars. * * @param currentConstraints * @param noDependenceVars */ private void storeConstraints(Collection<Formula> currentConstraints, Set<Token> noDependenceVars) { for (Formula constraint : currentConstraints) { if (!Util.formulaContainsAny(constraint, noDependenceVars)) this.constraints.add(constraint); } } /** * Writes the assert-partitions for the expanded formula to the * <code>outputExpressions</code>. * * @param formula * the main formula to expand * @param noDependenceVars * the variables (and functions) on which the controller may not * depend * @param controlSignals * the control signals * @throws SuraqException * if something goes wrong */ private void writeAssertPartitions(Formula formula, Set<Token> noDependenceVars, List<PropositionalVariable> controlSignals) throws SuraqException { // if (outputExpressions == null) // throw new SuraqException("outputExpressions not initialized!"); for (int count = 0; count < (1 << controlSignals.size()); count++) { Util.printToSystemOutWithWallClockTimePrefix(" Writing assert-partition number " + (count + 1) + " of " + (1 << controlSignals.size())); Formula tempFormula = formula;// .deepFormulaCopy(); Map<Token, Term> variableSubstitutions = new HashMap<Token, Term>(); Map<Token, UninterpretedFunction> ufSubstitutions = new HashMap<Token, UninterpretedFunction>(); // Debug counters for progress statistics: Util.printToSystemOutWithWallClockTimePrefix("There are " + noDependenceVars.size() + " nodepvars"); // int varCount = 0; // int lastPrint = 0; for (Token var : noDependenceVars) { // if (varCount++ >= (int) Math.ceil(lastPrint // * ((double) noDependenceVars.size() / 100))) { // System.out.print((++lastPrint) + "% "); // } // if (lastPrint == 100 || varCount == noDependenceVars.size()) // System.out.println(); if (noDependenceVarsCopies.containsKey(var)) // it's a variable variableSubstitutions.put(var, noDependenceVarsCopies.get(var).get(count)); else if (noDependenceFunctionsCopies.containsKey(var)) { // it's an uninterpreted function // System.err.println("There was a function (Ackerman didn't perform?)"); // old and slow: // tempFormula = // tempFormula.substituteUninterpretedFunction(var, // noDependenceFunctionsCopies.get(var).get(count)); // new (chillebold): ufSubstitutions.put(var, noDependenceFunctionsCopies.get(var).get(count)); } else // Util.printToSystemOutWithWallClockTimePrefix( // " This could be an exception: "+ throw new SuraqException( "noDependenceVar " + var.toString() + " is neither a variable nor an uninterpreted function."); } tempFormula = tempFormula.substituteUninterpretedFunction( ufSubstitutions, new HashMap<SMTLibObject, SMTLibObject>()); int currentCount = count; int mask = 1; for (int signalCount = 0; signalCount < controlSignals.size(); signalCount++) { variableSubstitutions.put(Token.generate(controlSignals.get( signalCount).getVarName()), PropositionalConstant .create((currentCount & mask) != 0)); currentCount = currentCount >> 1; } tempFormula = tempFormula.substituteFormula(variableSubstitutions, new HashMap<SMTLibObject, SMTLibObject>()); tempFormula = NotFormula.create(tempFormula); this.assertPartitionFormulas.put(count + 1, tempFormula); // SExpression assertPartitionExpression = new SExpression(); // assertPartitionExpression.addChild(SExpressionConstants.ASSERT); // // .addChild(SExpressionConstants.ASSERT_PARTITION); // assertPartitionExpression.addChild(tempFormula.toSmtlibV2()); // outputExpressions.add(assertPartitionExpression); } } /** * Writes the declarations of all domain variables, propositional variables, * uninterpreted functions, as well as the definition of all macros in * <code>formula</code>. For <code>noDependenceVars</code>, 2^ * <code>numControlSignals</code> copies are declared. * * @param formula * The formula for which to write the definitions. * @param noDependenceVars * the set of variables on which the controller may not depend. * @param numControlSignals * the number of control signals. * @throws SuraqException * if something goes wrong. */ private void writeDeclarationsAndDefinitions(Formula formula, Set<Token> noDependenceVars, int numControlSignals) throws SuraqException { Util.printToSystemOutWithWallClockTimePrefix(" step 0"); varTypes = new HashMap<Token, SExpression>(); varTypes.put(Token.generate(lambda.getVarName()), SExpressionConstants.VALUE_TYPE); Map<Token, Integer> functionArity = new HashMap<Token, Integer>(); Set<PropositionalVariable> pVars = new HashSet<PropositionalVariable>(); Set<SMTLibObject> done = new HashSet<SMTLibObject>(); formula.getPropositionalVariables(pVars, done); done.clear(); Util.printToSystemOutWithWallClockTimePrefix(" step 1: prop. vars: " + pVars.size()); for (PropositionalVariable var : pVars) { if (noDependenceVars.contains(var.toSmtlibV2())) { varTypes.put(Token.generate(var.getVarName()), SExpressionConstants.BOOL_TYPE); continue; // noDependenceVars will be handled later. } // outputExpressions // .add(SExpression.makeDeclareFun((Token) var.toSmtlibV2(), // SExpressionConstants.BOOL_TYPE, 0)); } Set<DomainVariable> dVars = new HashSet<DomainVariable>(); formula.getDomainVariables(dVars, done); done.clear(); Util.printToSystemOutWithWallClockTimePrefix(" step 2: domain vars: " + dVars.size()); for (DomainVariable var : dVars) { if (noDependenceVars.contains(var.toSmtlibV2())) { varTypes.put(Token.generate(var.getVarName()), SExpressionConstants.VALUE_TYPE); continue; // noDependenceVars will be handled later. } // outputExpressions.add(SExpression.makeDeclareFun( // (Token) var.toSmtlibV2(), SExpressionConstants.VALUE_TYPE, // 0)); } Set<ArrayVariable> arrayVars = new HashSet<ArrayVariable>(); formula.getArrayVariables(arrayVars, done); done.clear(); Util.printToSystemOutWithWallClockTimePrefix(" step 3: debug / Array Vars: " + arrayVars.size()); // DEBUG // For debugging purposes, also handle array variables // (so that performing only some of the reductions can be tested) for (ArrayVariable var : arrayVars) { if (noDependenceVars.contains(var.toSmtlibV2())) { varTypes.put(Token.generate(var.getVarName()), SExpressionConstants.ARRAY_TYPE); continue; // noDependenceVars will be handled later. } // outputExpressions.add(SExpression.makeDeclareFun( // (Token) var.toSmtlibV2(), SExpressionConstants.ARRAY_TYPE, // 0)); } // end debug Set<UninterpretedFunction> ufs = new HashSet<UninterpretedFunction>(); formula.getUninterpretedFunctions(ufs, done); done.clear(); Util.printToSystemOutWithWallClockTimePrefix(" step 4: UF: " + ufs.size()); for (UninterpretedFunction function : ufs) { if (noDependenceVars.contains(function.getName())) { varTypes.put(Token.generate(function.getName()), SExpressionConstants.VALUE_TYPE); functionArity.put(function.getName(), function.getNumParams()); continue; // noDependenceVars will be handled later. } // outputExpressions.add(SExpression.makeDeclareFun( // function.getName(), function.getType(), // function.getNumParams())); } long _cnt = noDependenceVars.size(); long stepsize = _cnt / 100 + 1; Util.printToSystemOutWithWallClockTimePrefix(" step 5: no dep vars: there are #" + _cnt + "; numControlSignals=" + numControlSignals); // Now dealing with noDependenceVars noDependenceVarsCopies = new HashMap<Token, List<Term>>(); noDependenceFunctionsCopies = new HashMap<Token, List<UninterpretedFunction>>(); long cnt = 0; int numCopies = (1 << numControlSignals); // info: Performance improved by factor #noDependenceVars for (Token var : noDependenceVars) { // debug output: if (cnt++ % stepsize == 0) System.out.print((100 * cnt) / _cnt + "% "); SExpression type = varTypes.get(var); if (type == null) { System.err .println("Type is null for '" + var + "'. Strange..."); } assert (type != null); int numParams = 0; if (functionArity.containsKey(var)) numParams = functionArity.get(var); List<Term> listOfVarCopies = null; if (noDependenceVarsCopies.containsKey(var)) listOfVarCopies = noDependenceVarsCopies.get(var); if (listOfVarCopies == null) listOfVarCopies = new ArrayList<Term>(); if (numParams == 0) noDependenceVarsCopies.put(var, listOfVarCopies); List<UninterpretedFunction> listOfFunctionCopies = null; if (noDependenceFunctionsCopies.containsKey(var)) listOfFunctionCopies = noDependenceFunctionsCopies.get(var); if (listOfFunctionCopies == null) listOfFunctionCopies = new ArrayList<UninterpretedFunction>(); if (numParams > 0) noDependenceFunctionsCopies.put(var, listOfFunctionCopies); for (int count = 1; count <= numCopies; count++) { String name = Util.freshVarNameCached(formula, var.toString() + "_copy_" + count); // outputExpressions.add(SExpression.makeDeclareFun( // Token.generate(name), type, numParams)); if (numParams == 0) { if (type.equals(SExpressionConstants.BOOL_TYPE)) listOfVarCopies.add(PropositionalVariable.create(name, count)); else if (type.equals(SExpressionConstants.VALUE_TYPE)) listOfVarCopies.add(DomainVariable.create(name, count)); else { assert (type.equals(SExpressionConstants.ARRAY_TYPE)); listOfVarCopies.add(ArrayVariable.create(name, count)); } } else { assert (type instanceof Token); listOfFunctionCopies.add(UninterpretedFunction.create(name, numParams, (Token) type, count)); } } } Util.printToSystemOutWithWallClockTimePrefix("\n step 6: macro"); Set<FunctionMacro> macros = new HashSet<FunctionMacro>(); formula.getFunctionMacros(macros, done); done.clear(); // for (FunctionMacro macro : macros) // outputExpressions.add(macro.toSmtlibV2()); } /** * Prints a final message. * * @param result * <code>true</code> if there were no errors, <code>false</code> * otherwise. * @param overallTimer */ private void printEnd(boolean result, Timer overallTimer) { System.out .println("################################################################################"); Util.printToSystemOutWithWallClockTimePrefix(" (Overall time - excluding checking of results: " + overallTimer + ")"); if (result) if (SuraqOptions.getInstance().isCheckResult()) Util.printToSystemOutWithWallClockTimePrefix("LIVE LONG AND PROSPER!"); else Util.printToSystemOutWithWallClockTimePrefix("Live long and prosper!"); else Util.printToSystemOutWithWallClockTimePrefix("There were errors.\nRESISTANCE IS FUTILE!"); } /** * */ private void printWelcome() { System.out .println("################################################################################"); System.out.println(" Welcome to"); System.out .println(" _____ __ __ ______ ____ ____"); System.out .println(" / ____\\ ) ) ( ( ( __ \\ ( ) / __ \\"); System.out .println(" ( (___ ( ( ) ) ) (__) ) / /\\ \\ / / \\ \\"); System.out .println(" \\___ \\ ) ) ( ( ( __/ ( (__) ) ( ( ) )"); System.out .println(" ) ) ( ( ) ) ) \\ \\ _ ) ( ( ( /\\) )"); System.out .println(" ___/ / ) \\__/ ( ( ( \\ \\_)) / /\\ \\ \\ \\_\\ \\/"); System.out .println(" /____/ \\______/ )_) \\__/ /__( )__\\ \\___\\ \\_"); System.out .println(" \\__)"); System.out.println(" MMM."); System.out.println(" NM. MMMMM"); System.out.println(" MMMM? IMMMMM MMM"); System.out.println(" MMMMN MMMMMM MMM"); System.out .println(" MMMMO MMMMMMM?MMMD"); System.out .println(" MMMMM MMMMMM MMMMM"); System.out .println(" .M MMMMM OMMMMMM MMMMO"); System.out.println(" MMMM$MMMM MMMMMM 7MMMM"); System.out.println(" MMMMNMMMM MMMMMM MMMMM"); System.out.println(" MMMMMMMMM MMMMMM.,MMMMM"); System.out.println(" MMMMMZMMMM MMMMMM MMMMM"); System.out.println(" MMMMM MMMM MMMMMM MMMMM"); System.out.println(" MMMMM MMMMM MMMMM MMMMMM"); System.out.println(" MMMMM DMMMM MMMMMM MMMMM"); System.out.println(" MMMMM .MMMMMMMMMMMMM7MMMMM"); System.out.println(" MMMMMM MMMMMMMMMMMMMMMMMMM"); System.out.println(" MMMMMMMMMMMMMMMMMMMMMMMMMM"); System.out.println(" =MMMMMMMMMMMMMMMMMMMMMMMMM"); System.out.println(" MMMMMMMMMMMMMMMMMMMMMMMMD"); System.out.println(" MMMMMMMMMMMMMMMMMMMMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMM =MMMMMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMMM7 IMMMMMMMMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMO"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM"); System.out .println(" MMMMMMMMMMMMMMMMMMMMMMMMMMMMM"); System.out.println(" MMMMMMMMMMMMMMMMMMMMMMMMM"); System.out.println(" MMMMMMMMMMMMMMMMMMMM"); System.out.println(" =MMMMMMMMMMMMM"); System.out.println(" MMMM,"); System.out.println(""); System.out .println("################################################################################"); System.out.println(""); } /** * Parses a Z3 proof string. * * @param proofStr * the string to parse. * @param propositionalVars * list of propositional variables. * @param domainVars * list of domain variables. * @param arrayVars * list of array variables. * @param uninterpretedFunctions * list of uninterpreted functions. * @return the Z3Proof Object * */ @Deprecated @SuppressWarnings("unused") private Z3Proof parseProof(String proofStr, Set<PropositionalVariable> propsitionalVars, Set<DomainVariable> domainVars, Set<ArrayVariable> arrayVars, Set<UninterpretedFunction> uninterpretedFunctions) { // expression parsing of proof SExpParser sExpProofParser = null; sExpProofParser = new SExpParser(proofStr); Timer timer = new Timer(); try { Util.printToSystemOutWithWallClockTimePrefix(" Parsing proof to S-Expressions..."); timer.start(); sExpProofParser.parse(); assert (sExpProofParser.wasParsingSuccessfull()); } catch (ParseError exc) { handleParseError(exc); noErrors = false; } finally { timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); } // parsing proof Set<PropositionalVariable> allPropVars = new HashSet<PropositionalVariable>(); allPropVars.addAll(propsitionalVars); allPropVars.addAll(tseitinEncoding.keySet()); ProofParser proofParser = new ProofParser( sExpProofParser.getRootExpr(), domainVars, allPropVars, arrayVars, uninterpretedFunctions); try { Util.printToSystemOutWithWallClockTimePrefix(" Parsing proof to SMTLIB objects..."); timer.start(); proofParser.parse(); assert (proofParser.wasParsingSuccessfull()); } catch (ParseError exc) { exc.printStackTrace(); handleParseError(exc); noErrors = false; throw new RuntimeException("Unable to parse proof!"); } finally { timer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Done. (" + timer + ")"); timer.reset(); } return proofParser.getRootProof(); } /** * Prints error message of a parse error. * * @param exc * the parse error. */ private void handleParseError(ParseError exc) { exc.printStackTrace(); System.err.println("PARSE ERROR!"); System.err.println(exc.getMessage()); System.err.println("Line: " + (exc.getLineNumber() > 0 ? exc.getLineNumber() : "unknown")); System.err.println("Column: " + (exc.getColumnNumber() > 0 ? exc.getColumnNumber() : "unknown")); System.err .println("Context: " + (exc.getContext() != "" ? exc.getContext() : "not available")); } /** * Prints size information of the given proof. * * @param proof */ private void printProofStats(Z3Proof proof) { SuraqOptions options = SuraqOptions.getInstance(); if (options.isVerbose()) { DecimalFormat myFormatter = new DecimalFormat("###,###,###"); Timer dagTimer = new Timer(); dagTimer.start(); int dagSize = proof.size(false); dagTimer.stop(); String dagSizeString = myFormatter.format(dagSize); Util.printToSystemOutWithWallClockTimePrefix(" Proof (DAG) size: " + dagSizeString + " (computed in " + dagTimer + ")"); Timer treeTimer = new Timer(); treeTimer.start(); int treeSize = proof.size(true); treeTimer.stop(); String treeSizeString = myFormatter.format(treeSize); Util.printToSystemOutWithWallClockTimePrefix(" Proof (tree) size: " + treeSizeString + " (computed in " + treeTimer + ")"); Timer depthTimer = new Timer(); depthTimer.start(); int depth = proof.depth(); depthTimer.stop(); Util.printToSystemOutWithWallClockTimePrefix(" Proof depth: " + depth + " (computed in " + depthTimer + ")"); System.out.println(); System.out.println(); } } /** * Dump the assertPartitionFormulas (and the required declarations) to the * given <code>filename</code>. Some extra information will be prepended. * * @param query * @param filename */ private void dumpSMTQuery(String filename) { try { Util.printToSystemOutWithWallClockTimePrefix("Dumping SMT query to file " + filename); File file = new File(filename); FileWriter fw = new FileWriter(file); BufferedWriter writer = new BufferedWriter(fw); writer.write("; This SMT file was created by the SURAQ synthesis tool.\n"); writer.write("; Date and time of creation: "); writer.write(new SimpleDateFormat("yyyy-MM-dd HH:mm") .format(Calendar.getInstance().getTime())); writer.write("\n"); writer.write("; Original spec file: "); writer.write(SuraqOptions.getInstance().getInput()); writer.write("\n"); writer.write("; Expected result: UNSAT\n;\n"); writer.write("; For more information contact Georg Hofferek <georg.hofferek@iaik.tugraz.at>.\n\n"); writer.write(SExpressionConstants.SET_LOGIC_QF_UF.toString()); writer.write(SExpressionConstants.DECLARE_SORT_VALUE.toString()); // writer.write(declarationStr); Util.writeDeclarations(AndFormula.generate(new ArrayList<Formula>( assertPartitionFormulas.values())), writer); writer.write("\n"); int count = 0; for (Integer key : assertPartitionFormulas.keySet()) { Util.printToSystemOutWithWallClockTimePrefix("Dumping partition " + ++count + " of " + assertPartitionFormulas.size()); Formula partitionFormula = assertPartitionFormulas.get(key); writer.write("(assert "); writer.write(partitionFormula.toString()); writer.write(")\n"); } writer.write(SExpressionConstants.CHECK_SAT.toString()); writer.close(); } catch (IOException exc) { Util.printToSystemOutWithWallClockTimePrefix("ERROR: IOException occured while dumping SMT query. Dump may be incomplete."); } if (SuraqOptions.getInstance().getExitAfterDump()) { Util.printToSystemOutWithWallClockTimePrefix("Done dumping. Will exit now because exitAfterDump was specified."); System.exit(0); } } /** * This method is for use in debugging; <strong>DO NOT USE IN * PRODUCTION!</strong> It will just do all input transformations (to create * internal data structure about the formula), and then parse the veriT * proof given by <code>proofReader</code>. It will return the parsed * <code>VeritProof</code>. * * @param proofReader * to read the proof from * @return parsed proof */ public VeritProof justDoInputTransformationAndThenParseThisProofFile( BufferedReader proofReader) { inputTransformations(new File(SuraqOptions.getInstance().getInput())); VeriTParser parser = new VeriTParser(proofReader, mainFormula, tseitinEncoding.keySet(), noDependenceVarsCopies.values(), noDependenceFunctionsCopies); parser.parse(); return parser.getProof(); } }