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 prove(self, prop, k, do_trans=False, do_base_case=True, do_induction=True, do_pcompress=True, do_term_check=True, do_abstraction=True): """ Prove a property using KIP. """ if __debug__: assert is_expr(prop), prop 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 assert is_bool(do_abstraction), do_abstraction #import time #stime = time.time() logger.debug('Original program:\n{}'.format(self)) if do_abstraction: prog = self.gen_abstraction(self, prop) logger.info('Abstract program:\n{}'.format(prog)) else: prog = self kip = KIP(prop, prog, k=k, do_base_case=do_base_case, do_induction=do_induction, do_pcompress=do_pcompress, do_term_check=do_term_check) if do_trans: raise AssertionError('trans: not implemented') r, m, k_ = kip.k_ind() #time_elapsed = time.time() - stime #logger.warn('Time elapsed: %.4f s'%time_elapsed) return r, m, k_
def r_mp2df(t, rs, is_max_plus, idx, is_eq): """ Convert max/min-plus format to disjunctive formula Inputs: t = single term rs = list of terms idx = operate over rs[idx:] """ if __debug__: assert not is_empty(rs) assert idx >= 0, idx assert is_bool(is_max_plus), is_max_plus rs_ = rs[idx:] if __debug__: assert not is_empty(rs_) first_elem = rs_[0] first_elem_f = ("{} {} {}".format(t, '==' if is_eq else '>=', first_elem)) if len(rs_) == 1: # t <= x ==> t <= x return first_elem_f else: # t <= max(x,y,z) ==> If(x>=y and x >= z, t <= x, ...) op = ">=" if is_max_plus else "<=" rest_f = IeqMPP.r_mp2df(t, rs, is_max_plus, idx + 1, is_eq) others = rs[:idx] + rs[idx + 1:] csts = ','.join('{} {} {}'.format(first_elem, op, t) for t in others) cond = ('And({})' if len(others) >= 2 else '{}').format(csts) return "If({}, {}, {})".format(cond, first_elem_f, rest_f)
def l_mp2df(ls, rs, is_max_plus, idx, is_eq): if __debug__: assert not is_empty(ls), ls assert not is_empty(rs), rs assert idx >= 0, idx assert is_bool(is_max_plus), is_max_plus ls_ = ls[idx:] if __debug__: assert ls_, ls_ first_elem = ls_[0] first_elem_f = IeqMPP.r_mp2df(first_elem, rs, is_max_plus, 0, is_eq) if len(ls_) == 1: #t <= max(x,y,z) return first_elem_f else: op = ">=" if is_max_plus else "<=" rest_f = IeqMPP.l_mp2df(ls, rs, is_max_plus, idx + 1, is_eq) others = ls[:idx] + ls[idx + 1:] csts = ','.join('{} {} {}'.format(first_elem, op, t) for t in others) cond = ("And({})" if len(others) >= 2 else "{}").format(csts) return "If({},{},{})".format(cond, first_elem_f, rest_f)
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 tprove(self, prop, expected, msg, do_trans=False, do_term_check=True, do_pcompress=True, do_induction=True, do_base_case=True, do_abstraction=True, do_assert=True, k=10): """ Shortcut to prove properties. Raise errors if the result of the proof is not as expected. """ if __debug__: assert is_expr(prop), prop assert expected in [True, False, None], expected assert is_str(msg), msg assert k >= 0, k assert all( is_bool(c) for c in [ do_term_check, do_pcompress, do_induction, do_base_case, do_assert, do_abstraction ]) logger.info('*****') (r, m, k_) = self.prove(prop, k=k, do_trans=do_trans, do_abstraction=do_abstraction, do_base_case=do_base_case, do_induction=do_induction, do_term_check=do_term_check, do_pcompress=do_pcompress) logger.info(msg) if r == True: logger.info('proved') elif r == False: logger.info('disproved') logger.debug(model_str(m)) else: logger.info('unproved') if r != expected: msg = "***** UNEXPECTED RESULT: output={}, expected={} *****" logger.warn(msg.format(r, expected)) if do_assert: raise AssertionError('unexpected result !!!') logger.info('*****\n')
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)