def D(self, i, s): """ Return a formula expressing state s_i is different than states [0, s_0, s_1, ..., s_(i-1)]. If s is None then the returned formula expresses state i different than states [0 ... i-1] """ if __debug__: assert i >= 2, 'i ({}) must start from 2!'.format(i) if len(self.state_vars) == 0: return None def S(i, s): """ Return a set (list) consisting of the variables at state i. I.e. x_1i, x_2i, ... """ return [self._at_state(v, i, s) for v in self.state_vars] cur_state = S(i, s) #states s_0 ... s_(j-1) pre_states = [S(i_, s) for i_ in range(i)] if s: #D(s,s+i) = s_i # [0,s_0,s_1,..,s_(i-1)] pre_states = [S(0, None)] + pre_states f = [ Not(self.state_eq(cur_state, pre_state)) for pre_state in pre_states ] return myAnd(f)
def state_eq(vs1, vs2): """ Generate a formula expressing the variables in vs1,vs2 are the same """ if __debug__: assert is_list(vs1) and all(is_expr_var(v) for v in vs1), vs1 assert is_list(vs2) and all(is_expr_var(v) for v in vs2), vs2 assert len(vs1) == len(vs2) eqts = [v1 == v2 for v1, v2 in zip(vs1, vs2)] return myAnd(eqts)
def I_S(self, i, s): """ Return the formula for (state) invariant at state i. """ if __debug__: assert is_list(self.invs_state) and\ all(is_state(a) for a in self.invs_state), self.invs_state assert i >= 0, i inv_state = myAnd([self._at_state(a, i, s) for a in self.invs_state]) return inv_state
def I_T(self, i, s): """ Return the formula for (trans) invariant at state i """ if __debug__: assert is_list(self.invs_trans) and\ all(is_trans(a) for a in self.invs_trans), self.invs_trans assert i >= 1, i inv_trans = myAnd([self._at_state(a, i, s) for a in self.invs_trans]) return inv_trans
def I(self, i, s): """ Return the formula for init condition at state i """ if __debug__: assert is_list(self.init_conds) and\ all(is_state(a) for a in self.init_conds), self.init_conds assert i >= 0, i init_cond = myAnd([self._at_state(a, i, s) for a in self.init_conds]) return init_cond
def __init__(self, prop, prog, k=100, do_base_case=True, do_induction=True, do_pcompress=True, do_term_check=True): if __debug__: assert is_expr(prop), prop assert isinstance(prog, Prog), prog assert k >= 0, k assert is_bool(do_base_case), do_base_case assert is_bool(do_induction), do_induction assert is_bool(do_pcompress), do_pcompress assert is_bool(do_term_check), do_term_check self.k = k self.prop = prop self.is_prop_state = is_state(self.prop) self.init_conds = prog.init_conds self.assumes_state = prog.assumes_state self.assumes_trans = prog.assumes_trans self.invs_state = prog.invs_state self.invs_trans = prog.invs_trans self.input_vars = prog.input_vars self.defs_vals = prog.defs.values() f = myAnd(self.defs_vals + self.assumes_state + self.assumes_trans) self.state_vars = self.get_state_vars(f, self.input_vars) logger.debug("KIP (k={})".format(k)) logger.debug("prop: '{}'".format(self.prop)) logger.debug("|state_vars|: {}".format(len(self.state_vars))) logger.debug(self.state_vars) if len(self.state_vars) == 0: logger.warn("No state vars") if do_pcompress: logger.warn("Disable path compression") do_pcompress = False if do_term_check: logger.warn("Disable termination check") do_term_check = False self.do_base_case = do_base_case self.do_induction = do_induction self.do_pcompress = do_pcompress self.do_term_check = do_term_check
def A_S(self, i, s): """ Return the formula for (state) assume at state i """ if __debug__: assert is_list(self.assumes_state) and\ all(is_state(a) for a in self.assumes_state),\ self.assumes_state assert i >= 0, i assume_state = myAnd( [self._at_state(a, i, s) for a in self.assumes_state]) return assume_state
def A_T(self, i, s): """ Return the formula for (trans) assume at state i """ if __debug__: assert is_list(self.assumes_trans) and\ all(is_trans(a) for a in self.assumes_trans),\ self.assumes_trans assert i >= 1, i assume_trans = myAnd( [self._at_state(a, i, s) for a in self.assumes_trans]) return assume_trans
def atT(c, when_c=None): """ Return And(!pre(c),c,when_c) When seeing the SCR syntax such as `@T(x) when c1`, the parser calls atT(x,c1') where c1' is c1 with all variables v => pre(v). In other words, the when_c only contains 'pre' variables. IMPORTANT: SCR syntax allows syntax such as `@T(x) when c1 OR @T(x) when c2` But I require explicit parentheses around these `(@T(x) when c1) OR (@T(x) when c2)`. The reason is to avoid ambiguity: 'c1 OR @T(x) when c2' could be treated as an expression c3, i.e. @T(x) when c3. EXAMPLES: >>> from z3 import * >>> x,y = Ints('x y') >>> atT(x==10) And(Not(x_pre == 10), x == 10) >>> atT(x==10, pre(x)!= pre(y)) And(Not(x_pre == 10), x == 10, x_pre != y_pre) >>> atT(Or(x==10,y==3),pre(x)!= pre(y)) And(Not(Or(x_pre == 10, y_pre == 3)), Or(x == 10, y == 3), x_pre != y_pre) """ if __debug__: assert is_state(c), c assert not when_c or is_pre_f(when_c),\ "'{}' does not have the right WHEN format. "\ "Perhaps missing parenthesis, e.g."\ "(@T(x) when c1) OR (@T(y) when c2). "\ "See document in function for details.".format(when_c) vss_c_cur = get_vars(c) vss_c_pre = map(pre, vss_c_cur) vss_c = zip(vss_c_cur, vss_c_pre) not_c = Not(substitute(c, *vss_c)) return myAnd(not_c, c, when_c)
def _term_check(k): c = [D(k_, _sbase) for k_ in range(2, k + 1)] #2..k c = myAnd(c) #Term check logger.debug('* Term Check ({})'.format(k)) if c is None: logger.warn('skipping term check') return None, None r_t, cex_t = KIP.entails(S_base, Not(c)) if r_t == True: logger.info('** proved (cycle found) ({}): {}'.format( k, self.prop)) return r_t, cex_t
def T(self, i, s): """ Return the formula for trans at state i. I.e. the transaction from state i-1 to state i T(i=0) is by default initial state (condition) T(i=1) is the trans from state 0 to state 1, and so on """ if __debug__: assert is_list(self.defs_vals) and\ all(is_expr(a) for a in self.defs_vals),\ self.defs_vals assert i >= 1, i trans = myAnd([self._at_state(a, i, s) for a in self.defs_vals]) return trans
def atC(v, when_c=None): """ Analogous to atT Return And(pre(v) != v, when_c) EXAMPLES: >>> from z3 import * >>> x,y = Bools('x y') >>> atC(x) x_pre != x >>> atC(x,when_c = pre(x) == pre(y)) And(x_pre != x, x_pre == y_pre) """ if __debug__: assert is_expr_var(v) and not is_pre(v), v assert not when_c or is_pre_f(when_c), when_c f = myAnd(pre(v) != v, when_c) return f
def mk_OIA(vs): """ Create an expression representing the One Input Assumption over the variables in vs. version 1 (this implementation): (x # pre(x) and y=pre(y) ...) OR (y # pre(y) and x=pre(x) ...) OR version 2: (x # pre(x) => y=pre(y) and ...) AND (y # pre(y) => x=pre(x) and ...) AND (x#pre(x) or y#pre(y) ...) Examples: >>> from z3 import * >>> x = Int('x') >>> y = Real('y') >>> z = Bool('z') >>> mk_OIA([x,y,z]) Or(And(x != x_pre, y == y_pre, z == z_pre), And(y != y_pre, x == x_pre, z == z_pre), And(z != z_pre, x == x_pre, y == y_pre)) >>> mk_OIA([x]) x != x_pre >>> mk_OIA([]) """ if __debug__: assert is_list(vs) and all(not is_pre(v) for v in vs), vs oia = lambda v, vs: myAnd(v != pre(v), *[v_ == pre(v_) for v_ in vs]) return myOr([oia(v, vs[:i] + vs[i + 1:]) for i, v in enumerate(vs)])