def _eval_simplify(self, **kwargs): from .add import Add from sympy.core.expr import Expr r = self r = r.func(*[i.simplify(**kwargs) for i in r.args]) if r.is_Relational: if not isinstance(r.lhs, Expr) or not isinstance(r.rhs, Expr): return r dif = r.lhs - r.rhs # replace dif with a valid Number that will # allow a definitive comparison with 0 v = None if dif.is_comparable: v = dif.n(2) elif dif.equals(0): # XXX this is expensive v = S.Zero if v is not None: r = r.func._eval_relation(v, S.Zero) r = r.canonical # If there is only one symbol in the expression, # try to write it on a simplified form free = list( filter(lambda x: x.is_real is not False, r.free_symbols)) if len(free) == 1: try: from sympy.solvers.solveset import linear_coeffs x = free.pop() dif = r.lhs - r.rhs m, b = linear_coeffs(dif, x) if m.is_zero is False: if m.is_negative: # Dividing with a negative number, so change order of arguments # canonical will put the symbol back on the lhs later r = r.func(-b / m, x) else: r = r.func(x, -b / m) else: r = r.func(b, S.zero) except ValueError: # maybe not a linear function, try polynomial from sympy.polys import Poly, poly, PolynomialError, gcd try: p = poly(dif, x) c = p.all_coeffs() constant = c[-1] c[-1] = 0 scale = gcd(c) c = [ctmp / scale for ctmp in c] r = r.func( Poly.from_list(c, x).as_expr(), -constant / scale) except PolynomialError: pass elif len(free) >= 2: try: from sympy.solvers.solveset import linear_coeffs from sympy.polys import gcd free = list(ordered(free)) dif = r.lhs - r.rhs m = linear_coeffs(dif, *free) constant = m[-1] del m[-1] scale = gcd(m) m = [mtmp / scale for mtmp in m] nzm = list(filter(lambda f: f[0] != 0, list(zip(m, free)))) if scale.is_zero is False: if constant != 0: # lhs: expression, rhs: constant newexpr = Add(*[i * j for i, j in nzm]) r = r.func(newexpr, -constant / scale) else: # keep first term on lhs lhsterm = nzm[0][0] * nzm[0][1] del nzm[0] newexpr = Add(*[i * j for i, j in nzm]) r = r.func(lhsterm, -newexpr) else: r = r.func(constant, S.zero) except ValueError: pass # Did we get a simplified result? r = r.canonical measure = kwargs['measure'] if measure(r) < kwargs['ratio'] * measure(self): return r else: return self
def test_dispersion(): x = Symbol("x") a = Symbol("a") fp = poly(S.Zero, x) assert sorted(dispersionset(fp)) == [0] fp = poly(S(2), x) assert sorted(dispersionset(fp)) == [0] fp = poly(x + 1, x) assert sorted(dispersionset(fp)) == [0] assert dispersion(fp) == 0 fp = poly((x + 1) * (x + 2), x) assert sorted(dispersionset(fp)) == [0, 1] assert dispersion(fp) == 1 fp = poly(x * (x + 3), x) assert sorted(dispersionset(fp)) == [0, 3] assert dispersion(fp) == 3 fp = poly((x - 3) * (x + 3), x) assert sorted(dispersionset(fp)) == [0, 6] assert dispersion(fp) == 6 fp = poly(x**4 - 3 * x**2 + 1, x) gp = fp.shift(-3) assert sorted(dispersionset(fp, gp)) == [2, 3, 4] assert dispersion(fp, gp) == 4 assert sorted(dispersionset(gp, fp)) == [] assert dispersion(gp, fp) is -oo fp = poly(x * (3 * x**2 + a) * (x - 2536) * (x**3 + a), x) gp = fp.as_expr().subs(x, x - 345).as_poly(x) assert sorted(dispersionset(fp, gp)) == [345, 2881] assert sorted(dispersionset(gp, fp)) == [2191] gp = poly((x - 2)**2 * (x - 3)**3 * (x - 5)**3, x) assert sorted(dispersionset(gp)) == [0, 1, 2, 3] assert sorted(dispersionset(gp, (gp + 4)**2)) == [1, 2] fp = poly(x * (x + 2) * (x - 1), x) assert sorted(dispersionset(fp)) == [0, 1, 2, 3] fp = poly(x**2 + sqrt(5) * x - 1, x, domain="QQ<sqrt(5)>") gp = poly(x**2 + (2 + sqrt(5)) * x + sqrt(5), x, domain="QQ<sqrt(5)>") assert sorted(dispersionset(fp, gp)) == [2] assert sorted(dispersionset(gp, fp)) == [1, 4] # There are some difficulties if we compute over Z[a] # and alpha happenes to lie in Z[a] instead of simply Z. # Hence we can not decide if alpha is indeed integral # in general. fp = poly( 4 * x**4 + (4 * a + 8) * x**3 + (a**2 + 6 * a + 4) * x**2 + (a**2 + 2 * a) * x, x, ) assert sorted(dispersionset(fp)) == [0, 1] # For any specific value of a, the dispersion is 3*a # but the algorithm can not find this in general. # This is the point where the resultant based Ansatz # is superior to the current one. fp = poly(a**2 * x**3 + (a**3 + a**2 + a + 1) * x, x) gp = fp.as_expr().subs(x, x - 3 * a).as_poly(x) assert sorted(dispersionset(fp, gp)) == [] fpa = fp.as_expr().subs(a, 2).as_poly(x) gpa = gp.as_expr().subs(a, 2).as_poly(x) assert sorted(dispersionset(fpa, gpa)) == [6] # Work with Expr instead of Poly f = (x + 1) * (x + 2) assert sorted(dispersionset(f)) == [0, 1] assert dispersion(f) == 1 f = x**4 - 3 * x**2 + 1 g = x**4 - 12 * x**3 + 51 * x**2 - 90 * x + 55 assert sorted(dispersionset(f, g)) == [2, 3, 4] assert dispersion(f, g) == 4 # Work with Expr and specify a generator f = (x + 1) * (x + 2) assert sorted(dispersionset(f, None, x)) == [0, 1] assert dispersion(f, None, x) == 1 f = x**4 - 3 * x**2 + 1 g = x**4 - 12 * x**3 + 51 * x**2 - 90 * x + 55 assert sorted(dispersionset(f, g, x)) == [2, 3, 4] assert dispersion(f, g, x) == 4
def relsimp(func, args, **kwargs): lhs, rhs = args r = func(lhs.simplify(**kwargs), rhs.simplify(**kwargs)) if not isinstance(r.lhs, Expr) or not isinstance(r.rhs, Expr): return r.canonical dif = r.lhs - r.rhs r = r.canonical # If there is only one symbol in the expression, # try to write it on a simplified form free = list(filter(lambda x: x.is_real is not False, r.free_symbols)) if len(free) == 1: try: x = free.pop() dif = r.lhs - r.rhs m, b = linear_coeffs(dif, x) if m.is_zero is False: if m.is_negative: # Dividing with a negative number, so change order of arguments # canonical will put the symbol back on the lhs later r = r.function(-b / m, x) else: r = r.function(x, -b / m) else: r = r.function(b, S.Zero) except ValueError: # maybe not a linear function, try polynomial try: p = poly(dif, x) c = p.all_coeffs() constant = c[-1] c[-1] = 0 scale = gcd(c) c = [ctmp / scale for ctmp in c] r = r.function(Poly.from_list(c, x).as_expr(), -constant / scale) except PolynomialError: pass elif len(free) >= 2: try: free = list(ordered(free)) dif = r.lhs - r.rhs m = linear_coeffs(dif, *free) constant = m[-1] del m[-1] scale = gcd(m) m = [mtmp / scale for mtmp in m] nzm = list(filter(lambda f: f[0] != 0, list(zip(m, free)))) if scale.is_zero is False: if constant != 0: # lhs: expression, rhs: constant newexpr = Add(*[i * j for i, j in nzm]) r = r.function(newexpr, -constant / scale) else: # keep first term on lhs lhsterm = nzm[0][0] * nzm[0][1] del nzm[0] newexpr = Add(*[i * j for i, j in nzm]) r = r.function(lhsterm, -newexpr) else: r = r.function(constant, S.Zero) except ValueError: pass # Did we get a simplified result? r = r.canonical rel = func(*args) measure = kwargs['measure'] if measure(r) < kwargs['ratio'] * measure(rel): return r else: return rel
def test_dispersion(): x = Symbol("x") a = Symbol("a") fp = poly(S(0), x) assert sorted(dispersionset(fp)) == [0] fp = poly(S(2), x) assert sorted(dispersionset(fp)) == [0] fp = poly(x + 1, x) assert sorted(dispersionset(fp)) == [0] assert dispersion(fp) == 0 fp = poly((x + 1)*(x + 2), x) assert sorted(dispersionset(fp)) == [0, 1] assert dispersion(fp) == 1 fp = poly(x*(x + 3), x) assert sorted(dispersionset(fp)) == [0, 3] assert dispersion(fp) == 3 fp = poly((x - 3)*(x + 3), x) assert sorted(dispersionset(fp)) == [0, 6] assert dispersion(fp) == 6 fp = poly(x**4 - 3*x**2 + 1, x) gp = fp.shift(-3) assert sorted(dispersionset(fp, gp)) == [2, 3, 4] assert dispersion(fp, gp) == 4 assert sorted(dispersionset(gp, fp)) == [] assert dispersion(gp, fp) == -oo fp = poly(x*(3*x**2+a)*(x-2536)*(x**3+a), x) gp = fp.as_expr().subs(x, x-345).as_poly(x) assert sorted(dispersionset(fp, gp)) == [345, 2881] assert sorted(dispersionset(gp, fp)) == [2191] gp = poly((x-2)**2*(x-3)**3*(x-5)**3, x) assert sorted(dispersionset(gp)) == [0, 1, 2, 3] assert sorted(dispersionset(gp, (gp+4)**2)) == [1, 2] fp = poly(x*(x+2)*(x-1), x) assert sorted(dispersionset(fp)) == [0, 1, 2, 3] fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ<sqrt(5)>') gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ<sqrt(5)>') assert sorted(dispersionset(fp, gp)) == [2] assert sorted(dispersionset(gp, fp)) == [1, 4] # There are some difficulties if we compute over Z[a] # and alpha happenes to lie in Z[a] instead of simply Z. # Hence we can not decide if alpha is indeed integral # in general. fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) assert sorted(dispersionset(fp)) == [0, 1] # For any specific value of a, the dispersion is 3*a # but the algorithm can not find this in general. # This is the point where the resultant based Ansatz # is superior to the current one. fp = poly(a**2*x**3 + (a**3 + a**2 + a + 1)*x, x) gp = fp.as_expr().subs(x, x - 3*a).as_poly(x) assert sorted(dispersionset(fp, gp)) == [] fpa = fp.as_expr().subs(a, 2).as_poly(x) gpa = gp.as_expr().subs(a, 2).as_poly(x) assert sorted(dispersionset(fpa, gpa)) == [6] # Work with Expr instead of Poly f = (x + 1)*(x + 2) assert sorted(dispersionset(f)) == [0, 1] assert dispersion(f) == 1 f = x**4 - 3*x**2 + 1 g = x**4 - 12*x**3 + 51*x**2 - 90*x + 55 assert sorted(dispersionset(f, g)) == [2, 3, 4] assert dispersion(f, g) == 4 # Work with Expr and specify a generator f = (x + 1)*(x + 2) assert sorted(dispersionset(f, None, x)) == [0, 1] assert dispersion(f, None, x) == 1 f = x**4 - 3*x**2 + 1 g = x**4 - 12*x**3 + 51*x**2 - 90*x + 55 assert sorted(dispersionset(f, g, x)) == [2, 3, 4] assert dispersion(f, g, x) == 4