package org.batfish.z3; import java.util.LinkedHashMap; import java.util.Map; import org.batfish.common.BatfishException; import org.batfish.job.BatfishJob; import org.batfish.main.Settings; import com.microsoft.z3.BoolExpr; import com.microsoft.z3.Context; import com.microsoft.z3.Fixedpoint; import com.microsoft.z3.FuncDecl; import com.microsoft.z3.Params; import com.microsoft.z3.Status; import com.microsoft.z3.Z3Exception; public class NodSatJob<Key> extends BatfishJob<NodSatResult<Key>> { private final SatQuerySynthesizer<Key> _query; private final Synthesizer _synthesizer; public NodSatJob(Settings settings, Synthesizer synthesizer, SatQuerySynthesizer<Key> query) { super(settings); _synthesizer = synthesizer; _query = query; } @Override public NodSatResult<Key> call() throws Exception { Map<Key, Boolean> results = new LinkedHashMap<>(); long startTime = System.currentTimeMillis(); long elapsedTime; try (Context ctx = new Context()) { NodProgram baseProgram = _query.synthesizeBaseProgram(_synthesizer, ctx); NodProgram queryProgram = _query.getNodProgram(baseProgram); NodProgram program = baseProgram.append(queryProgram); Params p = ctx.mkParams(); p.add("fixedpoint.engine", "datalog"); p.add("fixedpoint.datalog.default_relation", "doc"); // p.add("fixedpoint.print_answer", true); Fixedpoint fix = ctx.mkFixedpoint(); fix.setParameters(p); for (FuncDecl relationDeclaration : program.getRelationDeclarations() .values()) { fix.registerRelation(relationDeclaration); } for (BoolExpr rule : program.getRules()) { fix.addRule(rule, null); } for (int queryNum = 0; queryNum < program.getQueries() .size(); queryNum++) { BoolExpr query = program.getQueries().get(queryNum); Key key = _query.getKeys().get(queryNum); Status status = fix.query(query); elapsedTime = System.currentTimeMillis() - startTime; switch (status) { case SATISFIABLE: results.put(key, true); break; case UNKNOWN: return new NodSatResult<>(elapsedTime, _logger.getHistory(), new BatfishException("Query satisfiability unknown")); case UNSATISFIABLE: results.put(key, false); break; default: return new NodSatResult<>(elapsedTime, _logger.getHistory(), new BatfishException("invalid status")); } } elapsedTime = System.currentTimeMillis() - startTime; return new NodSatResult<>(results, _logger.getHistory(), elapsedTime); } catch (Z3Exception e) { elapsedTime = System.currentTimeMillis() - startTime; return new NodSatResult<>(elapsedTime, _logger.getHistory(), new BatfishException( "Error running NoD on concatenated data plane", e)); } } }