def flatten(self, path=[]): vardic = dict([(v.symbol_name(), v) for v in self.vars]) for sub in self.subs: instance, actual, module = sub formal = module.params ts = TS("FLATTEN") (ts.init, ts.trans, ts.invar) = module.flatten(path + [instance]) self.add_ts(ts) links = TRUE() for i in range(len(actual)): local_var = ".".join(path + [actual[i]]) module_var = sub[2].newname(formal[i].symbol_name(), path + [sub[0]]) links = And(links, EqualsOrIff(vardic[local_var], vardic[module_var])) ts = TS("LINKS") ts.invar = links self.add_ts(ts) s_init = self.single_init() s_invar = self.single_invar() s_trans = self.single_trans() replace_dic = dict([(v.symbol_name(), self.newname(v.symbol_name(), path)) for v in self.vars] + \ [(TS.get_prime_name(v.symbol_name()), self.newname(TS.get_prime_name(v.symbol_name()), path)) for v in self.vars]) s_init = substitute(s_init, replace_dic) s_invar = substitute(s_invar, replace_dic) s_trans = substitute(s_trans, replace_dic) return (s_init, s_trans, s_invar)
def apply_var_prefix(self, prefix): p_vars = set([Symbol(apply_prefix(v.symbol_name(), prefix), v.symbol_type()) for v in self.vars]) p_state_vars = set([Symbol(apply_prefix(v.symbol_name(), prefix), v.symbol_type()) for v in self.state_vars]) p_input_vars = set([Symbol(apply_prefix(v.symbol_name(), prefix), v.symbol_type()) for v in self.input_vars]) p_output_vars = set([Symbol(apply_prefix(v.symbol_name(), prefix), v.symbol_type()) for v in self.output_vars]) p_hidden_vars = set([Symbol(apply_prefix(v.symbol_name(), prefix), v.symbol_type()) for v in self.hidden_vars]) remapdic = dict([(v.symbol_name(), apply_prefix(v.symbol_name(), prefix)) for v in self.vars]+\ [(TS.get_prime(v).symbol_name(), apply_prefix(TS.get_prime(v).symbol_name(), prefix)) for v in self.vars]) p_init = substitute(self.init, remapdic) p_trans = substitute(self.trans, remapdic) p_invar = substitute(self.invar, remapdic) p_ftrans = None if self.ftrans is not None: p_ftrans = {} for var, cond_assign_list in self.ftrans.items(): p_ftrans[substitute(var, remapdic)] = [(substitute(condition, remapdic), substitute(value, remapdic)) for (condition, value) in cond_assign_list] self.vars = p_vars self.state_vars = p_state_vars self.input_vars = p_input_vars self.output_vars = p_output_vars self.hidden_vars = p_hidden_vars self.init = p_init self.trans = p_trans self.ftrans = p_ftrans self.invar = p_invar return self
def extend_ts(ts, modifier): affect_init = False if ts.ftrans is None: return (ts, []) new_ftrans = {} vars = [] for (assign, cond_assign_list) in ts.ftrans.items(): fv = get_free_variables(assign) assert len(fv) == 1 var = fv.pop() is_next = TS.has_next(var) refvar = TS.get_ref_var(var) nomvar = Symbol(NOMIN % refvar.symbol_name(), var.symbol_type()) fvar = Symbol(FAULT % refvar.symbol_name(), BOOL) vars.append(nomvar) vars.append(fvar) repldic = dict([(refvar.symbol_name(), nomvar.symbol_name()), \ (TS.get_prime(refvar).symbol_name(), TS.get_prime(nomvar).symbol_name())]) # Remapping nominal behavior to new variable new_ftrans[substitute(assign, repldic)] = [(substitute(c[0], repldic), substitute(c[1], repldic)) for c in cond_assign_list] # Definition of the nominal behavior new_ftrans[refvar] = [(Not(fvar), nomvar)] # Application of the faulty behavior new_ftrans[refvar].append( (fvar, modifier.get_behavior(nomvar, refvar))) ts.trans = And(ts.trans, Implies(fvar, TS.get_prime(fvar))) if affect_init: ts.init = substitute(ts.init, repldic) else: ts.init = And(ts.init, Not(fvar)) # add the vars to the transition system for var in vars: ts.add_var(var) ts.ftrans = new_ftrans return (ts, vars)
def to_prev(formula): varmap = [] for v in get_free_variables(formula): vname = TS.get_ref_name(v.symbol_name()) varmap.append((vname, TS.get_prev_name(vname))) varmap.append((TS.get_prime_name(vname), vname)) return substitute(formula, dict(varmap))
def apply_var_prefix(self, prefix): remapdic = dict([(v.symbol_name(), apply_prefix(v.symbol_name(), prefix)) for v in self.vars]+\ [(TS.get_prime(v).symbol_name(), apply_prefix(TS.get_prime(v).symbol_name(), prefix)) for v in self.vars]) p_init = None p_trans = None p_invar = None p_assumptions = None p_lemmas = None if self.assumptions is not None: p_assumptions = [substitute(a, remapdic) for a in self.assumptions] if self.lemmas is not None: p_lemmas = [substitute(l, remapdic) for l in self.lemmas] p_params = [ Symbol(apply_prefix(v.symbol_name(), prefix), v.symbol_type()) for v in self.params ] self.vars = set([]) self.state_vars = set([]) self.input_vars = set([]) self.output_vars = set([]) self.hidden_vars = set([]) self._s_init = None self._s_trans = None self._s_ftrans_t = None self._s_ftrans_i = None self._s_ftrans = None self._s_invar = None self.assumptions = p_assumptions self.lemmas = p_lemmas self.params = p_params tss = self.tss self.tss = set([]) for ts in tss: self.add_ts(ts.apply_var_prefix(prefix), reset=False) self.reset_formulae()
def substitute_mem(f, dic): if f in substitute_dic: return substitute_dic[f] ret = substitute(f, dic) substitute_dic[f] = ret return ret
def _flatten_rec(self, path=[]): self.is_flatten = True vardic = dict([(v.symbol_name(), v) for v in self.vars]) def full_path(name, path): ret = ".".join(path + [name]) if ret[0] == ".": return ret[1:] return ret for sub in self.subs: instance, actual, module = sub module.is_flatten = True formal = module.params ts = TS(FLATTEN) (ts.vars, \ ts.state_vars, \ ts.input_vars, \ ts.output_vars, \ ts.init, \ ts.trans, \ ts.ftrans, \ ts.invar) = module._flatten_rec(path+[instance]) self.add_ts(ts, reset=False) links = {} for i in range(len(actual)): # Unset parameter if actual[i] == None: continue if type(actual[i]) == str: local_expr = vardic[full_path(actual[i], path)] else: local_vars = [(v.symbol_name(), v.symbol_name().replace(self.name, ".".join(path))) \ for v in get_free_variables(actual[i])] local_expr = substitute(actual[i], dict(local_vars)) module_var = sub[2].newname(formal[i].symbol_name(), path + [sub[0]]) assert sub[2].name != "" if module_var not in vardic: modulevar = Symbol(module_var, formal[i].symbol_type()) self.vars.add(modulevar) vardic[module_var] = modulevar if vardic[module_var] in self.output_vars: links[local_expr] = [(TRUE(), vardic[module_var])] else: links[vardic[module_var]] = [(TRUE(), local_expr)] ts = TS(LINKS) ts.ftrans = links self.add_ts(ts, reset=False) s_init = self.single_init() s_invar = self.single_invar(include_ftrans=False) s_trans = self.single_trans(include_ftrans=False) replace_dic = dict([(v.symbol_name(), self.newname(v.symbol_name(), path)) for v in self.vars] + \ [(TS.get_prime_name(v.symbol_name()), self.newname(TS.get_prime_name(v.symbol_name()), path)) \ for v in self.vars]) substitute_dic = {} def substitute_mem(f, dic): if f in substitute_dic: return substitute_dic[f] ret = substitute(f, dic) substitute_dic[f] = ret return ret s_init = substitute_mem(s_init, replace_dic) s_invar = substitute_mem(s_invar, replace_dic) s_trans = substitute_mem(s_trans, replace_dic) s_ftrans = {} local_vars = [] local_state_vars = [] local_input_vars = [] local_output_vars = [] single_ftrans = self.single_ftrans() for var in list(self.vars): newsym = Symbol(replace_dic[var.symbol_name()], var.symbol_type()) local_vars.append(newsym) if var in self.state_vars: local_state_vars.append(newsym) if var in self.input_vars: local_input_vars.append(newsym) if var in self.output_vars: local_output_vars.append(newsym) if var in single_ftrans: cond_assign_list = single_ftrans[var] s_ftrans[newsym] = [(substitute_mem(condition, replace_dic), \ substitute_mem(value, replace_dic)) \ for (condition, value) in cond_assign_list] del (single_ftrans[var]) for var, cond_assign_list in single_ftrans.items(): s_ftrans[substitute_mem(var, replace_dic)] = [(substitute_mem(condition, replace_dic), \ substitute_mem(value, replace_dic)) \ for (condition, value) in cond_assign_list] return (local_vars, local_state_vars, local_input_vars, local_output_vars, s_init, s_trans, s_ftrans, s_invar)
def solve_safety_inc_int(self, hts, prop, k): init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() solver_proof = self.solver.copy("inc_int_proof") solver = self.solver.copy("inc_int") has_next = TS.has_next(prop) map_10 = dict([(TS.get_timed_name(v.symbol_name(), 1), TS.get_timed_name(v.symbol_name(), 0)) for v in hts.vars]) itp = Interpolator(logic=get_logic(trans)) init = And(init, invar) nprop = Not(prop) def check_overappr(Ri, R): self._reset_assertions(solver_proof) self._add_assertion(solver_proof, And(Ri, Not(R))) if not self._solve(solver_proof): Logger.log("Proof found with k=%s"%(t), 1) return TRUE() Logger.log("Extending initial states (%s)"%int_c, 1) return Or(R, Ri) t = 1 if has_next else 0 trans_t = self.unroll(trans, invar, k+1, gen_list=True) pivot = 2 trans_tA = And(trans_t[:pivot]) init_0 = self.at_time(init, 0) is_sat = True Ri = None self._reset_assertions(solver) while (t < k+1): Logger.log("\nSolving for k=%s"%t, 1) int_c = 0 R = init_0 # trans_t is composed as trans_i, invar_i, trans_i+1, invar_i+1, ... self._add_assertion(solver, trans_t[2*t]) self._add_assertion(solver, trans_t[(2*t)+1]) while True: Logger.log("Add init and invar", 2) self._push(solver) self._add_assertion(solver, R) npropt = self.at_time(nprop, t-1 if has_next else t) Logger.log("Add property time %d"%t, 2) self._add_assertion(solver, npropt) Logger.log("Interpolation at k=%s"%(t), 2) if t > 0: trans_tB = And(trans_t[pivot:(t*2)]) Ri = And(itp.binary_interpolant(And(R, trans_tA), And(trans_tB, npropt))) is_sat = Ri == None if is_sat and self._solve(solver): if R == init_0: Logger.log("Counterexample found with k=%s"%(t), 1) model = self._get_model(solver) return (t, model) else: Logger.log("No counterexample or proof found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) self._pop(solver) break else: self._pop(solver) if Ri is None: break Ri = substitute(Ri, map_10) res = check_overappr(Ri, R) if res == TRUE(): Logger.log("Proof found with k=%s"%(t), 1) return (t, True) R = res int_c += 1 t += 1 return (t-1, None)
def solve_safety_int(self, hts, prop, k): init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() has_next = TS.has_next(prop) map_10 = dict([(TS.get_timed_name(v.symbol_name(), 1), TS.get_timed_name(v.symbol_name(), 0)) for v in hts.vars]) itp = Interpolator(logic=get_logic(trans)) init = And(init, invar) nprop = Not(prop) pivot = 2 t = 1 if has_next else 0 while (t < k+1): Logger.log("\nSolving for k=%s"%t, 1) int_c = 0 init_0 = self.at_time(init, 0) R = init_0 trans_t = self.unroll(trans, invar, t, gen_list=True) trans_tA = And(trans_t[:pivot]) if t > 0 else TRUE() trans_tB = And(trans_t[pivot:]) if t > 0 else TRUE() while True: self._reset_assertions(self.solver) Logger.log("Add init and invar", 2) self._add_assertion(self.solver, R) self._add_assertion(self.solver, And(trans_tA, trans_tB)) npropt = self.at_time(nprop, t-1 if has_next else t) Logger.log("Add property time %d"%t, 2) self._add_assertion(self.solver, npropt) if self._solve(self.solver): if R == init_0: Logger.log("Counterexample found with k=%s"%(t), 1) model = self._get_model(self.solver) return (t, model) else: Logger.log("No counterexample or proof found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) break else: if len(trans_t) < 2: Logger.log("No counterexample found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) break Ri = And(itp.binary_interpolant(And(R, trans_tA), And(trans_tB, npropt))) Ri = substitute(Ri, map_10) self._reset_assertions(self.solver) self._add_assertion(self.solver, And(Ri, Not(R))) if not self._solve(self.solver): Logger.log("Proof found with k=%s"%(t), 1) return (t, True) else: R = Or(R, Ri) int_c += 1 Logger.log("Extending initial states (%s)"%int_c, 1) t += 1 return (t-1, None)
def at_ptime(self, formula, t): return substitute(formula, self.varmapb_t[t])
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)