def function_range(f, symbol, domain): """ Finds the range of a function in a given domain. This method is limited by the ability to determine the singularities and determine limits. Parameters ========== f : :py:class:`~.Expr` The concerned function. symbol : :py:class:`~.Symbol` The variable for which the range of function is to be determined. domain : :py:class:`~.Interval` The domain under which the range of the function has to be found. Examples ======== >>> from sympy import Interval, Symbol, S, exp, log, pi, sqrt, sin, tan >>> from sympy.calculus.util import function_range >>> x = Symbol('x') >>> function_range(sin(x), x, Interval(0, 2*pi)) Interval(-1, 1) >>> function_range(tan(x), x, Interval(-pi/2, pi/2)) Interval(-oo, oo) >>> function_range(1/x, x, S.Reals) Union(Interval.open(-oo, 0), Interval.open(0, oo)) >>> function_range(exp(x), x, S.Reals) Interval.open(0, oo) >>> function_range(log(x), x, S.Reals) Interval(-oo, oo) >>> function_range(sqrt(x), x, Interval(-5, 9)) Interval(0, 3) Returns ======= :py:class:`~.Interval` Union of all ranges for all intervals under domain where function is continuous. Raises ====== NotImplementedError If any of the intervals, in the given domain, for which function is continuous are not finite or real, OR if the critical points of the function on the domain cannot be found. """ if domain is S.EmptySet: return S.EmptySet period = periodicity(f, symbol) if period == S.Zero: # the expression is constant wrt symbol return FiniteSet(f.expand()) from sympy.series.limits import limit from sympy.solvers.solveset import solveset if period is not None: if isinstance(domain, Interval): if (domain.inf - domain.sup).is_infinite: domain = Interval(0, period) elif isinstance(domain, Union): for sub_dom in domain.args: if isinstance(sub_dom, Interval) and \ ((sub_dom.inf - sub_dom.sup).is_infinite): domain = Interval(0, period) intervals = continuous_domain(f, symbol, domain) range_int = S.EmptySet if isinstance(intervals, (Interval, FiniteSet)): interval_iter = (intervals, ) elif isinstance(intervals, Union): interval_iter = intervals.args else: raise NotImplementedError( filldedent(''' Unable to find range for the given domain. ''')) for interval in interval_iter: if isinstance(interval, FiniteSet): for singleton in interval: if singleton in domain: range_int += FiniteSet(f.subs(symbol, singleton)) elif isinstance(interval, Interval): vals = S.EmptySet critical_points = S.EmptySet critical_values = S.EmptySet bounds = ((interval.left_open, interval.inf, '+'), (interval.right_open, interval.sup, '-')) for is_open, limit_point, direction in bounds: if is_open: critical_values += FiniteSet( limit(f, symbol, limit_point, direction)) vals += critical_values else: vals += FiniteSet(f.subs(symbol, limit_point)) solution = solveset(f.diff(symbol), symbol, interval) if not iterable(solution): raise NotImplementedError( 'Unable to find critical points for {}'.format(f)) if isinstance(solution, ImageSet): raise NotImplementedError( 'Infinite number of critical points for {}'.format(f)) critical_points += solution for critical_point in critical_points: vals += FiniteSet(f.subs(symbol, critical_point)) left_open, right_open = False, False if critical_values is not S.EmptySet: if critical_values.inf == vals.inf: left_open = True if critical_values.sup == vals.sup: right_open = True range_int += Interval(vals.inf, vals.sup, left_open, right_open) else: raise NotImplementedError( filldedent(''' Unable to find range for the given domain. ''')) return range_int
def dict(self): return FiniteSet(*[Dict(dict(el)) for el in self.elements])
def symbols(self): return FiniteSet(self.symbol)
def elements(self): return FiniteSet(*[frozenset(((self.symbol, elem), )) for elem in self.set])
def _density(self): return dict((FiniteSet((self.symbol, val)), prob) for val, prob in self.distribution.dict.items())
def symbols(self): return FiniteSet(*[val.symbol for val in self.rs_space_dict.keys()])
def __new__(cls, symbols, *args): symbols = FiniteSet(*symbols) return Basic.__new__(cls, symbols, *args)
def test_issue_16871(): assert ImageSet(Lambda(x, x), FiniteSet(1)) == {1} assert ImageSet(Lambda(x, x - 3), S.Integers).intersection( S.Integers) is S.Integers
def test_Range_set(): empty = Range(0) assert Range(5) == Range(0, 5) == Range(0, 5, 1) r = Range(10, 20, 2) assert 12 in r assert 8 not in r assert 11 not in r assert 30 not in r assert list(Range(0, 5)) == list(range(5)) assert list(Range(5, 0, -1)) == list(range(5, 0, -1)) assert Range(5, 15).sup == 14 assert Range(5, 15).inf == 5 assert Range(15, 5, -1).sup == 15 assert Range(15, 5, -1).inf == 6 assert Range(10, 67, 10).sup == 60 assert Range(60, 7, -10).inf == 10 assert len(Range(10, 38, 10)) == 3 assert Range(0, 0, 5) == empty assert Range(oo, oo, 1) == empty assert Range(oo, 1, 1) == empty assert Range(-oo, 1, -1) == empty assert Range(1, oo, -1) == empty assert Range(1, -oo, 1) == empty assert Range(1, -4, oo) == empty assert Range(1, -4, -oo) == Range(1, 2) assert Range(1, 4, oo) == Range(1, 2) assert Range(-oo, oo).size == oo assert Range(oo, -oo, -1).size == oo raises(ValueError, lambda: Range(-oo, oo, 2)) raises(ValueError, lambda: Range(x, pi, y)) raises(ValueError, lambda: Range(x, y, 0)) assert 5 in Range(0, oo, 5) assert -5 in Range(-oo, 0, 5) assert oo not in Range(0, oo) ni = symbols('ni', integer=False) assert ni not in Range(oo) u = symbols('u', integer=None) assert Range(oo).contains(u) is not False inf = symbols('inf', infinite=True) assert inf not in Range(-oo, oo) raises(ValueError, lambda: Range(0, oo, 2)[-1]) raises(ValueError, lambda: Range(0, -oo, -2)[-1]) assert Range(-oo, 1, 1)[-1] is S.Zero assert Range(oo, 1, -1)[-1] == 2 assert inf not in Range(oo) inf = symbols('inf', infinite=True) assert inf not in Range(oo) assert Range(-oo, 1, 1)[-1] is S.Zero assert Range(oo, 1, -1)[-1] == 2 assert Range(1, 10, 1)[-1] == 9 assert all(i.is_Integer for i in Range(0, -1, 1)) it = iter(Range(-oo, 0, 2)) raises(TypeError, lambda: next(it)) assert empty.intersect(S.Integers) == empty assert Range(-1, 10, 1).intersect(S.Integers) == Range(-1, 10, 1) assert Range(-1, 10, 1).intersect(S.Naturals) == Range(1, 10, 1) assert Range(-1, 10, 1).intersect(S.Naturals0) == Range(0, 10, 1) # test slicing assert Range(1, 10, 1)[5] == 6 assert Range(1, 12, 2)[5] == 11 assert Range(1, 10, 1)[-1] == 9 assert Range(1, 10, 3)[-1] == 7 raises(ValueError, lambda: Range(oo, 0, -1)[1:3:0]) raises(ValueError, lambda: Range(oo, 0, -1)[:1]) raises(ValueError, lambda: Range(1, oo)[-2]) raises(ValueError, lambda: Range(-oo, 1)[2]) raises(IndexError, lambda: Range(10)[-20]) raises(IndexError, lambda: Range(10)[20]) raises(ValueError, lambda: Range(2, -oo, -2)[2:2:0]) assert Range(2, -oo, -2)[2:2:2] == empty assert Range(2, -oo, -2)[:2:2] == Range(2, -2, -4) raises(ValueError, lambda: Range(-oo, 4, 2)[:2:2]) assert Range(-oo, 4, 2)[::-2] == Range(2, -oo, -4) raises(ValueError, lambda: Range(-oo, 4, 2)[::2]) assert Range(oo, 2, -2)[::] == Range(oo, 2, -2) assert Range(-oo, 4, 2)[:-2:-2] == Range(2, 0, -4) assert Range(-oo, 4, 2)[:-2:2] == Range(-oo, 0, 4) raises(ValueError, lambda: Range(-oo, 4, 2)[:0:-2]) raises(ValueError, lambda: Range(-oo, 4, 2)[:2:-2]) assert Range(-oo, 4, 2)[-2::-2] == Range(0, -oo, -4) raises(ValueError, lambda: Range(-oo, 4, 2)[-2:0:-2]) raises(ValueError, lambda: Range(-oo, 4, 2)[0::2]) assert Range(oo, 2, -2)[0::] == Range(oo, 2, -2) raises(ValueError, lambda: Range(-oo, 4, 2)[0:-2:2]) assert Range(oo, 2, -2)[0:-2:] == Range(oo, 6, -2) raises(ValueError, lambda: Range(oo, 2, -2)[0:2:]) raises(ValueError, lambda: Range(-oo, 4, 2)[2::-1]) assert Range(-oo, 4, 2)[-2::2] == Range(0, 4, 4) assert Range(oo, 0, -2)[-10:0:2] == empty raises(ValueError, lambda: Range(oo, 0, -2)[-10:10:2]) raises(ValueError, lambda: Range(oo, 0, -2)[0::-2]) assert Range(oo, 0, -2)[0:-4:-2] == empty assert Range(oo, 0, -2)[:0:2] == empty raises(ValueError, lambda: Range(oo, 0, -2)[:1:-1]) # test empty Range assert Range(x, x, y) == empty assert empty.reversed == empty assert 0 not in empty assert list(empty) == [] assert len(empty) == 0 assert empty.size is S.Zero assert empty.intersect(FiniteSet(0)) is S.EmptySet assert bool(empty) is False raises(IndexError, lambda: empty[0]) assert empty[:0] == empty raises(NotImplementedError, lambda: empty.inf) raises(NotImplementedError, lambda: empty.sup) AB = [None] + list(range(12)) for R in [ Range(1, 10), Range(1, 10, 2), ]: r = list(R) for a, b, c in cartes(AB, AB, [-3, -1, None, 1, 3]): for reverse in range(2): r = list(reversed(r)) R = R.reversed result = list(R[a:b:c]) ans = r[a:b:c] txt = ('\n%s[%s:%s:%s] = %s -> %s' % (R, a, b, c, result, ans)) check = ans == result assert check, txt assert Range(1, 10, 1).boundary == Range(1, 10, 1) for r in (Range(1, 10, 2), Range(1, oo, 2)): rev = r.reversed assert r.inf == rev.inf and r.sup == rev.sup assert r.step == -rev.step builtin_range = range raises(TypeError, lambda: Range(builtin_range(1))) assert S(builtin_range(10)) == Range(10) assert S(builtin_range(1000000000000)) == Range(1000000000000) # test Range.as_relational assert Range(1, 4).as_relational(x) == (x >= 1) & (x <= 3) & Eq(x, floor(x)) assert Range(oo, 1, -2).as_relational(x) == (x >= 3) & (x < oo) & Eq(x, floor(x))
def function_range(f, symbol, domain): """ Finds the range of a function in a given domain. This method is limited by the ability to determine the singularities and determine limits. Examples ======== >>> from sympy import Symbol, S, exp, log, pi, sqrt, sin, tan >>> from sympy.sets import Interval >>> from sympy.calculus.util import function_range >>> x = Symbol('x') >>> function_range(sin(x), x, Interval(0, 2*pi)) [-1, 1] >>> function_range(tan(x), x, Interval(-pi/2, pi/2)) (-oo, oo) >>> function_range(1/x, x, S.Reals) (-oo, oo) >>> function_range(exp(x), x, S.Reals) (0, oo) >>> function_range(log(x), x, S.Reals) (-oo, oo) >>> function_range(sqrt(x), x , Interval(-5, 9)) [0, 3] """ from sympy.solvers.solveset import solveset vals = S.EmptySet period = periodicity(f, symbol) if not any(period is i for i in (None, S.Zero)): inf = domain.inf inf_period = S.Zero if inf.is_infinite else inf sup_period = inf_period + period periodic_interval = Interval(inf_period, sup_period) domain = domain.intersect(periodic_interval) intervals = continuous_domain(f, symbol, domain) range_int = S.EmptySet if isinstance(intervals, Interval): interval_iter = (intervals, ) else: interval_iter = intervals.args for interval in interval_iter: critical_points = S.EmptySet critical_values = S.EmptySet bounds = ((interval.left_open, interval.inf, '+'), (interval.right_open, interval.sup, '-')) for is_open, limit_point, direction in bounds: if is_open: critical_values += FiniteSet( limit(f, symbol, limit_point, direction)) vals += critical_values else: vals += FiniteSet(f.subs(symbol, limit_point)) critical_points += solveset(f.diff(symbol), symbol, domain) for critical_point in critical_points: vals += FiniteSet(f.subs(symbol, critical_point)) left_open, right_open = False, False if critical_values is not S.EmptySet: if critical_values.inf == vals.inf: left_open = True if critical_values.sup == vals.sup: right_open = True range_int += Interval(vals.inf, vals.sup, left_open, right_open) return range_int
def test_not_empty_in(): assert not_empty_in(FiniteSet(x, 2*x).intersect(Interval(1, 2, True, False)), x) == \ Interval(S.Half, 2, True, False) assert not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x) == \ Union(Interval(-sqrt(2), -1), Interval(1, 2)) assert not_empty_in(FiniteSet(x**2 + x, x).intersect(Interval(2, 4)), x) == \ Union(Interval(-sqrt(17)/2 - S.Half, -2), Interval(1, Rational(-1, 2) + sqrt(17)/2), Interval(2, 4)) assert not_empty_in(FiniteSet(x/(x - 1)).intersect(S.Reals), x) == \ Complement(S.Reals, FiniteSet(1)) assert not_empty_in(FiniteSet(a/(a - 1)).intersect(S.Reals), a) == \ Complement(S.Reals, FiniteSet(1)) assert not_empty_in(FiniteSet((x**2 - 3*x + 2)/(x - 1)).intersect(S.Reals), x) == \ Complement(S.Reals, FiniteSet(1)) assert not_empty_in(FiniteSet(3, 4, x/(x - 1)).intersect(Interval(2, 3)), x) == \ Interval(-oo, oo) assert not_empty_in(FiniteSet(4, x/(x - 1)).intersect(Interval(2, 3)), x) == \ Interval(S(3)/2, 2) assert not_empty_in(FiniteSet(x/(x**2 - 1)).intersect(S.Reals), x) == \ Complement(S.Reals, FiniteSet(-1, 1)) assert not_empty_in(FiniteSet(x, x**2).intersect(Union(Interval(1, 3, True, True), Interval(4, 5))), x) == \ Union(Interval(-sqrt(5), -2), Interval(-sqrt(3), -1, True, True), Interval(1, 3, True, True), Interval(4, 5)) assert not_empty_in(FiniteSet(1).intersect(Interval(3, 4)), x) == S.EmptySet assert not_empty_in(FiniteSet(x**2/(x + 2)).intersect(Interval(1, oo)), x) == \ Union(Interval(-2, -1, True, False), Interval(2, oo)) raises(ValueError, lambda: not_empty_in(x)) raises(ValueError, lambda: not_empty_in(Interval(0, 1), x)) raises(NotImplementedError, lambda: not_empty_in(FiniteSet(x).intersect(S.Reals), x, a))
def normalize_theta_set(theta): """ Normalize a Real Set `theta` in the Interval [0, 2*pi). It returns a normalized value of theta in the Set. For Interval, a maximum of one cycle [0, 2*pi], is returned i.e. for theta equal to [0, 10*pi], returned normalized value would be [0, 2*pi). As of now intervals with end points as non-multiples of `pi` is not supported. Raises ====== NotImplementedError The algorithms for Normalizing theta Set are not yet implemented. ValueError The input is not valid, i.e. the input is not a real set. RuntimeError It is a bug, please report to the github issue tracker. Examples ======== >>> from sympy.sets.fancysets import normalize_theta_set >>> from sympy import Interval, FiniteSet, pi >>> normalize_theta_set(Interval(9*pi/2, 5*pi)) Interval(pi/2, pi) >>> normalize_theta_set(Interval(-3*pi/2, pi/2)) Interval.Ropen(0, 2*pi) >>> normalize_theta_set(Interval(-pi/2, pi/2)) Union(Interval(0, pi/2), Interval.Ropen(3*pi/2, 2*pi)) >>> normalize_theta_set(Interval(-4*pi, 3*pi)) Interval.Ropen(0, 2*pi) >>> normalize_theta_set(Interval(-3*pi/2, -pi/2)) Interval(pi/2, 3*pi/2) >>> normalize_theta_set(FiniteSet(0, pi, 3*pi)) FiniteSet(0, pi) """ from sympy.functions.elementary.trigonometric import _pi_coeff as coeff if theta.is_Interval: interval_len = theta.measure # one complete circle if interval_len >= 2 * S.Pi: if interval_len == 2 * S.Pi and theta.left_open and theta.right_open: k = coeff(theta.start) return Union( Interval(0, k * S.Pi, False, True), Interval(k * S.Pi, 2 * S.Pi, True, True), ) return Interval(0, 2 * S.Pi, False, True) k_start, k_end = coeff(theta.start), coeff(theta.end) if k_start is None or k_end is None: raise NotImplementedError( "Normalizing theta without pi as coefficient is " "not yet implemented") new_start = k_start * S.Pi new_end = k_end * S.Pi if new_start > new_end: return Union( Interval(S.Zero, new_end, False, theta.right_open), Interval(new_start, 2 * S.Pi, theta.left_open, True), ) else: return Interval(new_start, new_end, theta.left_open, theta.right_open) elif theta.is_FiniteSet: new_theta = [] for element in theta: k = coeff(element) if k is None: raise NotImplementedError("Normalizing theta without pi as " "coefficient, is not Implemented.") else: new_theta.append(k * S.Pi) return FiniteSet(*new_theta) elif theta.is_Union: return Union( *[normalize_theta_set(interval) for interval in theta.args]) elif theta.is_subset(S.Reals): raise NotImplementedError( "Normalizing theta when, it is of type %s is not " "implemented" % type(theta)) else: raise ValueError(" %s is not a real set" % (theta))
def _intersect(self, other): from sympy.solvers.diophantine import diophantine if self.base_set is S.Integers: g = None if isinstance(other, ImageSet) and other.base_set is S.Integers: g = other.lamda.expr m = other.lamda.variables[0] elif other is S.Integers: m = g = Dummy('x') if g is not None: f = self.lamda.expr n = self.lamda.variables[0] # Diophantine sorts the solutions according to the alphabetic # order of the variable names, since the result should not depend # on the variable name, they are replaced by the dummy variables # below a, b = Dummy('a'), Dummy('b') f, g = f.subs(n, a), g.subs(m, b) solns_set = diophantine(f - g) if solns_set == set(): return EmptySet() solns = list(diophantine(f - g)) if len(solns) != 1: return # since 'a' < 'b', select soln for n nsol = solns[0][0] t = nsol.free_symbols.pop() return imageset(Lambda(n, f.subs(a, nsol.subs(t, n))), S.Integers) if other == S.Reals: from sympy.solvers.solveset import solveset_real from sympy.core.function import expand_complex if len(self.lamda.variables) > 1: return None f = self.lamda.expr n = self.lamda.variables[0] n_ = Dummy(n.name, real=True) f_ = f.subs(n, n_) re, im = f_.as_real_imag() im = expand_complex(im) return imageset(Lambda(n_, re), self.base_set.intersect(solveset_real(im, n_))) elif isinstance(other, Interval): from sympy.solvers.solveset import (invert_real, invert_complex, solveset) f = self.lamda.expr n = self.lamda.variables[0] base_set = self.base_set new_inf, new_sup = None, None new_lopen, new_ropen = other.left_open, other.right_open if f.is_real: inverter = invert_real else: inverter = invert_complex g1, h1 = inverter(f, other.inf, n) g2, h2 = inverter(f, other.sup, n) if all(isinstance(i, FiniteSet) for i in (h1, h2)): if g1 == n: if len(h1) == 1: new_inf = h1.args[0] if g2 == n: if len(h2) == 1: new_sup = h2.args[0] # TODO: Design a technique to handle multiple-inverse # functions # Any of the new boundary values cannot be determined if any(i is None for i in (new_sup, new_inf)): return range_set = S.EmptySet if all(i.is_real for i in (new_sup, new_inf)): # this assumes continuity of underlying function # however fixes the case when it is decreasing if new_inf > new_sup: new_inf, new_sup = new_sup, new_inf new_interval = Interval(new_inf, new_sup, new_lopen, new_ropen) range_set = base_set._intersect(new_interval) else: if other.is_subset(S.Reals): solutions = solveset(f, n, S.Reals) if not isinstance(range_set, (ImageSet, ConditionSet)): range_set = solutions._intersect(other) else: return if range_set is S.EmptySet: return S.EmptySet elif isinstance(range_set, Range) and range_set.size is not S.Infinity: range_set = FiniteSet(*list(range_set)) if range_set is not None: return imageset(Lambda(n, f), range_set) return else: return
def test_AccumBounds_pow(): assert AccumBounds(0, 2)**2 == AccumBounds(0, 4) assert AccumBounds(-1, 1)**2 == AccumBounds(0, 1) assert AccumBounds(1, 2)**2 == AccumBounds(1, 4) assert AccumBounds(-1, 2)**3 == AccumBounds(-1, 8) assert AccumBounds(-1, 1)**0 == 1 assert AccumBounds(1, 2)**Rational(5, 2) == AccumBounds(1, 4 * sqrt(2)) assert AccumBounds(-1, 2)**Rational(1, 3) == AccumBounds(-1, 2**Rational(1, 3)) assert AccumBounds(0, 2)**S.Half == AccumBounds(0, sqrt(2)) assert AccumBounds(-4, 2)**Rational(2, 3) == AccumBounds(0, 2 * 2**Rational(1, 3)) assert AccumBounds(-1, 5)**S.Half == AccumBounds(0, sqrt(5)) assert AccumBounds(-oo, 2)**S.Half == AccumBounds(0, sqrt(2)) assert AccumBounds(-2, 3)**Rational(-1, 4) == AccumBounds(0, oo) assert AccumBounds(1, 5)**(-2) == AccumBounds(Rational(1, 25), 1) assert AccumBounds(-1, 3)**(-2) == AccumBounds(0, oo) assert AccumBounds(0, 2)**(-2) == AccumBounds(Rational(1, 4), oo) assert AccumBounds(-1, 2)**(-3) == AccumBounds(-oo, oo) assert AccumBounds(-3, -2)**(-3) == AccumBounds(Rational(-1, 8), Rational(-1, 27)) assert AccumBounds(-3, -2)**(-2) == AccumBounds(Rational(1, 9), Rational(1, 4)) assert AccumBounds(0, oo)**S.Half == AccumBounds(0, oo) assert AccumBounds(-oo, -1)**Rational(1, 3) == AccumBounds(-oo, -1) assert AccumBounds(-2, 3)**(Rational(-1, 3)) == AccumBounds(-oo, oo) assert AccumBounds(-oo, 0)**(-2) == AccumBounds(0, oo) assert AccumBounds(-2, 0)**(-2) == AccumBounds(Rational(1, 4), oo) assert AccumBounds(Rational(1, 3), S.Half)**oo is S.Zero assert AccumBounds(0, S.Half)**oo is S.Zero assert AccumBounds(S.Half, 1)**oo == AccumBounds(0, oo) assert AccumBounds(0, 1)**oo == AccumBounds(0, oo) assert AccumBounds(2, 3)**oo is oo assert AccumBounds(1, 2)**oo == AccumBounds(0, oo) assert AccumBounds(S.Half, 3)**oo == AccumBounds(0, oo) assert AccumBounds(Rational(-1, 3), Rational(-1, 4))**oo is S.Zero assert AccumBounds(-1, Rational(-1, 2))**oo == AccumBounds(-oo, oo) assert AccumBounds(-3, -2)**oo == FiniteSet(-oo, oo) assert AccumBounds(-2, -1)**oo == AccumBounds(-oo, oo) assert AccumBounds(-2, Rational(-1, 2))**oo == AccumBounds(-oo, oo) assert AccumBounds(Rational(-1, 2), S.Half)**oo is S.Zero assert AccumBounds(Rational(-1, 2), 1)**oo == AccumBounds(0, oo) assert AccumBounds(Rational(-2, 3), 2)**oo == AccumBounds(0, oo) assert AccumBounds(-1, 1)**oo == AccumBounds(-oo, oo) assert AccumBounds(-1, S.Half)**oo == AccumBounds(-oo, oo) assert AccumBounds(-1, 2)**oo == AccumBounds(-oo, oo) assert AccumBounds(-2, S.Half)**oo == AccumBounds(-oo, oo) assert AccumBounds(1, 2)**x == Pow(AccumBounds(1, 2), x) assert AccumBounds(2, 3)**(-oo) is S.Zero assert AccumBounds(0, 2)**(-oo) == AccumBounds(0, oo) assert AccumBounds(-1, 2)**(-oo) == AccumBounds(-oo, oo) assert (tan(x)**sin(2 * x)).subs(x, AccumBounds(0, pi / 2)) == Pow( AccumBounds(-oo, oo), AccumBounds(0, 1))
def function_range(f, symbol, domain): """ Finds the range of a function in a given domain. This method is limited by the ability to determine the singularities and determine limits. Examples ======== >>> from sympy import Symbol, S, exp, log, pi, sqrt, sin, tan >>> from sympy.sets import Interval >>> from sympy.calculus.util import function_range >>> x = Symbol('x') >>> function_range(sin(x), x, Interval(0, 2*pi)) Interval(-1, 1) >>> function_range(tan(x), x, Interval(-pi/2, pi/2)) Interval(-oo, oo) >>> function_range(1/x, x, S.Reals) Union(Interval.open(-oo, 0), Interval.open(0, oo)) >>> function_range(exp(x), x, S.Reals) Interval.open(0, oo) >>> function_range(log(x), x, S.Reals) Interval(-oo, oo) >>> function_range(sqrt(x), x , Interval(-5, 9)) Interval(0, 3) """ from sympy.solvers.solveset import solveset if isinstance(domain, EmptySet): return S.EmptySet period = periodicity(f, symbol) if period is S.Zero: # the expression is constant wrt symbol return FiniteSet(f.expand()) if period is not None: if isinstance(domain, Interval): if (domain.inf - domain.sup).is_infinite: domain = Interval(0, period) elif isinstance(domain, Union): for sub_dom in domain.args: if isinstance(sub_dom, Interval) and \ ((sub_dom.inf - sub_dom.sup).is_infinite): domain = Interval(0, period) intervals = continuous_domain(f, symbol, domain) range_int = S.EmptySet if isinstance(intervals, (Interval, FiniteSet)): interval_iter = (intervals, ) elif isinstance(intervals, Union): interval_iter = intervals.args else: raise NotImplementedError( filldedent(''' Unable to find range for the given domain. ''')) for interval in interval_iter: if isinstance(interval, FiniteSet): for singleton in interval: if singleton in domain: range_int += FiniteSet(f.subs(symbol, singleton)) elif isinstance(interval, Interval): vals = S.EmptySet critical_points = S.EmptySet critical_values = S.EmptySet bounds = ((interval.left_open, interval.inf, '+'), (interval.right_open, interval.sup, '-')) for is_open, limit_point, direction in bounds: if is_open: critical_values += FiniteSet( limit(f, symbol, limit_point, direction)) vals += critical_values else: vals += FiniteSet(f.subs(symbol, limit_point)) solution = solveset(f.diff(symbol), symbol, interval) if isinstance(solution, ConditionSet): raise NotImplementedError( 'Unable to find critical points for {}'.format(f)) critical_points += solution for critical_point in critical_points: vals += FiniteSet(f.subs(symbol, critical_point)) left_open, right_open = False, False if critical_values is not S.EmptySet: if critical_values.inf == vals.inf: left_open = True if critical_values.sup == vals.sup: right_open = True range_int += Interval(vals.inf, vals.sup, left_open, right_open) else: raise NotImplementedError( filldedent(''' Unable to find range for the given domain. ''')) return range_int
def test_Range_symbolic(): # symbolic Range sr = Range(x, y, t) i = Symbol('i', integer=True) ip = Symbol('i', integer=True, positive=True) ir = Range(i, i + 20, 2) inf = symbols('inf', infinite=True) # args assert sr.args == (x, y, t) assert ir.args == (i, i + 20, 2) # reversed raises(ValueError, lambda: sr.reversed) assert ir.reversed == Range(i + 18, i - 2, -2) # contains assert inf not in sr assert inf not in ir assert .1 not in sr assert .1 not in ir assert i + 1 not in ir assert i + 2 in ir raises(TypeError, lambda: 1 in sr) # XXX is this what contains is supposed to do? # iter raises(ValueError, lambda: next(iter(sr))) assert next(iter(ir)) == i assert sr.intersect(S.Integers) == sr assert sr.intersect(FiniteSet(x)) == Intersection({x}, sr) raises(ValueError, lambda: sr[:2]) raises(ValueError, lambda: sr[0]) raises(ValueError, lambda: sr.as_relational(x)) # len assert len(ir) == ir.size == 10 raises(ValueError, lambda: len(sr)) raises(ValueError, lambda: sr.size) # bool assert bool(ir) == bool(sr) == True # getitem raises(ValueError, lambda: sr[0]) raises(ValueError, lambda: sr[-1]) raises(ValueError, lambda: sr[:2]) assert ir[:2] == Range(i, i + 4, 2) assert ir[0] == i assert ir[-2] == i + 16 assert ir[-1] == i + 18 raises(ValueError, lambda: Range(i)[-1]) assert Range(ip)[-1] == ip - 1 assert ir.inf == i assert ir.sup == i + 18 assert Range(ip).inf == 0 assert Range(ip).sup == ip - 1 raises(ValueError, lambda: Range(i).inf) # as_relational raises(ValueError, lambda: sr.as_relational(x)) assert ir.as_relational(x) == (x >= i) & Eq(x, floor(x)) & (x <= i + 18) assert Range(i, i + 1).as_relational(x) == Eq(x, i) # contains() for symbolic values (issue #18146) e = Symbol('e', integer=True, even=True) o = Symbol('o', integer=True, odd=True) assert Range(5).contains(i) == And(i >= 0, i <= 4) assert Range(1).contains(i) == Eq(i, 0) assert Range(-oo, 5, 1).contains(i) == (i <= 4) assert Range(-oo, oo).contains(i) == True assert Range(0, 8, 2).contains(i) == Contains(i, Range(0, 8, 2)) assert Range(0, 8, 2).contains(e) == And(e >= 0, e <= 6) assert Range(0, 8, 2).contains(2 * i) == And(2 * i >= 0, 2 * i <= 6) assert Range(0, 8, 2).contains(o) == False assert Range(1, 9, 2).contains(e) == False assert Range(1, 9, 2).contains(o) == And(o >= 1, o <= 7) assert Range(8, 0, -2).contains(o) == False assert Range(9, 1, -2).contains(o) == And(o >= 3, o <= 9) assert Range(-oo, 8, 2).contains(i) == Contains(i, Range(-oo, 8, 2))
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 test_fun(): assert (FiniteSet( *ImageSet(Lambda(x, sin(pi * x / 4)), Range(-10, 11))) == FiniteSet( -1, -sqrt(2) / 2, 0, sqrt(2) / 2, 1))
def spaces(self): return FiniteSet(*self.args)
def test_ImageSet(): raises(ValueError, lambda: ImageSet(x, S.Integers)) assert ImageSet(Lambda(x, 1), S.Integers) == FiniteSet(1) assert ImageSet(Lambda(x, y), S.Integers) == {y} assert ImageSet(Lambda(x, 1), S.EmptySet) == S.EmptySet empty = Intersection(FiniteSet(log(2) / pi), S.Integers) assert unchanged(ImageSet, Lambda(x, 1), empty) # issue #17471 squares = ImageSet(Lambda(x, x**2), S.Naturals) assert 4 in squares assert 5 not in squares assert FiniteSet(*range(10)).intersect(squares) == FiniteSet(1, 4, 9) assert 16 not in squares.intersect(Interval(0, 10)) si = iter(squares) a, b, c, d = next(si), next(si), next(si), next(si) assert (a, b, c, d) == (1, 4, 9, 16) harmonics = ImageSet(Lambda(x, 1 / x), S.Naturals) assert Rational(1, 5) in harmonics assert Rational(.25) in harmonics assert 0.25 not in harmonics assert Rational(.3) not in harmonics assert (1, 2) not in harmonics assert harmonics.is_iterable assert imageset(x, -x, Interval(0, 1)) == Interval(-1, 0) assert ImageSet(Lambda(x, x**2), Interval(0, 2)).doit() == Interval(0, 4) assert ImageSet(Lambda((x, y), 2 * x), {4}, {3}).doit() == FiniteSet(8) assert (ImageSet(Lambda((x, y), x + y), {1, 2, 3}, {10, 20, 30}).doit() == FiniteSet(11, 12, 13, 21, 22, 23, 31, 32, 33)) c = Interval(1, 3) * Interval(1, 3) assert Tuple(2, 6) in ImageSet(Lambda(((x, y), ), (x, 2 * y)), c) assert Tuple(2, S.Half) in ImageSet(Lambda(((x, y), ), (x, 1 / y)), c) assert Tuple(2, -2) not in ImageSet(Lambda(((x, y), ), (x, y**2)), c) assert Tuple(2, -2) in ImageSet(Lambda(((x, y), ), (x, -2)), c) c3 = ProductSet(Interval(3, 7), Interval(8, 11), Interval(5, 9)) assert Tuple(8, 3, 9) in ImageSet(Lambda(((t, y, x), ), (y, t, x)), c3) assert Tuple(Rational(1, 8), 3, 9) in ImageSet(Lambda(((t, y, x), ), (1 / y, t, x)), c3) assert 2 / pi not in ImageSet(Lambda(((x, y), ), 2 / x), c) assert 2 / S(100) not in ImageSet(Lambda(((x, y), ), 2 / x), c) assert Rational(2, 3) in ImageSet(Lambda(((x, y), ), 2 / x), c) S1 = imageset(lambda x, y: x + y, S.Integers, S.Naturals) assert S1.base_pset == ProductSet(S.Integers, S.Naturals) assert S1.base_sets == (S.Integers, S.Naturals) # Passing a set instead of a FiniteSet shouldn't raise assert unchanged(ImageSet, Lambda(x, x**2), {1, 2, 3}) S2 = ImageSet(Lambda(((x, y), ), x + y), {(1, 2), (3, 4)}) assert 3 in S2.doit() # FIXME: This doesn't yet work: #assert 3 in S2 assert S2._contains(3) is None raises(TypeError, lambda: ImageSet(Lambda(x, x**2), 1))
def symbols(self): return FiniteSet( *[sym for domain in self.domains for sym in domain.symbols])
def test_ComplexRegion_from_real(): c1 = ComplexRegion(Interval(0, 1) * Interval(0, 2 * S.Pi), polar=True) raises(ValueError, lambda: c1.from_real(c1)) assert c1.from_real(Interval(-1, 1)) == ComplexRegion( Interval(-1, 1) * FiniteSet(0), False)
def elements(self): return FiniteSet(*self)
def test_normalize_theta_set(): # Interval assert normalize_theta_set(Interval(pi, 2*pi)) == \ Union(FiniteSet(0), Interval.Ropen(pi, 2*pi)) assert normalize_theta_set(Interval(pi * Rational(9, 2), 5 * pi)) == Interval(pi / 2, pi) assert normalize_theta_set(Interval(pi * Rational(-3, 2), pi / 2)) == Interval.Ropen(0, 2 * pi) assert normalize_theta_set(Interval.open(pi*Rational(-3, 2), pi/2)) == \ Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi)) assert normalize_theta_set(Interval.open(pi*Rational(-7, 2), pi*Rational(-3, 2))) == \ Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi)) assert normalize_theta_set(Interval(-pi/2, pi/2)) == \ Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval.open(-pi/2, pi/2)) == \ Union(Interval.Ropen(0, pi/2), Interval.open(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval(-4 * pi, 3 * pi)) == Interval.Ropen(0, 2 * pi) assert normalize_theta_set(Interval(pi * Rational(-3, 2), -pi / 2)) == Interval( pi / 2, pi * Rational(3, 2)) assert normalize_theta_set(Interval.open(0, 2 * pi)) == Interval.open( 0, 2 * pi) assert normalize_theta_set(Interval.Ropen(-pi/2, pi/2)) == \ Union(Interval.Ropen(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval.Lopen(-pi/2, pi/2)) == \ Union(Interval(0, pi/2), Interval.open(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval(-pi/2, pi/2)) == \ Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval.open( 4 * pi, pi * Rational(9, 2))) == Interval.open(0, pi / 2) assert normalize_theta_set(Interval.Lopen( 4 * pi, pi * Rational(9, 2))) == Interval.Lopen(0, pi / 2) assert normalize_theta_set(Interval.Ropen( 4 * pi, pi * Rational(9, 2))) == Interval.Ropen(0, pi / 2) assert normalize_theta_set(Interval.open(3*pi, 5*pi)) == \ Union(Interval.Ropen(0, pi), Interval.open(pi, 2*pi)) # FiniteSet assert normalize_theta_set(FiniteSet(0, pi, 3 * pi)) == FiniteSet(0, pi) assert normalize_theta_set(FiniteSet(0, pi / 2, pi, 2 * pi)) == FiniteSet(0, pi / 2, pi) assert normalize_theta_set(FiniteSet(0, -pi / 2, -pi, -2 * pi)) == FiniteSet( 0, pi, pi * Rational(3, 2)) assert normalize_theta_set(FiniteSet(pi*Rational(-3, 2), pi/2)) == \ FiniteSet(pi/2) assert normalize_theta_set(FiniteSet(2 * pi)) == FiniteSet(0) # Unions assert normalize_theta_set(Union(Interval(0, pi/3), Interval(pi/2, pi))) == \ Union(Interval(0, pi/3), Interval(pi/2, pi)) assert normalize_theta_set(Union(Interval(0, pi), Interval(2*pi, pi*Rational(7, 3)))) == \ Interval(0, pi) # ValueError for non-real sets raises(ValueError, lambda: normalize_theta_set(S.Complexes)) # NotImplementedError for subset of reals raises(NotImplementedError, lambda: normalize_theta_set(Interval(0, 1))) # NotImplementedError without pi as coefficient raises(NotImplementedError, lambda: normalize_theta_set(Interval(1, 2 * pi))) raises(NotImplementedError, lambda: normalize_theta_set(Interval(2 * pi, 10))) raises(NotImplementedError, lambda: normalize_theta_set(FiniteSet(0, 3, 3 * pi)))
def symbols(self): return FiniteSet(sym for sym, val in self.elements)
def normalize_theta_set(theta): """ Normalize a Real Set theta in the Interval [0, 2*pi). It currently supports Interval and FiniteSet. It Returns a the normalized value of theta in the Set. For Interval, a maximum of one cycle [0, 2*pi], is returned i.e. for theta equal to [0, 10*pi], returned normalized value would be [0, 2*pi). As of now it supports theta as FiniteSet and Interval. Raises ====== NotImplementedError The algorithms for Normalizing theta Set are not yet implemented. ValueError The input is not valid, i.e. the input is not a real set. RuntimeError It is a bug, please report to the github issue tracker. Examples ======== >>> from sympy.sets.fancysets import normalize_theta_set >>> from sympy import Interval, FiniteSet, pi >>> normalize_theta_set(Interval(9*pi/2, 5*pi)) [pi/2, pi] >>> normalize_theta_set(Interval(-3*pi/2, pi/2)) [0, 2*pi) >>> normalize_theta_set(Interval(-pi/2, pi/2)) [0, pi/2] U [3*pi/2, 2*pi) >>> normalize_theta_set(Interval(-4*pi, 3*pi)) [0, 2*pi) >>> normalize_theta_set(Interval(-3*pi/2, -pi/2)) [pi/2, 3*pi/2] >>> normalize_theta_set(FiniteSet(0, pi, 3*pi)) {0, pi} """ from sympy.functions.elementary.trigonometric import _pi_coeff as coeff from sympy.functions.elementary.complexes import Abs if theta.is_Interval: # one complete circle if Abs(theta.args[0] - theta.args[1]) >= 2 * S.Pi: return Interval(0, 2 * S.Pi, False, True) new_theta = [] for val in [theta.args[0], theta.args[1]]: k = coeff(val) if (not k) and (k != S.Zero): raise NotImplementedError('Normalizing theta without pi as' 'coefficient, is not Implemented.') elif k == S.Zero: if val == S.Zero: new_theta.append(S.Zero) else: # when theta is n*pi new_theta.append(2 * S.Pi) else: new_theta.append(k * S.Pi) # for negative theta if new_theta[0] > new_theta[1]: return Union(Interval(S(0), new_theta[1]), Interval(new_theta[0], 2 * S.Pi, False, True)) else: return Interval(*new_theta) elif theta.is_FiniteSet: new_theta = [] for element in theta: k = coeff(element) if (not k) and (k != S.Zero): raise NotImplementedError('Normalizing theta without pi as' 'coefficient, is not Implemented.') elif k == S.Zero: if element == S.Zero: new_theta.append(S.Zero) else: new_theta.append(k * S.Pi) return FiniteSet(*new_theta) elif theta.is_subset(S.Reals): raise NotImplementedError("Normalizing theta when, its %s is not" "Implemented" % type(theta)) else: raise ValueError(" %s is not a real set" % (theta))
def __new__(cls, symbol, set): if not isinstance(set, FiniteSet): set = FiniteSet(*set) return Basic.__new__(cls, symbol, set)
def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals, continuous=False): """Solves a real univariate inequality. Parameters ========== expr : Relational The target inequality gen : Symbol The variable for which the inequality is solved relational : bool A Relational type output is expected or not domain : Set The domain over which the equation is solved continuous: bool True if expr is known to be continuous over the given domain (and so continuous_domain() doesn't need to be called on it) Raises ====== NotImplementedError The solution of the inequality cannot be determined due to limitation in `solvify`. Notes ===== Currently, we cannot solve all the inequalities due to limitations in `solvify`. Also, the solution returned for trigonometric inequalities are restricted in its periodic interval. See Also ======== solvify: solver returning solveset solutions with solve's output API Examples ======== >>> from sympy.solvers.inequalities import solve_univariate_inequality >>> from sympy import Symbol, sin, Interval, S >>> x = Symbol('x') >>> solve_univariate_inequality(x**2 >= 4, x) ((2 <= x) & (x < oo)) | ((x <= -2) & (-oo < x)) >>> solve_univariate_inequality(x**2 >= 4, x, relational=False) Union(Interval(-oo, -2, True), Interval(2, oo, False, True)) >>> domain = Interval(0, S.Infinity) >>> solve_univariate_inequality(x**2 >= 4, x, False, domain) Interval(2, oo, False, True) >>> solve_univariate_inequality(sin(x) > 0, x, relational=False) Interval(0, pi, True, True) """ from sympy.calculus.util import (continuous_domain, periodicity, function_range) from sympy.solvers.solvers import denoms from sympy.solvers.solveset import solveset_real, solvify # This keeps the function independent of the assumptions about `gen`. # `solveset` makes sure this function is called only when the domain is # real. d = Dummy(real=True) expr = expr.subs(gen, d) _gen = gen gen = d rv = None if expr is S.true: rv = domain elif expr is S.false: rv = S.EmptySet else: e = expr.lhs - expr.rhs period = periodicity(e, gen) if period is not None: frange = function_range(e, gen, domain) rel = expr.rel_op if rel == '<' or rel == '<=': if expr.func(frange.sup, 0): rv = domain elif not expr.func(frange.inf, 0): rv = S.EmptySet elif rel == '>' or rel == '>=': if expr.func(frange.inf, 0): rv = domain elif not expr.func(frange.sup, 0): rv = S.EmptySet inf, sup = domain.inf, domain.sup if sup - inf is S.Infinity: domain = Interval(0, period, False, True) if rv is None: solns = solvify(e, gen, domain) if solns is None: raise NotImplementedError( filldedent('''The inequality cannot be solved using solve_univariate_inequality.''')) singularities = [] for d in denoms(expr, gen): singularities.extend(solvify(d, gen, domain)) if not continuous: domain = continuous_domain(e, gen, domain) include_x = expr.func(0, 0) def valid(x): v = e.subs(gen, x) try: r = expr.func(v, 0) except TypeError: r = S.false if r in (S.true, S.false): return r if v.is_real is False: return S.false else: v = v.n(2) if v.is_comparable: return expr.func(v, 0) return S.false try: discontinuities = set(domain.boundary - FiniteSet(domain.inf, domain.sup)) # remove points that are not between inf and sup of domain critical_points = FiniteSet( *(solns + singularities + list(discontinuities))).intersection( Interval(domain.inf, domain.sup, domain.inf not in domain, domain.sup not in domain)) reals = _nsort(critical_points, separated=True)[0] except NotImplementedError: raise NotImplementedError( 'sorting of these roots is not supported') sol_sets = [S.EmptySet] start = domain.inf if valid(start) and start.is_finite: sol_sets.append(FiniteSet(start)) for x in reals: end = x if valid(_pt(start, end)): sol_sets.append(Interval(start, end, True, True)) if x in singularities: singularities.remove(x) else: if x in discontinuities: discontinuities.remove(x) _valid = valid(x) else: # it's a solution _valid = include_x if _valid: sol_sets.append(FiniteSet(x)) start = end end = domain.sup if valid(end) and end.is_finite: sol_sets.append(FiniteSet(end)) if valid(_pt(start, end)): sol_sets.append(Interval.open(start, end)) rv = Union(*sol_sets).subs(gen, _gen) return rv if not relational else rv.as_relational(_gen)
def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals, continuous=False): """Solves a real univariate inequality. Parameters ========== expr : Relational The target inequality gen : Symbol The variable for which the inequality is solved relational : bool A Relational type output is expected or not domain : Set The domain over which the equation is solved continuous: bool True if expr is known to be continuous over the given domain (and so continuous_domain() doesn't need to be called on it) Raises ====== NotImplementedError The solution of the inequality cannot be determined due to limitation in `solvify`. Notes ===== Currently, we cannot solve all the inequalities due to limitations in `solvify`. Also, the solution returned for trigonometric inequalities are restricted in its periodic interval. See Also ======== solvify: solver returning solveset solutions with solve's output API Examples ======== >>> from sympy.solvers.inequalities import solve_univariate_inequality >>> from sympy import Symbol, sin, Interval, S >>> x = Symbol('x') >>> solve_univariate_inequality(x**2 >= 4, x) ((2 <= x) & (x < oo)) | ((x <= -2) & (-oo < x)) >>> solve_univariate_inequality(x**2 >= 4, x, relational=False) Union(Interval(-oo, -2), Interval(2, oo)) >>> domain = Interval(0, S.Infinity) >>> solve_univariate_inequality(x**2 >= 4, x, False, domain) Interval(2, oo) >>> solve_univariate_inequality(sin(x) > 0, x, relational=False) Interval.open(0, pi) """ from sympy import im from sympy.calculus.util import (continuous_domain, periodicity, function_range) from sympy.solvers.solvers import denoms from sympy.solvers.solveset import solveset_real, solvify, solveset from sympy.solvers.solvers import solve # This keeps the function independent of the assumptions about `gen`. # `solveset` makes sure this function is called only when the domain is # real. _gen = gen _domain = domain if gen.is_extended_real is False: rv = S.EmptySet return rv if not relational else rv.as_relational(_gen) elif gen.is_extended_real is None: gen = Dummy('gen', extended_real=True) try: expr = expr.xreplace({_gen: gen}) except TypeError: raise TypeError( filldedent(''' When gen is real, the relational has a complex part which leads to an invalid comparison like I < 0. ''')) rv = None if expr is S.true: rv = domain elif expr is S.false: rv = S.EmptySet else: e = expr.lhs - expr.rhs period = periodicity(e, gen) if period is S.Zero: e = expand_mul(e) const = expr.func(e, 0) if const is S.true: rv = domain elif const is S.false: rv = S.EmptySet elif period is not None: frange = function_range(e, gen, domain) rel = expr.rel_op if rel == '<' or rel == '<=': if expr.func(frange.sup, 0): rv = domain elif not expr.func(frange.inf, 0): rv = S.EmptySet elif rel == '>' or rel == '>=': if expr.func(frange.inf, 0): rv = domain elif not expr.func(frange.sup, 0): rv = S.EmptySet inf, sup = domain.inf, domain.sup if sup - inf is S.Infinity: domain = Interval(0, period, False, True) if rv is None: n, d = e.as_numer_denom() try: if gen not in n.free_symbols and len(e.free_symbols) > 1: raise ValueError # this might raise ValueError on its own # or it might give None... solns = solvify(e, gen, domain) if solns is None: # in which case we raise ValueError raise ValueError except (ValueError, NotImplementedError): # replace gen with generic x since it's # univariate anyway raise NotImplementedError( filldedent(''' The inequality, %s, cannot be solved using solve_univariate_inequality. ''' % expr.subs(gen, Symbol('x')))) expanded_e = expand_mul(e) def valid(x): # this is used to see if gen=x satisfies the # relational by substituting it into the # expanded form and testing against 0, e.g. # if expr = x*(x + 1) < 2 then e = x*(x + 1) - 2 # and expanded_e = x**2 + x - 2; the test is # whether a given value of x satisfies # x**2 + x - 2 < 0 # # expanded_e, expr and gen used from enclosing scope v = expanded_e.subs(gen, expand_mul(x)) try: r = expr.func(v, 0) except TypeError: r = S.false if r in (S.true, S.false): return r if v.is_extended_real is False: return S.false else: v = v.n(2) if v.is_comparable: return expr.func(v, 0) # not comparable or couldn't be evaluated raise NotImplementedError( 'relationship did not evaluate: %s' % r) singularities = [] for d in denoms(expr, gen): singularities.extend(solvify(d, gen, domain)) if not continuous: domain = continuous_domain(expanded_e, gen, domain) include_x = '=' in expr.rel_op and expr.rel_op != '!=' try: discontinuities = set(domain.boundary - FiniteSet(domain.inf, domain.sup)) # remove points that are not between inf and sup of domain critical_points = FiniteSet( *(solns + singularities + list(discontinuities))).intersection( Interval(domain.inf, domain.sup, domain.inf not in domain, domain.sup not in domain)) if all(r.is_number for r in critical_points): reals = _nsort(critical_points, separated=True)[0] else: sifted = sift(critical_points, lambda x: x.is_extended_real) if sifted[None]: # there were some roots that weren't known # to be real raise NotImplementedError try: reals = sifted[True] if len(reals) > 1: reals = list(sorted(reals)) except TypeError: raise NotImplementedError except NotImplementedError: raise NotImplementedError( 'sorting of these roots is not supported') # If expr contains imaginary coefficients, only take real # values of x for which the imaginary part is 0 make_real = S.Reals if im(expanded_e) != S.Zero: check = True im_sol = FiniteSet() try: a = solveset(im(expanded_e), gen, domain) if not isinstance(a, Interval): for z in a: if z not in singularities and valid( z) and z.is_extended_real: im_sol += FiniteSet(z) else: start, end = a.inf, a.sup for z in _nsort(critical_points + FiniteSet(end)): valid_start = valid(start) if start != end: valid_z = valid(z) pt = _pt(start, z) if pt not in singularities and pt.is_extended_real and valid( pt): if valid_start and valid_z: im_sol += Interval(start, z) elif valid_start: im_sol += Interval.Ropen(start, z) elif valid_z: im_sol += Interval.Lopen(start, z) else: im_sol += Interval.open(start, z) start = z for s in singularities: im_sol -= FiniteSet(s) except (TypeError): im_sol = S.Reals check = False if isinstance(im_sol, EmptySet): raise ValueError( filldedent(''' %s contains imaginary parts which cannot be made 0 for any value of %s satisfying the inequality, leading to relations like I < 0. ''' % (expr.subs(gen, _gen), _gen))) make_real = make_real.intersect(im_sol) sol_sets = [S.EmptySet] start = domain.inf if valid(start) and start.is_finite: sol_sets.append(FiniteSet(start)) for x in reals: end = x if valid(_pt(start, end)): sol_sets.append(Interval(start, end, True, True)) if x in singularities: singularities.remove(x) else: if x in discontinuities: discontinuities.remove(x) _valid = valid(x) else: # it's a solution _valid = include_x if _valid: sol_sets.append(FiniteSet(x)) start = end end = domain.sup if valid(end) and end.is_finite: sol_sets.append(FiniteSet(end)) if valid(_pt(start, end)): sol_sets.append(Interval.open(start, end)) if im(expanded_e) != S.Zero and check: rv = (make_real).intersect(_domain) else: rv = Intersection((Union(*sol_sets)), make_real, _domain).subs(gen, _gen) return rv if not relational else rv.as_relational(_gen)
def test_powerset__iter__(): a = PowerSet(FiniteSet(1, 2)).__iter__() assert next(a) == S.EmptySet assert next(a) == FiniteSet(1) assert next(a) == FiniteSet(2) assert next(a) == FiniteSet(1, 2) a = PowerSet(S.Naturals).__iter__() assert next(a) == S.EmptySet assert next(a) == FiniteSet(1) assert next(a) == FiniteSet(2) assert next(a) == FiniteSet(1, 2) assert next(a) == FiniteSet(3) assert next(a) == FiniteSet(1, 3) assert next(a) == FiniteSet(2, 3) assert next(a) == FiniteSet(1, 2, 3)