def asintotas(f): # Igual usar singularities mejor: asintotas, verticales, horizontales y oblícuas (a,b) en oo y -oo asint = [] asintex = r'Asíntotas:\\' asint.append([ (i, limit(f, x, i)) for i in list(S.Reals - continuous_domain(f, x, domain=S.Reals)) ]) asintex += ', '.join( r'A.V. $x=' + str(i) + r'$\\' for i in list(S.Reals - continuous_domain(f, x, domain=S.Reals))) if abs(limit(f, x, oo)) != oo: asintex += r'A.H. $y=' + latex(limit(f, x, oo)) + r'$\\' if abs(limit(f, x, -oo)) != oo: asintex += r'A.H. $y=' + latex(limit(f, x, -oo)) + r'$\\' asint.append([(oo, limit(f, x, oo)), (-oo, limit(f, x, -oo))]) oblicuas = [] if abs(limit(f / x, x, oo)) != oo: oblicuas.append((oo, limit(f / x, x, oo) * x + limit(f - limit(f / x, x, oo) * x, x, oo))) #display(latex(limit(f/x,x,oo)*x+limit(f-limit(f/x,x,oo)*x,x,oo))) asintex += r'A.O. $y=' + latex( limit(f / x, x, oo) * x + limit(f - limit(f / x, x, oo) * x, x, oo)) + r'$ \\' if abs(limit(f / x, x, -oo)) != oo: oblicuas.append((-oo, limit(f / x, x, -oo) * x + limit(f - limit(f / x, x, -oo) * x, x, -oo))) asintex += r'A.O. $y=' + latex( limit(f / x, x, -oo) * x + limit(f - limit(f / x, x, -oo) * x, x, -oo)) + r'$ \\' asint.append(oblicuas) return asint, asintex
def test_continuous_domain(): x = Symbol('x') assert continuous_domain(sin(x), x, Interval(0, 2*pi)) == Interval(0, 2*pi) assert continuous_domain(tan(x), x, Interval(0, 2*pi)) == \ Union(Interval(0, pi/2, False, True), Interval(pi/2, 3*pi/2, True, True), Interval(3*pi/2, 2*pi, True, False)) assert continuous_domain((x - 1)/((x - 1)**2), x, S.Reals) == \ Union(Interval(-oo, 1, True, True), Interval(1, oo, True, True)) assert continuous_domain(log(x) + log(4*x - 1), x, S.Reals) == \ Interval(1/4, oo, True, True) assert continuous_domain(1/sqrt(x - 3), x, S.Reals) == Interval(3, oo, True, True)
def test_continuous_domain(): x = Symbol('x') assert continuous_domain(sin(x), x, Interval(0, 2 * pi)) == Interval(0, 2 * pi) assert continuous_domain(tan(x), x, Interval(0, 2*pi)) == \ Union(Interval(0, pi/2, False, True), Interval(pi/2, 3*pi/2, True, True), Interval(3*pi/2, 2*pi, True, False)) assert continuous_domain((x - 1)/((x - 1)**2), x, S.Reals) == \ Union(Interval(-oo, 1, True, True), Interval(1, oo, True, True)) assert continuous_domain(log(x) + log(4*x - 1), x, S.Reals) == \ Interval(1/4, oo, True, True) assert continuous_domain(1 / sqrt(x - 3), x, S.Reals) == Interval(3, oo, True, True)
def construct(self): expr2 = self.expr.subs(e, math.e) f = lambdify(x, expr2, 'numpy') domains = continuous_domain(self.expr, x, Interval(self.x_min, self.x_max)) if type(domains) is Union: domains = domains.args else: domains = [domains] self.setup_axes(animate=True) func_graph = VGroup() for domain in domains: graph = self.get_graph(f, self.function_color, get_left_bound(domain), get_right_bound(domain)) func_graph.add(graph) graph_lab = self.get_graph_label(func_graph[0], label=latex(self.expr)) self.play(ShowCreation(func_graph, run_time=3)) self.play(ShowCreation(graph_lab)) self.wait(5)
def test_continuous_domain(): x = Symbol('x') assert continuous_domain(sin(x), x, Interval(0, 2*pi)) == Interval(0, 2*pi) assert continuous_domain(tan(x), x, Interval(0, 2*pi)) == \ Union(Interval(0, pi/2, False, True), Interval(pi/2, pi*Rational(3, 2), True, True), Interval(pi*Rational(3, 2), 2*pi, True, False)) assert continuous_domain((x - 1)/((x - 1)**2), x, S.Reals) == \ Union(Interval(-oo, 1, True, True), Interval(1, oo, True, True)) assert continuous_domain(log(x) + log(4*x - 1), x, S.Reals) == \ Interval(Rational(1, 4), oo, True, True) assert continuous_domain(1/sqrt(x - 3), x, S.Reals) == Interval(3, oo, True, True) assert continuous_domain(1/x - 2, x, S.Reals) == \ Union(Interval.open(-oo, 0), Interval.open(0, oo)) assert continuous_domain(1/(x**2 - 4) + 2, x, S.Reals) == \ Union(Interval.open(-oo, -2), Interval.open(-2, 2), Interval.open(2, oo)) domain = continuous_domain(log(tan(x)**2 + 1), x, S.Reals) assert not domain.contains(3*pi/2) assert domain.contains(5) d = Symbol('d', even=True, zero=False) assert continuous_domain(x**(1/d), x, S.Reals) == Interval(0, oo)
def find_real_domain(f, symbol): from sympy import symbols try: # We first need to make sure all variables are registered as being real, before # we pass into continuous_domain, as the Sage conversion doesn't preserved Reals. for sym in f.free_symbols.difference({symbol}): f = f.subs(sym, symbols(str(sym), real=True)) new_symbol = symbols(str(symbol), real=True) f = f.subs(symbol, new_symbol) symbol = new_symbol return continuous_domain(f, symbol, S.Reals) except Exception as e: warnings.warn( "Failed to find the domain of: " + str(f) + "\n" + str(e), RuntimeWarning) return S.Reals
def estudio(f): # Estudio en una función a trozos set = S.Reals conj_singular = S.EmptySet for j, t in enumerate(f.args): #display(singularities(t[0],x)) #conj_singular = Union(conj_singular,singularities(t[0],x)) #display(Union(conj_singular,singularities(t[0],x))) #conj_singular = Union(conj_singular,Complement(S.Reals,continuous_domain(t[0],x,S.Reals))) #conj_singular = Union(conj_singular,Intersection(t[1].as_set(),Complement(S.Reals,continuous_domain(t[0],x,S.Reals)))) set2 = Intersection(set, t[1].as_set()) conj_singular = Union( conj_singular, Intersection( set2, Complement(S.Reals, continuous_domain(t[0], x, S.Reals)))) set = Complement(S.Reals, t[1].as_set()) sol = r"Singularidades de las expresiones analíticas: $" + latex( conj_singular) + "$" sol += r".\\ Posibles discontinuidades en los extremos de los trozos:" xs = [] estudio = [] for j, t in enumerate(trozos(f)): xs.append(str(t[0])) if (t[1] == t[2]): estudio.append( r"\\En {} es continua ya que hay límite y $\lim = f({})={}$". format(t[0], t[0], t[3])) display(r"En $x_0={}$ hay límite y f({})={}".format( t[0], t[0], t[3])) else: estudio.append( r"\\En {} no es continua porque no existe límite. Límites laterales: ${}$ y ${}$" .format(t[0], latex(t[1]), latex(t[2]))) display( r"En {} no existe límite. Límites laterales: {} y {}".format( t[0], t[1], t[2])) sol += ', '.join(xs) + r"." + '. '.join(estudio) return (sol)
def __init__(self, function): self.function = Explorer.get_sym(function) self.derivative = self.function.diff(x) self.derived_second = self.derivative.diff(x) self.domain = [continuous_domain(self.function, x, S.Reals)] self.y_point_of_intersection = (0, self.function.subs(x, 0)) self.x_point_of_intersections = [] self.extremums = [] self.inflection_points = [] self.vertical_asymptote = [] self.horizontal_asymptotes = [] self.place_ud_ = [] self.place_pn_ = [] self.x_point_of_intersection() self.get_extremum() self.get_inflection_point() self.find_vertical_asymptote() self.find_horizontal_asymptote() # למשתנה שבשורה הבאה נוספו ערכי נקודת פיתול מכיוון שיכול להיות שהממוצע יצא אחד מהם self.list_of_changes = sorted([-oo, oo] + [xy[0] for m,xy in self.extremums] + self.vertical_asymptote + [xy[0] for un, xy, nu in self.inflection_points] + [xy[0] for xy in self.x_point_of_intersections]) self.place_pn() self.place_ud()
def test_continuous_domain(): x = Symbol("x") assert continuous_domain(sin(x), x, Interval(0, 2 * pi)) == Interval(0, 2 * pi) assert continuous_domain(tan(x), x, Interval(0, 2 * pi)) == Union( Interval(0, pi / 2, False, True), Interval(pi / 2, pi * Rational(3, 2), True, True), Interval(pi * Rational(3, 2), 2 * pi, True, False), ) assert continuous_domain((x - 1) / ((x - 1)**2), x, S.Reals) == Union(Interval(-oo, 1, True, True), Interval(1, oo, True, True)) assert continuous_domain(log(x) + log(4 * x - 1), x, S.Reals) == Interval(Rational(1, 4), oo, True, True) assert continuous_domain(1 / sqrt(x - 3), x, S.Reals) == Interval(3, oo, True, True) assert continuous_domain(1 / x - 2, x, S.Reals) == Union(Interval.open(-oo, 0), Interval.open(0, oo)) assert continuous_domain(1 / (x**2 - 4) + 2, x, S.Reals) == Union(Interval.open(-oo, -2), Interval.open(-2, 2), Interval.open(2, oo))
from sympy import Symbol, Interval, Range from sympy.calculus.util import continuous_domain import numpy as np import math import matplotlib.pyplot as plt x = Symbol("x") y = input("Wprowadź wzór funkcji: f(x) = ") y = eval(y) x1 = float(input("Podaj początek przedziału: ")) x2 = float(input("Podaj koniec przedziału: ")) domain = continuous_domain(y, x, Interval(x1, x2)) view_range = np.arange(x1, x2 + 0.1, 0.01) index = 0 for i in view_range: view_range[index] = round(view_range[index], 2) if i not in domain: np.delete(view_range, index) index -= 1 index += 1 #end for x = view_range y = eval(str(y)) plt.plot(x, y) plt.show()
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)
from sympy import * from fractions import * from sympy import Symbol, S from sympy.calculus.util import continuous_domain import math x = Symbol("x") f = 1 / x - 2 z = continuous_domain(f, x, S.Reals) def dominio_rango(R): x = [] y = [] for a, b in R: x.append(a) y.append(b) return "El dominio es: ", sorted( set(x), key=x.index), " El rango es: ", sorted(set(y), key=y.index) print( "En caso de ingresar una relación el dominio y rango estarán definidos por sus ejes X y Y" ) print("Relación ingresada") print("[(1,1), (1,2), (2,3), (4,2)]") print(dominio_rango([(1, 1), (1, 2), (2, 3), (4, 2)]))
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_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 compute_admissible_domain(self, sym_function): """Deprecated, as continuos_domain is superslow""" x = self.symbol res = continuous_domain(sym_function, self.symbol, S.Reals) return res
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 nminmax(func, x, warningctx=None): # Find minimum and maximum at [0,1]. try: return [ minimum(func, x, Interval(0, 1)), maximum(func, x, Interval(0, 1)) ] except: pw = piecewise_fold(func.rewrite(Piecewise)) if isinstance(pw, Piecewise): try: return pwminmax(pw, x, Interval(0, 1)) except: pass print("WARNING: Resorting to numerical optimization: %s" % (func), file=sys.stderr) if warningctx: warningctx["warning"] = True cv = [0, 1] df = diff(func) mmh = isinstance(func, Min) or isinstance(func, Max) or isinstance( func, Heaviside) n = 40 if mmh else 20 for i in range(n): try: ns = nsolve(df, x, (S(i) / n, S(i + 1) / n), solver="bisect") cv.append(lowerbound(ns)) cv.append(upperbound(ns)) except: ss = S(i) / n se = S(i + 1) / n for k in range(1 + 1): cv.append(ss + (se - ss) * S(k) / 10) # Evaluate at critical points, and # remove incomparable values cv2 = [] # print(func.__class__) iscont = continuous_domain(func, x, Interval(0, 1)) == Interval(0, 1) # print([func.__class__,iscont]) # print(func) for c in cv: c2s = [func.subs(x, c)] # Finding limits for Min, Max, and Heaviside can be # extremely slow. Also check whether function is continuous # to avoid unnecessary limit computation if (not iscont) and (not mmh): try: c2s.append(funclimit(func, x, c, "+")) except: pass # XXX: Disabling because it can be extremely slow in some # cases, especially when Heaviside is involved # try: # c2s.append(funclimit(func, x, c, "-")) # except: # pass for c2 in c2s: # Change complex infinity to infinity if c2 == zoo: c2 = oo try: Min(c2) cv2.append(c2) except: pass cv = cv2 return [lowerbound(Min(*cv)), upperbound(Max(*cv))]