def Uop(bvop, bop, in_, out): # INVAR: (<op> in) = out) vars_ = [in_, out] comment = "" #(bvop.__name__ + " (in, out) = (%s, %s)")%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) in_B = get_type(in_).is_bool_type() outB = get_type(out).is_bool_type() bools = (1 if in_B else 0) + (1 if outB else 0) if bop == None: if in_B: in_ = B2BV(in_) if outB: out = B2BV(out) invar = EqualsOrIff(bvop(in_), out) else: if bools == 2: invar = EqualsOrIff(bop(in_), out) elif bools == 0: invar = EqualsOrIff(bvop(in_), out) else: if not in_B: invar = EqualsOrIff(bop(BV2B(in_)), out) if not outB: invar = EqualsOrIff(bop(in_), BV2B(out)) ts = TS(comment) ts.vars, ts.invar = get_free_variables(invar), invar return ts
def to_prev(formula): varmap = [] for v in get_free_variables(formula): vname = 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 simulate(self, prop, k): if self.config.strategy == VerificationStrategy.NU: self._init_at_time(self.hts.vars, 1) (t, model) = self.sim_no_unroll(self.hts, prop, k) else: self._init_at_time(self.hts.vars, k) if prop == TRUE(): self.config.incremental = False (t, model) = self.solve_safety_fwd(self.hts, Not(prop), k, False) else: (t, model) = self.solve_safety(self.hts, Not(prop), k) model = self._remap_model(self.hts.vars, model, t) if (t > -1) and (model is not None): Logger.log("Execution found", 1) trace = self.print_trace(self.hts, model, t, get_free_variables(prop), map_function=self.config.map_function) return (VerificationStatus.TRUE, trace) else: Logger.log("Deadlock wit k=%s" % k, 1) return (VerificationStatus.FALSE, None)
def _add_assertion(self, solver, formula, comment=None): if not self.config.skip_solving: solver.solver.add_assertion(formula) if Logger.level(3): buf = cStringIO() printer = SmtPrinter(buf) printer.printer(formula) print(buf.getvalue() + "\n") if solver.trace_file is not None: if comment: self._write_smt2_comment(solver, "%s: START" % comment) formula_fv = get_free_variables(formula) for v in formula_fv: if v in solver.smt2vars: continue if v.symbol_type() == BOOL: self._write_smt2_log( solver, "(declare-fun %s () Bool)" % (v.symbol_name())) elif v.symbol_type().is_array_type(): st = v.symbol_type() assert st.index_type.is_bv_type(), "Expecting BV indices" assert st.elem_type.is_bv_type(), "Expecting BV elements" self._write_smt2_log( solver, "(declare-fun %s () (Array (_ BitVec %s) (_ BitVec %s)))" % (v.symbol_name(), st.index_type.width, st.elem_type.width)) elif v.symbol_type().is_bv_type(): self._write_smt2_log( solver, "(declare-fun %s () (_ BitVec %s))" % (v.symbol_name(), v.symbol_type().width)) else: Logger.error("Unhandled type in smt2 translation") self._write_smt2_log(solver, "") for v in formula_fv: solver.smt2vars.add(v) if formula.is_and(): for f in conjunctive_partition(formula): buf = cStringIO() printer = SmtPrinter(buf) printer.printer(f) self._write_smt2_log(solver, "(assert %s)" % buf.getvalue()) else: buf = cStringIO() printer = SmtPrinter(buf) printer.printer(formula) self._write_smt2_log(solver, "(assert %s)" % buf.getvalue()) if comment: self._write_smt2_comment(solver, "%s: END" % comment)
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 MultiOp(op, end_op, out, *inparams): cum = inparams[0] for el in inparams[1:]: cum = op(cum, el) if end_op is not None: cum = end_op(cum) formula = EqualsOrIff(cum, out) ts = TS() ts.vars, ts.invar = get_free_variables(formula), formula return ts
def safety(self, prop, k, k_min, processes=1): lemmas = self.hts.lemmas self._init_at_time(self.hts.vars, k) (t, model) = self.solve_safety(self.hts, prop, k, k_min, lemmas, processes) if model == True: return (VerificationStatus.TRUE, None, t) elif model is not None: model = self._remap_model(self.hts.vars, model, t) trace = self.generate_trace(model, t, get_free_variables(prop)) return (VerificationStatus.FALSE, trace, t) else: return (VerificationStatus.UNK, None, t)
def parse_formulae(self, strforms): formulae = [] if strforms is None: return formulae for strform in strforms: if ("#" not in strform) and (strform != ""): formula = self.parse_formula(strform) formula_fv = get_free_variables(formula) nextvars = [v for v in formula_fv if TS.is_prime(v)] != [] prevvars = [v for v in formula_fv if TS.is_prev(v)] != [] formulae.append((strform, formula, (nextvars, prevvars))) return formulae
def BopBool(op, in0, in1, out): # INVAR: (in0 <op> in1) = out vars_ = [in0,in1,out] comment = (op.__name__ + " (in0, in1, out) = (%s, %s, %s)")%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) if out.symbol_type() == BOOL: bout = out else: bout = EqualsOrIff(out, BV(1, 1)) invar = Iff(op(in0,in1), bout) ts = TS(comment) ts.vars, ts.invar = get_free_variables(invar), invar return ts
def ltl_generic(self, prop, k, k_min=0): lemmas = self.hts.lemmas self._init_at_time(self.hts.vars, k) self._init_v_time(self.hts.vars, k) (t, model) = self.solve(self.hts, prop, k, lemmas) if model == True: return (VerificationStatus.TRUE, None, t) elif model is not None: model = self._remap_model(self.hts.vars, model, t) trace = self.generate_trace(model, t, get_free_variables(prop), find_loop=True) return (VerificationStatus.FALSE, trace, t) else: return (VerificationStatus.UNK, None, t)
def safety(self, prop, k, k_min): lemmas = self.hts.lemmas self._init_at_time(self.hts.vars, k) (t, model) = self.solve_safety(self.hts, prop, k, k_min, lemmas) if model == True: return (VerificationStatus.TRUE, None, t) elif model is not None: model = self._remap_model(self.hts.vars, model, t) trace = self.print_trace(self.hts, model, t, get_free_variables(prop), map_function=self.config.map_function) return (VerificationStatus.FALSE, trace, t) else: return (VerificationStatus.UNK, None, t)
def Bop(bvop, bop, in0, in1, out): # INVAR: (in0 <op> in1) = out vars_ = [in0, in1, out] comment = "" #(bvop.__name__ + " (in0, in1, out) = (%s, %s, %s)")%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) in0B = get_type(in0).is_bool_type() in1B = get_type(in1).is_bool_type() outB = get_type(out).is_bool_type() bools = (1 if in0B else 0) + (1 if in1B else 0) + (1 if outB else 0) if bop == None: if in0B: in0 = Ite(in0, BV(1, 1), BV(0, 1)) if in1B: in1 = Ite(in1, BV(1, 1), BV(0, 1)) if outB: out = Ite(out, BV(1, 1), BV(0, 1)) invar = EqualsOrIff(bvop(in0, in1), out) else: if bools == 3: invar = EqualsOrIff(bop(in0, in1), out) elif bools == 0: invar = EqualsOrIff(bvop(in0, in1), out) elif bools == 1: if in0B: invar = EqualsOrIff(bvop(B2BV(in0), in1), out) if in1B: invar = EqualsOrIff(bvop(in0, B2BV(in1)), out) if outB: invar = EqualsOrIff(BV2B(bvop(in0, in1)), out) else: if not in0B: invar = EqualsOrIff(bop(BV2B(in0), in1), out) if not in1B: invar = EqualsOrIff(bop(in0, BV2B(in1)), out) if not outB: invar = EqualsOrIff(B2BV(bop(in0, in1)), out) ts = TS(comment) ts.vars, ts.invar = get_free_variables(invar), invar return ts
def eventually(self, prop, k, k_min): lemmas = self.hts.lemmas self._init_at_time(self.hts.vars, k) (t, model) = self.solve_liveness(self.hts, prop, k, k_min, True, lemmas) model = self._remap_model(self.hts.vars, model, t) if model == True: return (VerificationStatus.TRUE, None, t) elif model is not None: trace = self.generate_trace(model, t, get_free_variables(prop), find_loop=True) return (VerificationStatus.FALSE, trace, t) else: return (VerificationStatus.UNK, None, t)
def parse_formulae(self, str_or_fnodes): formulae = [] if str_or_fnodes is None: return formulae for s in str_or_fnodes: if isinstance(s, str): if ('#' in s) or len(s) == 0: continue formula = self.parse_formula(s) else: formula = s formula_fv = get_free_variables(formula) nextvars = [v for v in formula_fv if TS.is_prime(v)] != [] prevvars = [v for v in formula_fv if TS.is_prev(v)] != [] formulae.append((str(s), formula, (nextvars, prevvars))) return formulae
def parse_line(self, string:str)->Union[FNode, None]: if '=' not in string: raise RuntimeError("Expecting a single equality but got: {}".format(string)) split = string.split("=") if len(split) > 2: raise RuntimeError("Expecting exactly one equality but got: {}".format(string)) lhs, rhs = split try: lhs = self.parser.parse_formula(lhs) rhs = self.parser.parse_formula(rhs) except UndefinedSymbolError: return None for fv in get_free_variables(lhs): if not self._pysmt_formula_manager.is_state_symbol(fv): return None if not rhs.is_constant(): raise RuntimeError("Expecting a constant on the right side but got: {}".format(rhs)) return EqualsOrIff(lhs, rhs)
def _free_variables(self, formula): if formula not in self.fv_dict: fv = get_free_variables(formula) self.fv_dict[formula] = frozenset([TS.get_ref_var(v) for v in fv]) return self.fv_dict[formula]
def has_next(formula): varlist = get_free_variables(formula) for v in varlist: if TS.is_prime(v): return True return False
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 parametric_safety(self, prop, k_max, k_min, parameters, monotonic=True, at_most=-1): if len(parameters) == 0: Logger.error("Parameters size cannot be 0") lemmas = self.hts.lemmas self._init_at_time(self.hts.vars, k_max) monotonic = True # if monotonic: # for p in parameters: # self.set_preferred((p, False)) self.region = FALSE() generalize = lambda model, t: self._get_param_assignments( model, t, parameters, monotonic) if at_most == -1: cardinality = len(parameters) else: cardinality = at_most prev_cs_count = 0 prove = self.config.prove step = 5 same_res_counter = 0 k = step end = False has_next = TS.has_next(prop) # Strategy selection increase_k = False if cardinality == -2: (t, status) = self.solve_safety_inc_fwd(self.hts, prop, k_max, k_min, all_vars=False, generalize=generalize) else: sn = SortingNetwork.sorting_network(parameters) if increase_k: # Approach with incremental increase of bmc k while k < k_max + 1: for at in range(cardinality): Logger.msg("[%d,%d]" % ((at + 1), k), 0, not (Logger.level(1))) sn_k = sn[at + 1] if at + 1 < len(sn) else FALSE() bound_constr = Or(sn_k, self.region) bound_constr = bound_constr if not has_next else Or( bound_constr, TS.to_next(bound_constr)) self.config.prove = False (t, status) = self.solve_safety_inc_bwd( self.hts, Or(prop, bound_constr), k, generalize=generalize) if (prev_cs_count == self.cs_count): same_res_counter += 1 else: same_res_counter = 0 prev_cs_count = self.cs_count if (prove == True) and ((same_res_counter > 1) or (at == cardinality - 1)): Logger.msg("[>%d,%d]" % ((at + 1), k), 0, not (Logger.level(1))) if (at_most > -1) and (at_most < cardinality): sn_k = sn[at_most - 1] else: sn_k = FALSE() bound_constr = Or(sn_k, self.region) bound_constr = bound_constr if not has_next else Or( bound_constr, TS.to_next(bound_constr)) self.config.prove = True (t, status) = self.solve_safety( self.hts, Or(prop, bound_constr), k, max(k_min, k - step)) if status == True: end = True break if (same_res_counter > 2) and (k < k_max): break if end: break k += step else: # Approach with fixed bmc k for at in range(cardinality): Logger.msg("[%d]" % ((at + 1)), 0, not (Logger.level(1))) sn_k = sn[at + 1] if at + 1 < len(sn) else FALSE() bound_constr = Or(sn_k, self.region) bound_constr = bound_constr if not has_next else Or( bound_constr, TS.to_next(bound_constr)) self.config.prove = False (t, status) = self.solve_safety_inc_bwd( self.hts, Or(prop, bound_constr), k_max, generalize=generalize) if simplify(self.region) == TRUE(): break if (prev_cs_count == self.cs_count): same_res_counter += 1 else: same_res_counter = 0 prev_cs_count = self.cs_count if (prove == True) and ((same_res_counter > 1) or (at == cardinality - 1)): Logger.msg("[>%d]" % ((at + 1)), 0, not (Logger.level(1))) if (at_most > -1) and (at_most < cardinality): sn_k = sn[at_most - 1] else: sn_k = FALSE() bound_constr = Or(sn_k, self.region) bound_constr = bound_constr if not has_next else Or( bound_constr, TS.to_next(bound_constr)) self.config.prove = True (t, status) = self.solve_safety(self.hts, Or(prop, bound_constr), k_max, k_min) if status == True: break traces = None if (self.models is not None) and (simplify(self.region) not in [TRUE(), FALSE()]): traces = [] for (model, time) in self.models: model = self._remap_model(self.hts.vars, model, time) trace = self.generate_trace(model, time, get_free_variables(prop)) traces.append(trace) region = [] dass = {} # Sorting result by size for ass in list(disjunctive_partition(self.region)): cp = list(conjunctive_partition(ass)) size = len(cp) if size not in dass: dass[size] = [] dass[size].append(ass) indexes = list(dass.keys()) indexes.sort() for size in indexes: region += dass[size] if status == True: return (VerificationStatus.TRUE, traces, region) elif status is not None: return (VerificationStatus.FALSE, traces, region) else: return (VerificationStatus.UNK, traces, region)
def generate_STS(self, lines): ts = TS("Additional system") init = TRUE() trans = TRUE() invar = TRUE() states = {} assigns = set([]) varsmap = {} def def_var(name, vtype): if name in varsmap: return varsmap[name] var = Symbol(name, vtype) ts.add_state_var(var) return var for line in lines: if line.comment: continue if line.init: if T_I not in states: states[T_I] = TRUE() if line.init.varname != "": (value, typev) = self.__get_value(line.init.value) ivar = def_var(line.init.varname, typev) state = EqualsOrIff(ivar, value) else: state = TRUE() if line.init.value == T_TRUE else FALSE() states[T_I] = And(states[T_I], state) # Optimization for the initial state assignment init = And(init, state) state = TRUE() if line.state: sname = T_S + line.state.id if (line.state.varname != ""): (value, typev) = self.__get_value(line.state.value) ivar = def_var(line.state.varname, typev) state = EqualsOrIff(ivar, value) assval = (sname, line.state.varname) if assval not in assigns: assigns.add(assval) else: Logger.error( "Double assignment for variable \"%s\" at state \"%s\"" % (line.state.varname, sname)) else: state = TRUE() if line.state.value == T_TRUE else FALSE() if sname not in states: states[sname] = TRUE() states[sname] = And(states[sname], state) stateid_width = math.ceil(math.log(len(states)) / math.log(2)) stateid_var = Symbol(self.new_state_id(), BVType(stateid_width)) init = And(init, EqualsOrIff(stateid_var, BV(0, stateid_width))) invar = And( invar, Implies(EqualsOrIff(stateid_var, BV(0, stateid_width)), states[T_I])) states[T_I] = EqualsOrIff(stateid_var, BV(0, stateid_width)) count = 1 state_items = list(states.keys()) state_items.sort() for state in state_items: if state == T_I: continue invar = And( invar, Implies(EqualsOrIff(stateid_var, BV(count, stateid_width)), states[state])) states[state] = EqualsOrIff(stateid_var, BV(count, stateid_width)) count += 1 transdic = {} for line in lines: if line.comment: continue if line.trans: if states[line.trans.start] not in transdic: transdic[states[line.trans.start]] = [] transdic[states[line.trans.start]].append( states[line.trans.end]) for transition in transdic: (start, end) = (transition, transdic[transition]) trans = And(trans, Implies(start, TS.to_next(Or(end)))) vars_ = [v for v in get_free_variables(trans) if not TS.is_prime(v)] vars_ += get_free_variables(init) vars_ += get_free_variables(invar) invar = And(invar, BVULE(stateid_var, BV(count - 1, stateid_width))) ts.set_behavior(init, trans, invar) ts.add_state_var(stateid_var) hts = HTS("ETS") hts.add_ts(ts) invar_props = [] ltl_props = [] return (hts, invar_props, ltl_props)
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)