def test_Max(): from sympy.abc import x, y, z n = Symbol('n', negative=True) n_ = Symbol('n_', negative=True) nn = Symbol('nn', nonnegative=True) nn_ = Symbol('nn_', nonnegative=True) p = Symbol('p', positive=True) p_ = Symbol('p_', positive=True) np = Symbol('np', nonpositive=True) np_ = Symbol('np_', nonpositive=True) r = Symbol('r', real=True) assert Max(5, 4) == 5 # lists raises(ValueError, lambda: Max()) assert Max(x, y) == Max(y, x) assert Max(x, y, z) == Max(z, y, x) assert Max(x, Max(y, z)) == Max(z, y, x) assert Max(x, Min(y, oo)) == Max(x, y) assert Max(n, -oo, n_, p, 2) == Max(p, 2) assert Max(n, -oo, n_, p) == p assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p) assert Max(0, x, 1, y) == Max(1, x, y) assert Max(r, r + 1, r - 1) == 1 + r assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000) assert Max(cos(x), sin(x)) == Max(sin(x), cos(x)) assert Max(cos(x), sin(x)).subs(x, 1) == sin(1) assert Max(cos(x), sin(x)).subs(x, S(1)/2) == cos(S(1)/2) raises(ValueError, lambda: Max(cos(x), sin(x)).subs(x, I)) raises(ValueError, lambda: Max(I)) raises(ValueError, lambda: Max(I, x)) raises(ValueError, lambda: Max(S.ComplexInfinity, 1)) # interesting: # Max(n, -oo, n_, p, 2) == Max(p, 2) # True # Max(n, -oo, n_, p, 1000) == Max(p, 1000) # False assert Max(1, x).diff(x) == Heaviside(x - 1) assert Max(x, 1).diff(x) == Heaviside(x - 1) assert Max(x**2, 1 + x, 1).diff(x) == \ 2*x*Heaviside(x**2 - Max(1, x + 1)) \ + Heaviside(x - Max(1, x**2) + 1) a, b = Symbol('a', real=True), Symbol('b', real=True) # a and b are both real, Max(a, b) should be real assert Max(a, b).is_real # issue 7233 e = Max(0, x) assert e.evalf == e.n assert e.n().args == (0, x)
def __rdiv__(self, other): if isinstance(other, Expr): if other.is_real: if other.is_zero: return S.Zero if S.Zero in self: if self.min == S.Zero: if other.is_positive: return AccumBounds(Mul(other, 1 / self.max), oo) if other.is_negative: return AccumBounds(-oo, Mul(other, 1 / self.max)) if self.max == S.Zero: if other.is_positive: return AccumBounds(-oo, Mul(other, 1 / self.min)) if other.is_negative: return AccumBounds(Mul(other, 1 / self.min), oo) return AccumBounds(-oo, oo) else: return AccumBounds(Min(other / self.min, other / self.max), Max(other / self.min, other / self.max)) return Mul(other, 1 / self, evaluate=False) else: return NotImplemented
def __mul__(self, other): if isinstance(other, Expr): if isinstance(other, AccumBounds): return AccumBounds( Min(Mul(self.min, other.min), Mul(self.min, other.max), Mul(self.max, other.min), Mul(self.max, other.max)), Max(Mul(self.min, other.min), Mul(self.min, other.max), Mul(self.max, other.min), Mul(self.max, other.max))) if other is S.Infinity: if self.min.is_zero: return AccumBounds(0, oo) if self.max.is_zero: return AccumBounds(-oo, 0) if other is S.NegativeInfinity: if self.min.is_zero: return AccumBounds(-oo, 0) if self.max.is_zero: return AccumBounds(0, oo) if other.is_real: if other.is_zero: if self == AccumBounds(-oo, oo): return AccumBounds(-oo, oo) if self.max is S.Infinity: return AccumBounds(0, oo) if self.min is S.NegativeInfinity: return AccumBounds(-oo, 0) return S.Zero if other.is_positive: return AccumBounds(Mul(self.min, other), Mul(self.max, other)) elif other.is_negative: return AccumBounds(Mul(self.max, other), Mul(self.min, other)) if isinstance(other, Order): return other return Mul(self, other, evaluate=False) return NotImplemented
def major(self): """Longer axis of the ellipse (if it can be determined) else hradius. Returns ======= major : number or expression See Also ======== hradius, vradius, minor Examples ======== >>> from sympy import Point, Ellipse, Symbol >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.major 3 >>> a = Symbol('a') >>> b = Symbol('b') >>> Ellipse(p1, a, b).major a >>> Ellipse(p1, b, a).major b >>> m = Symbol('m') >>> M = m + 1 >>> Ellipse(p1, m, M).major m + 1 """ rv = Max(*self[1:3]) if rv.func is Max: return self.hradius return rv
def __rtruediv__(self, other): if isinstance(other, Expr): if other.is_extended_real: if other.is_zero: return S.Zero if (self.min.is_extended_nonpositive and self.max.is_extended_nonnegative): if self.min.is_zero: if other.is_extended_positive: return AccumBounds(Mul(other, 1 / self.max), oo) if other.is_extended_negative: return AccumBounds(-oo, Mul(other, 1 / self.max)) if self.max.is_zero: if other.is_extended_positive: return AccumBounds(-oo, Mul(other, 1 / self.min)) if other.is_extended_negative: return AccumBounds(Mul(other, 1 / self.min), oo) return AccumBounds(-oo, oo) else: return AccumBounds(Min(other / self.min, other / self.max), Max(other / self.min, other / self.max)) return Mul(other, 1 / self, evaluate=False) else: return NotImplemented
def compute_a_n(prob_fun, alpha=0): P = prob_fun t = Symbol('t0', positive=True) a_n = Symbol('a_n', positive=True) a_n_integral = Integral( ((1 + alpha) - (1 - alpha) * P(t)) * f_star(P, t, []), (t, a_n, 1)) a_n_integrated = a_n_integral.doit() P_a_n_solutions = solve(a_n_integrated - 2 * (1 - alpha), P(a_n)) P_a_n = Max(*P_a_n_solutions) print("P(a_n) = %s" % P_a_n) a_n_solutions = solve(P(a_n) - P_a_n, a_n) a_n_solutions_in_range = [soln for soln in a_n_solutions if 0 < soln <= 1] assert len(a_n_solutions_in_range) == 1 a_n = a_n_solutions_in_range[0] print("a_n = %s" % a_n) h_n_integral = Integral(f_star(P, t, []), (t, a_n, 1)) h_n_integrated = h_n_integral.doit() h_n = (1 - alpha) / h_n_integrated print("h_n = %s" % h_n) return (a_n, h_n)
def test_Min(): from sympy.abc import x, y, z n = Symbol('n', negative=True) n_ = Symbol('n_', negative=True) nn = Symbol('nn', nonnegative=True) nn_ = Symbol('nn_', nonnegative=True) p = Symbol('p', positive=True) p_ = Symbol('p_', positive=True) np = Symbol('np', nonpositive=True) np_ = Symbol('np_', nonpositive=True) r = Symbol('r', real=True) assert Min(5, 4) == 4 assert Min(-oo, -oo) == -oo assert Min(-oo, n) == -oo assert Min(n, -oo) == -oo assert Min(-oo, np) == -oo assert Min(np, -oo) == -oo assert Min(-oo, 0) == -oo assert Min(0, -oo) == -oo assert Min(-oo, nn) == -oo assert Min(nn, -oo) == -oo assert Min(-oo, p) == -oo assert Min(p, -oo) == -oo assert Min(-oo, oo) == -oo assert Min(oo, -oo) == -oo assert Min(n, n) == n assert Min(n, np) == Min(n, np) assert Min(np, n) == Min(np, n) assert Min(n, 0) == n assert Min(0, n) == n assert Min(n, nn) == n assert Min(nn, n) == n assert Min(n, p) == n assert Min(p, n) == n assert Min(n, oo) == n assert Min(oo, n) == n assert Min(np, np) == np assert Min(np, 0) == np assert Min(0, np) == np assert Min(np, nn) == np assert Min(nn, np) == np assert Min(np, p) == np assert Min(p, np) == np assert Min(np, oo) == np assert Min(oo, np) == np assert Min(0, 0) == 0 assert Min(0, nn) == 0 assert Min(nn, 0) == 0 assert Min(0, p) == 0 assert Min(p, 0) == 0 assert Min(0, oo) == 0 assert Min(oo, 0) == 0 assert Min(nn, nn) == nn assert Min(nn, p) == Min(nn, p) assert Min(p, nn) == Min(p, nn) assert Min(nn, oo) == nn assert Min(oo, nn) == nn assert Min(p, p) == p assert Min(p, oo) == p assert Min(oo, p) == p assert Min(oo, oo) == oo assert Min(n, n_).func is Min assert Min(nn, nn_).func is Min assert Min(np, np_).func is Min assert Min(p, p_).func is Min # lists raises(ValueError, lambda: Min()) assert Min(x, y) == Min(y, x) assert Min(x, y, z) == Min(z, y, x) assert Min(x, Min(y, z)) == Min(z, y, x) assert Min(x, Max(y, -oo)) == Min(x, y) assert Min(p, oo, n, p, p, p_) == n assert Min(p_, n_, p) == n_ assert Min(n, oo, -7, p, p, 2) == Min(n, -7) assert Min(2, x, p, n, oo, n_, p, 2, -2, -2) == Min(-2, x, n, n_) assert Min(0, x, 1, y) == Min(0, x, y) assert Min(1000, 100, -100, x, p, n) == Min(n, x, -100) assert Min(cos(x), sin(x)) == Min(cos(x), sin(x)) assert Min(cos(x), sin(x)).subs(x, 1) == cos(1) assert Min(cos(x), sin(x)).subs(x, S(1) / 2) == sin(S(1) / 2) raises(ValueError, lambda: Min(cos(x), sin(x)).subs(x, I)) raises(ValueError, lambda: Min(I)) raises(ValueError, lambda: Min(I, x)) raises(ValueError, lambda: Min(S.ComplexInfinity, x)) assert Min(1, x).diff(x) == Heaviside(1 - x) assert Min(x, 1).diff(x) == Heaviside(1 - x) assert Min(0, -x, 1 - 2*x).diff(x) == -Heaviside(x + Min(0, -2*x + 1)) \ - 2*Heaviside(2*x + Min(0, -x) - 1) # issue 7619 f = Function('f') assert Min(1, 2 * Min(f(1), 2)) # doesn't fail # issue 7233 e = Min(0, x) assert e.evalf == e.n assert e.n().args == (0, x) # issue 8643 m = Min(n, p_, n_, r) assert m.is_positive is False assert m.is_nonnegative is False assert m.is_negative is True m = Min(p, p_) assert m.is_positive is True assert m.is_nonnegative is True assert m.is_negative is False m = Min(p, nn_, p_) assert m.is_positive is None assert m.is_nonnegative is True assert m.is_negative is False m = Min(nn, p, r) assert m.is_positive is None assert m.is_nonnegative is None assert m.is_negative is None
def test_sympy__functions__elementary__miscellaneous__Max(): from sympy.functions.elementary.miscellaneous import Max assert _test_args(Max(x, 2))
def test_Max(): from sympy.abc import x, y, z n = Symbol('n', negative=True) n_ = Symbol('n_', negative=True) nn = Symbol('nn', nonnegative=True) nn_ = Symbol('nn_', nonnegative=True) p = Symbol('p', positive=True) p_ = Symbol('p_', positive=True) np = Symbol('np', nonpositive=True) np_ = Symbol('np_', nonpositive=True) r = Symbol('r', real=True) assert Max(5, 4) == 5 # lists raises(ValueError, lambda: Max()) assert Max(x, y) == Max(y, x) assert Max(x, y, z) == Max(z, y, x) assert Max(x, Max(y, z)) == Max(z, y, x) assert Max(x, Min(y, oo)) == Max(x, y) assert Max(n, -oo, n_, p, 2) == Max(p, 2) assert Max(n, -oo, n_, p) == p assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p) assert Max(0, x, 1, y) == Max(1, x, y) assert Max(r, r + 1, r - 1) == 1 + r assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000) assert Max(cos(x), sin(x)) == Max(sin(x), cos(x)) assert Max(cos(x), sin(x)).subs(x, 1) == sin(1) assert Max(cos(x), sin(x)).subs(x, S(1) / 2) == cos(S(1) / 2) raises(ValueError, lambda: Max(cos(x), sin(x)).subs(x, I)) raises(ValueError, lambda: Max(I)) raises(ValueError, lambda: Max(I, x)) raises(ValueError, lambda: Max(S.ComplexInfinity, 1)) assert Max(n, -oo, n_, p, 2) == Max(p, 2) assert Max(n, -oo, n_, p, 1000) == Max(p, 1000) assert Max(1, x).diff(x) == Heaviside(x - 1) assert Max(x, 1).diff(x) == Heaviside(x - 1) assert Max(x**2, 1 + x, 1).diff(x) == \ 2*x*Heaviside(x**2 - Max(1, x + 1)) \ + Heaviside(x - Max(1, x**2) + 1) e = Max(0, x) assert e.evalf == e.n assert e.n().args == (0, x) # issue 8643 m = Max(p, p_, n, r) assert m.is_positive is True assert m.is_nonnegative is True assert m.is_negative is False m = Max(n, n_) assert m.is_positive is False assert m.is_nonnegative is False assert m.is_negative is True m = Max(n, n_, r) assert m.is_positive is None assert m.is_nonnegative is None assert m.is_negative is None m = Max(n, nn, r) assert m.is_positive is None assert m.is_nonnegative is True assert m.is_negative is False
def _sort_expr_cond(self, sym, a, b, targetcond=None): """Determine what intervals the expr, cond pairs affect. 1) If cond is True, then log it as default 1.1) Currently if cond can't be evaluated, throw NotImplementedError. 2) For each inequality, if previous cond defines part of the interval update the new conds interval. - eg x < 1, x < 3 -> [oo,1],[1,3] instead of [oo,1],[oo,3] 3) Sort the intervals to make it easier to find correct exprs Under normal use, we return the expr,cond pairs in increasing order along the real axis corresponding to the symbol sym. If targetcond is given, we return a list of (lowerbound, upperbound) pairs for this condition.""" default = None int_expr = [] expr_cond = [] or_cond = False or_intervals = [] for expr, cond in self.args: if isinstance(cond, Or): for cond2 in sorted(cond.args, key=default_sort_key): expr_cond.append((expr, cond2)) else: expr_cond.append((expr, cond)) if cond is True: break for expr, cond in expr_cond: if cond is True: default = expr break elif isinstance(cond, Equality): continue elif isinstance(cond, And): lower = S.NegativeInfinity upper = S.Infinity for cond2 in cond.args: if cond2.lts.has(sym): upper = Min(cond2.gts, upper) elif cond2.gts.has(sym): lower = Max(cond2.lts, lower) else: lower, upper = cond.lts, cond.gts # part 1: initialize with givens if cond.lts.has(sym): # part 1a: expand the side ... lower = S.NegativeInfinity # e.g. x <= 0 ---> -oo <= 0 elif cond.gts.has(sym): # part 1a: ... that can be expanded upper = S.Infinity # e.g. x >= 0 ---> oo >= 0 else: raise NotImplementedError( "Unable to handle interval evaluation of expression.") # part 1b: Reduce (-)infinity to what was passed in. lower, upper = Max(a, lower), Min(b, upper) for n in xrange(len(int_expr)): # Part 2: remove any interval overlap. For any conflicts, the # iterval already there wins, and the incoming interval updates # its bounds accordingly. if self.__eval_cond(lower < int_expr[n][1]) and \ self.__eval_cond(lower >= int_expr[n][0]): lower = int_expr[n][1] elif len(int_expr[n][1].free_symbols) and \ self.__eval_cond(lower >= int_expr[n][0]): if self.__eval_cond(lower == int_expr[n][0]): lower = int_expr[n][1] else: int_expr[n][1] = Min(lower, int_expr[n][1]) elif len(int_expr[n][1].free_symbols) and \ lower < int_expr[n][0] is not True: upper = Min(upper, int_expr[n][0]) elif self.__eval_cond(upper > int_expr[n][0]) and \ self.__eval_cond(upper <= int_expr[n][1]): upper = int_expr[n][0] elif len(int_expr[n][0].free_symbols) and \ self.__eval_cond(upper < int_expr[n][1]): int_expr[n][0] = Max(upper, int_expr[n][0]) if self.__eval_cond( lower >= upper) is not True: # Is it still an interval? int_expr.append([lower, upper, expr]) if cond is targetcond: return [(lower, upper)] elif isinstance(targetcond, Or) and cond in targetcond.args: or_cond = Or(or_cond, cond) or_intervals.append((lower, upper)) if or_cond == targetcond: or_intervals.sort(key=lambda x: x[0]) return or_intervals int_expr.sort(key=lambda x: x[1].sort_key() if x[1].is_number else S.NegativeInfinity.sort_key()) int_expr.sort(key=lambda x: x[0].sort_key() if x[0].is_number else S.Infinity.sort_key()) from sympy.functions.elementary.miscellaneous import MinMaxBase for n in xrange(len(int_expr)): if len(int_expr[n][0].free_symbols) or len( int_expr[n][1].free_symbols): if isinstance(int_expr[n][1], Min) or int_expr[n][1] == b: newval = Min(*int_expr[n][:-1]) if n > 0 and int_expr[n][0] == int_expr[n - 1][1]: int_expr[n - 1][1] = newval int_expr[n][0] = newval else: newval = Max(*int_expr[n][:-1]) if n < len(int_expr) - 1 and int_expr[n][1] == int_expr[ n + 1][0]: int_expr[n + 1][0] = newval int_expr[n][1] = newval # Add holes to list of intervals if there is a default value, # otherwise raise a ValueError. holes = [] curr_low = a for int_a, int_b, expr in int_expr: if (curr_low < int_a) is True: holes.append([curr_low, Min(b, int_a), default]) elif (curr_low >= int_a) is not True: holes.append([curr_low, Min(b, int_a), default]) curr_low = Min(b, int_b) if (curr_low < b) is True: holes.append([Min(b, curr_low), b, default]) elif (curr_low >= b) is not True: holes.append([Min(b, curr_low), b, default]) if holes and default is not None: int_expr.extend(holes) if targetcond is True: return [(h[0], h[1]) for h in holes] elif holes and default is None: raise ValueError("Called interval evaluation over piecewise " "function on undefined intervals %s" % ", ".join([str((h[0], h[1])) for h in holes])) return int_expr
def sym_transform(self): return list(map(lambda x: log(Max(RealNumber(self.guard) + RealNumber(self.offset), x + RealNumber(self.offset))), self.syms()))
def _sup(self): # We use Max so that sup is meaningful in combination with symbolic # end points. from sympy.functions.elementary.miscellaneous import Max return Max(*[set.sup for set in self.args])
def test_Max(): from sympy.abc import x, y, z n = Symbol('n', negative=True) n_ = Symbol('n_', negative=True) nn = Symbol('nn', nonnegative=True) nn_ = Symbol('nn_', nonnegative=True) p = Symbol('p', positive=True) p_ = Symbol('p_', positive=True) np = Symbol('np', nonpositive=True) np_ = Symbol('np_', nonpositive=True) r = Symbol('r', real=True) assert Max(5, 4) == 5 # lists raises(ValueError, lambda: Max()) assert Max(x, y) == Max(y, x) assert Max(x, y, z) == Max(z, y, x) assert Max(x, Max(y, z)) == Max(z, y, x) assert Max(x, Min(y, oo)) == Max(x, y) assert Max(n, -oo, n_, p, 2) == Max(p, 2) assert Max(n, -oo, n_, p) == p assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p) assert Max(0, x, 1, y) == Max(1, x, y) assert Max(r, r + 1, r - 1) == 1 + r assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000) assert Max(cos(x), sin(x)) == Max(sin(x), cos(x)) assert Max(cos(x), sin(x)).subs(x, 1) == sin(1) assert Max(cos(x), sin(x)).subs(x, S(1)/2) == cos(S(1)/2) raises(ValueError, lambda: Max(cos(x), sin(x)).subs(x, I)) raises(ValueError, lambda: Max(I)) raises(ValueError, lambda: Max(I, x)) raises(ValueError, lambda: Max(S.ComplexInfinity, 1)) assert Max(n, -oo, n_, p, 2) == Max(p, 2) assert Max(n, -oo, n_, p, 1000) == Max(p, 1000) assert Max(1, x).diff(x) == Heaviside(x - 1) assert Max(x, 1).diff(x) == Heaviside(x - 1) assert Max(x**2, 1 + x, 1).diff(x) == \ 2*x*Heaviside(x**2 - Max(1, x + 1)) \ + Heaviside(x - Max(1, x**2) + 1) e = Max(0, x) assert e.evalf == e.n assert e.n().args == (0, x) # issue 8643 m = Max(p, p_, n, r) assert m.is_positive is True assert m.is_nonnegative is True assert m.is_negative is False m = Max(n, n_) assert m.is_positive is False assert m.is_nonnegative is False assert m.is_negative is True m = Max(n, n_, r) assert m.is_positive is None assert m.is_nonnegative is None assert m.is_negative is None m = Max(n, nn, r) assert m.is_positive is None assert m.is_nonnegative is True assert m.is_negative is False
def _eval_imageset(self, f): from sympy.functions.elementary.miscellaneous import Min, Max from sympy.solvers import solve from sympy.core.function import diff from sympy.series import limit from sympy.calculus.singularities import singularities # TODO: handle piecewise defined functions # TODO: handle functions with infinitely many solutions (eg, sin, tan) # TODO: handle multivariate functions expr = f.expr if len(expr.free_symbols) > 1 or len(f.variables) != 1: return var = f.variables[0] if not self.start.is_comparable or not self.end.is_comparable: return try: sing = [ x for x in singularities(expr, var) if x.is_real and x in self ] except NotImplementedError: return if self.left_open: _start = limit(expr, var, self.start, dir="+") elif self.start not in sing: _start = f(self.start) if self.right_open: _end = limit(expr, var, self.end, dir="-") elif self.end not in sing: _end = f(self.end) if len(sing) == 0: solns = solve(diff(expr, var), var) extr = [_start, _end ] + [f(x) for x in solns if x.is_real and x in self] start, end = Min(*extr), Max(*extr) left_open, right_open = False, False if _start <= _end: # the minimum or maximum value can occur simultaneously # on both the edge of the interval and in some interior # point if start == _start and start not in solns: left_open = self.left_open if end == _end and end not in solns: right_open = self.right_open else: if start == _end and start not in solns: left_open = self.right_open if end == _start and end not in solns: right_open = self.left_open return Interval(start, end, left_open, right_open) else: return imageset(f, Interval(self.start, sing[0], self.left_open, True)) + \ Union(*[imageset(f, Interval(sing[i], sing[i + 1]), True, True) for i in range(1, len(sing) - 1)]) + \ imageset(f, Interval(sing[-1], self.end, True, self.right_open))
def width( self ): if self.fields: return Max(*(f.highBit for f in self.fields)) else: return 0
def test_issue_10395(): eq = x * Max(0, y) assert nfloat(eq) == eq eq = x * Max(y, -1.1) assert nfloat(eq) == eq assert Max(y, 4).n() == Max(4.0, y)
def test_Min_Max(): # see gh-10375 assert lambdify((x, y, z), Min(x, y, z))(1, 2, 3) == 1 assert lambdify((x, y, z), Max(x, y, z))(1, 2, 3) == 3
def test_issue_21399(): from sympy.abc import a, b, c assert Max(Min(a, b), Min(a, b, c)) == Min(a, b)
def sum_limit(r, w, n0, di, i0, index=0): return slice( di, Max(0, -(i0 // r[index])), Min(-1 // r[index] + w.shape[index], (n0 - i0 - 1) // r[index]) + 1)
def _print_Max(self, expr): from sympy.functions.elementary.miscellaneous import Max if len(expr.args) == 1: return self._print(expr.args[0]) return "%smax(%s, %s)" % (self._ns, self._print(expr.args[0]), self._print(Max(*expr.args[1:])))
def test_issue_12638(): from sympy.abc import a, b, c, d assert Min(a, b, c, Max(a, b)) == Min(a, b, c) assert Min(a, b, Max(a, b, c)) == Min(a, b) assert Min(a, b, Max(a, c)) == Min(a, b)
def _intervals(self, sym): """Return a list of unique tuples, (a, b, e, i), where a and b are the lower and upper bounds in which the expression e of argument i in self is defined and a < b (when involving numbers) or a <= b when involving symbols. If there are any relationals not involving sym, or any relational cannot be solved for sym, NotImplementedError is raised. The calling routine should have removed such relationals before calling this routine. The evaluated conditions will be returned as ranges. Discontinuous ranges will be returned separately with identical expressions. The first condition that evaluates to True will be returned as the last tuple with a, b = -oo, oo. """ from sympy.solvers.inequalities import _solve_inequality from sympy.logic.boolalg import to_cnf, distribute_or_over_and assert isinstance(self, Piecewise) def _solve_relational(r): if sym not in r.free_symbols: nonsymfail(r) rv = _solve_inequality(r, sym) if isinstance(rv, Relational): free = rv.args[1].free_symbols if rv.args[0] != sym or sym in free: raise NotImplementedError( filldedent(''' Unable to solve relational %s for %s.''' % (r, sym))) if rv.rel_op == '==': # this equality has been affirmed to have the form # Eq(sym, rhs) where rhs is sym-free; it represents # a zero-width interval which will be ignored # whether it is an isolated condition or contained # within an And or an Or rv = S.false elif rv.rel_op == '!=': try: rv = Or(sym < rv.rhs, sym > rv.rhs) except TypeError: # e.g. x != I ==> all real x satisfy rv = S.true elif rv == (S.NegativeInfinity < sym) & (sym < S.Infinity): rv = S.true return rv def nonsymfail(cond): raise NotImplementedError( filldedent(''' A condition not involving %s appeared: %s''' % (sym, cond))) # make self canonical wrt Relationals reps = dict([(r, _solve_relational(r)) for r in self.atoms(Relational)]) # process args individually so if any evaluate, their position # in the original Piecewise will be known args = [i.xreplace(reps) for i in self.args] # precondition args expr_cond = [] default = idefault = None for i, (expr, cond) in enumerate(args): if cond is S.false: continue elif cond is S.true: default = expr idefault = i break cond = to_cnf(cond) if isinstance(cond, And): cond = distribute_or_over_and(cond) if isinstance(cond, Or): expr_cond.extend([(i, expr, o) for o in cond.args if not isinstance(o, Equality)]) elif cond is not S.false: expr_cond.append((i, expr, cond)) # determine intervals represented by conditions int_expr = [] for iarg, expr, cond in expr_cond: if isinstance(cond, And): lower = S.NegativeInfinity upper = S.Infinity for cond2 in cond.args: if isinstance(cond2, Equality): lower = upper # ignore break elif cond2.lts == sym: upper = Min(cond2.gts, upper) elif cond2.gts == sym: lower = Max(cond2.lts, lower) else: nonsymfail(cond2) # should never get here elif isinstance(cond, Relational): lower, upper = cond.lts, cond.gts # part 1: initialize with givens if cond.lts == sym: # part 1a: expand the side ... lower = S.NegativeInfinity # e.g. x <= 0 ---> -oo <= 0 elif cond.gts == sym: # part 1a: ... that can be expanded upper = S.Infinity # e.g. x >= 0 ---> oo >= 0 else: nonsymfail(cond) else: raise NotImplementedError('unrecognized condition: %s' % cond) lower, upper = lower, Max(lower, upper) if (lower >= upper) is not S.true: int_expr.append((lower, upper, expr, iarg)) if default is not None: int_expr.append( (S.NegativeInfinity, S.Infinity, default, idefault)) return list(uniq(int_expr))
def test_instantiation_evaluation(): from sympy.abc import v, w, x, y, z assert Min(1, Max(2, x)) == 1 assert Max(3, Min(2, x)) == 3 assert Min(Max(x, y), Max(x, z)) == Max(x, Min(y, z)) assert set(Min(Max(w, x), Max(y, z)).args) == set([Max(w, x), Max(y, z)]) assert Min(Max(x, y), Max(x, z), w) == Min(w, Max(x, Min(y, z))) A, B = Min, Max for i in range(2): assert A(x, B(x, y)) == x assert A(x, B(y, A(x, w, z))) == A(x, B(y, A(w, z))) A, B = B, A assert Min(w, Max(x, y), Max(v, x, z)) == Min(w, Max(x, Min(y, Max(v, z))))
def test_evalf_bugs(): assert NS(sin(1) + exp(-10**10), 10) == NS(sin(1), 10) assert NS(exp(10**10) + sin(1), 10) == NS(exp(10**10), 10) assert NS('expand_log(log(1+1/10**50))', 20) == '1.0000000000000000000e-50' assert NS('log(10**100,10)', 10) == '100.0000000' assert NS('log(2)', 10) == '0.6931471806' assert NS('(sin(x)-x)/x**3', 15, subs={x: '1/10**50'}) == '-0.166666666666667' assert NS(sin(1) + Rational(1, 10**100) * I, 15) == '0.841470984807897 + 1.00000000000000e-100*I' assert x.evalf() == x assert NS((1 + I)**2 * I, 6) == '-2.00000' d = { n: (-1)**Rational(6, 7), y: (-1)**Rational(4, 7), x: (-1)**Rational(2, 7) } assert NS((x * (1 + y * (1 + n))).subs(d).evalf(), 6) == '0.346011 + 0.433884*I' assert NS(((-I - sqrt(2) * I)**2).evalf()) == '-5.82842712474619' assert NS((1 + I)**2 * I, 15) == '-2.00000000000000' # issue 4758 (1/2): assert NS(pi.evalf(69) - pi) == '-4.43863937855894e-71' # issue 4758 (2/2): With the bug present, this still only fails if the # terms are in the order given here. This is not generally the case, # because the order depends on the hashes of the terms. assert NS(20 - 5008329267844 * n**25 - 477638700 * n**37 - 19 * n, subs={n: .01}) == '19.8100000000000' assert NS( ((x - 1) * (1 - x)** 1000).n()) == '(1.00000000000000 - x)**1000*(x - 1.00000000000000)' assert NS((-x).n()) == '-x' assert NS((-2 * x).n()) == '-2.00000000000000*x' assert NS((-2 * x * y).n()) == '-2.00000000000000*x*y' assert cos(x).n(subs={x: 1 + I}) == cos(x).subs(x, 1 + I).n() # issue 6660. Also NaN != mpmath.nan # In this order: # 0*nan, 0/nan, 0*inf, 0/inf # 0+nan, 0-nan, 0+inf, 0-inf # >>> n = Some Number # n*nan, n/nan, n*inf, n/inf # n+nan, n-nan, n+inf, n-inf assert (0 * E**(oo)).n() is S.NaN assert (0 / E**(oo)).n() is S.Zero assert (0 + E**(oo)).n() is S.Infinity assert (0 - E**(oo)).n() is S.NegativeInfinity assert (5 * E**(oo)).n() is S.Infinity assert (5 / E**(oo)).n() is S.Zero assert (5 + E**(oo)).n() is S.Infinity assert (5 - E**(oo)).n() is S.NegativeInfinity #issue 7416 assert as_mpmath(0.0, 10, {'chop': True}) == 0 #issue 5412 assert ((oo * I).n() == S.Infinity * I) assert ((oo + oo * I).n() == S.Infinity + S.Infinity * I) #issue 11518 assert NS(2 * x**2.5, 5) == '2.0000*x**2.5000' #issue 13076 assert NS(Mul(Max(0, y), x, evaluate=False).evalf()) == 'x*Max(0, y)' #issue 18516 assert NS( log( S(3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376 ) / 36360291795869936842385267079543319118023385026001623040346035832580600191583895484198508262979388783308179702534403855752855931517013066142992430916562025780021771247847643450125342836565813209972590371590152578728008385990139795377610001 ).evalf(15, chop=True)) == '-oo'
def _sup(self): from sympy.functions.elementary.miscellaneous import Max return Max(*self)
def _intervals(self, sym): """Return a list of tuples, (a, b, e, i), where a and b are the lower and upper bounds in which the expression e of argument i in self is defined. If there are any relationals not involving sym, or any relational cannot be solved for sym, NotImplementedError is raised. The evaluated conditions will be returned as ranges. Discontinuous ranges will be returned separately with identical expressions and the first condition that evaluates to True will be returned as the last tuple with a, b = -oo, oo. """ from sympy.solvers.inequalities import _solve_inequality from sympy.logic.boolalg import to_cnf, distribute_or_over_and assert isinstance(self, Piecewise) def _solve_relational(r): rv = _solve_inequality(r, sym) if isinstance(rv, Relational) and \ sym in rv.free_symbols: if rv.args[0] != sym: raise NotImplementedError( filldedent(''' Unable to solve relational %s for %s.''' % (r, sym))) if rv.rel_op == '!=': try: rv = Or(sym < rv.rhs, sym > rv.rhs) except TypeError: # e.g. x != I ==> all real x satisfy rv = S.true if rv == (S.NegativeInfinity < sym) & (sym < S.Infinity): rv = S.true return rv def nonsymfail(cond): raise NotImplementedError( filldedent(''' A condition not involving %s appeared: %s''' % (sym, cond))) # make self canonical wrt Relationals reps = dict([(r, _solve_relational(r)) for r in self.atoms(Relational)]) # process args individually so if any evaluate, their position # in the original Piecewise will be known args = [i.xreplace(reps) for i in self.args] # precondition args expr_cond = [] default = idefault = None for i, (expr, cond) in enumerate(args): if cond == False: continue elif cond == True: default = expr idefault = i break elif sym not in cond.free_symbols: nonsymfail(cond) cond = to_cnf(cond) if isinstance(cond, And): cond = distribute_or_over_and(cond) if isinstance(cond, Or): expr_cond.extend([(i, expr, o) for o in cond.args]) elif cond != False: expr_cond.append((i, expr, cond)) # determine intervals represented by conditions int_expr = [] for iarg, expr, cond in expr_cond: if isinstance(cond, Equality): if cond.lhs == sym: v = cond.rhs int_expr.append((v, v, expr.subs(sym, v), iarg)) continue else: nonsymfail(cond) if isinstance(cond, And): lower = S.NegativeInfinity upper = S.Infinity nonsym = False rhs = None for cond2 in cond.args: if isinstance(cond2, Equality): # all relationals were solved and # only sym-dependent ones made it to here assert cond2.lhs == sym assert sym not in cond2.rhs.free_symbols if rhs is None: rhs = cond2.rhs else: same = Eq(cond2.rhs, rhs) if same == False: cond = S.false break elif same != True: raise Undecidable('%s did not evaluate' % same) elif cond2.lts == sym: upper = Min(cond2.gts, upper) elif cond2.gts == sym: lower = Max(cond2.lts, lower) else: # mark but don't fail until later nonsym = cond2 if rhs is not None and cond not in (S.true, S.false): lower = upper = rhs cond = cond.subs(sym, lower) # cond might have evaluated b/c of an Eq if cond is S.true: default = expr continue elif cond is S.false: continue elif nonsym is not False: nonsymfail(nonsym) else: pass # for coverage elif isinstance(cond, Relational): lower, upper = cond.lts, cond.gts # part 1: initialize with givens if cond.lts == sym: # part 1a: expand the side ... lower = S.NegativeInfinity # e.g. x <= 0 ---> -oo <= 0 elif cond.gts == sym: # part 1a: ... that can be expanded upper = S.Infinity # e.g. x >= 0 ---> oo >= 0 else: nonsymfail(cond) else: raise NotImplementedError('unrecognized condition: %s' % cond) lower, upper = lower, Max(lower, upper) if (lower > upper) is not S.true: int_expr.append((lower, upper, expr, iarg)) if default is not None: int_expr.append( (S.NegativeInfinity, S.Infinity, default, idefault)) return int_expr
def __pow__(self, other): from sympy.functions.elementary.miscellaneous import real_root if isinstance(other, Expr): if other is S.Infinity: if self.min.is_nonnegative: if self.max < 1: return S.Zero if self.min > 1: return S.Infinity return AccumBounds(0, oo) elif self.max.is_negative: if self.min > -1: return S.Zero if self.max < -1: return FiniteSet(-oo, oo) return AccumBounds(-oo, oo) else: if self.min > -1: if self.max < 1: return S.Zero return AccumBounds(0, oo) return AccumBounds(-oo, oo) if other is S.NegativeInfinity: return (1/self)**oo if other.is_real and other.is_number: if other.is_zero: return S.One if other.is_Integer: if self.min.is_positive: return AccumBounds(Min(self.min**other, self.max**other), Max(self.min**other, self.max**other)) elif self.max.is_negative: return AccumBounds(Min(self.max**other, self.min**other), Max(self.max**other, self.min**other)) if other % 2 == 0: if other.is_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(self.min**other, oo) return AccumBounds(0, oo) return AccumBounds(S.Zero, Max(self.min**other, self.max**other)) else: if other.is_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(-oo, self.min**other) return AccumBounds(-oo, oo) return AccumBounds(self.min**other, self.max**other) num, den = other.as_numer_denom() if num == S(1): if den % 2 == 0: if S.Zero in self: if self.min.is_negative: return AccumBounds(0, real_root(self.max, den)) return AccumBounds(real_root(self.min, den), real_root(self.max, den)) num_pow = self**num return num_pow**(1/den) return Pow(self, other, evaluate=False) return NotImplemented
def __pow__(self, other): if isinstance(other, Expr): if other is S.Infinity: if self.min.is_extended_nonnegative: if self.max < 1: return S.Zero if self.min > 1: return S.Infinity return AccumBounds(0, oo) elif self.max.is_extended_negative: if self.min > -1: return S.Zero if self.max < -1: return zoo return S.NaN else: if self.min > -1: if self.max < 1: return S.Zero return AccumBounds(0, oo) return AccumBounds(-oo, oo) if other is S.NegativeInfinity: return (1 / self)**oo # generically true if (self.max - self.min).is_nonnegative: # well defined if self.min.is_nonnegative: # no 0 to worry about if other.is_nonnegative: # no infinity to worry about return self.func(self.min**other, self.max**other) if other.is_zero: return S.One # x**0 = 1 if other.is_Integer or other.is_integer: if self.min.is_extended_positive: return AccumBounds(Min(self.min**other, self.max**other), Max(self.min**other, self.max**other)) elif self.max.is_extended_negative: return AccumBounds(Min(self.max**other, self.min**other), Max(self.max**other, self.min**other)) if other % 2 == 0: if other.is_extended_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(self.min**other, oo) return AccumBounds(0, oo) return AccumBounds(S.Zero, Max(self.min**other, self.max**other)) elif other % 2 == 1: if other.is_extended_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(-oo, self.min**other) return AccumBounds(-oo, oo) return AccumBounds(self.min**other, self.max**other) # non-integer exponent # 0**neg or neg**frac yields complex if (other.is_number or other.is_rational) and ( self.min.is_extended_nonnegative or (other.is_extended_nonnegative and self.min.is_extended_nonnegative)): num, den = other.as_numer_denom() if num is S.One: return AccumBounds(*[i**(1 / den) for i in self.args]) elif den is not S.One: # e.g. if other is not Float return (self**num)**(1 / den) # ok for non-negative base if isinstance(other, AccumBounds): if (self.min.is_extended_positive or self.min.is_extended_nonnegative and other.min.is_extended_nonnegative): p = [self**i for i in other.args] if not any(i.is_Pow for i in p): a = [j for i in p for j in i.args or (i, )] try: return self.func(min(a), max(a)) except TypeError: # can't sort pass return Pow(self, other, evaluate=False) return NotImplemented
def limit_seq(expr, n=None, trials=5): """Finds the limit of a sequence as index ``n`` tends to infinity. Parameters ========== expr : Expr SymPy expression for the ``n-th`` term of the sequence n : Symbol, optional The index of the sequence, an integer that tends to positive infinity. If None, inferred from the expression unless it has multiple symbols. trials: int, optional The algorithm is highly recursive. ``trials`` is a safeguard from infinite recursion in case the limit is not easily computed by the algorithm. Try increasing ``trials`` if the algorithm returns ``None``. Admissible Terms ================ The algorithm is designed for sequences built from rational functions, indefinite sums, and indefinite products over an indeterminate n. Terms of alternating sign are also allowed, but more complex oscillatory behavior is not supported. Examples ======== >>> from sympy import limit_seq, Sum, binomial >>> from sympy.abc import n, k, m >>> limit_seq((5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5), n) 5/3 >>> limit_seq(binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n)), n) 3/4 >>> limit_seq(Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n), n) 4 See Also ======== sympy.series.limitseq.dominant References ========== .. [1] Computing Limits of Sequences - Manuel Kauers """ from sympy.concrete.summations import Sum if n is None: free = expr.free_symbols if len(free) == 1: n = free.pop() elif not free: return expr else: raise ValueError("Expression has more than one variable. " "Please specify a variable.") elif n not in expr.free_symbols: return expr expr = expr.rewrite(fibonacci, S.GoldenRatio) expr = expr.rewrite(factorial, subfactorial, gamma) n_ = Dummy("n", integer=True, positive=True) n1 = Dummy("n", odd=True, positive=True) n2 = Dummy("n", even=True, positive=True) # If there is a negative term raised to a power involving n, or a # trigonometric function, then consider even and odd n separately. powers = (p.as_base_exp() for p in expr.atoms(Pow)) if (any(b.is_negative and e.has(n) for b, e in powers) or expr.has(cos, sin)): L1 = _limit_seq(expr.xreplace({n: n1}), n1, trials) if L1 is not None: L2 = _limit_seq(expr.xreplace({n: n2}), n2, trials) if L1 != L2: if L1.is_comparable and L2.is_comparable: return AccumulationBounds(Min(L1, L2), Max(L1, L2)) else: return None else: L1 = _limit_seq(expr.xreplace({n: n_}), n_, trials) if L1 is not None: return L1 else: if expr.is_Add: limits = [limit_seq(term, n, trials) for term in expr.args] if any(result is None for result in limits): return None else: return Add(*limits) # Maybe the absolute value is easier to deal with (though not if # it has a Sum). If it tends to 0, the limit is 0. elif not expr.has(Sum): lim = _limit_seq(Abs(expr.xreplace({n: n_})), n_, trials) if lim is not None and lim.is_zero: return S.Zero
def _set_function(f, x): # noqa:F811 from sympy.functions.elementary.miscellaneous import Min, Max from sympy.solvers.solveset import solveset from sympy.core.function import diff, Lambda from sympy.series import limit from sympy.calculus.singularities import singularities from sympy.sets import Complement # TODO: handle functions with infinitely many solutions (eg, sin, tan) # TODO: handle multivariate functions expr = f.expr if len(expr.free_symbols) > 1 or len(f.variables) != 1: return var = f.variables[0] if not var.is_real: if expr.subs(var, Dummy(real=True)).is_real is False: return if expr.is_Piecewise: result = S.EmptySet domain_set = x for (p_expr, p_cond) in expr.args: if p_cond is true: intrvl = domain_set else: intrvl = p_cond.as_set() intrvl = Intersection(domain_set, intrvl) if p_expr.is_Number: image = FiniteSet(p_expr) else: image = imageset(Lambda(var, p_expr), intrvl) result = Union(result, image) # remove the part which has been `imaged` domain_set = Complement(domain_set, intrvl) if domain_set is S.EmptySet: break return result if not x.start.is_comparable or not x.end.is_comparable: return try: sing = [i for i in singularities(expr, var) if i.is_real and i in x] except NotImplementedError: return if x.left_open: _start = limit(expr, var, x.start, dir="+") elif x.start not in sing: _start = f(x.start) if x.right_open: _end = limit(expr, var, x.end, dir="-") elif x.end not in sing: _end = f(x.end) if len(sing) == 0: solns = list(solveset(diff(expr, var), var)) extr = [_start, _end] + [f(i) for i in solns if i.is_real and i in x] start, end = Min(*extr), Max(*extr) left_open, right_open = False, False if _start <= _end: # the minimum or maximum value can occur simultaneously # on both the edge of the interval and in some interior # point if start == _start and start not in solns: left_open = x.left_open if end == _end and end not in solns: right_open = x.right_open else: if start == _end and start not in solns: left_open = x.right_open if end == _start and end not in solns: right_open = x.left_open return Interval(start, end, left_open, right_open) else: return imageset(f, Interval(x.start, sing[0], x.left_open, True)) + \ Union(*[imageset(f, Interval(sing[i], sing[i + 1], True, True)) for i in range(0, len(sing) - 1)]) + \ imageset(f, Interval(sing[-1], x.end, True, x.right_open))
def _rsolve_hypergeometric(f, x, P, Q, k, m): """Recursive wrapper to rsolve_hypergeometric. Returns a Tuple of (formula, series independent terms, maximum power of x in independent terms) if successful otherwise ``None``. See :func:`rsolve_hypergeometric` for details. """ from sympy.polys import lcm, roots from sympy.integrals import integrate # transformation - c proots, qroots = roots(P, k), roots(Q, k) all_roots = dict(proots) all_roots.update(qroots) scale = lcm( [r.as_numer_denom()[1] for r, t in all_roots.items() if r.is_rational]) f, P, Q, m = _transformation_c(f, x, P, Q, k, m, scale) # transformation - a qroots = roots(Q, k) if qroots: k_min = Min(*qroots.keys()) else: k_min = S.Zero shift = k_min + m f, P, Q, m = _transformation_a(f, x, P, Q, k, m, shift) l = (x * f).limit(x, 0) if not isinstance(l, Limit) and l != 0: # Ideally should only be l != 0 return None qroots = roots(Q, k) if qroots: k_max = Max(*qroots.keys()) else: k_max = S.Zero ind, mp = S.Zero, -oo for i in range(k_max + m + 1): r = f.diff(x, i).limit(x, 0) / factorial(i) if r.is_finite is False: old_f = f f, P, Q, m = _transformation_a(f, x, P, Q, k, m, i) f, P, Q, m = _transformation_e(f, x, P, Q, k, m) sol, ind, mp = _rsolve_hypergeometric(f, x, P, Q, k, m) sol = _apply_integrate(sol, x, k) sol = _apply_shift(sol, i) ind = integrate(ind, x) ind += (old_f - ind).limit(x, 0) # constant of integration mp += 1 return sol, ind, mp elif r: ind += r * x**(i + shift) pow_x = Rational((i + shift), scale) if pow_x > mp: mp = pow_x # maximum power of x ind = ind.subs(x, x**(1 / scale)) sol = _compute_formula(f, x, P, Q, k, m, k_max) sol = _apply_shift(sol, shift) sol = _apply_scale(sol, scale) return sol, ind, mp
def _eval_interval(self, sym, a, b): """Evaluates the function along the sym in a given interval ab""" # FIXME: Currently complex intervals are not supported. A possible # replacement algorithm, discussed in issue 2128, can be found in the # following papers; # http://portal.acm.org/citation.cfm?id=281649 # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4127&rep=rep1&type=pdf if a is None or b is None: # In this case, it is just simple substitution return super(Piecewise, self)._eval_interval(sym, a, b) mul = 1 if (a == b) is True: return S.Zero elif (a > b) is True: a, b, mul = b, a, -1 elif (a <= b) is not True: newargs = [] for e, c in self.args: intervals = self._sort_expr_cond(sym, S.NegativeInfinity, S.Infinity, c) values = [] for lower, upper in intervals: if (a < lower) is True: mid = lower rep = b val = e.subs(sym, b) - e.subs(sym, mid) val += self._eval_interval(sym, a, mid) elif (a > upper) is True: mid = upper rep = b val = e.subs(sym, b) - e.subs(sym, mid) val += self._eval_interval(sym, a, mid) elif (a >= lower) is True and (a <= upper) is True: rep = b val = e.subs(sym, b) - e.subs(sym, a) elif (b < lower) is True: mid = lower rep = a val = e.subs(sym, mid) - e.subs(sym, a) val += self._eval_interval(sym, mid, b) elif (b > upper) is True: mid = upper rep = a val = e.subs(sym, mid) - e.subs(sym, a) val += self._eval_interval(sym, mid, b) elif ((b >= lower) is True) and ((b <= upper) is True): rep = a val = e.subs(sym, b) - e.subs(sym, a) else: raise NotImplementedError( """The evaluation of a Piecewise interval when both the lower and the upper limit are symbolic is not yet implemented.""" ) values.append(val) if len(set(values)) == 1: try: c = c.subs(sym, rep) except AttributeError: pass e = values[0] newargs.append((e, c)) else: for i in range(len(values)): newargs.append( (values[i], (c is True and i == len(values) - 1) or And(rep >= intervals[i][0], rep <= intervals[i][1]))) return Piecewise(*newargs) # Determine what intervals the expr,cond pairs affect. int_expr = self._sort_expr_cond(sym, a, b) # Finally run through the intervals and sum the evaluation. ret_fun = 0 for int_a, int_b, expr in int_expr: ret_fun += expr._eval_interval(sym, Max(a, int_a), Min(b, int_b)) return mul * ret_fun