def eval_lambda(f, d, is_formula=True): """ Evaluates lambda function f Examples: sage: assert InvMPP.eval_lambda('lambda x,y: max(x - 13,-3) >= y', {'x':11,'y':100}) == False sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 5', {'x':2,'y':3,'d':7}) sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 6', {'x':2,'y':3,'d':7}) == False sage: assert InvMPP.eval_lambda('lambda x,y: x+y', {'x':2,'y':3,'d':7}, is_formula=False) == 5 sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 10 or x + y == 5', {'x':2,'y':3,'d':7}) sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 1 or x + y == 2', {'x':2,'y':3,'d':7}) == False """ if __debug__: assert is_str(f) and 'lambda' in f, f assert is_dict(d), d assert all(is_str(k) for k in d), d.keys() f = sage_eval(f) vs = f.func_code.co_varnames assert set(vs) <= set(d.keys()), (vs,d.keys()) #if d has more keys than variables in f then remove those extra keys d=dict([(k,d[k]) for k in vs]) rs = f(**d) return bool(rs) if is_formula else rs
def eval_lambda(f, d, is_formula=True): """ Evaluates lambda function f Examples: sage: assert InvMPP.eval_lambda('lambda x,y: max(x - 13,-3) >= y', {'x':11,'y':100}) == False sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 5', {'x':2,'y':3,'d':7}) sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 6', {'x':2,'y':3,'d':7}) == False sage: assert InvMPP.eval_lambda('lambda x,y: x+y', {'x':2,'y':3,'d':7}, is_formula=False) == 5 sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 10 or x + y == 5', {'x':2,'y':3,'d':7}) sage: assert InvMPP.eval_lambda('lambda x,y: x+y == 1 or x + y == 2', {'x':2,'y':3,'d':7}) == False """ if __debug__: assert is_str(f) and 'lambda' in f, f assert is_dict(d), d assert all(is_str(k) for k in d), d.keys() f = sage_eval(f) vs = f.func_code.co_varnames assert set(vs) <= set(d.keys()), (vs, d.keys()) #if d has more keys than variables in f then remove those extra keys d = dict([(k, d[k]) for k in vs]) rs = f(**d) return bool(rs) if is_formula else rs
def __init__(self, filename, verbose=VLog.DEBUG): if __debug__: assert filename is None or is_str(filename), filename logger.level = verbose import dig_inv, dig_refine, dig_arrays, dig_polynomials for f in [dig_miscs, dig_inv, dig_refine, dig_arrays, dig_polynomials]: f.logger.set_level(logger.level) from platform import node, system, release, machine margs = [ get_cur_time(time_only=False), version(), ' '.join([node(), system(), release(), machine()]) ] logger.info("DIG (Dynamic Invariant Generator)\n" "{}, {}, {}".format(*margs)) if filename is not None: self._setup(filename) else: logger.warn('No filename given, manual setup')
def __init__(self, p): """ Ex: sage: m = InvMPP(('lambda p,r: 422 >= min(p,r + 29)', 'If(p <= r + 29, 422 >= p, 422 >= r + 29)')) sage: print m 422 >= min(p,r + 29), If(p <= r + 29, 422 >= p, 422 >= r + 29) sage: m.get_score() 62 """ if __debug__: assert (is_tuple(p) and len(p) == 2 and is_str(p[0]) and 'lambda' in p[0] and is_str(p[1])), p super(InvMPP, self).__init__(p[0].strip(), p_str=p[1])
def __init__(self, p): """ Ex: sage: m = InvMPP(('lambda p,r: 422 >= min(p,r + 29)', 'If(p <= r + 29, 422 >= p, 422 >= r + 29)')) sage: print m 422 >= min(p,r + 29), If(p <= r + 29, 422 >= p, 422 >= r + 29) sage: m.get_score() 62 """ if __debug__: assert (is_tuple(p) and len(p)==2 and is_str(p[0]) and 'lambda' in p[0] and is_str(p[1])), p super(InvMPP,self).__init__(p[0].strip(), p_str=p[1])
def __init__(self, p, p_str=None): if __debug__: assert p_str is None or is_str(p_str), p_str self.p = p if p_str is None: p_str = str(p) self.p_str = Inv.rm_lambda(p_str)
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 __init__(self, p): """ Ex: 'lambda a,b,c,i,j: a[i][j]==2*b[i]+c[j]' """ if __debug__: assert (is_str(p) and all(s in p for s in ['lambda', '[', ']'])), p super(InvNestedArray, self).__init__(p.strip()) self.idx_info = None #no info about idx (only for FlatArr)
def __init__(self, p): """ Ex: flat arr: 'lambda A, B, A0: (A[A0]) + (-7*B[2*A0]) + (-3*A0) == 0 nested arr: 'lambda A,B,i1: A[i1] == B[-2*i1 + 5]' """ if __debug__: assert (is_str(p) and all(s in p for s in ['lambda', '[', ']'])), p super(InvArray, self).__init__(p)
def _setup(self,filename): if __debug__: assert is_str(filename), filename rf = dig_miscs.ReadFile(filename) self.filename = rf.filename self.xinfo = rf.xinfo self.ss_arr, self.tcs_arr = rf.ss_arr, rf.tcs_arr self.ss_num, self.tcs_num = rf.ss_num, rf.tcs_num
def __init__(self, p): """ Ex: flat arr: 'lambda A, B, A0: (A[A0]) + (-7*B[2*A0]) + (-3*A0) == 0 nested arr: 'lambda A,B,i1: A[i1] == B[-2*i1 + 5]' """ if __debug__: assert (is_str(p) and all(s in p for s in ['lambda','[' ,']'])), p super(InvArray,self).__init__(p)
def __init__(self, p): """ Ex: 'lambda a,b,c,i,j: a[i][j]==2*b[i]+c[j]' """ if __debug__: assert (is_str(p) and all(s in p for s in ['lambda','[' ,']'])), p super(InvNestedArray,self).__init__(p.strip()) self.idx_info = None #no info about idx (only for FlatArr)
def _setup(self, filename): if __debug__: assert is_str(filename), filename rf = dig_miscs.ReadFile(filename) self.filename = rf.filename self.xinfo = rf.xinfo self.ss_arr, self.tcs_arr = rf.ss_arr, rf.tcs_arr self.ss_num, self.tcs_num = rf.ss_num, rf.tcs_num
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 __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 __init__(self,filename,verbose=VLog.DEBUG): if __debug__: assert filename is None or is_str(filename), filename logger.level = verbose import dig_inv, refine, dig_arrays, dig_polynomials for f in [dig_inv, refine, dig_arrays, dig_polynomials, dig_miscs]: f.logger.set_level(logger.level) from platform import node, system, release, machine margs = [get_cur_time(time_only=False),version(), ' '.join([node(),system(),release(),machine()])] logger.info("{}, {}, {}".format(*margs)) if filename is not None: self._setup(filename) else: logger.warn('No filename given, manual setup')
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 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