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 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 get_invs(self, deg=2): """ Default method to obtain invariants By default, DIG finds flat/nested relations over arr vars and finds eqts/ieqs(deduction) over num vars. """ rs = [] if not is_empty(self.ss_arr): logger.debug('*** Generate Array Invs over {} ***'.format( self.ss_arr)) rs = rs + self.get_flat_array() rs = rs + self.get_nested_array() if not is_empty(self.ss_num): logger.debug('*** Generate Polynomial Invs over {} ***'.format( self.ss_num)) if __debug__: assert deg >= 1, deg terms = dig_miscs.gen_terms(deg, self.ss_num) logger.debug('deg={}, |ss_num|={}, |terms|={}'.format( deg, len(self.ss_num), len(terms))) rs = rs + self.get_eqts(terms) return rs
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 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 get_invs(self, deg=2): """ Default method to obtain invariants By default, DIG finds flat/nested relations over arr vars and finds eqts/ieqs(deduction) over num vars. """ rs = [] if not is_empty(self.ss_arr): logger.debug('*** Generate Array Invs over {} ***\n' .format(self.ss_arr)) rs = rs + self.get_flat_array() rs = rs + self.get_nested_array() if not is_empty(self.ss_num): logger.debug('*** Generate Polynomial Invs over {} ***\n' .format(self.ss_num)) if __debug__: assert deg >= 1, deg terms = dig_miscs.gen_terms(deg, self.ss_num) logger.debug('deg={}, |ss_num|={}, |terms|={}' .format(deg,len(self.ss_num),len(terms))) rs = rs + self.get_eqts(terms) return rs
def rfilter(self, tcs, do_parallel=True): if is_empty(self.ps) or is_empty(tcs): logger.debug('rfilter skips (|ps|={}, |tcs|={})'.format( len(self.ps), len(tcs))) return None logger.debug('rfilter(|ps|={}, |tcs|={})'.format( len(self.ps), len(tcs))) if not isinstance(self.ps[0], InvExp): from dig_miscs import Miscs tcs = Miscs.keys_to_str(tcs) def wprocess(tasks, Q): rs = [p for p in tasks if all(p.seval(tc) for tc in tcs)] if Q is None: #no multiprocessing return rs else: Q.put(rs) tasks = self.ps if do_parallel: from vu_common import get_workloads from multiprocessing import (Process, Queue, current_process, cpu_count) Q = Queue() workloads = get_workloads(tasks, max_nprocesses=cpu_count(), chunksiz=2) logger.debug("workloads 'refine' {}: {}".format( len(workloads), map(len, workloads))) workers = [ Process(target=wprocess, args=(wl, Q)) for wl in workloads ] for w in workers: w.start() wrs = [] for _ in workers: wrs.extend(Q.get()) else: wrs = wprocess(tasks, Q=None) self.ps = wrs Refine.print_diff('rfilter', len(tasks), len(self.ps))
def rem_dup_arrs(ps, ainfo): """ Remove relations that involve elements from same arrays Examples: sage: var('x_0 x_1 y_0 y_1') (x_0, x_1, y_0, y_1) sage: ainfo = {x_0:{'name':'x','idxs':[0]},x_1:{'name':'x','idxs':[1]}, y_0:{'name':'y','idxs':[0]},y_1:{'name':'y','idxs':[1]}} sage: FlatArray.rem_dup_arrs([x_0 + x_1 == 0, x_1 + y_1 == 0, x_0 + y_1 + y_0==0, x_0 + x_1-2==0], ainfo) dig_arrays:Warn:Removed 3 array eqts x_0 + x_1 == 0 x_0 + y_0 + y_1 == 0 x_0 + x_1 - 2 == 0 [x_1 + y_1 == 0] """ get_anames = lambda p: [ainfo[v]['name'] for v in get_vars(p)] ps_rem, ps = vpartition(ps, lambda p: vall_uniq(get_anames(p))) if not is_empty(ps_rem): logger.warn('Removed {} array eqts\n{}' .format(len(ps_rem), list_str(ps_rem,'\n'))) return ps
def wprocess(ae,Q): r = ae.peelme(data=self.tcs[0]) if not is_empty(r): logger.debug('Nesting {} has {} rel(s)\n{}' .format(ae,len(r),'\n'.join(r))) Q.put(r)
def imply(fs, gs): """ Checks if the set f of formulas implies the set f of formulas sage: var('x y') (x, y) sage: assert imply([x-6==0],x*x-36==0) sage: assert imply([x-6==0,x+6==0],x*x-36==0) sage: assert not imply([x*x-36==0],x-6==0) sage: assert not imply([x-6==0],x-36==0) sage: assert imply(x-7>=0,x>=6) sage: assert not imply(x-7>=0,x>=8) sage: assert not imply(x-6>=0,x-7>=0) sage: assert not imply([x-7>=0,y+5>=0],x+y-3>=0) sage: assert imply([x-7>=0,y+5>=0],x+y-2>=0) sage: assert imply([x-2*y>=0,y-1>=0],x-2>=0) sage: assert not imply([],x-2>=0) sage: assert imply([x-7>=0,y+5>=0],x+y-2>=0) sage: assert imply([x^2-9>=0,x>=0],x-3>=0) sage: assert not imply([1/2*x**2 - 3/28*x + 1 >= 0],1/20*x**2 - 9/20*x + 1 >= 0) sage: assert imply([1/20*x**2 - 9/20*x + 1 >= 0],1/2*x**2 - 3/28*x + 1 >= 0) sage: assert imply([x-6==0],x*x-36==0) sage: assert not imply([x+7>=0,y+5>=0],x*y+36>=0) sage: assert not imply([x+7>=0,y+5>=0],x*y+35>=0) sage: assert not imply([x+7>=0,y+5>=0],x*y-35>=0) sage: assert not imply([x+7>=0],x-8>=0) sage: assert imply([x+7>=0],x+8>=0) sage: assert imply([x+7>=0],x+8.9>=0) sage: assert imply([x>=7,y>=5],x*y>=35) sage: assert not imply([x>=-7,y>=-5],x*y>=35) sage: assert imply([x-7>=0,y+5>=0],[x+y-2>=0,x>=2-y]) """ if is_empty(fs) or is_empty(gs): return False #conservative approach if not isinstance(fs, list): fs = [fs] if not isinstance(gs, list): gs = [gs] fs = [toZ3(f, is_real=True) for f in fs] gs = [toZ3(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 rfilter(self,tcs,do_parallel=True): if is_empty(self.ps) or is_empty(tcs): logger.debug('rfilter skips (|ps|={}, |tcs|={})' .format(len(self.ps), len(tcs))) return None logger.debug('rfilter(|ps|={}, |tcs|={})' .format(len(self.ps), len(tcs))) if not isinstance(self.ps[0],InvExp): from dig_miscs import Miscs tcs = Miscs.keys_to_str(tcs) def wprocess(tasks,Q): rs = [p for p in tasks if all(p.seval(tc) for tc in tcs)] if Q is None: #no multiprocessing return rs else: Q.put(rs) tasks = self.ps if do_parallel: from vu_common import get_workloads from multiprocessing import (Process, Queue, current_process, cpu_count) Q=Queue() workloads = get_workloads(tasks, max_nprocesses=cpu_count(), chunksiz=2) logger.debug("workloads 'refine' {}: {}" .format(len(workloads),map(len,workloads))) workers = [Process(target=wprocess,args=(wl,Q)) for wl in workloads] for w in workers: w.start() wrs = [] for _ in workers: wrs.extend(Q.get()) else: wrs = wprocess(tasks,Q=None) self.ps = wrs Refine.print_diff('rfilter', len(tasks), len(self.ps))
def solve(self): #FlatArray #Create new variables and traces logger.info('Compute new traces (treating array elems as new vars)') ainfo = {} #{A_0_0=[0,0],B_1_2_3=[1,2,3]} tsinfo = {} #{A: [A_0,A_1, ..], B:[B_0_0,B_0_1,..]} print self.tcs tcs = [FlatArray.compute_new_trace(tc, ainfo, tsinfo) for tc in self.tcs] ps = self.get_rels_elems1(tcs) #ps = self.get_rels_elems2(tcs,tsinfo) #Group arrays and in each group, find rels among array idxs gs = FlatArray.group_arr_eqts(ps, ainfo) logger.info('Partition {} eqts into {} groups' .format(len(ps), len(gs))) sols = [] for i,(gns,gps) in enumerate(gs.iteritems()): if __debug__: assert not is_empty(gps) # Modify/reformat if necessary gps = FlatArray.modify_arr_eqts(gps, ainfo) #Find rels over array indices logger.debug("{}. Find rels over idx from {} eqts (group {})" .format(i,len(gps),gns)) gps = [FlatArray.parse_arr_eqt(p,ainfo) for p in gps] gsols = FlatArray.find_rels(gps) sols.extend(gsols) if is_empty(sols): logger.warn('No rels found over arr idxs, use orig results') sols = flatten(ps) self.sols = map(InvEqt, sols) self.do_refine = False else: self.sols = map(InvFlatArray, sols) self.print_sols()
def get_eqts(self, terms=None): if terms is None: terms = self.ss_num from dig_polynomials import Eqt solver = Eqt(terms, self.tcs_num, self.xinfo) solver.go() sols = solver.sols if not (is_empty(sols) or is_empty(self.xinfo['Assume'])): #deduce new info if external knowledge (assumes) is avail from dig_polynomials import IeqDeduce solver = IeqDeduce(xinfo=self.xinfo, eqts=[s.p for s in sols]) solver.solve() solver.print_sols() sols = sols + solver.sols return sols
def get_eqts(self,terms=None): if terms is None: terms = self.ss_num from dig_polynomials import Eqt solver = Eqt(terms, self.tcs_num, self.xinfo) solver.go() sols = solver.sols if not (is_empty(sols) or is_empty(self.xinfo['Assume'])): #deduce new info if external knowledge (assumes) is avail from dig_polynomials import IeqDeduce solver = IeqDeduce(xinfo = self.xinfo, eqts = [s.p for s in sols]) solver.solve() solver.print_sols() sols = sols + solver.sols return sols
def rinfer(self): """ Return a (preferably minimal) subset of ps that infers all properties in ps. sage: logger.set_level(VLog.DEBUG) sage: var('a s t y') (a, s, t, y) sage: rf = Refine(map(InvEqt,[a*a - s + t == 0, t*t - 4*s + 2*t + 1 == 0, \ a*s - 1/2*s*t + 1/2*s == 0, a*x - 1/2*x*t + 1/2*x == 0, \ a - 1/2*t + 1/2 == 0, a*t - 2*s + 3/2*t + 1/2 == 0])) sage: rf.rinfer() refine:Debug:rinfer(|ps|=6) refine:Debug:rinfer (before 6, after 2, diff 4) sage: assert \ set([p.p for p in rf.ps]) == set([a - 1/2*t + 1/2 == 0, t^2 - 4*s + 2*t + 1 == 0]) or \ set([p.p for p in rf.ps]) == set([a - 1/2*t + 1/2 == 0, a^2 - s + t == 0]) sage: rf = Refine(map(InvIeq,[x-7>=0, x + y -2>=0, y+5 >= 0, -7 + x >= 0])); rf.rinfer(); sorted(rf.ps,key=str) refine:Debug:vset (before 4, after 3, diff 1) refine:Debug:rinfer(|ps|=3) refine:Debug:rinfer (before 3, after 2, diff 1) [x - 7 >= 0, y + 5 >= 0] sage: rf = Refine(map(InvEqt,[x+y==0])); rf.rinfer(); sorted(rf.ps,key=str) refine:Debug:rinfer skips (|ps|=1) [x + y == 0] """ if len(self.ps) <= 1: logger.debug('rinfer skips (|ps|={})'.format(len(self.ps))) return None logger.debug('rinfer(|ps|={})'.format(len(self.ps))) ps = [p.p for p in self.ps if isinstance(p, InvExp)] if is_empty(ps): logger.warn('cannot do inferrence on non polynomial rels') return None self.ps = [ InvEqt(p) if p.operator() == operator.eq else InvIeq(p) for p in Refine.rinfer_helper(ps) ] Refine.print_diff('rinfer', len(ps), len(self.ps))
def rinfer(self): """ Return a (preferably minimal) subset of ps that infers all properties in ps. sage: logger.set_level(VLog.DEBUG) sage: var('a s t y') (a, s, t, y) sage: rf = Refine(map(InvEqt,[a*a - s + t == 0, t*t - 4*s + 2*t + 1 == 0, \ a*s - 1/2*s*t + 1/2*s == 0, a*x - 1/2*x*t + 1/2*x == 0, \ a - 1/2*t + 1/2 == 0, a*t - 2*s + 3/2*t + 1/2 == 0])) sage: rf.rinfer() refine:Debug:rinfer(|ps|=6) refine:Debug:rinfer (before 6, after 2, diff 4) sage: assert \ set([p.p for p in rf.ps]) == set([a - 1/2*t + 1/2 == 0, t^2 - 4*s + 2*t + 1 == 0]) or \ set([p.p for p in rf.ps]) == set([a - 1/2*t + 1/2 == 0, a^2 - s + t == 0]) sage: rf = Refine(map(InvIeq,[x-7>=0, x + y -2>=0, y+5 >= 0, -7 + x >= 0])); rf.rinfer(); sorted(rf.ps,key=str) refine:Debug:vset (before 4, after 3, diff 1) refine:Debug:rinfer(|ps|=3) refine:Debug:rinfer (before 3, after 2, diff 1) [x - 7 >= 0, y + 5 >= 0] sage: rf = Refine(map(InvEqt,[x+y==0])); rf.rinfer(); sorted(rf.ps,key=str) refine:Debug:rinfer skips (|ps|=1) [x + y == 0] """ if len(self.ps) <= 1: logger.debug('rinfer skips (|ps|={})'.format(len(self.ps))) return None logger.debug('rinfer(|ps|={})'.format(len(self.ps))) ps = [p.p for p in self.ps if isinstance(p,InvExp)] if is_empty(ps): logger.warn('cannot do inferrence on non polynomial rels') return None self.ps = [InvEqt(p) if p.operator() == operator.eq else InvIeq(p) for p in Refine.rinfer_helper(ps)] Refine.print_diff('rinfer', len(ps), len(self.ps))
def _get_clp(self, typ, terms=None, subset_siz=None): if terms is None: terms = self.ss_num if is_empty(terms): return [] import dig_polynomials as dp if 'gen' in typ: solver = dp.IeqCLPGen(terms, self.tcs_num, self.xinfo) else: solver = dp.IeqCLPFixed(terms, self.tcs_num, self.xinfo) solver.subset_siz = subset_siz solver.go() return solver.sols
def toZ3(p, is_real): """ Convert a Sage expression to a Z3 expression Initially implements with a dictionary containing variables e.g. {x:Real('x')} but the code is longer and more complicated. This implemention does not require a dictionary pass in. Todo: cache this function sage: toZ3(x*x*x, False) x*x*x """ assert is_sage_expr(p), p def retval(p): if p.is_symbol(): _f = z3.Real if is_real else z3.Int else: _f = z3.RealVal if is_real else z3.IntVal return _f(str(p)) try: oprs = p.operands() except Exception: return retval(p) if is_empty(oprs): return retval(p) else: op = p.operator() #z3 has problem w/ t^c , so use t*t*t.. if op == operator.pow: assert len(oprs) == 2, oprs t, c = oprs t = toZ3(t, is_real) vs = [t] * c z3exp = reduce(operator.mul, vs) else: oprs = [toZ3(o, is_real) for o in oprs] z3exp = reduce(op, oprs) assert z3.is_expr(z3exp), z3exp return z3exp
def print_summary(filename,expect,sols_filename,sols_run): if is_empty(sols_filename): return print("\nSUMMARY ({})".format(filename)) print("Expect ({}): {}".format(len(expect), ', '.join(map(str,expect)))) time_total = 0.0 for (nr,rs,deg,etime) in sols_filename: print '* Run {}, time {}, deg {}'.format(nr, etime, deg) Inv.print_invs(rs) time_total = time_total + etime print('\nObtain {} unique results over {} run' .format(len(sols_run), len(sols_filename))) Inv.print_invs(sols_run,nice_format=False) time_str = '{0:.1f}'.format(time_total/len(sols_filename)) print('TIME AVG {}, #invs {}, ({})\n' .format(time_str,len(sols_run), filename))
def print_summary(filename, expect, sols_filename, sols_run): if is_empty(sols_filename): return print("\nSUMMARY ({})".format(filename)) print("Expect ({}): {}".format(len(expect), ', '.join(map(str, expect)))) time_total = 0.0 for (nr, rs, deg, etime) in sols_filename: print '* Run {}, time {}, deg {}'.format(nr, etime, deg) Inv.print_invs(rs) time_total = time_total + etime print('\nObtain {} unique results over {} run'.format( len(sols_run), len(sols_filename))) Inv.print_invs(sols_run, nice_format=False) time_str = '{0:.1f}'.format(time_total / len(sols_filename)) print('TIME AVG {}, #invs {}, ({})\n'.format(time_str, len(sols_run), filename))
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 _get_mpp(self, typ, terms=None, subset_siz=None): if terms is None: terms = self.ss_num if is_empty(terms): return [] import dig_polynomials as dp solver = dp.IeqMPPGen if 'gen' in typ else dp.IeqMPPFixed solver = solver(terms, self.tcs_num, self.xinfo) if 'max_then_min' in typ: mpp_opt = dp.IeqMPP.opt_max_then_min elif 'min' in typ: mpp_opt = dp.IeqMPP.opt_min_plus else: mpp_opt = dp.IeqMPP.opt_max_plus solver.mpp_opt = mpp_opt solver.subset_siz = subset_siz solver.go() return solver.sols
def to_z3exp(p, is_real): """ Convert a Sage expression to a Z3 expression Initially implements with a dictionary containing variables e.g. {x:Real('x')} but the code is longer and more complicated. This implemention does not require a dictionary pass in. Todo: cache this function """ assert is_sage_expr(p), p def retval(p): if p.is_symbol(): z3exp = (z3.Real if is_real else z3.Int)(str(p)) else: z3exp = (z3.RealVal if is_real else z3.IntVal)(str(p)) if __debug__: assert z3.is_expr(z3exp), z3exp return z3exp try: oprs = p.operands() except Exception: return retval(p) if is_empty(oprs): return retval(p) else: oprs = [SMT_Z3.to_z3exp(o, is_real) for o in oprs] z3exp = SMT_Z3._reduce(p.operator(),oprs) assert z3.is_expr(z3exp), z3exp return z3exp
def get_gid(ls): k = [i for i, l in enumerate(ls) if not is_sage_inf(l) and l != 0] return None if is_empty(k) else tuple(k)
def rfilter_old(self, tcs): """ Returns the subset of ps that satisfies all testcases tcs Examples: sage: logger.set_level(VLog.DEBUG) sage: var('y z') (y, z) sage: rf = Refine(map(InvIeq,[x^2 >= 0 , x-y >= 7]));rf.rfilter([{x:1,y:0}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=2, |tcs|=1) refine:Debug:rfilter (before 2, after 1, diff 1) [x^2 >= 0] sage: rf = Refine(map(InvIeq,[2*x -y >= 0])); rf.rfilter([{y: 14, x: 7}, {y: 13, x: 7}, {y: 6, x: 4}, {y: 1, x: 1}, {y: 2, x: 1}, {y: 5, x: 100}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=1, |tcs|=6) [2*x - y >= 0] sage: rf = Refine(map(InvIeq,[2*x -y >= 0])); rf.rfilter([{y: 14, x: 7}, {y: 13, x: 7}, {y: 6, x: 4}, {y: 1, x: 1}, {y: 2, x: 1}, {y: 25, x: 9}, {y:25 , x*y: 15, x: 9}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=1, |tcs|=7) refine:Debug:rfilter (before 1, after 0, diff 1) [] ** This is by design sage: rf = Refine(map(InvIeq,[x^3 >= 0 , x-y >= 7])); rf.rfilter([{z:1}]) refine:Debug:rfilter(|ps|=2, |tcs|=1) refine:Debug:rfilter (before 2, after 0, diff 2) sage: assert(rf.ps == []) sage: rf = Refine(map(InvMPP,[('lambda x: x>=10',''), ('lambda x,y: max(x,y)>12',''), ('lambda x: x>=10','')])); rf.rfilter([{x:20,y:0},{x:9,y:13}]); sorted(rf.ps,key=str) refine:Debug:vset (before 3, after 2, diff 1) refine:Debug:rfilter(|ps|=2, |tcs|=2) refine:Debug:rfilter (before 2, after 1, diff 1) ['lambda x,y: max(x,y)>12'] sage: rf = Refine(map(InvMPP,[('lambda x: x>=10', ''), ('lambda x,y: max(x,y)>12','')])); rf.rfilter([{x:20,y:0}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=2, |tcs|=1) ['lambda x: x>=10', 'lambda x,y: max(x,y)>12'] sage: rf = Refine(map(InvMPP,[('lambda x: x>=10',''), ('lambda x,y: max(x,y)>12','')])); rf.rfilter([]); sorted(rf.ps,key=str) refine:Debug:rfilter skips (|ps|=2, |tcs|=0) ['lambda x: x>=10', 'lambda x,y: max(x,y)>12'] """ if is_empty(self.ps) or is_empty(tcs): logger.debug('rfilter skips (|ps|={}, |tcs|={})' .format(len(self.ps), len(tcs))) return None logger.debug('rfilter(|ps|={}, |tcs|={})' .format(len(self.ps), len(tcs))) if not isinstance(self.ps[0],InvExp): from dig_miscs import Miscs tcs = Miscs.keys_to_str(tcs) old_len = len(self.ps) self.ps = [p for p in self.ps if all(p.seval(tc) for tc in tcs)] Refine.print_diff('rfilter', old_len, len(self.ps))
def rfilter_old(self, tcs): """ Returns the subset of ps that satisfies all testcases tcs Examples: sage: logger.set_level(VLog.DEBUG) sage: var('y z') (y, z) sage: rf = Refine(map(InvIeq,[x^2 >= 0 , x-y >= 7]));rf.rfilter([{x:1,y:0}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=2, |tcs|=1) refine:Debug:rfilter (before 2, after 1, diff 1) [x^2 >= 0] sage: rf = Refine(map(InvIeq,[2*x -y >= 0])); rf.rfilter([{y: 14, x: 7}, {y: 13, x: 7}, {y: 6, x: 4}, {y: 1, x: 1}, {y: 2, x: 1}, {y: 5, x: 100}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=1, |tcs|=6) [2*x - y >= 0] sage: rf = Refine(map(InvIeq,[2*x -y >= 0])); rf.rfilter([{y: 14, x: 7}, {y: 13, x: 7}, {y: 6, x: 4}, {y: 1, x: 1}, {y: 2, x: 1}, {y: 25, x: 9}, {y:25 , x*y: 15, x: 9}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=1, |tcs|=7) refine:Debug:rfilter (before 1, after 0, diff 1) [] ** This is by design sage: rf = Refine(map(InvIeq,[x^3 >= 0 , x-y >= 7])); rf.rfilter([{z:1}]) refine:Debug:rfilter(|ps|=2, |tcs|=1) refine:Debug:rfilter (before 2, after 0, diff 2) sage: assert(rf.ps == []) sage: rf = Refine(map(InvMPP,[('lambda x: x>=10',''), ('lambda x,y: max(x,y)>12',''), ('lambda x: x>=10','')])); rf.rfilter([{x:20,y:0},{x:9,y:13}]); sorted(rf.ps,key=str) refine:Debug:vset (before 3, after 2, diff 1) refine:Debug:rfilter(|ps|=2, |tcs|=2) refine:Debug:rfilter (before 2, after 1, diff 1) ['lambda x,y: max(x,y)>12'] sage: rf = Refine(map(InvMPP,[('lambda x: x>=10', ''), ('lambda x,y: max(x,y)>12','')])); rf.rfilter([{x:20,y:0}]); sorted(rf.ps,key=str) refine:Debug:rfilter(|ps|=2, |tcs|=1) ['lambda x: x>=10', 'lambda x,y: max(x,y)>12'] sage: rf = Refine(map(InvMPP,[('lambda x: x>=10',''), ('lambda x,y: max(x,y)>12','')])); rf.rfilter([]); sorted(rf.ps,key=str) refine:Debug:rfilter skips (|ps|=2, |tcs|=0) ['lambda x: x>=10', 'lambda x,y: max(x,y)>12'] """ if is_empty(self.ps) or is_empty(tcs): logger.debug('rfilter skips (|ps|={}, |tcs|={})' .format(len(self.ps), len(tcs))) return logger.debug('rfilter(|ps|={}, |tcs|={})' .format(len(self.ps), len(tcs))) if not isinstance(self.ps[0],InvExp): from dig_miscs import Miscs tcs = Miscs.keys_to_str(tcs) old_len = len(self.ps) self.ps = [p for p in self.ps if all(p.seval(tc) for tc in tcs)] Refine.print_diff('rfilter', old_len, len(self.ps))
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_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)
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)