package de.psi.alloy4smt.ast; import java.io.File; import java.io.FileWriter; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import kodkod.ast.Formula; import kodkod.ast.Relation; import kodkod.engine.fol2sat.HigherOrderDeclException; import kodkod.engine.fol2sat.Translation; import kodkod.engine.fol2sat.Translator; import kodkod.engine.satlab.SATFactory; import kodkod.engine.satlab.SATSolver; import kodkod.instance.Tuple; import kodkod.instance.TupleSet; import de.psi.alloy4smt.ast.PreparedCommand.IntrefSigRecord; import de.psi.alloy4smt.hysat.HysatSolver; import edu.mit.csail.sdg.alloy4.A4Reporter; import edu.mit.csail.sdg.alloy4.ConstList; import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.alloy4.ErrorFatal; import edu.mit.csail.sdg.alloy4.ErrorType; import edu.mit.csail.sdg.alloy4.Pair; import edu.mit.csail.sdg.alloy4.Pos; import edu.mit.csail.sdg.alloy4compiler.ast.Command; import edu.mit.csail.sdg.alloy4compiler.ast.Decl; import edu.mit.csail.sdg.alloy4compiler.ast.Expr; import edu.mit.csail.sdg.alloy4compiler.ast.ExprQt; import edu.mit.csail.sdg.alloy4compiler.ast.Sig; import edu.mit.csail.sdg.alloy4compiler.ast.Sig.Field; import edu.mit.csail.sdg.alloy4compiler.parser.CompModule; import edu.mit.csail.sdg.alloy4compiler.parser.CompUtil; import edu.mit.csail.sdg.alloy4compiler.translator.A4Options; import edu.mit.csail.sdg.alloy4compiler.translator.A4Options.SatSolver; import edu.mit.csail.sdg.alloy4compiler.translator.A4Solution; import edu.mit.csail.sdg.alloy4compiler.translator.BoundsComputer; import edu.mit.csail.sdg.alloy4compiler.translator.ScopeComputer; import edu.mit.csail.sdg.alloy4compiler.translator.Simplifier; import edu.mit.csail.sdg.alloy4compiler.translator.TranslateAlloyToKodkod; import edu.mit.csail.sdg.alloy4compiler.translator.TranslateKodkodToJava; public final class HyTranslator extends TranslateAlloyToKodkod { public static class Dbg { public static Formula kFormula; } public static final String intrefmod = "module util/intref\n" + "abstract sig IntRef { aqclass: IntRef }\n"; public static void execute(String document) throws Err { Map<String, String> fm = new HashMap<String, String>(); fm.put("/tmp/x", document); fm.put("/tmp/util/intref.als", intrefmod); final CompModule module = CompUtil.parseEverything_fromFile(null, fm, "/tmp/x"); final IntRefPreprocessor pp = IntRefPreprocessor.processModule(module); execute(null, pp.commands.get(0), new HysatSolver()); } public static void execute(String document, HysatSolver solver) throws Err { Map<String, String> fm = new HashMap<String, String>(); fm.put("/tmp/x", document); fm.put("/tmp/util/intref.als", intrefmod); final CompModule module = CompUtil.parseEverything_fromFile(null, fm, "/tmp/x"); final IntRefPreprocessor pp = IntRefPreprocessor.processModule(module); execute(null, pp.commands.get(0), solver); } public static void execute(A4Reporter rep, PreparedCommand preparedCommand, final HysatSolver solver) throws Err { rep = rep == null ? A4Reporter.NOP : rep; final A4Options opt = makeA4Options(); final Iterable<Sig> sigs = preparedCommand.sigs; final Command cmd = preparedCommand.command; final ConstList<String> hyexprs = preparedCommand.hysatExprs; final ConstList<String> intrefatoms = hyexprs != null ? preparedCommand.getIntrefAtoms() : null; final Pair<A4Solution, ScopeComputer> pair = ScopeComputer.compute(rep, opt, sigs, cmd); final A4Solution sol = pair.a; BoundsComputer.compute(rep, sol, pair.b, sigs); Expr formula = cmd.formula; Relation equalsrel = null; TupleSet equalsupper = null; if (hyexprs != null) { Sig.Field equalsfield = preparedCommand.intref.addField("equals", preparedCommand.intref.setOf()); equalsupper = preparedCommand.getIntRefEqualsTupleSet(sol.getFactory()); equalsrel = sol.addRel("IntRef/equals", null, equalsupper); sol.addField(equalsfield, equalsrel); /* * fact { * all disj a, b: intref/IntRef { * (b in a.equals or a in b.equals) <=> a.aqclass = b.aqclass * (b in a.equals) => (b.aqclass = a or b.aqclass in a.equals) * } * } */ Decl da = preparedCommand.intref.oneOf("a"); Decl db = preparedCommand.intref.oneOf("b"); Field aqclass = Helpers.getFieldByName(preparedCommand.intref.getFields(), "aqclass"); // b in a.equals or a in b.equals Expr e1 = db.get().in(da.get().join(equalsfield)).or(da.get().in(db.get().join(equalsfield))); // a.aqclass = b.aqclass Expr e2 = da.get().join(aqclass).equal(db.get().join(aqclass)); // b in a.equals Expr e3 = db.get().in(da.get().join(equalsfield)); // b.aqclass = a or b.aqclass in a.equals Expr e4 = db.get().join(aqclass).equal(da.get()).or(db.get().join(aqclass).in(da.get().join(equalsfield))); // a != b Expr e5 = da.get().equal(db.get()).not(); Expr sub = e5.implies(e1.iff(e2).and(e3.implies(e4))); formula = formula.and(ExprQt.Op.ALL.make(null, null, Arrays.asList(new Decl[] {da, db}), sub)); for (IntrefSigRecord record : preparedCommand.intrefRecords) { if (record.mapfield != null) { Relation rel = (Relation) sol.a2k(record.mapfield); TupleSet bound = record.getMapBounds(preparedCommand.command, sol.getFactory()); sol.shrink(rel, bound, bound); } } } HyTranslator tr = null; Translation tl = null; try { tr = new HyTranslator(rep, cmd, opt, sol); sol.solver.options().setLogTranslation(2); sol.solver.options().setSolver(new SATFactory() { @Override public SATSolver instance() { if (hyexprs != null) { for (String atom : intrefatoms) { solver.addHysatVariable(atom, -1000000, 1000000); } for (String expr : hyexprs) { solver.addHysatExpr(expr); } } return solver; } @Override public boolean prover() { return false; } @Override public boolean minimizer() { return false; } @Override public boolean incremental() { return false; } @Override public String toString() { return "HySAT solver"; } }); tr.makeFacts(formula); List<String> atoms = new Vector<String>(); for (Iterator<Object> it = tr.frame.getFactory().universe().iterator(); it.hasNext();) { atoms.add((String) it.next()); } Formula kformula = tr.frame.makeFormula(rep, new Simplifier()); Dbg.kFormula = kformula; String kodkodout = TranslateKodkodToJava.convert(kformula, tr.frame.getBitwidth(), atoms, tr.frame.getBounds(), null); File tmpout = File.createTempFile("kodkodout", ".txt"); FileWriter writer = new FileWriter(tmpout); writer.write(kodkodout); writer.close(); tl = Translator.translate(kformula, tr.frame.getBounds(), tr.frame.solver.options()); } catch (HigherOrderDeclException ex) { Pos p = tr!=null ? tr.frame.kv2typepos(ex.decl().variable()).b : Pos.UNKNOWN; throw new ErrorType(p, "Analysis cannot be performed since it requires higher-order quantification that could not be skolemized."); } catch (Throwable ex) { if (ex instanceof Err) throw (Err)ex; else throw new ErrorFatal("Unknown exception occurred: "+ex, ex); } if (equalsrel != null) { int[] relvars = tl.primaryVariables(equalsrel).toArray(); int i = 0; for (Tuple t : equalsupper) { solver.addHysatExpr("cnf_" + relvars[i] + " <-> (" + t.atom(0).toString() + " = " + t.atom(1).toString() + ")"); ++i; } } solver.solve(); } private static A4Options makeA4Options() { final A4Options opt = new A4Options(); opt.recordKodkod = true; opt.tempDirectory = "/tmp"; opt.solverDirectory = "/tmp"; opt.solver = SatSolver.SAT4J; opt.skolemDepth = 4; return opt; } private HyTranslator(A4Reporter rep, Command cmd, A4Options opt, A4Solution frame) throws Err { super(rep, opt, frame, cmd); } }