def test_next(): reset_env() arrtype = ArrayType(BVType(3), BVType(4)) arr = Symbol("arr", arrtype) idx = Symbol("idx", BVType(3)) parser = StringParser() [(_, f, _)] = parser.parse_formulae(["next(arr)[idx]"]) assert (f.args()[1] == idx)
def run_verification(config): reset_env() Logger.verbosity = config.verbosity coreir_parser = None ets_parser = None sts_parser = None if config.ltl: ltl_reset_env() hts = HTS("Top level") if config.strfiles[0][-4:] != ".pkl": ps = ProblemSolver() (hts, invar_props, ltl_props) = ps.parse_model("./", config.strfiles, config.abstract_clock, config.symbolic_init, deterministic=config.deterministic, boolean=config.boolean, no_clock=config.no_clock) config.parser = ps.parser if config.pickle_file: Logger.msg("Pickling model to %s\n" % (config.pickle_file), 1) sys.setrecursionlimit(50000) with open(config.pickle_file, "wb") as f: pickle.dump(hts, f) else: if config.pickle_file: raise RuntimeError("Don't need to re-pickle the input file %s" % (config.strfile)) Logger.msg("Loading pickle file %s\n" % (config.strfile), 0) with open(config.pickle_file, "rb") as f: hts = pickle.load(f) Logger.log("DONE", 0) printsmv = True mc_config = MCConfig() sparser = StringParser() sparser.remap_or2an = config.parser.remap_or2an ltlparser = LTLParser() # if equivalence checking wait to add assumptions to combined system if config.assumptions is not None and config.equivalence is None: Logger.log("Adding %d assumptions... " % len(config.assumptions), 1) assumps = [t[1] for t in sparser.parse_formulae(config.assumptions)] hts.assumptions = assumps lemmas = None if config.lemmas is not None: Logger.log("Adding %d lemmas... " % len(config.lemmas), 1) parsed_formulae = sparser.parse_formulae(config.lemmas) if list(set([t[2] for t in parsed_formulae]))[0][0] != False: Logger.error("Lemmas do not support \"next\" operators") lemmas = [t[1] for t in parsed_formulae] hts.lemmas = lemmas mc_config.smt2file = config.smt2file mc_config.full_trace = config.full_trace mc_config.trace_vars_change = config.trace_vars_change mc_config.trace_all_vars = config.trace_all_vars mc_config.prefix = config.prefix mc_config.strategy = config.strategy mc_config.skip_solving = config.skip_solving mc_config.map_function = config.parser.remap_an2or mc_config.solver_name = config.solver_name mc_config.vcd_trace = config.vcd mc_config.prove = config.prove mc_config.incremental = config.incremental if config.ltl: bmc_ltl = BMCLTL(hts, mc_config) else: bmc_safety = BMCSafety(hts, mc_config) if config.translate: Logger.log("Writing system to \"%s\"" % (config.translate), 0) printer = PrintersFactory.printer_by_name(config.printer) props = [] if config.ltl: props += ltlparser.parse_formulae(config.properties) props += [(str(p), p, None) for p in ltl_props] else: props += sparser.parse_formulae(config.properties) props += [(str(p), p, None) for p in invar_props] with open(config.translate, "w") as f: f.write(printer.print_hts(hts, props)) if config.simulate: count = 0 if config.properties is None: props = [("True", TRUE(), None)] else: props = sparser.parse_formulae(config.properties) for (strprop, prop, _) in props: Logger.log("Simulation for property \"%s\":" % (strprop), 0) res, trace = bmc_safety.simulate(prop, config.bmc_length) if res == VerificationStatus.TRUE: count += 1 print_trace("Execution", trace, count, config.prefix) else: Logger.log("No execution found", 0) if config.safety: count = 0 props = sparser.parse_formulae(config.properties) props += [(str(p), p, None) for p in invar_props] if len(props) == 0: Logger.warning("Safety verification requires at least a property") for (strprop, prop, _) in props: Logger.log("Safety verification for property \"%s\":" % (strprop), 0) res, trace, t = bmc_safety.safety(prop, config.bmc_length, config.bmc_length_min) Logger.log("\nProperty is %s" % res, 0) if res == VerificationStatus.FALSE: count += 1 print_trace("Counterexample", trace, count, config.prefix) return 0 if config.equivalence or config.fsm_check: if config.equivalence: parser2 = CoreIRParser(config.abstract_clock, config.symbolic_init, config.run_passes) Logger.msg("Parsing file \"%s\"... " % (config.equivalence), 0) hts2 = parser2.parse_file(config.equivalence) Logger.log("DONE", 0) symb = " (symbolic init)" if config.symbolic_init else "" Logger.log( "Equivalence checking%s with k=%s:" % (symb, config.bmc_length), 0) if Logger.level(1): print(hts2.print_statistics("System 2", Logger.level(2))) else: hts2 = hts # TODO: Make incremental solving optional htseq, miter_out = Miter.combine_systems(hts, hts2, config.bmc_length, config.symbolic_init, config.properties, True) if config.assumptions is not None: Logger.log( "Adding %d assumptions to combined system... " % len(config.assumptions), 1) assumps = [ t[1] for t in sparser.parse_formulae(config.assumptions) ] htseq.assumptions = assumps # create bmc object for combined system bmcseq = BMC(htseq, mc_config) res, trace, t = bmcseq.safety(miter_out, config.bmc_length, config.bmc_length_min) msg = "Systems are %s equivalent" if config.equivalence else "System is%s deterministic" if res == VerificationStatus.FALSE: Logger.log(msg % (" not"), 0) print_trace("Counterexample", trace, 1, config.prefix) elif res == VerificationStatus.UNK: if config.symbolic_init: # strong equivalence with symbolic initial state Logger.log(msg % (""), 0) else: Logger.log(msg % ("") + " up to k=%i" % t, 0) else: Logger.log(msg % ("") + " up to k=%i" % t, 0) if config.ltl: count = 0 props = ltlparser.parse_formulae(config.properties) props += [(str(p), p, None) for p in ltl_props] if len(props) == 0: Logger.warning("LTL verification requires at least a property") for (strprop, prop, _) in props: Logger.log("LTL verification for property \"%s\":" % (strprop), 0) res, trace, t = bmc_ltl.ltl(prop, config.bmc_length, config.bmc_length_min) Logger.log("\nProperty is %s" % res, 0) if res == VerificationStatus.FALSE: count += 1 print_trace("Counterexample", trace, count, config.prefix) return 0
def combine_systems(hts, hts2, k, symbolic_init, eqprop=None, inc=True, non_deterministic=False): htseq = HTS("eq") hts1_varnames = [v.symbol_name() for v in hts.vars] hts2_varnames = [v.symbol_name() for v in hts2.vars] map1 = dict([(v, TS.get_prefix_name(v, S1)) for v in hts1_varnames]+\ [(TS.get_prime_name(v), TS.get_prefix_name(TS.get_prime_name(v), S1)) for v in hts1_varnames]) map2 = dict([(v, TS.get_prefix_name(v, S2)) for v in hts2_varnames]+\ [(TS.get_prime_name(v), TS.get_prefix_name(TS.get_prime_name(v), S2)) for v in hts2_varnames]) ts1_init = TRUE() ts2_init = TRUE() if not symbolic_init: ts1_init = substitute(hts.single_init(), map1) ts2_init = substitute(hts2.single_init(), map2) ts1 = TS() ts1.vars = set([TS.get_prefix(v, S1) for v in hts.vars]) ts1.set_behavior(ts1_init,\ substitute(hts.single_trans(), map1),\ substitute(hts.single_invar(), map1)) ts1.state_vars = set([TS.get_prefix(v, S1) for v in hts.state_vars]) ts2 = TS() ts2.vars = set([TS.get_prefix(v, S2) for v in hts2.vars]) ts2.set_behavior(ts2_init,\ substitute(hts2.single_trans(), map2),\ substitute(hts2.single_invar(), map2)) ts2.state_vars = set([TS.get_prefix(v, S2) for v in hts2.state_vars]) htseq.add_ts(ts1) htseq.add_ts(ts2) assumptions = [] lemmas = [] def sets_intersect(set1, set2): for el in set1: if not el in set2: return False return True if hts.assumptions is not None: for assumption in hts.assumptions: assumptions.append(assumption) if hts.lemmas is not None: for lemma in hts.lemmas: lemmas.append(lemma) if hts2.assumptions is not None: for assumption in hts2.assumptions: assumptions.append(assumption) if hts2.lemmas is not None: for lemma in hts2.lemmas: lemmas.append(lemma) for assumption in assumptions: fv_assumption = get_free_variables(assumption) c_assumption = TRUE() if sets_intersect(fv_assumption, hts.vars): c_assumption = And(c_assumption, substitute(assumption, map1)) if sets_intersect(fv_assumption, hts2.vars): c_assumption = And(c_assumption, substitute(assumption, map2)) if c_assumption != TRUE(): htseq.add_assumption(c_assumption) for lemma in lemmas: fv_lemma = get_free_variables(lemma) c_lemma = TRUE() if sets_intersect(fv_lemma, hts.vars): c_lemma = And(c_lemma, substitute(lemma, map1)) if sets_intersect(fv_lemma, hts2.vars): c_lemma = And(c_lemma, substitute(lemma, map2)) if c_lemma != TRUE(): htseq.add_lemma(c_lemma) miter_out = Symbol(EQS, BOOL) inputs = hts.input_vars.intersection(hts2.input_vars) outputs = hts.output_vars.intersection(hts2.output_vars) htseq.input_vars = set([ TS.get_prefix(v, S1) for v in hts.input_vars ]).union(set([TS.get_prefix(v, S2) for v in hts2.input_vars])) htseq.output_vars = set([ TS.get_prefix(v, S1) for v in hts.output_vars ]).union(set([TS.get_prefix(v, S2) for v in hts2.output_vars])) if symbolic_init or (not non_deterministic): states = hts.state_vars.intersection(hts2.state_vars) else: states = [] eqinputs = TRUE() eqoutputs = TRUE() eqstates = TRUE() for inp in inputs: eqinputs = And( eqinputs, EqualsOrIff(TS.get_prefix(inp, S1), TS.get_prefix(inp, S2))) for out in outputs: eqoutputs = And( eqoutputs, EqualsOrIff(TS.get_prefix(out, S1), TS.get_prefix(out, S2))) for svar in states: eqstates = And( eqstates, EqualsOrIff(TS.get_prefix(svar, S1), TS.get_prefix(svar, S2))) if eqprop is None: if symbolic_init or (not non_deterministic): invar = And(eqinputs, Iff(miter_out, Implies(eqstates, eqoutputs))) else: invar = And(eqinputs, Iff(miter_out, eqoutputs)) Logger.log('Inferring equivalence property: {}'.format(invar), 2) else: sparser = StringParser() eqprop = sparser.parse_formulae(eqprop) if len(eqprop) > 1: Logger.error("Expecting a single equivalence property") eqprop = eqprop[0][1] invar = Iff(miter_out, eqprop) Logger.log('Using provided equivalence property: {}'.format(invar), 2) tsmo = TS() tsmo.vars = set([miter_out]) tsmo.invar = invar htseq.add_ts(tsmo) return (htseq, miter_out)
def solve_problem(self, problem, config): Logger.log("\n*** Analyzing problem \"%s\" ***" % (problem), 1) Logger.msg("Solving \"%s\" " % problem.name, 0, not (Logger.level(1))) sparser = StringParser() lparser = LTLParser() mc_config = self.problem2mc_config(problem, config) bmc_safety = BMCSafety(problem.hts, mc_config) bmc_ltl = BMCLTL(problem.hts, mc_config) res = VerificationStatus.UNC bmc_length = max(problem.bmc_length, config.bmc_length) bmc_length_min = max(problem.bmc_length_min, config.bmc_length_min) parsing_defs = [ mc_config.properties, mc_config.lemmas, mc_config.assumptions ] for i in range(len(parsing_defs)): if parsing_defs[i] is not None: pdef_file = problem.relative_path + parsing_defs[i] if os.path.isfile(pdef_file): with open(pdef_file) as f: parsing_defs[i] = [ p.strip() for p in f.read().strip().split("\n") ] else: parsing_defs[i] = [ p.strip() for p in parsing_defs[i].split(MODEL_SP) ] else: parsing_defs[i] = None [mc_config.properties, mc_config.lemmas, mc_config.assumptions] = parsing_defs assumps = None lemmas = None accepted_ver = False if problem.monitors is not None: varsdict = dict([(var.symbol_name(), var) for var in problem.hts.vars]) for strmonitor in problem.monitors.split(")"): strmonitor = strmonitor.replace(" ", "") if strmonitor == "": continue instance, mtype = strmonitor.split("=") mtype, pars = mtype.split("(") pars = pars.split(",") monitor = MonitorsFactory.monitor_by_name(mtype) pars = [varsdict[v] if v in varsdict else v for v in pars] ts = monitor.get_sts(instance, pars) problem.hts.add_ts(ts) if problem.verification != VerificationType.EQUIVALENCE: assumps = [ t[1] for t in sparser.parse_formulae(mc_config.assumptions) ] lemmas = [t[1] for t in sparser.parse_formulae(mc_config.lemmas)] for ass in assumps: problem.hts.add_assumption(ass) for lemma in lemmas: problem.hts.add_lemma(lemma) if problem.verification != VerificationType.LTL: (strprop, prop, types) = sparser.parse_formulae(mc_config.properties)[0] else: (strprop, prop, types) = lparser.parse_formulae(mc_config.properties)[0] if problem.verification == VerificationType.SAFETY: accepted_ver = True res, trace, _ = bmc_safety.safety(prop, bmc_length, bmc_length_min) if problem.verification == VerificationType.LTL: accepted_ver = True res, trace, _ = bmc_ltl.ltl(prop, bmc_length, bmc_length_min) if problem.verification == VerificationType.SIMULATION: accepted_ver = True res, trace = bmc_safety.simulate(prop, bmc_length) if problem.verification == VerificationType.EQUIVALENCE: accepted_ver = True if problem.equivalence: (problem.hts2, _, _) = self.parse_model(problem.relative_path, \ problem.equivalence, \ problem.abstract_clock, \ problem.symbolic_init, "System 2", \ no_clock=problem.no_clock, \ run_passes=problem.run_coreir_passes) htseq, miter_out = Miter.combine_systems(problem.hts, \ problem.hts2, \ bmc_length, \ problem.symbolic_init, \ mc_config.properties, \ True) if mc_config.assumptions is not None: assumps = [ t[1] for t in sparser.parse_formulae(mc_config.assumptions) ] if mc_config.lemmas is not None: lemmas = [ t[1] for t in sparser.parse_formulae(mc_config.lemmas) ] if assumps is not None: for assumption in assumps: htseq.add_assumption(assumption) if lemmas is not None: for lemma in lemmas: htseq.add_lemma(lemma) bmcseq = BMCSafety(htseq, mc_config) res, trace, t = bmcseq.safety(miter_out, bmc_length, bmc_length_min) if not accepted_ver: Logger.error("Invalid verification type") problem.status = res problem.trace = trace if problem.assumptions is not None: problem.hts.assumptions = None Logger.log("\n*** Problem \"%s\" is %s ***" % (problem, res), 1)