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 Mux(in0, in1, sel, out): # if Modules.functional # INVAR: out' = Ite(sel = 0, in0, in1) # else # INVAR: ((sel = 0) -> (out = in0)) & ((sel = 1) -> (out = in1)) vars_ = [in0, in1, sel, out] comment = "Mux (in0, in1, sel, out) = (%s, %s, %s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if sel.symbol_type() == BOOL: sel0 = Not(sel) sel1 = sel else: sel0 = EqualsOrIff(sel, BV(0, 1)) sel1 = EqualsOrIff(sel, BV(1, 1)) if Modules.functional: invar = And(EqualsOrIff(out, Ite(sel0, in0, in1))) else: invar = And(Implies(sel0, EqualsOrIff(in0, out)), Implies(sel1, EqualsOrIff(in1, out))) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def Clock(clk): # INIT: clk = 0 # TRANS: clk' = !clk comment = "Clock (clk) = (" + clk.symbol_name() + ")" if clk.symbol_type() == BOOL: clk0 = Not(clk) clk1 = clk else: clk0 = EqualsOrIff(clk, BV(0, 1)) clk1 = EqualsOrIff(clk, BV(1, 1)) init = clk0 invar = TRUE() if False: trans = EqualsOrIff(clk0, TS.to_next(clk1)) else: # Implementation that leverages on the boolean propagation trans1 = Implies(clk0, TS.to_next(clk1)) trans2 = Implies(clk1, TS.to_next(clk0)) trans = And(trans1, trans2) if Modules.abstract_clock: invar = clk0 init = TRUE() trans = TRUE() ts = TS(comment) ts.vars, ts.state_vars = set([clk]), set([clk]) ts.set_behavior(init, trans, invar) return ts
def solve_safety_inc_zz(self, hts, prop, k): self._reset_assertions(self.solver) if TS.has_next(prop): Logger.error( "Invariant checking with next variables only supports FWD strategy" ) init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() initt = self.at_time(And(init, invar), 0) Logger.log("Add init at_0", 2) self._add_assertion(self.solver, initt) propt = self.at_ptime(And(Not(prop), invar), -1) Logger.log("Add property pat_%d" % 0, 2) self._add_assertion(self.solver, propt) t = 0 while (t < k + 1): self._push(self.solver) even = (t % 2) == 0 th = int(t / 2) if even: eq = And([ EqualsOrIff(self.at_time(v, th), self.at_ptime(v, th - 1)) for v in hts.vars ]) else: eq = And([ EqualsOrIff(self.at_time(v, th + 1), self.at_ptime(v, th - 1)) for v in hts.vars ]) Logger.log("Add equivalence time %d" % t, 2) self._add_assertion(self.solver, eq) if self._solve(self.solver): Logger.log("Counterexample found with k=%s" % (t), 1) model = self._get_model(self.solver) return (t, model) else: Logger.log("No counterexample found with k=%s" % (t), 1) Logger.msg(".", 0, not (Logger.level(1))) self._pop(self.solver) if even: trans_t = self.unroll(trans, invar, th + 1, th) else: trans_t = self.unroll(trans, invar, th, th + 1) self._add_assertion(self.solver, trans_t) t += 1 return (t - 1, None)
def Orr(in_, out): # INVAR: (in = 0) -> (out = 0) & (in != 0) -> (out = 1) vars_ = [in_, out] comment = "Orr (in, out) = (%s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if (in_.symbol_type() == BOOL) and (out.symbol_type() == BOOL): invar = EqualsOrIff(in_, out) else: if out.symbol_type() == BOOL: out0 = Not(out) out1 = out else: out0 = EqualsOrIff(out, BV(0, 1)) out1 = EqualsOrIff(out, BV(1, 1)) true_res = Implies( EqualsOrIff(in_, BV(0, in_.symbol_type().width)), out0) false_res = Implies( Not(EqualsOrIff(in_, BV(0, in_.symbol_type().width))), out1) invar = And(true_res, false_res) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def dag_shape(self, model): partial_model = [] for (label, value) in model: if value.is_false(): continue else: s = label.symbol_name() # print(s) #Type x, l or r if(s[0] == 'x'): # print('VALUE+++++++',s) partial_model.append(EqualsOrIff(label, value)) if(s[0] == 'l'): # print('LEFT+++++++',s) partial_model.append(EqualsOrIff(label, value)) # partial_model.append(EqualsOrIff(label, value)) if(s[0] == 'r'): # print('RIGHT+++++++',s) partial_model.append(EqualsOrIff(label, value)) # partial_model.append(EqualsOrIff(label, value)) # print(s,'vertex', s[2], s[4:]) # else: # print(s,s[0], 'edge', s[2], s[4]) return partial_model
def Negedge(self, x): if get_type(x).is_bool_type(): if (self.encoder_config is not None) and (self.encoder_config.abstract_clock): return Not(x) return And(x, Not(TS.to_next(x))) if (self.encoder_config is not None) and (self.encoder_config.abstract_clock): return EqualsOrIff(x, BV(0,1)) return And(BV2B(x), EqualsOrIff(TS.to_next(x), BV(0,1)))
def Posedge(self, x): if get_type(x).is_bool_type(): if (self.encoder_config is not None) and (self.encoder_config.abstract_clock): return x return And(Not(x), TS.to_next(x)) if (self.encoder_config is not None) and (self.encoder_config.abstract_clock): return EqualsOrIff(x, BV(1,1)) return And(EqualsOrIff(x, BV(0,1)), BV2B(TS.to_next(x)))
def get_ordered_zero(self): self.zero = None self.firste = None self.le = None res = [] for g in self.curr._globals: gstr = pretty_print_str(g) if gstr == "zero": gt = g.symbol_type() assert (gt in self._enumsorts) domain = self._enumsorts[gt] eq = EqualsOrIff(g, domain[0]) res.append(eq) self.zero = (domain[0], g) elif gstr == "firste": gt = g.symbol_type() assert (gt in self._enumsorts) domain = self._enumsorts[gt] eq = EqualsOrIff(g, domain[1]) res.append(eq) self.firste = (domain[1], g) for pre in self.curr._le: pret = pre.symbol_type() orderedt = pret.param_types[0] if orderedt in self._enumsorts: self._ordered_sorts[orderedt] = pre self.le = pre domain = self._enumsorts[orderedt] # end = 2 end = len(domain) for i in range(end): for j in range(i, end): arg1 = domain[i] arg2 = domain[j] rel1 = Function(pre, [arg1, arg2]) rel2 = Function(pre, [arg2, arg1]) if (i == j): res.append(rel1) elif (i < j): res.append(rel1) res.append(Not(rel2)) elif (i > j): res.append(Not(rel1)) res.append(rel2) else: assert (0) if len(res) == 0: return TRUE() else: print("\nZero axiom: ") for v in res: print("\t", end="") pretty_print(v) return And(res)
def Andr(in_, out): # INVAR: (in = 2**width - 1) -> (out = 1) & (in != 2**width - 1) -> (out = 0) vars_ = [in_, out] comment = "Andr (in, out) = (%s, %s)"%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) width = in_.symbol_type().width eq_all_ones = EqualsOrIff(in_, BV(2**width - 1,width)) true_res = Implies(eq_all_ones, EqualsOrIff(out, BV(1,1))) false_res = Implies(Not(eq_all_ones), EqualsOrIff(out, BV(0,1))) invar = And(true_res, false_res) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def mem_access(addr, locations, width_idx, idx=0): first_loc = min(2**width_idx, len(locations)) - 1 ite_chain = locations[first_loc] for i in reversed(range(0, first_loc)): location = BV(i, width_idx) ite_chain = Ite(EqualsOrIff(addr, location), locations[i], ite_chain) return ite_chain
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 _op_raw_eq(self, *args): # We emulate the integer through a bitvector but # since a constraint with the form (assert (= (str.len Symb_str) bit_vect)) # is not valid we need to tranform the concrete vqalue of the bitvector in an integer # # TODO: implement logic for integer return EqualsOrIff(*_normalize_arguments(*args))
def all_loopbacks(self, vars, k, heqvar=None): lvars = list(vars) vars_k = [TS.get_timed(v, k) for v in lvars] loopback = FALSE() eqvar = None heqvars = None if heqvar is not None: eqvar = Symbol(EQVAR, BOOL) heqvars = [] peqvars = FALSE() for i in range(k): vars_i = [TS.get_timed(v, i) for v in lvars] eq_k_i = And( [EqualsOrIff(vars_k[j], vars_i[j]) for j in range(len(lvars))]) if heqvar is not None: eqvar_i = TS.get_timed(eqvar, i) peqvars = Or(peqvars, eqvar_i) eq_k_i = And(eqvar_i, Iff(eqvar_i, eq_k_i)) heqvars.append(Iff(TS.get_timed(heqvar, i), peqvars)) loopback = Or(loopback, eq_k_i) if heqvar is not None: loopback = And(loopback, And(heqvars)) return loopback
def is_long_clause(system, cl): sort2sz = {} cube = Not(cl) if cube.is_exists(): qvars = cube.quantifier_vars() for qv in qvars: qvt = qv.symbol_type() if qvt not in sort2sz: sort2sz[qvt] = 0 sort2sz[qvt] += 1 fullsorts = set() for s_fin in system._enumsorts.keys(): sz = len(s_fin.domain) if sz < 3: continue if s_fin in sort2sz: if sort2sz[s_fin] >= sz: fullsorts.add(s_fin) if len(fullsorts) == 0: return False atoms = cube.get_atoms() for enumsort in fullsorts: isLong = True enumqvars = system._enum2qvar[enumsort] for i in range(len(enumqvars)-1): for j in range(i+1, len(enumqvars)): eq = EqualsOrIff(enumqvars[i], enumqvars[j]) if eq not in atoms: isLong = False break if not isLong: break if isLong: return True return False
def _get_param_assignments(self, model, time, parameters, monotonic=True): p_ass = [] fwd = False for p in parameters: p_time = model[TS.get_ptimed(p, 0)] if p.symbol_type() == BOOL: if monotonic: if p_time == TRUE(): p_ass.append(p) else: p_ass.append(p if p_time == TRUE() else Not(p)) else: p_ass.append(EqualsOrIff(p, p_time)) p_ass = And(p_ass) self.region = simplify(Or(self.region, p_ass)) if self.models is None: self.models = [] self.models.append((model, time)) Logger.msg("+", 0, not (Logger.level(1))) self.cs_count += 1 Logger.log( "Found assignment \"%s\"" % (p_ass.serialize(threshold=100)), 1) return (p_ass, False)
def _get_param_assignments(self, model, time, parameters, monotonic=True): p_ass = [] fwd = False for p in parameters: # search the trace for any enabled faults ever_true = False for t in range(time + 1): p_time = model[TS.get_ptimed(p, 0)] if p.symbol_type() == BOOL: if p_time == TRUE(): ever_true = True break if ever_true: p_ass.append(p) elif not monotonic: p_ass.append(EqualsOrIff(p, FALSE())) p_ass = And(p_ass) self.region = simplify(Or(self.region, p_ass)) if self.models is None: self.models = [] self.models.append((model, time)) Logger.msg("+", 0, not (Logger.level(1))) self.cs_count += 1 Logger.log( "Found assignment \"%s\"" % (p_ass.serialize(threshold=100)), 1) return (p_ass, False)
def solve(self, formula): """Provides a satisfiable assignment to the state variables that are consistent with the input formula""" if self.solver.solve([formula]): return And([ EqualsOrIff(v, self.solver.get_value(v)) for v in self.system.variables ]) return None
def get_sts(self, params): if len(params) != len(self.interface.split()): Logger.error("Invalid parameters for clock behavior \"%s\"" % (self.name)) clk = params[0] valuepar = params[1] if (not type(clk) == FNode) or (not clk.is_symbol()): Logger.error("Clock symbol \"%s\" not found" % (str(clk))) if (type(valuepar) == FNode) and (valuepar.is_bv_constant()): value = valuepar.constant_value() else: try: value = int(valuepar) except: Logger.error( "Clock value should be an integer number instead of \"%s\"" % valuepar) init = [] invar = [] trans = [] vars = set([]) if clk.symbol_type().is_bv_type(): pos_clk = EqualsOrIff(clk, BV(1, 1)) neg_clk = EqualsOrIff(clk, BV(0, 1)) else: pos_clk = clk neg_clk = Not(clk) if value == 1: invar.append(pos_clk) else: invar.append(neg_clk) ts = TS("Clock Behavior") ts.vars, ts.init, ts.invar, ts.trans = vars, And(init), And( invar), And(trans) Logger.log( "Adding clock behavior \"%s(%s)\"" % (self.name, ", ".join([str(p) for p in params])), 1) return ts
def check_equal_and_valid(self, formula, expected): simplified = formula.simplify() self.assertEqual(simplified, expected) # Check the formula equality by a solver. if self.env.factory.all_solvers(QF_BV): self.assertValid(EqualsOrIff(simplified, formula), logic=QF_BV)
def compile_ftrans(self): if self.ftrans is None: return None ret_trans = TRUE() ret_invar = TRUE() use_ites = False if use_ites: for var, cond_assign_list in self.ftrans.items(): if TS.has_next(var): ite_list = TS.to_prev(var) else: ite_list = var for (condition, value) in reversed(cond_assign_list): if condition == TRUE(): ite_list = value else: ite_list = Ite(condition, value, ite_list) if TS.has_next(ite_list): ret_trans = And(ret_trans, EqualsOrIff(var, ite_list)) else: ret_invar = And(ret_invar, EqualsOrIff(var, ite_list)) else: for var, cond_assign_list in self.ftrans.items(): effects = [] all_neg_cond = [] for (condition, value) in cond_assign_list: effects.append( simplify(Implies(condition, EqualsOrIff(var, value)))) all_neg_cond.append(Not(condition)) if not TS.has_next(var) and not TS.has_next(condition): ret_invar = And(ret_invar, And(effects)) else: ret_trans = And(ret_trans, And(effects)) if TS.has_next(var): no_change = EqualsOrIff(var, TS.to_prev(var)) ret_trans = And( ret_trans, simplify(Implies(And(all_neg_cond), no_change))) return (ret_invar, ret_trans)
def all_smt(formula, keys): target_logic = get_logic(formula) print("Target Logic: %s" % target_logic) with Solver(logic=target_logic) as solver: solver.add_assertion(formula) while solver.solve(): partial_model = [EqualsOrIff(k, solver.get_value(k)) for k in keys] print(partial_model) solver.add_assertion(Not(And(partial_model)))
def Wrap(in_, out): # INVAR: (in = out) vars_ = [in_,out] comment = ("Wrap (in, out) = (%s, %s)")%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) invar = EqualsOrIff(in_, out) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def Slice(in_, out, low, high): # INVAR: (extract low high in) = out high -= 1 vars_ = [in_,out, low, high] comment = "Mux (in, out, low, high) = (%s, %s, %s, %s)"%(tuple([str(x) for x in vars_])) Logger.log(comment, 3) invar = EqualsOrIff(BVExtract(in_, low, high), out) ts = TS(comment) ts.vars, ts.invar = set([in_, out]), invar return ts
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 = in0.symbol_type() == BOOL in1B = in1.symbol_type() == BOOL outB = out.symbol_type() == BOOL 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 = set(vars_), invar return ts
def solve(formula, n, max_models=None, solver="msat"): s = Solver(name=solver) st = s.is_sat(formula) if st: vs = [x for xs in variables(n) for x in xs] k = 0 s.add_assertion(formula) while s.solve() and ((not max_models) or k < max_models): k = k + 1 model = s.get_model() s.add_assertion(Not(And([EqualsOrIff(v, model[v]) for v in vs]))) yield to_bn(model, n)
def Neq(in0, in1, out): # INVAR: (((in0 != in1) -> (out = #b1)) & ((in0 == in1) -> (out = #b0))) vars_ = [in0, in1, out] comment = "Eq (in0, in1, out) = (%s, %s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) # TODO: Create functional encoding if Modules.functional: if out.symbol_type() == BOOL: invar = EqualsOrIff(out, Not(EqualsOrIff(in0, in1))) else: invar = EqualsOrIff(out, BVNot(BVComp(in0, in1))) else: eq = EqualsOrIff(in0, in1) if out.symbol_type() == BOOL: out0 = Not(out) out1 = out else: out0 = EqualsOrIff(out, BV(0, 1)) out1 = EqualsOrIff(out, BV(1, 1)) invar = And(Implies(Not(eq), out1), Implies(eq, out0)) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def Zext(in_, out): # INVAR: (<op> in) = out) vars_ = [in_, out] comment = ("ZExt (in, out) = (%s, %s)") % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if (in_.symbol_type() == BOOL) and (out.symbol_type() == BOOL): invar = EqualsOrIff(in_, out) if (in_.symbol_type() != BOOL) and (out.symbol_type() == BOOL): invar = EqualsOrIff(BV2B(in_), out) if (in_.symbol_type() == BOOL) and (out.symbol_type() != BOOL): length = (out.symbol_type().width) - 1 if length == 0: invar = EqualsOrIff(in_, BV2B(out)) else: invar = EqualsOrIff(BVZExt(B2BV(in_), length), out) if (in_.symbol_type() != BOOL) and (out.symbol_type() != BOOL): length = (out.symbol_type().width) - (in_.symbol_type().width) if length == 0: invar = EqualsOrIff(in_, out) else: invar = EqualsOrIff(BVZExt(in_, length), out) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
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 test_simple_sorts(self): # (define-sort I () Int) # (define-sort Set (T) (Array T Bool)) I = INT SET = PartialType("Set", lambda t1: ArrayType(t1, BOOL)) self.assertEqual(ArrayType(INT, BOOL), SET(I)) # (declare-const s1 (Set I)) # (declare-const a I) # (declare-const b Int) s1 = FreshSymbol(SET(I)) a = FreshSymbol(I) b = FreshSymbol(INT) # (= (select s1 a) true) # (= (select s1 b) false) f1 = EqualsOrIff(Select(s1, a), TRUE()) f2 = EqualsOrIff(Select(s1, b), FALSE()) self.assertIsNotNone(f1) self.assertIsNotNone(f2) # Cannot instantiate a PartialType directly: with self.assertRaises(PysmtValueError): FreshSymbol(SET) # (declare-sort A 0) # Uninterpreted sort A = Type("A", 0) B = Type("B") c1 = FreshSymbol(A) c2 = FreshSymbol(A) c3 = FreshSymbol(Type("A")) c4 = FreshSymbol(B) EqualsOrIff(c1, c2) EqualsOrIff(c2, c3) with self.assertRaises(PysmtTypeError): EqualsOrIff(c1, c4) with self.assertRaises(PysmtValueError): Type("A", 1) C = Type("C", 1) CA = self.env.type_manager.get_type_instance(C, A) CB = self.env.type_manager.get_type_instance(C, B) c5 = FreshSymbol(CA) c6 = FreshSymbol(CB) self.assertIsNotNone(c5) with self.assertRaises(PysmtTypeError): EqualsOrIff(c5, c6) # Nesting self.env.enable_infix_notation = True ty = C(C(C(C(C(A))))) self.assertIsNotNone(FreshSymbol(ty)) pty = PartialType("pty", lambda S, T: S(S(S(S(S(T)))))) self.assertEqual(pty(C, A), ty)