def test_function_range(): x, y, a, b = symbols('x y a b') assert function_range(sin(x), x, Interval(-pi/2, pi/2)) == Interval(-1, 1) assert function_range(sin(x), x, Interval(0, pi)) == Interval(0, 1) assert function_range(tan(x), x, Interval(0, pi)) == Interval(-oo, oo) assert function_range(tan(x), x, Interval(pi/2, pi)) == Interval(-oo, 0) assert function_range((x + 3)/(x - 2), x, Interval(-5, 5)) == Interval(-oo, oo) assert function_range(1/(x**2), x, Interval(-1, 1)) == Interval(1, oo) assert function_range(exp(x), x, Interval(-1, 1)) == Interval(exp(-1), exp(1)) assert function_range(log(x) - x, x, S.Reals) == Interval(-oo, -1) assert function_range(sqrt(3*x - 1), x, Interval(0, 2)) == Interval(0, sqrt(5)) raises(NotImplementedError, lambda : function_range(exp(x)*(sin(x)-cos(x))/2 - x, x, S.Reals))
def test_function_range(): x = Symbol('x') assert function_range(sin(x), x, Interval(-pi/2, pi/2)) == Interval(-1, 1) assert function_range(sin(x), x, Interval(0, pi)) == Interval(0, 1) assert function_range(tan(x), x, Interval(0, pi)) == Interval(-oo, oo) assert function_range(tan(x), x, Interval(pi/2, pi)) == Interval(-oo, 0) assert function_range((x + 3)/(x - 2), x, Interval(-5, 5)) == Interval(-oo, oo) assert function_range(1/(x**2), x, Interval(-1, 1)) == Interval(1, oo) assert function_range(exp(x), x, Interval(-1, 1)) == Interval(exp(-1), exp(1)) assert function_range(log(x) - x, x, S.Reals) == Interval(-oo, -1) assert function_range(sqrt(3*x - 1), x, Interval(0, 2)) == Interval(0, sqrt(5))
def range(self): result = function_range(self.symexpr, symX, sympy.Reals) if isinstance(result, sympy.FiniteSet): return FiniteReal(*[float(x) for x in result.args]) pos_inf = FiniteReal(oo) if result.right == oo else EmptySet neg_inf = FiniteReal(-oo) if result.left == -oo else EmptySet return make_union(convert_sympy(result), pos_inf, neg_inf)
def test_function_range(): x, y, a, b = symbols('x y a b') assert function_range(sin(x), x, Interval(-pi / 2, pi / 2)) == Interval(-1, 1) assert function_range(sin(x), x, Interval(0, pi)) == Interval(0, 1) assert function_range(tan(x), x, Interval(0, pi)) == Interval(-oo, oo) assert function_range(tan(x), x, Interval(pi / 2, pi)) == Interval(-oo, 0) assert function_range((x + 3) / (x - 2), x, Interval(-5, 5)) == Interval(-oo, oo) assert function_range(1 / (x**2), x, Interval(-1, 1)) == Interval(1, oo) assert function_range(exp(x), x, Interval(-1, 1)) == Interval(exp(-1), exp(1)) assert function_range(log(x) - x, x, S.Reals) == Interval(-oo, -1) assert function_range(sqrt(3 * x - 1), x, Interval(0, 2)) == Interval(0, sqrt(5)) raises( NotImplementedError, lambda: function_range(exp(x) * (sin(x) - cos(x)) / 2 - x, x, S.Reals))
def test_function_range(): x = Symbol('x') assert function_range(sin(x), x, Interval(-pi / 2, pi / 2)) == Interval(-1, 1) assert function_range(sin(x), x, Interval(0, pi)) == Interval(0, 1) assert function_range(tan(x), x, Interval(0, pi)) == Interval(-oo, oo) assert function_range(tan(x), x, Interval(pi / 2, pi)) == Interval(-oo, 0) assert function_range((x + 3) / (x - 2), x, Interval(-5, 5)) == Interval(-oo, oo) assert function_range(1 / (x**2), x, Interval(-1, 1)) == Interval(1, oo) assert function_range(exp(x), x, Interval(-1, 1)) == Interval(exp(-1), exp(1)) assert function_range(log(x) - x, x, S.Reals) == Interval(-oo, -1) assert function_range(sqrt(3 * x - 1), x, Interval(0, 2)) == Interval(0, sqrt(5))
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_real is False: rv = S.EmptySet return rv if not relational else rv.as_relational(_gen) elif gen.is_real is None: gen = Dummy('gen', 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_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: from sympy.utilities.iterables import sift sifted = sift(critical_points, lambda x: x.is_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_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_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) empty = 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_issue_16469(): x = Symbol("x", real=True) f = abs(x) assert function_range(f, x, S.Reals) == Interval(0, oo, False, True)
def test_function_range(): x, y, a, b = symbols('x y a b') assert function_range(sin(x), x, Interval(-pi/2, pi/2) ) == Interval(-1, 1) assert function_range(sin(x), x, Interval(0, pi) ) == Interval(0, 1) assert function_range(tan(x), x, Interval(0, pi) ) == Interval(-oo, oo) assert function_range(tan(x), x, Interval(pi/2, pi) ) == Interval(-oo, 0) assert function_range((x + 3)/(x - 2), x, Interval(-5, 5) ) == Union(Interval(-oo, Rational(2, 7)), Interval(Rational(8, 3), oo)) assert function_range(1/(x**2), x, Interval(-1, 1) ) == Interval(1, oo) assert function_range(exp(x), x, Interval(-1, 1) ) == Interval(exp(-1), exp(1)) assert function_range(log(x) - x, x, S.Reals ) == Interval(-oo, -1) assert function_range(sqrt(3*x - 1), x, Interval(0, 2) ) == Interval(0, sqrt(5)) assert function_range(x*(x - 1) - (x**2 - x), x, S.Reals ) == FiniteSet(0) assert function_range(x*(x - 1) - (x**2 - x) + y, x, S.Reals ) == FiniteSet(y) assert function_range(sin(x), x, Union(Interval(-5, -3), FiniteSet(4)) ) == Union(Interval(-sin(3), 1), FiniteSet(sin(4))) assert function_range(cos(x), x, Interval(-oo, -4) ) == Interval(-1, 1) assert function_range(cos(x), x, S.EmptySet) == S.EmptySet raises(NotImplementedError, lambda : function_range( exp(x)*(sin(x) - cos(x))/2 - x, x, S.Reals)) raises(NotImplementedError, lambda : function_range( sin(x) + x, x, S.Reals)) # issue 13273 raises(NotImplementedError, lambda : function_range( log(x), x, S.Integers)) raises(NotImplementedError, lambda : function_range( sin(x)/2, x, S.Naturals))
def test_function_range(): x, y, a, b = symbols('x y a b') assert function_range(sin(x), x, Interval(-pi/2, pi/2) ) == Interval(-1, 1) assert function_range(sin(x), x, Interval(0, pi) ) == Interval(0, 1) assert function_range(tan(x), x, Interval(0, pi) ) == Interval(-oo, oo) assert function_range(tan(x), x, Interval(pi/2, pi) ) == Interval(-oo, 0) assert function_range((x + 3)/(x - 2), x, Interval(-5, 5) ) == Union(Interval(-oo, 2/7), Interval(8/3, oo)) assert function_range(1/(x**2), x, Interval(-1, 1) ) == Interval(1, oo) assert function_range(exp(x), x, Interval(-1, 1) ) == Interval(exp(-1), exp(1)) assert function_range(log(x) - x, x, S.Reals ) == Interval(-oo, -1) assert function_range(sqrt(3*x - 1), x, Interval(0, 2) ) == Interval(0, sqrt(5)) assert function_range(x*(x - 1) - (x**2 - x), x, S.Reals ) == FiniteSet(0) assert function_range(x*(x - 1) - (x**2 - x) + y, x, S.Reals ) == FiniteSet(y) assert function_range(sin(x), x, Union(Interval(-5, -3), FiniteSet(4)) ) == Union(Interval(-sin(3), 1), FiniteSet(sin(4))) assert function_range(cos(x), x, Interval(-oo, -4) ) == Interval(-1, 1) raises(NotImplementedError, lambda : function_range( exp(x)*(sin(x) - cos(x))/2 - x, x, S.Reals)) raises(NotImplementedError, lambda : function_range( log(x), x, S.Integers)) raises(NotImplementedError, lambda : function_range( sin(x)/2, x, S.Naturals))
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_real is False: rv = S.EmptySet return rv if not relational else rv.as_relational(_gen) elif gen.is_real is None: gen = Dummy('gen', 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 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): raise NotImplementedError(filldedent(''' The inequality cannot be solved using solve_univariate_inequality. ''')) 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, 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) # 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(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: from sympy.utilities.iterables import sift sifted = sift(critical_points, lambda x: x.is_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 real values of x for which the imaginary part is 0 are taken 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_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_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) empty = 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 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) (-oo, -2] U [2, oo) >>> domain = Interval(0, S.Infinity) >>> solve_univariate_inequality(x**2 >= 4, x, False, domain) [2, oo) >>> solve_univariate_inequality(sin(x) > 0, x, relational=False) (0, pi) """ 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: singularities = [] for d in denoms(e): singularities.extend(solvify(d, gen, domain)) if not continuous: domain = continuous_domain(e, gen, domain) solns = solvify(e, gen, domain) if solns is None: raise NotImplementedError( filldedent('''The inequality cannot be solved using solve_univariate_inequality.''')) 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 start = domain.inf sol_sets = [S.EmptySet] try: discontinuities = domain.boundary - FiniteSet( domain.inf, domain.sup) critical_points = set(solns + singularities + list(discontinuities)) reals = _nsort(critical_points, separated=True)[0] except NotImplementedError: raise NotImplementedError( 'sorting of these roots is not supported') if valid(start) and start.is_finite: sol_sets.append(FiniteSet(start)) for x in reals: end = x if end in [S.NegativeInfinity, S.Infinity]: if valid(S(0)): sol_sets.append(Interval(start, S.Infinity, True, True)) break pt = ((start + end) / 2 if start is not S.NegativeInfinity else (end / 2 if end.is_positive else (2 * end if end.is_negative else end - 1))) if valid(pt): sol_sets.append(Interval(start, end, True, True)) if x in singularities: singularities.remove(x) elif include_x: sol_sets.append(FiniteSet(x)) start = end end = domain.sup # in case start == -oo then there were no solutions so we just # check a point between -oo and oo (e.g. 0) else pick a point # past the last solution (which is start after the end of the # for-loop above pt = (0 if start is S.NegativeInfinity else (start / 2 if start.is_negative else (2 * start if start.is_positive else start + 1))) if pt >= end: pt = (start + end) / 2 if valid(pt): sol_sets.append(Interval(start, end, True, True)) rv = Union(*sol_sets).subs(gen, _gen) return rv if not relational else rv.as_relational(_gen)
def solve_decomposition(f, symbol, domain): """ Function to solve equations via the principle of "Decomposition and Rewriting". Examples ======== >>> from sympy import exp, sin, Symbol, pprint, S >>> from sympy.solvers.solveset import solve_decomposition as sd >>> x = Symbol('x') >>> f1 = exp(2*x) - 3*exp(x) + 2 >>> sd(f1, x, S.Reals) {0, log(2)} >>> f2 = sin(x)**2 + 2*sin(x) + 1 >>> pprint(sd(f2, x, S.Reals), use_unicode=False) 3*pi {2*n*pi + ---- | n in Integers()} 2 >>> f3 = sin(x + 2) >>> pprint(sd(f3, x, S.Reals), use_unicode=False) {2*n*pi - 2 | n in Integers()} U {pi*(2*n + 1) - 2 | n in Integers()} """ from sympy.solvers.decompogen import decompogen from sympy.calculus.util import function_range # decompose the given function g_s = decompogen(f, symbol) # `y_s` represents the set of values for which the function `g` is to be # solved. # `solutions` represent the solutions of the equations `g = y_s` or # `g = 0` depending on the type of `y_s`. # As we are interested in solving the equation: f = 0 y_s = FiniteSet(0) for g in g_s: frange = function_range(g, symbol, domain) y_s = Intersection(frange, y_s) result = S.EmptySet if isinstance(y_s, FiniteSet): for y in y_s: solutions = solveset(Eq(g, y), symbol, domain) if not isinstance(solutions, ConditionSet): result += solutions else: if isinstance(y_s, ImageSet): iter_iset = (y_s,) elif isinstance(y_s, Union): iter_iset = y_s.args for iset in iter_iset: new_solutions = solveset(Eq(iset.lamda.expr, g), symbol, domain) dummy_var = tuple(iset.lamda.expr.free_symbols)[0] base_set = iset.base_set if isinstance(new_solutions, FiniteSet): new_exprs = new_solutions elif isinstance(new_solutions, Intersection): if isinstance(new_solutions.args[1], FiniteSet): new_exprs = new_solutions.args[1] for new_expr in new_exprs: result += ImageSet(Lambda(dummy_var, new_expr), base_set) if result is S.EmptySet: return ConditionSet(symbol, Eq(f, 0), domain) y_s = result return y_s
def solve_decomposition(f, symbol, domain): """ Function to solve equations via the principle of "Decomposition and Rewriting". Examples ======== >>> from sympy import exp, sin, Symbol, pprint, S >>> from sympy.solvers.solveset import solve_decomposition as sd >>> x = Symbol('x') >>> f1 = exp(2*x) - 3*exp(x) + 2 >>> sd(f1, x, S.Reals) {0, log(2)} >>> f2 = sin(x)**2 + 2*sin(x) + 1 >>> pprint(sd(f2, x, S.Reals), use_unicode=False) 3*pi {2*n*pi + ---- | n in Integers()} 2 >>> f3 = sin(x + 2) >>> pprint(sd(f3, x, S.Reals), use_unicode=False) {2*n*pi - 2 | n in Integers()} U {pi*(2*n + 1) - 2 | n in Integers()} """ from sympy.solvers.decompogen import decompogen from sympy.calculus.util import function_range # decompose the given function g_s = decompogen(f, symbol) # `y_s` represents the set of values for which the function `g` is to be # solved. # `solutions` represent the solutions of the equations `g = y_s` or # `g = 0` depending on the type of `y_s`. # As we are interested in solving the equation: f = 0 y_s = FiniteSet(0) for g in g_s: frange = function_range(g, symbol, domain) y_s = Intersection(frange, y_s) result = S.EmptySet if isinstance(y_s, FiniteSet): for y in y_s: solutions = solveset(Eq(g, y), symbol, domain) if not isinstance(solutions, ConditionSet): result += solutions else: if isinstance(y_s, ImageSet): iter_iset = (y_s, ) elif isinstance(y_s, Union): iter_iset = y_s.args for iset in iter_iset: new_solutions = solveset(Eq(iset.lamda.expr, g), symbol, domain) dummy_var = tuple(iset.lamda.expr.free_symbols)[0] base_set = iset.base_set if isinstance(new_solutions, FiniteSet): new_exprs = new_solutions elif isinstance(new_solutions, Intersection): if isinstance(new_solutions.args[1], FiniteSet): new_exprs = new_solutions.args[1] for new_expr in new_exprs: result += ImageSet(Lambda(dummy_var, new_expr), base_set) if result is S.EmptySet: return ConditionSet(symbol, Eq(f, 0), domain) y_s = result return y_s
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) (-oo, -2] U [2, oo) >>> domain = Interval(0, S.Infinity) >>> solve_univariate_inequality(x**2 >= 4, x, False, domain) [2, oo) >>> solve_univariate_inequality(sin(x) > 0, x, relational=False) (0, pi) """ 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: singularities = [] for d in denoms(e): singularities.extend(solvify(d, gen, domain)) if not continuous: domain = continuous_domain(e, gen, domain) solns = solvify(e, gen, domain) if solns is None: raise NotImplementedError(filldedent('''The inequality cannot be solved using solve_univariate_inequality.''')) 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 start = domain.inf sol_sets = [S.EmptySet] try: discontinuities = domain.boundary - FiniteSet(domain.inf, domain.sup) critical_points = set(solns + singularities + list(discontinuities)) reals = _nsort(critical_points, separated=True)[0] except NotImplementedError: raise NotImplementedError('sorting of these roots is not supported') if valid(start) and start.is_finite: sol_sets.append(FiniteSet(start)) for x in reals: end = x if end in [S.NegativeInfinity, S.Infinity]: if valid(S(0)): sol_sets.append(Interval(start, S.Infinity, True, True)) break pt = ((start + end)/2 if start is not S.NegativeInfinity else (end/2 if end.is_positive else (2*end if end.is_negative else end - 1))) if valid(pt): sol_sets.append(Interval(start, end, True, True)) if x in singularities: singularities.remove(x) elif include_x: sol_sets.append(FiniteSet(x)) start = end end = domain.sup # in case start == -oo then there were no solutions so we just # check a point between -oo and oo (e.g. 0) else pick a point # past the last solution (which is start after the end of the # for-loop above pt = (0 if start is S.NegativeInfinity else (start/2 if start.is_negative else (2*start if start.is_positive else start + 1))) if pt >= end: pt = (start + end)/2 if valid(pt): sol_sets.append(Interval(start, end, True, True)) rv = Union(*sol_sets).subs(gen, _gen) return rv if not relational else rv.as_relational(_gen)