def __init__(self, init_conds, defs, input_vars, assumes): """ This class models a program using 1. initial condition 2. transition (definitions of updated variables) 3. assumptions Input variables: - init_cond: list of initial conditions e.g. [Block == Off,Reset == On,WaterPres == wp_init_val, Overridden == False,SafetyInjection == On,Pressure == TooLow] - defs: a dictionary consisting variables being updated by the transition - input_vars: variables that are INDEPDENT. SCR programs don't have these, because input (monitored) vars are dependent due to OIA - assumes: list of assumptions Two types of assumptions: (1) state assumes: those for each *state* e.g. And(0 <= WaterPres,WaterPres < 2000): WaterPres is in range 0,2000 at any state (2) trans assumes: those for each *transition* e.g. One Input Assumption asserts only 1 var can changed at a time or And(pre(WaterPres) - 10 <= WaterPres, WaterPres <= pre(WaterPres) + 10) """ if __debug__: assert is_list(init_conds) and \ all(is_state(c) for c in init_conds), init_conds assert is_dict(defs) and \ all(is_expr(v) for v in defs.values()), defs assert is_list(input_vars) and \ all(is_expr_var(v) for v in input_vars), input_vars assert is_list(assumes) and \ all(is_expr(a) for a in assumes), assumes self.defs = defs self.init_conds = init_conds self.input_vars = input_vars self.assumes_state = [] self.assumes_trans = [] for a in assumes: Prog.append_f(a, self.assumes_state, self.assumes_trans) #Known invariants (lemmas). Use add_inv() to add an inv as lemma self.invs_state = [] self.invs_trans = []
def gen_disj_exp(ls, rs, is_max_plus, is_eq): """ Return disjunctive format Examples: sage: var('y') y sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=True,is_eq=True) 'If(x - 10 >= y - 3,x - 10 == y + 12,y - 3 == y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=True,is_eq=False) 'If(x - 10 >= y - 3,x - 10 >= y + 12,y - 3 >= y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=False,is_eq=False) 'If(x - 10 <= y - 3,x - 10 >= y + 12,y - 3 >= y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=False,is_eq=False) 'If(x - 10 <= y - 3,x - 10 >= y + 12,y - 3 >= y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y,12], is_max_plus=False,is_eq=False) 'If(x - 10 <= y - 3,If(y <= 12, x - 10 >= y, x - 10 >= 12),If(y <= 12, y - 3 >= y, y - 3 >= 12))' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y,12], is_max_plus=False,is_eq=True) 'If(x - 10 <= y - 3,If(y <= 12, x - 10 == y, x - 10 == 12),If(y <= 12, y - 3 == y, y - 3 == 12))' """ if not is_list(ls): ls = [ls] if not is_list(rs): rs = [rs] return IeqMPP.l_mp2df(ls, rs, is_max_plus, 0, is_eq)
def gen_lambda_exp(ls, rs, is_max_plus, is_formula, is_eq): """ Return lambda expression lambda x,y, ... = max(x,y...) >= max(x,y...) Examples: sage: var('y') y sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y,5], is_max_plus=True) 'lambda x,y: max(x - 10,y - 3) - max(y,5) >= 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y,5], is_max_plus=True,is_formula=True,is_eq=False) 'lambda x,y: max(x - 10,y - 3) - max(y,5) >= 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y,5], is_max_plus=True,is_formula=False,is_eq=False) 'lambda x,y: max(x - 10,y - 3) - max(y,5)' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y], is_max_plus=True,is_formula=False,is_eq=False) 'lambda x,y: max(x - 10,y - 3) - (y)' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y], is_max_plus=True,is_formula=False,is_eq=True) 'lambda x,y: max(x - 10,y - 3) - (y)' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y], is_max_plus=True,is_formula=True,is_eq=True) 'lambda x,y: max(x - 10,y - 3) - (y) == 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y+12], is_max_plus=False,is_formula=True,is_eq=True) 'lambda x,y: min(x - 10,y - 3) - (y + 12) == 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y+12], is_max_plus=False,is_formula=True,is_eq=True) 'lambda x,y: min(x - 10,y - 3) - (y + 12) == 0' sage: """ if __debug__: assert is_list(ls) and ls, ls assert is_list(rs) and rs, rs op = 'max' if is_max_plus else 'min' str_op = (lambda s: '{}({})'.format(op, ','.join(map(str, s))) if len(s) >= 2 else s[0]) if len(rs) == 1: if len(ls) == 1: #(x+3,y+8), (3,8), (3,y) ss = ls[0] - rs[0] else: #len(ls) >= 2 rss = rs[0] lss = str_op(ls) if rss.is_zero(): ss = lss else: if rss.operator is None: #x,,y7 ss = '{} - {}'.format(lss, rss) else: #x + 3, y - 3 ss = '{} - ({})'.format(lss, rss) else: #len(rs) >= 2: ss = '{} - {}'.format(str_op(ls), str_op(rs)) ss = ('lambda {}: {}{}'.format( ','.join(map(str, get_vars(ls + rs))), ss, ' {} 0'.format('==' if is_eq else '>=') if is_formula else '')) return ss
def slice_defs(prop, defs, assumes_state, assumes_trans): """ Return a new (potentially empty) def dictionary from the old one consisting of only necessary variable definitions to prove property """ if __debug__: assert is_dict(defs), defs assert is_list(assumes_state), assumes_state assert is_list(assumes_trans), assumes_trans fs = [prop] + assumes_state + assumes_trans fs = [f for f in fs if is_expr(f)] vs = [get_vars(f) for f in fs] vs = [cur(v_) if is_pre(v_) else v_ for v_ in vflatten(vs)] vs = vset(vs, fhash) vs_ = [Prog.get_influence_vs(v, defs, []) for v in vs] vs = vset(vflatten(vs + vs_), fhash) a_defs = OrderedDict() for v in vs: k = fhash(v) if k in defs: a_defs[k] = defs[k] return a_defs
def append_f(f, list_state, list_trans): if __debug__: assert is_expr(f), f assert is_list(list_state), list_state assert is_list(list_trans), list_trans if is_trans(f): list_trans.append(f) else: list_state.append(f)
def __init__(self, eqts, xinfo): assumes = xinfo['Assume'] if __debug__: assert is_list(eqts) and eqts, eqts assert is_list(assumes) and assumes, assumes assert all(is_sage_rel(x) for x in assumes + eqts), (assumes, eqts) super(IeqDeduce, self).__init__(terms=[], tcs=[], xinfo=xinfo) logger.debug('|assumes|={}, |eqts|={}'.format(len(assumes), len(eqts))) self.eqts = eqts
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 __init__(self, eqts, xinfo): assumes = xinfo['Assume'] if __debug__: assert is_list(eqts) and eqts, eqts assert is_list(assumes) and assumes, assumes assert all(is_sage_rel(x) for x in assumes + eqts), (assumes,eqts) super(IeqDeduce,self).__init__(terms=[], tcs=[], xinfo=xinfo) logger.debug('|assumes|={}, |eqts|={}' .format(len(assumes),len(eqts))) self.eqts = eqts
def sparse(ls, is_max_plus): """ Parse the result from 'compute_ext_rays_polar' in TPLib into proper lambda format Examples: sage: var('x,y,z,d') (x, y, z, d) #TODO: (may be bug) any diff btw is_max_plus=True vs False ??? sage: IeqMPP.sparse([x-oo,y+0,z-oo,SR(0)-oo,x-6,y-oo,z-oo,SR(0)-oo], is_max_plus=True) ('lambda x,y: -x + y + 6 >= 0', 'y >= x - 6') sage: IeqMPP.sparse([x-oo,y-oo,z-oo,d+9,x-6,y-oo,z-oo,d+20], is_max_plus=True) ('lambda d,x: d + 9 - max(x - 6,d + 20) >= 0', 'If(x - 6 >= d + 20, d + 9 >= x - 6, d + 9 >= d + 20)') sage: IeqMPP.sparse([x-1,SR(0)-oo,x-oo,SR(0)+0], is_max_plus=True) ('lambda x: x - 1 >= 0', 'x - 1 >= 0') sage: IeqMPP.sparse([x+0,SR(0)-oo,x-oo,SR(0)+1], is_max_plus=True) ('lambda x: x - 1 >= 0', 'x >= 1') sage: IeqMPP.sparse([x-oo,y+0,z-oo,SR(0)-oo,x-6,y-oo,z-oo,SR(0)-oo], is_max_plus=False) ('lambda x,y: -x + y + 6 >= 0', 'y >= x - 6') sage: IeqMPP.sparse([x-oo,y-oo,z-oo,d+9,x-6,y-oo,z-oo,d+20], is_max_plus=False) ('lambda d,x: d + 9 - min(x - 6,d + 20) >= 0', 'If(x - 6 <= d + 20, d + 9 >= x - 6, d + 9 >= d + 20)') sage: IeqMPP.sparse([x-1,SR(0)-oo,x-oo,SR(0)+0], is_max_plus=False) ('lambda x: x - 1 >= 0', 'x - 1 >= 0') sage: IeqMPP.sparse([x+0,SR(0)-oo,x-oo,SR(0)+1], is_max_plus=False) ('lambda x: x - 1 >= 0', 'x >= 1') """ if __debug__: assert is_list(ls) and is_even(len(ls)), ls assert is_bool(is_max_plus), is_max_plus mp = len(ls) / 2 lhs = [l for l in ls[:mp] if not is_sage_inf(l)] rhs = [l for l in ls[mp:] if not is_sage_inf(l)] # if lhs contains the same exact elems as rhs then remove # b/c it's a tautology, e.g. max(x,y) >= max(y,x) if set(lhs) == set(rhs): return None # if one of these is empty, i.e. contain only +/-Inf originally if not lhs or not rhs: return None return IeqMPP.gen_lambda_disj(lhs, rhs, is_max_plus, is_eq=False)
def group_rs(rs, max_group_siz=10): """ Heuristic method to remove mpp invs having similar format, e.g., 2: ('lambda n,x: max(x - 46655,0) >= n - 35', 'If(x - 46655 >= 0, x - 46655 >= n - 35, 0 >= n - 35)') 3: ('lambda n,x: max(x - 205378,0) >= n - 58', 'If(x - 205378 >= 0, x - 205378 >= n - 58, 0 >= n - 58)') 4: ('lambda n,x: max(x - 405223,0) >= n - 73', 'If(x - 405223 >= 0, x - 405223 >= n - 73, 0 >= n - 73)') 5: ('lambda n,x: max(x - 328508,0) >= n - 68', 'If(x - 328508 >= 0, x - 328508 >= n - 68, 0 >= n - 68)') 6: ('lambda n,x: max(x - 342999,0) >= n - 69', 'If(x - 342999 >= 0, x - 342999 >= n - 69, 0 >= n - 69)') 7: ('lambda n,x: max(x - 830583,0) >= n - 93', 'If(x - 830583 >= 0, x - 830583 >= n - 93, 0 >= n - 93)') 8: ('lambda n,x: max(x - 511999,0) >= n - 79', 'If(x - 511999 >= 0, x - 511999 >= n - 79, 0 >= n - 79)') 9: ('lambda n,x: max(x - 287495,0) >= n - 65', 'If(x - 287495 >= 0, x - 287495 >= n - 65, 0 >= n - 65)') 10: ('lambda n,x: max(x - 5831999,0) >= n - 179', 'If(x - 5831999 >= 0, x - 5831999 >= n - 179, 0 >= n - 179)') 11: ('lambda n,x: max(x - 7077887,0) >= n - 191', 'If(x - 7077887 >= 0, x - 7077887 >= n - 191, 0 >= n - 191)') 12: ('lambda n,x: max(x - 5735338,0) >= n - 178', 'If(x - 5735338 >= 0, x - 5735338 >= n - 178, 0 >= n - 178)') """ if __debug__: assert is_list(rs) and all(is_list(ls) for ls in rs), rs def get_gid(ls): k = [ i for i, l in enumerate(ls) if not SR(l).is_infinity() and l != 0 ] return None if is_empty(k) else tuple(k) d = {} for ls in rs: k = get_gid(ls) if k not in d: d[k] = [] d[k].append(ls) # db_msg = ['|gid {}|: {}' # .format(k,len(vs)) for k,vs in d.iteritems()] # logger.debug(', '.join(db_msg)) rs = [] for k, vs in d.iteritems(): #Don't remove group None, aka 'nice group' if k is None or len(vs) <= max_group_siz: rs.extend(vs) else: logger.warn('rm MPP group id {} (siz: {})'.format(k, len(vs))) return rs
def sparse(ls, is_max_plus): """ Parse the result from 'compute_ext_rays_polar' in TPLib into proper lambda format Examples: sage: var('x,y,z,d') (x, y, z, d) sage: IeqMPP.sparse([-oo,0,-oo,-oo,-6,-oo,-oo,-oo],[x,y,z,SR(0)], IeqMPP.opt_max_plus) ('lambda x,y: -x + y + 6 >= 0', 'y >= x - 6') sage: IeqMPP.sparse([-oo,-oo,-oo,9,-6,-oo,-oo,20],[x,y,z,d], IeqMPP.opt_max_plus) ('lambda d,x: d + 9 - max(x - 6,d + 20) >= 0', 'If(x - 6 >= d + 20, d + 9 >= x - 6, d + 9 >= d + 20)') sage: IeqMPP.sparse([-1,-oo,-oo,0],[x,SR(0)],IeqMPP.opt_max_plus) ('lambda x: x - 1 >= 0', 'x - 1 >= 0') sage: IeqMPP.sparse([0,-oo,-oo,1],[x,SR(0)],IeqMPP.opt_max_plus) ('lambda x: x - 1 >= 0', 'x >= 1') sage: IeqMPP.sparse([-oo,0,-oo,-oo,-6,-oo,-oo,-oo],[x,y,z,SR(0)], IeqMPP.opt_min_plus) ('lambda x,y: -x + y + 6 >= 0', 'y >= x - 6') sage: IeqMPP.sparse([-oo,-oo,-oo,9,-6,-oo,-oo,20],[x,y,z,d], IeqMPP.opt_min_plus) ('lambda d,x: d + 9 - min(x - 6,d + 20) >= 0', 'If(x - 6 <= d + 20, d + 9 >= x - 6, d + 9 >= d + 20)') sage: IeqMPP.sparse([-1,-oo,-oo,0],[x,SR(0)],IeqMPP.opt_min_plus) ('lambda x: x - 1 >= 0', 'x - 1 >= 0') sage: IeqMPP.sparse([0,-oo,-oo,1],[x,SR(0)],IeqMPP.opt_min_plus) ('lambda x: x - 1 >= 0', 'x >= 1') """ if __debug__: assert is_list(ls) and is_even(len(ls)), ls assert is_bool(is_max_plus), is_max_plus mp = len(ls)/2 lhs = [l for l in ls[:mp] if not l.is_infinity()] rhs = [l for l in ls[mp:] if not l.is_infinity()] #if lhs contains the same exact elems as rhs then remove #b/c it's a tautology, e.g. max(x,y) >= max(y,x) if set(lhs) == set(rhs): return None #if one of these is empty, i.e. contain only +/-Inf originally if not lhs or not rhs: return None return IeqMPP.gen_lambda_disj(lhs, rhs, is_max_plus,is_eq=False)
def sparse(ls, is_max_plus): """ Parse the result from 'compute_ext_rays_polar' in TPLib into proper lambda format Examples: sage: var('x,y,z,d') (x, y, z, d) sage: IeqMPP.sparse([-oo,0,-oo,-oo,-6,-oo,-oo,-oo],[x,y,z,SR(0)], IeqMPP.opt_max_plus) ('lambda x,y: -x + y + 6 >= 0', 'y >= x - 6') sage: IeqMPP.sparse([-oo,-oo,-oo,9,-6,-oo,-oo,20],[x,y,z,d], IeqMPP.opt_max_plus) ('lambda d,x: d + 9 - max(x - 6,d + 20) >= 0', 'If(x - 6 >= d + 20, d + 9 >= x - 6, d + 9 >= d + 20)') sage: IeqMPP.sparse([-1,-oo,-oo,0],[x,SR(0)],IeqMPP.opt_max_plus) ('lambda x: x - 1 >= 0', 'x - 1 >= 0') sage: IeqMPP.sparse([0,-oo,-oo,1],[x,SR(0)],IeqMPP.opt_max_plus) ('lambda x: x - 1 >= 0', 'x >= 1') sage: IeqMPP.sparse([-oo,0,-oo,-oo,-6,-oo,-oo,-oo],[x,y,z,SR(0)], IeqMPP.opt_min_plus) ('lambda x,y: -x + y + 6 >= 0', 'y >= x - 6') sage: IeqMPP.sparse([-oo,-oo,-oo,9,-6,-oo,-oo,20],[x,y,z,d], IeqMPP.opt_min_plus) ('lambda d,x: d + 9 - min(x - 6,d + 20) >= 0', 'If(x - 6 <= d + 20, d + 9 >= x - 6, d + 9 >= d + 20)') sage: IeqMPP.sparse([-1,-oo,-oo,0],[x,SR(0)],IeqMPP.opt_min_plus) ('lambda x: x - 1 >= 0', 'x - 1 >= 0') sage: IeqMPP.sparse([0,-oo,-oo,1],[x,SR(0)],IeqMPP.opt_min_plus) ('lambda x: x - 1 >= 0', 'x >= 1') """ if __debug__: assert is_list(ls) and is_even(len(ls)), ls assert is_bool(is_max_plus), is_max_plus mp = len(ls) / 2 lhs = [l for l in ls[:mp] if not l.is_infinity()] rhs = [l for l in ls[mp:] if not l.is_infinity()] #if lhs contains the same exact elems as rhs then remove #b/c it's a tautology, e.g. max(x,y) >= max(y,x) if set(lhs) == set(rhs): return None #if one of these is empty, i.e. contain only +/-Inf originally if not lhs or not rhs: return None return IeqMPP.gen_lambda_disj(lhs, rhs, is_max_plus, is_eq=False)
def group_rs(rs, max_group_siz=10): """ Heuristic method to remove mpp invs having similar format, e.g., 2: ('lambda n,x: max(x - 46655,0) >= n - 35', 'If(x - 46655 >= 0, x - 46655 >= n - 35, 0 >= n - 35)') 3: ('lambda n,x: max(x - 205378,0) >= n - 58', 'If(x - 205378 >= 0, x - 205378 >= n - 58, 0 >= n - 58)') 4: ('lambda n,x: max(x - 405223,0) >= n - 73', 'If(x - 405223 >= 0, x - 405223 >= n - 73, 0 >= n - 73)') 5: ('lambda n,x: max(x - 328508,0) >= n - 68', 'If(x - 328508 >= 0, x - 328508 >= n - 68, 0 >= n - 68)') 6: ('lambda n,x: max(x - 342999,0) >= n - 69', 'If(x - 342999 >= 0, x - 342999 >= n - 69, 0 >= n - 69)') 7: ('lambda n,x: max(x - 830583,0) >= n - 93', 'If(x - 830583 >= 0, x - 830583 >= n - 93, 0 >= n - 93)') 8: ('lambda n,x: max(x - 511999,0) >= n - 79', 'If(x - 511999 >= 0, x - 511999 >= n - 79, 0 >= n - 79)') 9: ('lambda n,x: max(x - 287495,0) >= n - 65', 'If(x - 287495 >= 0, x - 287495 >= n - 65, 0 >= n - 65)') 10: ('lambda n,x: max(x - 5831999,0) >= n - 179', 'If(x - 5831999 >= 0, x - 5831999 >= n - 179, 0 >= n - 179)') 11: ('lambda n,x: max(x - 7077887,0) >= n - 191', 'If(x - 7077887 >= 0, x - 7077887 >= n - 191, 0 >= n - 191)') 12: ('lambda n,x: max(x - 5735338,0) >= n - 178', 'If(x - 5735338 >= 0, x - 5735338 >= n - 178, 0 >= n - 178)') """ if __debug__: assert is_list(rs) and all(is_list(ls) for ls in rs), rs def get_gid(ls): k = [i for i,l in enumerate(ls) if not SR(l).is_infinity() and l != 0] return None if is_empty(k) else tuple(k) d = {} for ls in rs: k = get_gid(ls) if k not in d: d[k] = [] d[k].append(ls) # db_msg = ['|gid {}|: {}' # .format(k,len(vs)) for k,vs in d.iteritems()] # logger.debug(', '.join(db_msg)) rs = [] for k,vs in d.iteritems(): #Don't remove group None, aka 'nice group' if k is None or len(vs) <= max_group_siz: rs.extend(vs) else: logger.warn('rm MPP group id {} (siz: {})' .format(k, len(vs))) return rs
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 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 gen_disj_exp(ls,rs,is_max_plus,is_eq): """ Return disjunctive format sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=True,is_eq=True) 'If(x - 10 >= y - 3,x - 10 == y + 12,y - 3 == y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=True,is_eq=False) 'If(x - 10 >= y - 3,x - 10 >= y + 12,y - 3 >= y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=False,is_eq=False) 'If(x - 10 <= y - 3,x - 10 >= y + 12,y - 3 >= y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y+12], is_max_plus=False,is_eq=False) 'If(x - 10 <= y - 3,x - 10 >= y + 12,y - 3 >= y + 12)' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y,12], is_max_plus=False,is_eq=False) 'If(x - 10 <= y - 3,If(y <= 12, x - 10 >= y, x - 10 >= 12),If(y <= 12, y - 3 >= y, y - 3 >= 12))' sage: IeqMPP.gen_disj_exp([x-10,y-3],[y,12], is_max_plus=False,is_eq=True) 'If(x - 10 <= y - 3,If(y <= 12, x - 10 == y, x - 10 == 12),If(y <= 12, y - 3 == y, y - 3 == 12))' """ if not is_list(ls): ls = [ls] if not is_list(rs): rs = [rs] return IeqMPP.l_mp2df(ls,rs,is_max_plus,0,is_eq)
def __init__(self, p): """ Ex: ('lambda A, B, A0: (A[A0]) + (-7*B[2*A0]) + (-3*A0) == 0', [{'A0': 2}, {'A0': 0}, {'A0': 1}]) """ if __debug__: assert (is_tuple(p) and len(p) == 2 and is_str(p[0]) and all(s in p[0] for s in ['lambda', '[', ']']) and is_list(p[1]) and all(is_dict(v) for v in p[1])), p super(InvFlatArray, self).__init__(p[0].strip()) self.idx_info = p[1]
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 __init__(self, p): """ Ex: ('lambda A, B, A0: (A[A0]) + (-7*B[2*A0]) + (-3*A0) == 0', [{'A0': 2}, {'A0': 0}, {'A0': 1}]) """ if __debug__: assert (is_tuple(p) and len(p)==2 and is_str(p[0]) and all(s in p[0] for s in ['lambda','[' ,']']) and is_list(p[1]) and all(is_dict(v) for v in p[1])), p super(InvFlatArray,self).__init__(p[0].strip()) self.idx_info = p[1]
def print_invs(ps, nice_format=True): """ sage: var('y') y #TODO # sage: from dig_polynomials import InvEqt # sage: Inv.print_invs(map(InvEqt, [3*x==2,x*x==1])) # 0: 3*x == 2 # 1: x^2 == 1 TODO # sage: Inv.print_invs(map(IExp,[3*x==2,x>=2, x*x+y == 2*y*y,('lambda expr: max(x,y) >= 0', 'If(x>=y,x>=0,y>=0)')]),nice_format=False) # [3*x == 2, x^2 + y == 2*y^2, x >= 2, If(x>=y,x>=0,y>=0)] """ if __debug__: assert (is_list(ps) and all(isinstance(p,Inv) for p in ps)), map(type,ps) if ps: ps = sorted(ps, key=lambda p: p.get_score()) ps_poly_eqt = [] #ps_poly_ieq = [] ps_other = [] for p in ps: if '==' in str(p): ps_poly_eqt.append(p) else: ps_other.append(p) ps = ps_poly_eqt + ps_other if nice_format: str_ = lambda p: ('{}, {}'.format(Inv.rm_lambda(p.p), p.p_str) if isinstance(p,InvMPP) else p.p_str) rs = '\n'.join('{:>5}: {}' .format(i,str_(p)) for i,p in enumerate(ps)) else: rs = '[{}]'.format(', '.join(map(str,ps))) print rs
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 print_invs(ps, nice_format=True): """ sage: var('y') y #TODO # sage: from dig_polynomials import InvEqt # sage: Inv.print_invs(map(InvEqt, [3*x==2,x*x==1])) # 0: 3*x == 2 # 1: x^2 == 1 TODO # sage: Inv.print_invs(map(IExp,[3*x==2,x>=2, x*x+y == 2*y*y,('lambda expr: max(x,y) >= 0', 'If(x>=y,x>=0,y>=0)')]),nice_format=False) # [3*x == 2, x^2 + y == 2*y^2, x >= 2, If(x>=y,x>=0,y>=0)] """ if __debug__: assert (is_list(ps) and all(isinstance(p, Inv) for p in ps)), map(type, ps) if ps: ps = sorted(ps, key=lambda p: p.get_score()) ps_poly_eqt = [] #ps_poly_ieq = [] ps_other = [] for p in ps: if '==' in str(p): ps_poly_eqt.append(p) else: ps_other.append(p) ps = ps_poly_eqt + ps_other if nice_format: str_ = lambda p: ('{}, {}'.format(Inv.rm_lambda(p.p), p.p_str) if isinstance(p, InvMPP) else p.p_str) rs = '\n'.join('{:>5}: {}'.format(i, str_(p)) for i, p in enumerate(ps)) else: rs = '[{}]'.format(', '.join(map(str, ps))) print rs
def preprocess(self, xinfo): """ Preprocess input data 1) transforms external functions to special arrays 1) change arr repr to value->index repr to speed up arr idx lookup 2) generate nodes """ if __debug__: assert is_dict(xinfo), xinfo evs = ExtFun.gen_extvars(xinfo=xinfo) #arrays only evs = [OrderedDict([(k,v) for k,v in ev.iteritems() if is_list(v)]) for ev in evs] evs = Miscs.keys_to_str(evs) if not is_empty(evs): #add to traces self.tcs = [merge_dict(evs + [tc]) for tc in self.tcs] self.tcs_extra = [merge_dict(evs + [tc]) for tc in self.tcs_extra] mytcs = [] for tc in self.tcs: #arrs reprent ext funs (already in new format) efs = ExtFun.gen_extfuns(tc=tc,xinfo=xinfo) #convert normal arr format to new format arrs = [(k, Miscs.getListIdxs(v)) for k,v in tc.items()] arrs = OrderedDict(arrs) d = merge_dict(efs + [arrs]) mytcs.append(d) self.tcs = mytcs self.trees = [Tree({'root':k, 'children': [None] * len(c.values()[0][0]), 'commute': ExtFun(k).is_commute()}) for k,c in self.tcs[0].items()] self.xinfo = xinfo
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)])
def set_sols(self, sols): if __debug__: assert (is_list(sols) and all(isinstance(s,Inv) for s in sols)), sols self._sols = sols
def gen_lambda_exp(ls, rs, is_max_plus, is_formula, is_eq): """ Return lambda expression lambda x,y, ... = max(x,y...) >= max(x,y...) Examples: sage: var('y') y sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y,5], is_max_plus=True) 'lambda x,y: max(x - 10,y - 3) - max(y,5) >= 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y,5], is_max_plus=True,is_formula=True,is_eq=False) 'lambda x,y: max(x - 10,y - 3) - max(y,5) >= 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y,5], is_max_plus=True,is_formula=False,is_eq=False) 'lambda x,y: max(x - 10,y - 3) - max(y,5)' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y], is_max_plus=True,is_formula=False,is_eq=False) 'lambda x,y: max(x - 10,y - 3) - (y)' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y], is_max_plus=True,is_formula=False,is_eq=True) 'lambda x,y: max(x - 10,y - 3) - (y)' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y], is_max_plus=True,is_formula=True,is_eq=True) 'lambda x,y: max(x - 10,y - 3) - (y) == 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y+12], is_max_plus=False,is_formula=True,is_eq=True) 'lambda x,y: min(x - 10,y - 3) - (y + 12) == 0' sage: IeqMPP.gen_lambda_exp([x-10,y-3],[y+12], is_max_plus=False,is_formula=True,is_eq=True) 'lambda x,y: min(x - 10,y - 3) - (y + 12) == 0' sage: """ if __debug__: assert is_list(ls) and ls, ls assert is_list(rs) and rs, rs op = 'max' if is_max_plus else 'min' str_op = (lambda s: '{}({})' .format(op, ','.join(map(str,s))) if len(s)>=2 else s[0]) if len(rs) == 1: if len(ls) == 1: #(x+3,y+8), (3,8), (3,y) ss = ls[0] - rs[0] else: #len(ls) >= 2 rss = rs[0] lss = str_op(ls) if rss.is_zero(): ss = lss else: if rss.operator is None: #x,,y7 ss = '{} - {}'.format(lss,rss) else:#x + 3, y - 3 ss = '{} - ({})'.format(lss,rss) else: #len(rs) >= 2: ss = '{} - {}'.format(str_op(ls), str_op(rs)) ss = ('lambda {}: {}{}' .format(','.join(map(str, get_vars(ls+rs))), ss, ' {} 0'.format('==' if is_eq else '>=') if is_formula else '')) return ss
def eval_lambda(f, idx_info, tc): """ Evaluate array expression p, e.g. p: A[i,j,k]=B[2i+3j+k] if idx_info is specified then only test p on the idxs from idx_info Assumes: the first array in lambda is the pivot lambda A,B,i,j,k: ... => i,j,k belong to A inv = 'lambda B,C,D,i,j: B[i][j]=C[D[2i+3]]' returns true if inv is true on tc Examples: sage: var('a,b,c,i,j') (a, b, c, i, j) sage: InvArray.eval_lambda('lambda a,b,c,i,j: a[i][j]==2*b[i]+c[j]', None, {'a':[[4,-5],[20,11]],'b':[1,9],'c':[2,-7]}) True sage: InvArray.eval_lambda('lambda c,a,b,xor,i: c[i] == xor(a[i],b[i])', None, {'a': [147, 156, 184, 76], 'b': [51, 26, 247, 189], 'c': [160, 334, 79, 281]}) False sage: InvArray.eval_lambda('lambda c,a,b,xor,i1: c[i1] == xor(a[i1],b[i1])', None, {'a': [147, 156, 184, 76], 'b': [51, 26, 247, 189], 'c': [160, 134, 79, 241]}) True sage: InvArray.eval_lambda('lambda rvu, t, rvu1, rvu0: (rvu[rvu0][rvu1]) + (-t[4*rvu0 + rvu1]) == 0', None, {'t': [28, 131, 11, 85, 133, 46, 179, 20, 227, 148, 225, 197, 38, 221, 221, 126], 'rvu': [[28, 131, 11, 85], [133, 46, 179, 20], [227, 148, 225, 197], [38, 221, 221, 126]]}) True #The following illustrate the use of idxVals, #i.e. p is only true under certain array rages sage: InvArray.eval_lambda('lambda st, rvu, st0, st1: (-st[st0][st1]) + (rvu[4*st0 + st1]) == 0', None, tc = {'rvu': [28, 131, 11, 85, 193, 124, 103, 215, 66, 26, 68, 54, 176, 102, 15, 237], 'st': [[28, 131, 11, 85, 133, 46, 179, 20, 227, 148, 225, 197, 38, 221, 221, 126], [193, 124, 103, 215, 106, 229, 162, 168, 166, 78, 144, 234, 199, 254, 152, 250], [66, 26, 68, 54, 206, 16, 155, 248, 231, 198, 240, 43, 208, 205, 213, 26], [176, 102, 15, 237, 49, 141, 213, 97, 137, 155, 50, 243, 112, 51, 124, 107]]}) False sage: InvArray.eval_lambda('lambda st, rvu, st0, st1: (-st[st0][st1]) + (rvu[4*st0 + st1]) == 0', idx_info = [{'st0': 0, 'st1': 0}, {'st0': 0, 'st1': 1}, {'st0': 2, 'st1': 2}, {'st0': 2, 'st1': 3}, {'st0': 3, 'st1': 0}, {'st0': 3, 'st1': 1}, {'st0': 3, 'st1': 2}, {'st0': 3, 'st1': 3}, {'st0': 0, 'st1': 2}, {'st0': 0, 'st1': 3}, {'st0': 1, 'st1': 0}, {'st0': 1, 'st1': 1}, {'st0': 1, 'st1': 2}, {'st0': 1, 'st1': 3}, {'st0': 2, 'st1': 0}, {'st0': 2, 'st1': 1}], tc = {'rvu': [28, 131, 11, 85, 193, 124, 103, 215, 66, 26, 68, 54, 176, 102, 15, 237], 'st': [[28, 131, 11, 85, 133, 46, 179, 20, 227, 148, 225, 197, 38, 221, 221, 126], [193, 124, 103, 215, 106, 229, 162, 168, 166, 78, 144, 234, 199, 254, 152, 250], [66, 26, 68, 54, 206, 16, 155, 248, 231, 198, 240, 43, 208, 205, 213, 26], [176, 102, 15, 237, 49, 141, 213, 97, 137, 155, 50, 243, 112, 51, 124, 107]]}) True """ """ Note: sage_eval vs eval sage_eval works on str of the format 'lambda x,y: 2*x+y' whereas eval works on str of the format 2*x+y directly (no lambda) Also, the result of sage_eval can apply on dicts whose keys are str e.g. f(**{'x':2,'y':3}) whereas the result of eval applies on dict whose keys are variables e.g. f(**{x:2,y:3}) """ if __debug__: assert is_str(f) and 'lambda' in f, f assert (idx_info is None or is_list(idx_info) and all(is_dict(v) for v in idx_info)), indx_info assert is_dict(tc), tc assert all(is_str(k) for k in tc), tc.keys() f = sage_eval(f) vs = f.func_code.co_varnames arrs = [v for v in vs if v in tc] #A,B extfuns = [v for v in vs if v in ExtFun.efdict] idxStr = [v for v in vs if v not in arrs + extfuns] #i,j,k d_tc = dict([(v, tc[v]) for v in arrs]) d_extfun = dict([(v, ExtFun(v).get_fun()) for v in extfuns]) d_ = merge_dict([d_tc, d_extfun]) if idx_info is None: #obtain idxsVals from the pivot array pivotContents = tc[arrs[0]] idxVals = [idx for idx, _ in Miscs.travel(pivotContents)] idx_info = [dict(zip(idxStr, idxV)) for idxV in idxVals] ds = [merge_dict([d_, idx_info_]) for idx_info_ in idx_info] try: return all(f(**d) for d in ds) except IndexError: return False except TypeError: return False except NameError as msg: logger.warn(msg) return False
def set_sols(self, sols): if __debug__: assert (is_list(sols) and all(isinstance(s, Inv) for s in sols)), sols self._sols = sols
def eval_lambda(f, idx_info, tc): """ Evaluate array expression p, e.g. p: A[i,j,k]=B[2i+3j+k] if idx_info is specified then only test p on the idxs from idx_info Assumes: the first array in lambda is the pivot lambda A,B,i,j,k: ... => i,j,k belong to A inv = 'lambda B,C,D,i,j: B[i][j]=C[D[2i+3]]' returns true if inv is true on tc Examples: sage: var('a,b,c,i,j') (a, b, c, i, j) sage: InvArray.eval_lambda('lambda a,b,c,i,j: a[i][j]==2*b[i]+c[j]', None, {'a':[[4,-5],[20,11]],'b':[1,9],'c':[2,-7]}) True sage: InvArray.eval_lambda('lambda c,a,b,xor,i: c[i] == xor(a[i],b[i])', None, {'a': [147, 156, 184, 76], 'b': [51, 26, 247, 189], 'c': [160, 334, 79, 281]}) False sage: InvArray.eval_lambda('lambda c,a,b,xor,i1: c[i1] == xor(a[i1],b[i1])', None, {'a': [147, 156, 184, 76], 'b': [51, 26, 247, 189], 'c': [160, 134, 79, 241]}) True sage: InvArray.eval_lambda('lambda rvu, t, rvu1, rvu0: (rvu[rvu0][rvu1]) + (-t[4*rvu0 + rvu1]) == 0', None, {'t': [28, 131, 11, 85, 133, 46, 179, 20, 227, 148, 225, 197, 38, 221, 221, 126], 'rvu': [[28, 131, 11, 85], [133, 46, 179, 20], [227, 148, 225, 197], [38, 221, 221, 126]]}) True #The following illustrate the use of idxVals, #i.e. p is only true under certain array rages sage: InvArray.eval_lambda('lambda st, rvu, st0, st1: (-st[st0][st1]) + (rvu[4*st0 + st1]) == 0', None, tc = {'rvu': [28, 131, 11, 85, 193, 124, 103, 215, 66, 26, 68, 54, 176, 102, 15, 237], 'st': [[28, 131, 11, 85, 133, 46, 179, 20, 227, 148, 225, 197, 38, 221, 221, 126], [193, 124, 103, 215, 106, 229, 162, 168, 166, 78, 144, 234, 199, 254, 152, 250], [66, 26, 68, 54, 206, 16, 155, 248, 231, 198, 240, 43, 208, 205, 213, 26], [176, 102, 15, 237, 49, 141, 213, 97, 137, 155, 50, 243, 112, 51, 124, 107]]}) False sage: InvArray.eval_lambda('lambda st, rvu, st0, st1: (-st[st0][st1]) + (rvu[4*st0 + st1]) == 0', idx_info = [{'st0': 0, 'st1': 0}, {'st0': 0, 'st1': 1}, {'st0': 2, 'st1': 2}, {'st0': 2, 'st1': 3}, {'st0': 3, 'st1': 0}, {'st0': 3, 'st1': 1}, {'st0': 3, 'st1': 2}, {'st0': 3, 'st1': 3}, {'st0': 0, 'st1': 2}, {'st0': 0, 'st1': 3}, {'st0': 1, 'st1': 0}, {'st0': 1, 'st1': 1}, {'st0': 1, 'st1': 2}, {'st0': 1, 'st1': 3}, {'st0': 2, 'st1': 0}, {'st0': 2, 'st1': 1}], tc = {'rvu': [28, 131, 11, 85, 193, 124, 103, 215, 66, 26, 68, 54, 176, 102, 15, 237], 'st': [[28, 131, 11, 85, 133, 46, 179, 20, 227, 148, 225, 197, 38, 221, 221, 126], [193, 124, 103, 215, 106, 229, 162, 168, 166, 78, 144, 234, 199, 254, 152, 250], [66, 26, 68, 54, 206, 16, 155, 248, 231, 198, 240, 43, 208, 205, 213, 26], [176, 102, 15, 237, 49, 141, 213, 97, 137, 155, 50, 243, 112, 51, 124, 107]]}) True """ """ Note: sage_eval vs eval sage_eval works on str of the format 'lambda x,y: 2*x+y' whereas eval works on str of the format 2*x+y directly (no lambda) Also, the result of sage_eval can apply on dicts whose keys are str e.g. f(**{'x':2,'y':3}) whereas the result of eval applies on dict whose keys are variables e.g. f(**{x:2,y:3}) """ if __debug__: assert is_str(f) and 'lambda' in f, f assert (idx_info is None or is_list(idx_info) and all(is_dict(v) for v in idx_info)), indx_info assert is_dict(tc), tc assert all(is_str(k) for k in tc), tc.keys() f = sage_eval(f) vs = f.func_code.co_varnames arrs = [v for v in vs if v in tc] #A,B extfuns = [v for v in vs if v in ExtFun.efdict] idxStr = [v for v in vs if v not in arrs+extfuns] #i,j,k d_tc = dict([(v,tc[v]) for v in arrs]) d_extfun= dict([(v,ExtFun(v).get_fun()) for v in extfuns]) d_ = merge_dict([d_tc,d_extfun]) if idx_info is None: #obtain idxsVals from the pivot array pivotContents = tc[arrs[0]] idxVals = [idx for idx,_ in Miscs.travel(pivotContents)] idx_info = [dict(zip(idxStr,idxV)) for idxV in idxVals] ds = [merge_dict([d_, idx_info_]) for idx_info_ in idx_info] try: return all(f(**d) for d in ds) except IndexError: return False except TypeError: return False except NameError as msg: logger.warn(msg) return False
def __init__(self, ps): if __debug__: assert is_list(ps) and all(isinstance(p,Inv) for p in ps), ps self.ps = vset(ps) Refine.print_diff('vset', len(ps), len(self.ps))
def get_state_vars(f, exclude_vars): """ f: a formula, e.g. the transition formula exclude_vars: variables that are not considered as state vars, e.g. independent variables From Verifying Safety Property of Lustre Programs: Temporal Induction Let L be a Lustre program, S be the tuple of L's state variables, non-input variables that occur within a pre. Then only non-input variables that occur within a pre are considered program states node test( X: bool ) returns ( P : bool ); var A, B, C : bool; let A = X -> pre A; B = not (not X -> pre(C)); C = not B; P = A = B; #property to be proved, not important, not part of input >>> from z3 import Bools, Implies, Ints, If, Or #states variables = [A,C] >>> A,A_pre,B,B_pre,C,C_pre,X = Bools('A A_pre B B_pre C C_pre X') >>> af = A == A_pre >>> bf = B == Not(Not(Implies(X,C_pre))) >>> cf = C == Not(B) >>> trans = And(af,bf,cf) >>> exclude_vars = [X] >>> KIP.get_state_vars(trans, exclude_vars) [A, C] >>> af = A == Implies(X,A_pre) >>> bf = B == Not(Implies(Not(X),C_pre)) >>> cf = C == Not(B) >>> trans = And(af,bf,cf) >>> exclude_vars = [X] >>> KIP.get_state_vars(trans, exclude_vars) [A, C] #state variables = c , R is not included because R_pre is not used >>> R,c_pre,c = Ints('R c_pre c') >>> trans = If(Or(R == 100, c_pre == 2), c == 0, c == c_pre + 1) >>> KIP.get_state_vars(trans, exclude_vars=[]) [c] #this algorithm would return [], instead of [C] #this is by design because it doesn't make sense to have #C_pre without C in trans >>> KIP.get_state_vars(A == C_pre,[]) [] """ if __debug__: assert f is None or is_expr(f), f assert is_list(exclude_vars), exclude_vars if f is None: return [] #start with state_vars being all vars in trans state_vars = get_vars(f) #keep those that not being excluded state_vars = [ v for v in state_vars if not expr_member(v, exclude_vars) ] #keep those v that are not pre but v's pre is part of the f state_vars = [ v for v in state_vars if not is_pre(v) and expr_member(pre(v), state_vars) ] if __debug__: assert all(not is_pre(v) for v in state_vars) return state_vars
def imply(fs, gs): """ Checks if the set f of formulas implies the set f of formulas sage: var('x y') (x, y) sage: SMT_Z3.imply([x-6==0],x*x-36==0) True sage: SMT_Z3.imply([x-6==0,x+6==0],x*x-36==0) True sage: SMT_Z3.imply([x*x-36==0],x-6==0) False sage: SMT_Z3.imply([x-6==0],x-36==0) False sage: SMT_Z3.imply(x-7>=0,x>=6) True sage: SMT_Z3.imply(x-7>=0,x>=8) False sage: SMT_Z3.imply(x-6>=0,x-7>=0) False sage: SMT_Z3.imply([x-7>=0,y+5>=0],x+y-3>=0) False sage: SMT_Z3.imply([x-7>=0,y+5>=0],x+y-2>=0) True sage: SMT_Z3.imply([x-2*y>=0,y-1>=0],x-2>=0) True sage: SMT_Z3.imply([],x-2>=0) False sage: SMT_Z3.imply([x-7>=0,y+5>=0],x+y-2>=0) True sage: SMT_Z3.imply([x^2-9>=0,x>=0],x-3>=0) True sage: SMT_Z3.imply([1/2*x**2 - 3/28*x + 1 >= 0],1/20*x**2 - 9/20*x + 1 >= 0) False sage: SMT_Z3.imply([1/20*x**2 - 9/20*x + 1 >= 0],1/2*x**2 - 3/28*x + 1 >= 0) True sage: SMT_Z3.imply([x-6==0],x*x-36==0) True sage: SMT_Z3.imply([x+7>=0,y+5>=0],x*y+36>=0) False sage: SMT_Z3.imply([x+7>=0,y+5>=0],x*y+35>=0) False sage: SMT_Z3.imply([x+7>=0,y+5>=0],x*y-35>=0) False sage: SMT_Z3.imply([x+7>=0],x-8>=0) False sage: SMT_Z3.imply([x+7>=0],x+8>=0) True sage: SMT_Z3.imply([x+7>=0],x+8.9>=0) True sage: SMT_Z3.imply([x>=7,y>=5],x*y>=35) True sage: SMT_Z3.imply([x>=-7,y>=-5],x*y>=35) False sage: SMT_Z3.imply([x-7>=0,y+5>=0],[x+y-2>=0,x>=2-y]) True """ if __debug__: assert fs is not None, fs assert gs is not None, gs if is_empty(fs) or is_empty(gs): return False #conservative approach if not is_list(fs): fs = [fs] if not is_list(gs): gs = [gs] fs = [SMT_Z3.to_z3exp(f, is_real=True) for f in fs] gs = [SMT_Z3.to_z3exp(g, is_real=True) for g in gs] claim = z3.Implies(z3.And(fs), z3.And(gs)) is_proved, _ = vprove(claim) return is_proved
def get_influence_vs(v, defs, rs): """ Return a list of variables that influences v (i.e. the definition of v depends on these variables) >>> from z3 import Bools, BoolVal >>> from scr_miscs import mk_OIA >>> s,t = Bools('s t') >>> x,y,z = Bools('x y z') >>> vs = [x,y,z] >>> o = mk_OIA(vs) >>> vv = [o,o,And(o,s)] >>> vs2 = [t] >>> vv2 = [BoolVal(True)] >>> vs_k = map(fhash,vs + vs2) >>> vs_v =vv + vv2 >>> defs = OrderedDict(zip(vs_k,vs_v)) >>> print Prog.get_influence_vs(x,defs,rs=[]) [s, y, z] #>>> print Prog.get_influence_vs(x,defs,assumes=[x==s],rs=[]) #[s, y, z] #>>> print Prog.get_influence_vs(x,defs,assumes=[y==t],rs=[]) #[s, y, z, t] """ if __debug__: assert is_expr_var(v), v assert is_dict(defs), defs assert is_list(rs), rs if is_pre(v): v = cur(v) #return if already in the result set if expr_member(v, rs): return rs try: vs = get_vars(defs[fhash(v)]) #print vs except KeyError: return rs rs = rs + [v] #convert v_pre to v vs = [cur(v_) if is_pre(v_) else v_ for v_ in vs] vs = vset(vs, fhash) for v_ in vs: rs_ = Prog.get_influence_vs(v_, defs, rs) rs = rs + rs_ rs = rs + vs rs = vset(rs, fhash) #remove myself v_idx = map(fhash, rs).index(fhash(v)) rs = rs[:v_idx] + rs[v_idx + 1:] return sorted(rs, key=str)