def deduce(assumes ,eqts): """ Examples sage: logger.set_level(VLog.DEBUG) sage: var('r a b q y x'); IeqDeduce.deduce([r>=2*b],[b==y*a,x==q*y+r]) (r, a, b, q, y, x) dig_polynomials:Debug:* deduce(|assumes|=1,|eqts|=2) dig_polynomials:Debug:assumed ps: r >= 2*b [r >= 2*a*y, -q*y + x >= 2*b] sage: var('s n a t'); IeqDeduce.deduce([s<=n],[t==2*a+1,s==a**2+2*a+1]) (s, n, a, t) dig_polynomials:Debug:* deduce(|assumes|=1,|eqts|=2) dig_polynomials:Debug:assumed ps: s <= n [a^2 + 2*a + 1 <= n] """ logger.debug('* deduce(|assumes|={},|eqts|={})' .format(len(assumes),len(eqts))) logger.debug('assumed ps: {}'.format(', '.join(map(str,assumes)))) combs = [(aps,ei) for aps in assumes for ei in eqts if any(x in get_vars(aps) for x in get_vars(ei))] sols= [IeqDeduce.substitute(e1,e2) for e1,e2 in combs] sols = flatten(sols,list) return sols
def deduce(assumes, eqts): """ Examples sage: logger.set_level(VLog.DEBUG) sage: var('r a b q y x'); IeqDeduce.deduce([r>=2*b],[b==y*a,x==q*y+r]) (r, a, b, q, y, x) dig_polynomials:Debug:* deduce(|assumes|=1,|eqts|=2) dig_polynomials:Debug:assumed ps: r >= 2*b [r >= 2*a*y, -q*y + x >= 2*b] sage: var('s n a t'); IeqDeduce.deduce([s<=n],[t==2*a+1,s==a**2+2*a+1]) (s, n, a, t) dig_polynomials:Debug:* deduce(|assumes|=1,|eqts|=2) dig_polynomials:Debug:assumed ps: s <= n [a^2 + 2*a + 1 <= n] """ logger.debug('* deduce(|assumes|={},|eqts|={})'.format( len(assumes), len(eqts))) logger.debug('assumed ps: {}'.format(', '.join(map(str, assumes)))) combs = [(aps, ei) for aps in assumes for ei in eqts if any(x in get_vars(aps) for x in get_vars(ei))] sols = [IeqDeduce.substitute(e1, e2) for e1, e2 in combs] sols = flatten(sols, list) return sols
def substitute(e1, e2): """ Examples: sage: var('x t q b y a') (x, t, q, b, y, a) sage: IeqDeduce.substitute(t-2*b>=0,x==q*y+t) [-q*y - 2*b + x >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b-y*a==0) [-2*a*y + t >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b-4==0) [t - 8 >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b+4==0) [t + 8 >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b^2+4==0) [t + 4*I >= 0, t - 4*I >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b^2-4==0) [t + 4 >= 0, t - 4 >= 0] #todo: cannot do when e2 is not equation sage: IeqDeduce.substitute(2*b>=0,b>=5) dig_polynomials:Warn:substitution fails on b >= 5 2*b >= 0 sage: IeqDeduce.substitute(2*b==0,b>=5) dig_polynomials:Warn:substitution fails on b >= 5 2*b == 0 """ e1_vs = get_vars(e1) e2_vs = get_vars(e2) rs = [ solve(e2, e2_v, solution_dict=True) for e2_v in e2_vs if e2_v in e1_vs ] rs = flatten(rs) try: rs = [e1.subs(rs_) for rs_ in rs] return rs except Exception: logger.warn('substitution fails on {}'.format(e2)) return e1
def substitute(e1,e2): """ Examples: sage: var('x t q b y a') (x, t, q, b, y, a) sage: IeqDeduce.substitute(t-2*b>=0,x==q*y+t) [-q*y - 2*b + x >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b-y*a==0) [-2*a*y + t >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b-4==0) [t - 8 >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b+4==0) [t + 8 >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b^2+4==0) [t + 4*I >= 0, t - 4*I >= 0] sage: IeqDeduce.substitute(t-2*b>=0,b^2-4==0) [t + 4 >= 0, t - 4 >= 0] #todo: cannot do when e2 is not equation sage: IeqDeduce.substitute(2*b>=0,b>=5) dig_polynomials:Warn:substitution fails on b >= 5 2*b >= 0 sage: IeqDeduce.substitute(2*b==0,b>=5) dig_polynomials:Warn:substitution fails on b >= 5 2*b == 0 """ e1_vs = get_vars(e1) e2_vs = get_vars(e2) rs = [solve(e2,e2_v,solution_dict=True) for e2_v in e2_vs if e2_v in e1_vs] rs = flatten(rs) try: rs = [e1.subs(rs_) for rs_ in rs] return rs except Exception: logger.warn('substitution fails on {}'.format(e2)) return e1
def get_score(self): """ Gives higher scores to invs with 'nicer' shapes Examples: sage: var('r a q y') (r, a, q, y) sage: assert InvIeq((1/2)*x**2 + 134.134234*y + 1 >= 0).get_score() == 12 sage: assert InvEqt(x**3 + 2.432*x + 8 == 0).get_score() == 6 sage: assert InvIeq(x**2+x+7 >= 0).get_score() == 3 In case we cannot compute the score, returns the strlen of the inv sage: InvIeq(r + 2*a/q >= 0).get_score() 14 """ try: Q = PolynomialRing(QQ, get_vars(self.p)) p_lhs_poly = Q(self.p.lhs()) rs = p_lhs_poly.coefficients() rs = [abs(r_.n()).str(skip_zeroes=True) for r_ in rs if r_ != 0.0] rs = [sum(map(len,r_.split('.'))) for r_ in rs] rs = sum(rs) return rs except Exception: return len(self.p_str)
def getCoefs(p): """ Return coefficients of an expression """ Q = sage.all.PolynomialRing(sage.all.QQ, sageutil.get_vars(p)) rs = Q(p.lhs()).coefficients() return rs
def get_score(self): """ Gives higher scores to invs with 'nicer' shapes Examples: sage: var('r a q y') (r, a, q, y) sage: assert InvIeq((1/2)*x**2 + 134.134234*y + 1 >= 0).get_score() == 12 sage: assert InvEqt(x**3 + 2.432*x + 8 == 0).get_score() == 6 sage: assert InvIeq(x**2+x+7 >= 0).get_score() == 3 In case we cannot compute the score, returns the strlen of the inv sage: InvIeq(r + 2*a/q >= 0).get_score() 14 """ try: Q = PolynomialRing(QQ, get_vars(self.p)) p_lhs_poly = Q(self.p.lhs()) rs = p_lhs_poly.coefficients() rs = [abs(r_.n()).str(skip_zeroes=True) for r_ in rs if r_ != 0.0] rs = [sum(map(len, r_.split('.'))) for r_ in rs] rs = sum(rs) return rs except Exception: return len(self.p_str)
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 sreduce(ps): """ Return the basis (e.g., a min subset of ps that implies ps) of the set of eqts input ps using Groebner basis Examples: sage: var('a y b q k') (a, y, b, q, k) sage: rs = InvEqt.sreduce([a*y-b==0,q*y+k-x==0,a*x-a*k-b*q==0]) sage: assert set(rs) == set([a*y - b == 0, q*y + k - x == 0]) sage: rs = InvEqt.sreduce([x*y==6,y==2,x==3]) sage: assert set(rs) == set([x - 3 == 0, y - 2 == 0]) #Attribute error occurs when only 1 var, thus return as is sage: rs = InvEqt.sreduce([x*x==4,x==2]) sage: assert set(rs) == set([x == 2, x^2 == 4]) """ if __debug__: assert all(p.operator() == operator.eq for p in ps), ps try: Q = PolynomialRing(QQ, get_vars(ps)) I = Q * ps #ps_ = I.radical().groebner_basis() ps = I.radical().interreduced_basis() ps = [(SR(p) == 0) for p in ps] except AttributeError: pass return ps
def reducePoly(ps): """ Return the basis (e.g., a min subset of ps that implies ps) of the set of eqts input ps using Groebner basis sage: var('a y b q k') (a, y, b, q, k) sage: rs = reducePoly([a*y-b==0,q*y+k-x==0,a*x-a*k-b*q==0]) sage: assert set(rs) == set([a*y - b == 0, q*y + k - x == 0]) sage: rs = reducePoly([x*y==6,y==2,x==3]) sage: assert set(rs) == set([x - 3 == 0, y - 2 == 0]) #Attribute error occurs when only 1 var, thus return as is sage: rs = reducePoly([x*x==4,x==2]) sage: assert set(rs) == set([x == 2, x^2 == 4]) """ assert ps, ps assert (p.operator() == sage.all.operator.eq for p in ps), ps try: Q = sage.all.PolynomialRing(sage.all.QQ, sageutil.get_vars(ps)) I = Q * ps ps = I.radical().interreduced_basis() ps = [(sage.all.SR(p) == 0) for p in ps] except AttributeError: pass return ps
def sreduce(ps): """ Return the basis (e.g., a min subset of ps that implies ps) of the set of eqts input ps using Groebner basis Examples: sage: var('a y b q k') (a, y, b, q, k) sage: rs = InvEqt.sreduce([a*y-b==0,q*y+k-x==0,a*x-a*k-b*q==0]) sage: assert set(rs) == set([a*y - b == 0, q*y + k - x == 0]) sage: rs = InvEqt.sreduce([x*y==6,y==2,x==3]) sage: assert set(rs) == set([x - 3 == 0, y - 2 == 0]) #Attribute error occurs when only 1 var, thus return as is sage: rs = InvEqt.sreduce([x*x==4,x==2]) sage: assert set(rs) == set([x == 2, x^2 == 4]) """ if __debug__: assert all(p.operator() == operator.eq for p in ps), ps try: Q = PolynomialRing(QQ,get_vars(ps)) I = Q*ps #ps_ = I.radical().groebner_basis() ps = I.radical().interreduced_basis() ps = [(SR(p)==0) for p in ps] except AttributeError: pass return 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 to_z3(p): typ = "{} = z3.Ints('{}')" vs = map(str, get_vars(p)) z3_vars_decl = typ.format(','.join(vs),' '.join(vs)) exec(z3_vars_decl) f = eval(str(p)) print f print z3.is_expr(f)
def to_z3(p): print("WARN: deprecated, don't use eval()") typ = "{} = z3.Ints('{}')" vs = map(str, get_vars(p)) z3_vars_decl = typ.format(','.join(vs),' '.join(vs)) exec(z3_vars_decl) f = eval(str(p)) print z3.is_expr(f)
def f_eq(d): if isinstance(d, list): f_ = template for d_ in d: f_ = f_.subs(d_) rhsVals = CM.vset([d_.rhs() for d_ in d]) uk_vars = sageutil.get_vars(rhsVals) else: f_ = template(d) uk_vars = sageutil.get_vars(d.values()) #e.g., r15,r16 ... if not uk_vars: return f_ iM = sage.all.identity_matrix(len(uk_vars)) #standard basis rs = [dict(zip(uk_vars, l)) for l in iM.rows()] rs = [f_(r) for r in rs] return rs
def getCoefsLen(p): try: Q = sage.all.PolynomialRing(sage.all.QQ, sageutil.get_vars(ps)) rs = Q(p.lhs()).coefficients() rs = (abs(r_.n()).str(skip_zeroes=True) for r_ in rs if r_ != 0.0) rs = (sum(map(len, r_.split('.'))) for r_ in rs) rs = sum(rs) return rs except Exception: return len(str(p))
def analyze_sol(cls, sol): assert isinstance(sol, dict) and sol rs = sageutil.get_vars(sol.values()) #r1,r2,r3 .. imatrix = [[1 if j == i else 0 for j in range(len(rs))] for i in range(len(rs))] rs = [dict(zip(rs, l)) for l in imatrix] #rs: [{r2: 0, r3: 0, r1: 1}, {r2: 1, r3: 0, r1: 0}, {r2: 0, r3: 1, r1: 0}] #d: {uk_2: r3, uk_3: r2, uk_4: r1, uk_0: -7*r1 - 7*r3, uk_1: -2*r1 - r2 - 2*r3} rs = [[(uk, rs.subs(rd)) for uk, rs in sol.iteritems()] for rd in rs] return rs
def group_arr_eqts(ps, ainfo): """ Group the resulting list of eqts among array elements. Also remove eqts that involve elements from same arrays 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.group_arr_eqts([x_0 + x_1 == 0, x_1 + y_1 == 0, \ x_0 + y_1 + y_0==0, x_0 + x_1-2==0 , \ y_0 == 1, x_1 == 2, x_0 == 3], ainfo) dig_arrays:Warn:Removed arr eqt: x_0 + x_1 == 0 dig_arrays:Warn:Removed arr eqt: x_0 + y_0 + y_1 == 0 dig_arrays:Warn:Removed arr eqt: x_0 + x_1 - 2 == 0 OrderedDict([(('x', 'y'), [x_1 + y_1 == 0]), (('y',), [y_0 == 1]), (('x',), [x_1 == 2, x_0 == 3])]) sage: FlatArray.group_arr_eqts([x_0 == 0, x_1==1], ainfo) OrderedDict([(('x',), [x_0 == 0, x_1 == 1])]) sage: FlatArray.group_arr_eqts([x_0 + x_1 == 0, x_0 + x_1-2==0], ainfo) dig_arrays:Warn:Removed arr eqt: x_0 + x_1 == 0 dig_arrays:Warn:Removed arr eqt: x_0 + x_1 - 2 == 0 OrderedDict() """ gs = OrderedDict() get_anames = lambda p: tuple([ainfo[v]['name'] for v in get_vars(p)]) for p in ps: anames = get_anames(p) if not vall_uniq(anames): #e.g. A_1 + A_2 = 0 logger.warn('Removed arr eqt: {}'.format(p)) continue anames if anames in gs: gs[anames].append(p) else: gs[anames]=[p] return gs
def instantiate(self, term, nTraces): assert is_sage_expr(term), term assert nTraces is None or nTraces >= 1, nTraces if nTraces is None: exprs = set(term.subs(t) for t in self.mydicts) else: nTracesExtra = nTraces * 5 exprs = set() for i, t in enumerate(self.mydicts): expr = term.subs(t) if expr not in exprs: exprs.add(expr) if len(exprs) >= nTracesExtra: break #instead of doing this, can find out the # 0's in traces #the more 0's , the better exprs = sorted(exprs, key=lambda expr: len(get_vars(expr))) exprs = set(exprs[:nTraces]) return exprs
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 sreduce(ps): """ Return a minimum subset of ps that implies ps Use a greedy method to remove redundant properties. Thus it's quick, but not exact. Examples: sage: var('a y b q k s t z') (a, y, b, q, k, s, t, z) sage: InvIeq.sreduce([a*y-b==0,q*y+k-x==0,a*x-a*k-b*q==0]) [q*y + k - x == 0, a*y - b == 0] sage: InvIeq.sreduce([a*y-b==0,a*z-a*x+b*q==0,q*y+z-x==0]) [q*y - x + z == 0, a*y - b == 0] sage: InvIeq.sreduce([x-7>=0, x + y -2>=0, y+5 >= 0]) [x - 7 >= 0, y + 5 >= 0] sage: InvIeq.sreduce([x+y==0,x-y==1]) [x + y == 0, x - y == 1] sage: InvIeq.sreduce([x^2-1>=0,x-1>=0]) [x - 1 >= 0] sage: InvIeq.sreduce([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]) [t^2 - 4*s + 2*t + 1 == 0, a - 1/2*t + 1/2 == 0] sage: InvIeq.sreduce([x*x-y*y==0,x-y==0,x*x-y*y==0,2*x*y-2*y*y==0]) [x - y == 0] sage: InvIeq.sreduce([x-1>=0 , t*y - 6 >= 0, t - 1 >= 0, y - 6 >= 0, t*y - y >= 0, t*x - x >= 0, y*x - 6*x>=0 , y^2 - 36 >= 0, t^2 - 3*t + 2 >= 0, t^2 - 5*t + 6 >= 0 , t*y - 6*t - y + 6 >= 0]) [x - 1 >= 0, t - 1 >= 0, y - 6 >= 0, t^2 - 3*t + 2 >= 0, t^2 - 5*t + 6 >= 0] sage: InvIeq.sreduce([x*y==6, y-2==0, x-3==0]) [y - 2 == 0, x - 3 == 0] sage: InvIeq.sreduce([x*x==4,x==2]) [x == 2] sage: InvIeq.sreduce([x==2,x*x==4]) [x == 2] sage: InvIeq.sreduce([x==2,x*x==4,x==-2]) [x == 2, x == -2] sage: InvIeq.sreduce([x==2,x==-2,x*x==4]) [x == 2, x == -2] sage: InvIeq.sreduce([x*x==4,x==2,x==-2]) [x == 2, x == -2] """ from smt_z3py import SMT_Z3 #Remove "longer" property first (i.e. those with more variables) ps = sorted(ps, reverse=True, key=lambda p: len(get_vars(p))) rs = list(ps) #make a copy for p in ps: if p in rs: #note, the use of set makes things in non order xclude_p = vsetdiff(rs, [p]) if SMT_Z3.imply(xclude_p, p): rs = xclude_p return rs
def sreduce(ps): """ Return a minimum subset of ps that implies ps Use a greedy method to remove redundant properties. Thus it's quick, but not exact. Examples: sage: var('a y b q k s t z') (a, y, b, q, k, s, t, z) sage: InvIeq.sreduce([a*y-b==0,q*y+k-x==0,a*x-a*k-b*q==0]) [q*y + k - x == 0, a*y - b == 0] sage: InvIeq.sreduce([a*y-b==0,a*z-a*x+b*q==0,q*y+z-x==0]) [q*y - x + z == 0, a*y - b == 0] sage: InvIeq.sreduce([x-7>=0, x + y -2>=0, y+5 >= 0]) [x - 7 >= 0, y + 5 >= 0] sage: InvIeq.sreduce([x+y==0,x-y==1]) [x + y == 0, x - y == 1] sage: InvIeq.sreduce([x^2-1>=0,x-1>=0]) [x - 1 >= 0] sage: InvIeq.sreduce([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]) [t^2 - 4*s + 2*t + 1 == 0, a - 1/2*t + 1/2 == 0] sage: InvIeq.sreduce([x*x-y*y==0,x-y==0,x*x-y*y==0,2*x*y-2*y*y==0]) [x - y == 0] sage: InvIeq.sreduce([x-1>=0 , t*y - 6 >= 0, t - 1 >= 0, y - 6 >= 0, t*y - y >= 0, t*x - x >= 0, y*x - 6*x>=0 , y^2 - 36 >= 0, t^2 - 3*t + 2 >= 0, t^2 - 5*t + 6 >= 0 , t*y - 6*t - y + 6 >= 0]) [x - 1 >= 0, t - 1 >= 0, y - 6 >= 0, t^2 - 3*t + 2 >= 0, t^2 - 5*t + 6 >= 0] sage: InvIeq.sreduce([x*y==6, y-2==0, x-3==0]) [y - 2 == 0, x - 3 == 0] sage: InvIeq.sreduce([x*x==4,x==2]) [x == 2] sage: InvIeq.sreduce([x==2,x*x==4]) [x == 2] sage: InvIeq.sreduce([x==2,x*x==4,x==-2]) [x == 2, x == -2] sage: InvIeq.sreduce([x==2,x==-2,x*x==4]) [x == 2, x == -2] sage: InvIeq.sreduce([x*x==4,x==2,x==-2]) [x == 2, x == -2] """ from smt_z3py import SMT_Z3 #Remove "longer" property first (i.e. those with more variables) ps = sorted(ps, reverse=True, key=lambda p: len(get_vars(p))) rs = list(ps) #make a copy for p in ps: if p in rs: #note, the use of set makes things in non order xclude_p = vsetdiff(rs,[p]) if SMT_Z3.imply(xclude_p,p): rs = xclude_p return rs