def test_subs_CondSet(): s = FiniteSet(z, y) c = ConditionSet(x, x < 2, s) # you can only replace sym with a symbol that is not in # the free symbols assert c.subs(x, 1) == c assert c.subs(x, y) == c assert c.subs(x, w) == ConditionSet(w, w < 2, s) assert ConditionSet(x, x < y, s ).subs(y, w) == ConditionSet(x, x < w, s.subs(y, w)) # to eventually be removed c = ConditionSet((x, y), {x + 1, x + y}, S.Reals) assert c.subs(x, z) == c
def test_dummy_eq(): C = ConditionSet I = S.Integers c = C(x, x < 1, I) assert c.dummy_eq(C(y, y < 1, I)) assert c.dummy_eq(1) == False assert c.dummy_eq(C(x, x < 1, S.Reals)) == False raises(ValueError, lambda: c.dummy_eq(C(x, x < 1, S.Reals), z)) # to eventually be removed c1 = ConditionSet((x, y), {x + 1, x + y}, S.Reals) c2 = ConditionSet((x, y), {x + 1, x + y}, S.Reals) c3 = ConditionSet((x, y), {x + 1, x + y}, S.Complexes) assert c1.dummy_eq(c2) assert c1.dummy_eq(c3) is False assert c.dummy_eq(c1) is False assert c1.dummy_eq(c) is False
def test_subs_CondSet(): s = FiniteSet(z, y) c = ConditionSet(x, x < 2, s) # you can only replace sym with a symbol that is not in # the free symbols assert c.subs(x, 1) == c assert c.subs(x, y) == ConditionSet(y, y < 2, s) # double subs needed to change dummy if the base set # also contains the dummy orig = ConditionSet(y, y < 2, s) base = orig.subs(y, w) and_dummy = base.subs(y, w) assert base == ConditionSet(y, y < 2, {w, z}) assert and_dummy == ConditionSet(w, w < 2, {w, z}) assert c.subs(x, w) == ConditionSet(w, w < 2, s) assert ConditionSet(x, x < y, s ).subs(y, w) == ConditionSet(x, x < w, s.subs(y, w)) # if the user uses assumptions that cause the condition # to evaluate, that can't be helped from SymPy's end n = Symbol('n', negative=True) assert ConditionSet(n, 0 < n, S.Integers) is S.EmptySet p = Symbol('p', positive=True) assert ConditionSet(n, n < y, S.Integers ).subs(n, x) == ConditionSet(x, x < y, S.Integers) nc = Symbol('nc', commutative=False) raises(ValueError, lambda: ConditionSet( x, x < p, S.Integers).subs(x, nc)) raises(ValueError, lambda: ConditionSet( x, x < p, S.Integers).subs(x, n)) raises(ValueError, lambda: ConditionSet( x + 1, x < 1, S.Integers)) raises(ValueError, lambda: ConditionSet( x + 1, x < 1, s)) assert ConditionSet( n, n < x, Interval(0, oo)).subs(x, p) == Interval(0, oo) assert ConditionSet( n, n < x, Interval(-oo, 0)).subs(x, p) == S.EmptySet assert ConditionSet(f(x), f(x) < 1, {w, z} ).subs(f(x), y) == ConditionSet(y, y < 1, {w, z})
def test_simplified_FiniteSet_in_CondSet(): assert ConditionSet(x, And(x < 1, x > -3), FiniteSet(0, 1, 2)) == FiniteSet(0) assert ConditionSet(x, x < 0, FiniteSet(0, 1, 2)) == EmptySet assert ConditionSet(x, And(x < -3), EmptySet) == EmptySet y = Symbol('y') assert (ConditionSet(x, And(x > 0), FiniteSet(-1, 0, 1, y)) == Union( FiniteSet(1), ConditionSet(x, And(x > 0), FiniteSet(y)))) assert (ConditionSet(x, Eq(Mod(x, 3), 1), FiniteSet(1, 4, 2, y)) == Union( FiniteSet(1, 4), ConditionSet(x, Eq(Mod(x, 3), 1), FiniteSet(y))))
def _solve_real_trig(f, symbol): """ Helper to solve trigonometric equations """ f = trigsimp(f) f = f.rewrite(exp) f = together(f) g, h = fraction(f) y = Dummy('y') g, h = g.expand(), h.expand() g, h = g.subs(exp(I*symbol), y), h.subs(exp(I*symbol), y) if g.has(symbol) or h.has(symbol): return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Reals) solns = solveset_complex(g, y) - solveset_complex(h, y) if isinstance(solns, FiniteSet): return Union(*[invert_complex(exp(I*symbol), s, symbol)[1] for s in solns]) elif solns is S.EmptySet: return S.EmptySet else: return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Reals)
def _solve_as_poly(f, symbol, solveset_solver, invert_func): """ Solve the equation using polynomial techniques if it already is a polynomial equation or, with a change of variables, can be made so. """ result = None if f.is_polynomial(symbol): solns = roots(f, symbol, cubics=True, quartics=True, quintics=True, domain='EX') num_roots = sum(solns.values()) if degree(f, symbol) <= num_roots: result = FiniteSet(*solns.keys()) else: poly = Poly(f, symbol) solns = poly.all_roots() if poly.degree() <= len(solns): result = FiniteSet(*solns) else: result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes) else: poly = Poly(f) if poly is None: result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes) gens = [g for g in poly.gens if g.has(symbol)] if len(gens) == 1: poly = Poly(poly, gens[0]) gen = poly.gen deg = poly.degree() poly = Poly(poly.as_expr(), poly.gen, composite=True) poly_solns = FiniteSet(*roots(poly, cubics=True, quartics=True, quintics=True).keys()) if len(poly_solns) < deg: result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes) if gen != symbol: y = Dummy('y') lhs, rhs_s = invert_func(gen, y, symbol) if lhs is symbol: result = Union(*[rhs_s.subs(y, s) for s in poly_solns]) else: result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes) else: result = ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes) if result is not None: if isinstance(result, FiniteSet): # this is to simplify solutions like -sqrt(-I) to sqrt(2)/2 # - sqrt(2)*I/2. We are not expanding for solution with free # variables because that makes the solution more complicated. For # example expand_complex(a) returns re(a) + I*im(a) if all([s.free_symbols == set() and not isinstance(s, RootOf) for s in result]): s = Dummy('s') result = imageset(Lambda(s, expand_complex(s)), result) return result else: return ConditionSet(Lambda(symbol, Eq(f, 0)), S.Complexes)
def test_contains(): assert 6 in ConditionSet(x, x > 5, Interval(1, 7)) assert (8 in ConditionSet(x, y > 5, Interval(1, 7))) is False # `in` should give True or False; in this case there is not # enough information for that result raises(TypeError, lambda: 6 in ConditionSet(x, y > 5, Interval(1, 7))) assert ConditionSet(x, y > 5, Interval(1, 7)).contains(6) == (y > 5) assert ConditionSet(x, y > 5, Interval(1, 7)).contains(8) is S.false assert ConditionSet(x, y > 5, Interval(1, 7)).contains(w) == And( S.One <= w, w <= 7, y > 5) assert 0 not in ConditionSet(x, 1 / x >= 0, S.Reals)
def test_improve_coverage(): from sympy.solvers.solveset import _has_rational_power x = Symbol('x') y = exp(x + 1 / x**2) solution = solveset(y**2 + y, x, S.Reals) unsolved_object = ConditionSet( x, Eq((exp((x**3 + 1) / x**2) + 1) * exp((x**3 + 1) / x**2), 0), S.Reals) assert solution == unsolved_object assert _has_rational_power(sin(x) * exp(x) + 1, x) == (False, S.One) assert _has_rational_power((sin(x)**2) * (exp(x) + 1)**3, x) == (False, S.One)
def test_flatten(): """Tests whether there is basic denesting functionality""" inner = ConditionSet(x, sin(x) + x > 0) outer = ConditionSet(x, Contains(x, inner), S.Reals) assert outer == ConditionSet(x, sin(x) + x > 0, S.Reals) inner = ConditionSet(y, sin(y) + y > 0) outer = ConditionSet(x, Contains(y, inner), S.Reals) assert outer != ConditionSet(x, sin(x) + x > 0, S.Reals) inner = ConditionSet(x, sin(x) + x > 0).intersect(Interval(-1, 1)) outer = ConditionSet(x, Contains(x, inner), S.Reals) assert outer == ConditionSet(x, sin(x) + x > 0, Interval(-1, 1)) def test_duplicate(): from sympy.core.function import BadSignatureError # test coverage for line 95 in conditionset.py, check for duplicates in symbols dup = symbols('a,a') raises(BadSignatureError, lambda: ConditionSet(dup, x < 0))
def test_as_dummy(): _0 = Symbol('_0') assert ConditionSet(x, x < 1, Interval(y, oo)).as_dummy() == ConditionSet( _0, _0 < 1, Interval(y, oo)) assert ConditionSet(x, x < 1, Interval(x, oo)).as_dummy() == ConditionSet( _0, _0 < 1, Interval(x, oo)) assert ConditionSet(x, x < 1, ImageSet(Lambda(y, y**2), S.Integers)).as_dummy() == ConditionSet( _0, _0 < 1, ImageSet(Lambda(_0, _0**2), S.Integers))
def _solve_abs(f, symbol): """ Helper function to solve equation involving absolute value function """ p, q, r = Wild('p'), Wild('q'), Wild('r') pattern_match = f.match(p*Abs(q) + r) or {} if not pattern_match.get(p, S.Zero).is_zero: f_p, f_q, f_r = pattern_match[p], pattern_match[q], pattern_match[r] q_pos_cond = solve_univariate_inequality(f_q >= 0, symbol, relational=False) q_neg_cond = solve_univariate_inequality(f_q < 0, symbol, relational=False) sols_q_pos = solveset_real(f_p*f_q + f_r, symbol).intersect(q_pos_cond) sols_q_neg = solveset_real(f_p*(-f_q) + f_r, symbol).intersect(q_neg_cond) return Union(sols_q_pos, sols_q_neg) else: return ConditionSet(symbol, Eq(f, 0), S.Complexes)
def test_CondSet(): sin_sols_principal = ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi, False, True)) assert pi in sin_sols_principal assert pi/2 not in sin_sols_principal assert 3*pi not in sin_sols_principal assert 5 in ConditionSet(x, x**2 > 4, S.Reals) assert 1 not in ConditionSet(x, x**2 > 4, S.Reals) # in this case, 0 is not part of the base set so # it can't be in any subset selected by the condition assert 0 not in ConditionSet(x, y > 5, Interval(1, 7)) # since 'in' requires a true/false, the following raises # an error because the given value provides no information # for the condition to evaluate (since the condition does # not depend on the dummy symbol): the result is `y > 5`. # In this case, ConditionSet is just acting like # Piecewise((Interval(1, 7), y > 5), (S.EmptySet, True)). raises(TypeError, lambda: 6 in ConditionSet(x, y > 5, Interval(1, 7))) assert isinstance(ConditionSet(x, x < 1, {x, y}).base_set, FiniteSet) raises(TypeError, lambda: ConditionSet(x, x + 1, {x, y})) raises(TypeError, lambda: ConditionSet(x, x, 1)) I = S.Integers C = ConditionSet assert C(x, x < 1, C(x, x < 2, I) ) == C(x, (x < 1) & (x < 2), I) assert C(y, y < 1, C(x, y < 2, I) ) == C(x, (x < 1) & (y < 2), I) assert C(y, y < 1, C(x, x < 2, I) ) == C(y, (y < 1) & (y < 2), I) assert C(y, y < 1, C(x, y < x, I) ) == C(x, (x < 1) & (y < x), I) assert C(y, x < 1, C(x, y < x, I) ) == C(L, (x < 1) & (y < L), I) c = C(y, x < 1, C(x, L < y, I)) assert c == C(c.sym, (L < y) & (x < 1), I) assert c.sym not in (x, y, L) c = C(y, x < 1, C(x, y < x, FiniteSet(L))) assert c == C(L, And(x < 1, y < L), FiniteSet(L))
def test_solve_abs(): assert solveset_real(Abs(x) - 2, x) == FiniteSet(-2, 2) assert solveset_real(Abs(x + 3) - 2*Abs(x - 3), x) == \ FiniteSet(1, 9) assert solveset_real(2*Abs(x) - Abs(x - 1), x) == \ FiniteSet(-1, Rational(1, 3)) assert solveset_real(Abs(x - 7) - 8, x) == FiniteSet(-S(1), S(15)) # issue 9565. Note: solveset_real does not solve this as it is # solveset's job to handle Relationals assert solveset(Abs((x - 1)/(x - 5)) <= S(1)/3, domain=S.Reals ) == Interval(-1, 2) # issue #10069 assert solveset_real(abs(1/(x - 1)) - 1 > 0, x) == \ ConditionSet(x, Eq((1 - Abs(x - 1))/Abs(x - 1) > 0, 0), S.Reals) assert solveset(abs(1/(x - 1)) - 1 > 0, x, domain=S.Reals ) == Union(Interval.open(0, 1), Interval.open(1, 2))
def test_solve_sqrt_3(): R = Symbol('R') eq = sqrt(2)*R*sqrt(1/(R + 1)) + (R + 1)*(sqrt(2)*sqrt(1/(R + 1)) - 1) sol = solveset_complex(eq, R) assert sol == FiniteSet(*[S(5)/3 + 4*sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3, -sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3 + 40*re(1/((-S(1)/2 - sqrt(3)*I/2)*(S(251)/27 + sqrt(111)*I/9)**(S(1)/3)))/9 + sqrt(30)*sin(atan(3*sqrt(111)/251)/3)/3 + S(5)/3 + I*(-sqrt(30)*cos(atan(3*sqrt(111)/251)/3)/3 - sqrt(10)*sin(atan(3*sqrt(111)/251)/3)/3 + 40*im(1/((-S(1)/2 - sqrt(3)*I/2)*(S(251)/27 + sqrt(111)*I/9)**(S(1)/3)))/9)]) # the number of real roots will depend on the value of m: for m=1 there are 4 # and for m=-1 there are none. eq = -sqrt((m - q)**2 + (-m/(2*q) + S(1)/2)**2) + sqrt((-m**2/2 - sqrt( 4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4)**2 + (m**2/2 - m - sqrt( 4*m**4 - 4*m**2 + 8*m + 1)/4 - S(1)/4)**2) unsolved_object = ConditionSet(Lambda(q, Eq((-2*sqrt(4*q**2*(m - q)**2 + (-m + q)**2) + sqrt((-2*m**2 - sqrt(4*m**4 - 4*m**2 + 8*m + 1) - 1)**2 + (2*m**2 - 4*m - sqrt(4*m**4 - 4*m**2 + 8*m + 1) - 1)**2)*Abs(q))/Abs(q), 0)), S.Reals) assert solveset_real(eq, q) == unsolved_object
def test_dummy_eq(): C = ConditionSet I = S.Integers c = C(x, x < 1, I) assert c.dummy_eq(C(y, y < 1, I)) assert c.dummy_eq(1) == False assert c.dummy_eq(C(x, x < 1, S.Reals)) == False raises(ValueError, lambda: c.dummy_eq(C(x, x < 1, S.Reals), z)) c1 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals) c2 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals) c3 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Complexes) assert c1.dummy_eq(c2) assert c1.dummy_eq(c3) is False assert c.dummy_eq(c1) is False assert c1.dummy_eq(c) is False
def _solve_abs(f, symbol, domain): """ Helper function to solve equation involving absolute value function """ if not domain.is_subset(S.Reals): raise ValueError(filldedent(''' Absolute values cannot be inverted in the complex domain.''')) p, q, r = Wild('p'), Wild('q'), Wild('r') pattern_match = f.match(p*Abs(q) + r) or {} if not pattern_match.get(p, S.Zero).is_zero: f_p, f_q, f_r = pattern_match[p], pattern_match[q], pattern_match[r] q_pos_cond = solve_univariate_inequality(f_q >= 0, symbol, relational=False) q_neg_cond = solve_univariate_inequality(f_q < 0, symbol, relational=False) sols_q_pos = solveset_real(f_p*f_q + f_r, symbol).intersect(q_pos_cond) sols_q_neg = solveset_real(f_p*(-f_q) + f_r, symbol).intersect(q_neg_cond) return Union(sols_q_pos, sols_q_neg) else: return ConditionSet(symbol, Eq(f, 0), domain)
def test_solve_decomposition(): x = Symbol('x') n = Dummy('n') f1 = exp(3*x) - 6*exp(2*x) + 11*exp(x) - 6 f2 = sin(x)**2 - 2*sin(x) + 1 f3 = sin(x)**2 - sin(x) f4 = sin(x + 1) f5 = exp(x + 2) - 1 f6 = 1/log(x) s1 = ImageSet(Lambda(n, 2*n*pi), S.Integers) s2 = ImageSet(Lambda(n, 2*n*pi + pi), S.Integers) s3 = ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers) s4 = ImageSet(Lambda(n, 2*n*pi - 1), S.Integers) s5 = ImageSet(Lambda(n, (2*n + 1)*pi - 1), S.Integers) assert solve_decomposition(f1, x, S.Reals) == FiniteSet(0, log(2), log(3)) assert solve_decomposition(f2, x, S.Reals) == s3 assert solve_decomposition(f3, x, S.Reals) == Union(s1, s2, s3) assert solve_decomposition(f4, x, S.Reals) == Union(s4, s5) assert solve_decomposition(f5, x, S.Reals) == FiniteSet(-2) assert solve_decomposition(f6, x, S.Reals) == ConditionSet(x, Eq(f6, 0), S.Reals)
def solveset(f, symbol=None, domain=S.Complexes): """Solves a given inequality or equation with set as output Parameters ========== f : Expr or a relational. The target equation or inequality symbol : Symbol The variable for which the equation is solved domain : Set The domain over which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is True or is equal to zero. An `EmptySet` is returned if `f` is False or nonzero. A `ConditionSet` is returned as unsolved object if algorithms to evaluatee complete solution are not yet implemented. `solveset` claims to be complete in the solution set that it returns. Raises ====== NotImplementedError The algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. Notes ===== Python interprets 0 and 1 as False and True, respectively, but in this function they refer to solutions of an expression. So 0 and 1 return the Domain and EmptySet, respectively, while True and False return the opposite (as they are assumed to be solutions of relational expressions). See Also ======== solveset_real: solver for real domain solveset_complex: solver for complex domain Examples ======== >>> from sympy import exp, sin, Symbol, pprint, S >>> from sympy.solvers.solveset import solveset, solveset_real * The default domain is complex. Not specifying a domain will lead to the solving of the equation in the complex domain (and this is not affected by the assumptions on the symbol): >>> x = Symbol('x') >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers()} >>> x = Symbol('x', real=True) >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers()} * If you want to use `solveset` to solve the equation in the real domain, provide a real domain. (Using `solveset\_real` does this automatically.) >>> R = S.Reals >>> x = Symbol('x') >>> solveset(exp(x) - 1, x, R) {0} >>> solveset_real(exp(x) - 1, x) {0} The solution is mostly unaffected by assumptions on the symbol, but there may be some slight difference: >>> pprint(solveset(sin(x)/x,x), use_unicode=False) ({2*n*pi | n in Integers()} \ {0}) U ({2*n*pi + pi | n in Integers()} \ {0}) >>> p = Symbol('p', positive=True) >>> pprint(solveset(sin(p)/p, p), use_unicode=False) {2*n*pi | n in Integers()} U {2*n*pi + pi | n in Integers()} * Inequalities can be solved over the real domain only. Use of a complex domain leads to a NotImplementedError. >>> solveset(exp(x) > 1, x, R) (0, oo) """ f = sympify(f) if f is S.true: return domain if f is S.false: return S.EmptySet if not isinstance(f, (Expr, Number)): raise ValueError("%s is not a valid SymPy expression" % (f)) free_symbols = f.free_symbols if not free_symbols: b = Eq(f, 0) if b is S.true: return domain elif b is S.false: return S.EmptySet else: raise NotImplementedError(filldedent(''' relationship between value and 0 is unknown: %s''' % b)) if symbol is None: if len(free_symbols) == 1: symbol = free_symbols.pop() else: raise ValueError(filldedent(''' The independent variable must be specified for a multivariate equation.''')) elif not getattr(symbol, 'is_Symbol', False): raise ValueError('A Symbol must be given, not type %s: %s' % (type(symbol), symbol)) if isinstance(f, Eq): from sympy.core import Add f = Add(f.lhs, - f.rhs, evaluate=False) elif f.is_Relational: if not domain.is_subset(S.Reals): raise NotImplementedError(filldedent(''' Inequalities in the complex domain are not supported. Try the real domain by setting domain=S.Reals''')) try: result = solve_univariate_inequality( f, symbol, relational=False) - _invalid_solutions( f, symbol, domain) except NotImplementedError: result = ConditionSet(symbol, f, domain) return result return _solveset(f, symbol, domain, _check=True)
def _solveset(f, symbol, domain, _check=False): """Helper for solveset to return a result from an expression that has already been sympify'ed and is known to contain the given symbol.""" # _check controls whether the answer is checked or not from sympy.simplify.simplify import signsimp orig_f = f f = together(f) if f.is_Mul: _, f = f.as_independent(symbol, as_Add=False) if f.is_Add: a, h = f.as_independent(symbol) m, h = h.as_independent(symbol, as_Add=False) f = a/m + h # XXX condition `m != 0` should be added to soln f = piecewise_fold(f) # assign the solvers to use solver = lambda f, x, domain=domain: _solveset(f, x, domain) if domain.is_subset(S.Reals): inverter_func = invert_real else: inverter_func = invert_complex inverter = lambda f, rhs, symbol: inverter_func(f, rhs, symbol, domain) result = EmptySet() if f.expand().is_zero: return domain elif not f.has(symbol): return EmptySet() elif f.is_Mul and all(_is_finite_with_finite_vars(m, domain) for m in f.args): # if f(x) and g(x) are both finite we can say that the solution of # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in # general. g(x) can grow to infinitely large for the values where # f(x) == 0. To be sure that we are not silently allowing any # wrong solutions we are using this technique only if both f and g are # finite for a finite input. result = Union(*[solver(m, symbol) for m in f.args]) elif _is_function_class_equation(TrigonometricFunction, f, symbol) or \ _is_function_class_equation(HyperbolicFunction, f, symbol): result = _solve_trig(f, symbol, domain) elif f.is_Piecewise: dom = domain result = EmptySet() expr_set_pairs = f.as_expr_set_pairs() for (expr, in_set) in expr_set_pairs: if in_set.is_Relational: in_set = in_set.as_set() if in_set.is_Interval: dom -= in_set solns = solver(expr, symbol, in_set) result += solns else: lhs, rhs_s = inverter(f, 0, symbol) if lhs == symbol: # do some very minimal simplification since # repeated inversion may have left the result # in a state that other solvers (e.g. poly) # would have simplified; this is done here # rather than in the inverter since here it # is only done once whereas there it would # be repeated for each step of the inversion if isinstance(rhs_s, FiniteSet): rhs_s = FiniteSet(*[Mul(* signsimp(i).as_content_primitive()) for i in rhs_s]) result = rhs_s elif isinstance(rhs_s, FiniteSet): for equation in [lhs - rhs for rhs in rhs_s]: if equation == f: if any(_has_rational_power(g, symbol)[0] for g in equation.args) or _has_rational_power( equation, symbol)[0]: result += _solve_radical(equation, symbol, solver) elif equation.has(Abs): result += _solve_abs(f, symbol, domain) else: result += _solve_as_rational(equation, symbol, domain) else: result += solver(equation, symbol) else: result = ConditionSet(symbol, Eq(f, 0), domain) if _check: if isinstance(result, ConditionSet): # it wasn't solved or has enumerated all conditions # -- leave it alone return result # whittle away all but the symbol-containing core # to use this for testing fx = orig_f.as_independent(symbol, as_Add=True)[1] fx = fx.as_independent(symbol, as_Add=False)[1] if isinstance(result, FiniteSet): # check the result for invalid solutions result = FiniteSet(*[s for s in result if isinstance(s, RootOf) or domain_check(fx, symbol, s)]) return result
def solveset(f, symbol=None, domain=S.Complexes): """Solves a given inequality or equation with set as output Parameters ========== f : Expr or a relational. The target equation or inequality symbol : Symbol The variable for which the equation is solved domain : Set The domain over which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is True or is equal to zero. An `EmptySet` is returned if no solution is found. A `ConditionSet` is returned as unsolved object if algorithms to evaluatee complete solution are not yet implemented. `solveset` claims to be complete in the solution set that it returns. Raises ====== NotImplementedError The algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. `solveset` uses two underlying functions `solveset_real` and `solveset_complex` to solve equations. They are the solvers for real and complex domain respectively. `solveset` ignores the assumptions on the variable being solved for and instead, uses the `domain` parameter to decide which solver to use. See Also ======== solveset_real: solver for real domain solveset_complex: solver for complex domain Examples ======== >>> from sympy import exp, Symbol, Eq, pprint, S, solveset >>> from sympy.abc import x * The default domain is complex. Not specifying a domain will lead to the solving of the equation in the complex domain. >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers()} * If you want to solve equation in real domain by the `solveset` interface, then specify that the domain is real. Alternatively use `solveset\_real`. >>> x = Symbol('x') >>> solveset(exp(x) - 1, x, S.Reals) {0} >>> solveset(Eq(exp(x), 1), x, S.Reals) {0} * Inequalities can be solved over the real domain only. Use of a complex domain leads to a NotImplementedError. >>> solveset(exp(x) > 1, x, S.Reals) (0, oo) """ from sympy.solvers.inequalities import solve_univariate_inequality if symbol is None: free_symbols = f.free_symbols if len(free_symbols) == 1: symbol = free_symbols.pop() else: raise ValueError( filldedent(''' The independent variable must be specified for a multivariate equation.''')) elif not symbol.is_Symbol: raise ValueError('A Symbol must be given, not type %s: %s' % (type(symbol), symbol)) f = sympify(f) if f is S.false: return EmptySet() if f is S.true: return domain if isinstance(f, Eq): from sympy.core import Add f = Add(f.lhs, -f.rhs, evaluate=False) if f.is_Relational: if not domain.is_subset(S.Reals): raise NotImplementedError("Inequalities in the complex domain are " "not supported. Try the real domain by" "setting domain=S.Reals") try: result = solve_univariate_inequality( f, symbol, relational=False).intersection(domain) except NotImplementedError: result = ConditionSet(symbol, f, domain) return result if isinstance(f, (Expr, Number)): if domain is S.Reals: return solveset_real(f, symbol) elif domain is S.Complexes: return solveset_complex(f, symbol) elif domain.is_subset(S.Reals): return Intersection(solveset_real(f, symbol), domain) else: return Intersection(solveset_complex(f, symbol), domain)
def solveset_complex(f, symbol): """ Solve a complex valued equation. Parameters ========== f : Expr The target equation symbol : Symbol The variable for which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` equal to zero. An `EmptySet` is returned if no solution is found. A `ConditionSet` is returned as an unsolved object if algorithms to evaluate complete solutions are not yet implemented. `solveset_complex` claims to be complete in the solution set that it returns. Raises ====== NotImplementedError The algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. See Also ======== solveset_real: solver for real domain Examples ======== >>> from sympy import Symbol, exp >>> from sympy.solvers.solveset import solveset_complex >>> from sympy.abc import x, a, b, c >>> solveset_complex(a*x**2 + b*x +c, x) {-b/(2*a) - sqrt(-4*a*c + b**2)/(2*a), -b/(2*a) + sqrt(-4*a*c + b**2)/(2*a)} * Due to the fact that complex extension of my real valued functions are multivariate even some simple equations can have infinitely many solution. >>> solveset_complex(exp(x) - 1, x) ImageSet(Lambda(_n, 2*_n*I*pi), Integers()) """ if not symbol.is_Symbol: raise ValueError(" %s is not a symbol" % (symbol)) f = sympify(f) original_eq = f if not isinstance(f, (Expr, Number)): raise ValueError(" %s is not a valid sympy expression" % (f)) f = together(f) # Without this equations like a + 4*x**2 - E keep oscillating # into form a/4 + x**2 - E/4 and (a + 4*x**2 - E)/4 if not fraction(f)[1].has(symbol): f = expand(f) if f.is_zero: return S.Complexes elif not f.has(symbol): result = EmptySet() elif f.is_Mul and all([_is_finite_with_finite_vars(m) for m in f.args]): result = Union(*[solveset_complex(m, symbol) for m in f.args]) else: lhs, rhs_s = invert_complex(f, 0, symbol) if lhs == symbol: result = rhs_s elif isinstance(rhs_s, FiniteSet): equations = [lhs - rhs for rhs in rhs_s] result = EmptySet() for equation in equations: if equation == f: if any( _has_rational_power(g, symbol)[0] for g in equation.args): result += _solve_radical(equation, symbol, solveset_complex) else: result += _solve_as_rational( equation, symbol, solveset_solver=solveset_complex, as_poly_solver=_solve_as_poly_complex) else: result += solveset_complex(equation, symbol) else: result = ConditionSet(symbol, Eq(f, 0), S.Complexes) if isinstance(result, FiniteSet): result = [ s for s in result if isinstance(s, RootOf) or domain_check(original_eq, symbol, s) ] return FiniteSet(*result) else: return result
def test_contains(): assert 6 in ConditionSet(x, x > 5, Interval(1, 7)) assert (8 in ConditionSet(x, y > 5, Interval(1, 7))) is False # `in` should give True or False; in this case there is not # enough information for that result raises(TypeError, lambda: 6 in ConditionSet(x, y > 5, Interval(1, 7))) # here, there is enough information but the comparison is # not defined raises(TypeError, lambda: 0 in ConditionSet(x, 1/x >= 0, S.Reals)) assert ConditionSet(x, y > 5, Interval(1, 7) ).contains(6) == (y > 5) assert ConditionSet(x, y > 5, Interval(1, 7) ).contains(8) is S.false assert ConditionSet(x, y > 5, Interval(1, 7) ).contains(w) == And(Contains(w, Interval(1, 7)), y > 5) # This returns an unevaluated Contains object # because 1/0 should not be defined for 1 and 0 in the context of # reals. assert ConditionSet(x, 1/x >= 0, S.Reals).contains(0) == \ Contains(0, ConditionSet(x, 1/x >= 0, S.Reals), evaluate=False) c = ConditionSet((x, y), x + y > 1, S.Integers**2) assert not c.contains(1) assert c.contains((2, 1)) assert not c.contains((0, 1)) c = ConditionSet((w, (x, y)), w + x + y > 1, S.Integers*S.Integers**2) assert not c.contains(1) assert not c.contains((1, 2)) assert not c.contains(((1, 2), 3)) assert not c.contains(((1, 2), (3, 4))) assert c.contains((1, (3, 4)))
def test_solve_complex_unsolvable(): unsolved_object = ConditionSet(x, Eq(2 * cos(x) - 1, 0), S.Complexes) solution = solveset_complex(cos(x) - S.Half, x) assert solution == unsolved_object
def test_SetKind_ConditionSet(): assert ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi)).kind is SetKind(NumberKind) assert ConditionSet(x, x < 0).kind is SetKind(NumberKind)
def test_CondSet(): sin_sols_principal = ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi, False, True)) assert pi in sin_sols_principal assert pi/2 not in sin_sols_principal assert 3*pi not in sin_sols_principal assert oo not in sin_sols_principal assert 5 in ConditionSet(x, x**2 > 4, S.Reals) assert 1 not in ConditionSet(x, x**2 > 4, S.Reals) # in this case, 0 is not part of the base set so # it can't be in any subset selected by the condition assert 0 not in ConditionSet(x, y > 5, Interval(1, 7)) # since 'in' requires a true/false, the following raises # an error because the given value provides no information # for the condition to evaluate (since the condition does # not depend on the dummy symbol): the result is `y > 5`. # In this case, ConditionSet is just acting like # Piecewise((Interval(1, 7), y > 5), (S.EmptySet, True)). raises(TypeError, lambda: 6 in ConditionSet(x, y > 5, Interval(1, 7))) X = MatrixSymbol('X', 2, 2) matrix_set = ConditionSet(X, Eq(X*Matrix([[1, 1], [1, 1]]), X)) Y = Matrix([[0, 0], [0, 0]]) assert matrix_set.contains(Y).doit() is S.true Z = Matrix([[1, 2], [3, 4]]) assert matrix_set.contains(Z).doit() is S.false assert isinstance(ConditionSet(x, x < 1, {x, y}).base_set, FiniteSet) raises(TypeError, lambda: ConditionSet(x, x + 1, {x, y})) raises(TypeError, lambda: ConditionSet(x, x, 1)) I = S.Integers U = S.UniversalSet C = ConditionSet assert C(x, False, I) is S.EmptySet assert C(x, True, I) is I assert C(x, x < 1, C(x, x < 2, I) ) == C(x, (x < 1) & (x < 2), I) assert C(y, y < 1, C(x, y < 2, I) ) == C(x, (x < 1) & (y < 2), I), C(y, y < 1, C(x, y < 2, I)) assert C(y, y < 1, C(x, x < 2, I) ) == C(y, (y < 1) & (y < 2), I) assert C(y, y < 1, C(x, y < x, I) ) == C(x, (x < 1) & (y < x), I) assert unchanged(C, y, x < 1, C(x, y < x, I)) assert ConditionSet(x, x < 1).base_set is U # arg checking is not done at instantiation but this # will raise an error when containment is tested assert ConditionSet((x,), x < 1).base_set is U c = ConditionSet((x, y), x < y, I**2) assert (1, 2) in c assert (1, pi) not in c raises(TypeError, lambda: C(x, x > 1, C((x, y), x > 1, I**2))) # signature mismatch since only 3 args are accepted raises(TypeError, lambda: C((x, y), x + y < 2, U, U))
def test_as_relational(): assert ConditionSet((x, y), x > 1, S.Integers**2).as_relational((x, y) ) == (x > 1) & Contains((x, y), S.Integers**2) assert ConditionSet(x, x > 1, S.Integers).as_relational(x ) == Contains(x, S.Integers) & (x > 1)
def test_issue_10555(): f = Function('f') assert solveset(f(x) - pi/2, x, S.Reals) == \ ConditionSet(x, Eq(2*f(x) - pi, 0), S.Reals)
def test_conditionset_equality(): ''' Checking equality of different representations of ConditionSet''' assert solveset(Eq(tan(x), y), x) == ConditionSet(x, Eq(tan(x), y), S.Complexes)
def test_issue_9849(): assert ConditionSet(x, Eq(x, x), S.Naturals) == S.Naturals assert ConditionSet(x, Eq(Abs(sin(x)), -1), S.Naturals) == S.EmptySet
def test_subs_CondSet(): s = FiniteSet(z, y) c = ConditionSet(x, x < 2, s) # you can only replace sym with a symbol that is not in # the free symbols assert c.subs(x, 1) == c assert c.subs(x, y) == ConditionSet(y, y < 2, s) # double subs needed to change dummy if the base set # also contains the dummy orig = ConditionSet(y, y < 2, s) base = orig.subs(y, w) and_dummy = base.subs(y, w) assert base == ConditionSet(y, y < 2, {w, z}) assert and_dummy == ConditionSet(w, w < 2, {w, z}) assert c.subs(x, w) == ConditionSet(w, w < 2, s) assert ConditionSet(x, x < y, s).subs(y, w) == ConditionSet(x, x < w, s.subs(y, w)) # if the user uses assumptions that cause the condition # to evaluate, that can't be helped from SymPy's end n = Symbol('n', negative=True) assert ConditionSet(n, 0 < n, S.Integers) is S.EmptySet p = Symbol('p', positive=True) assert ConditionSet(n, n < y, S.Integers).subs(n, x) == ConditionSet( x, x < y, S.Integers) nc = Symbol('nc', commutative=False) raises(ValueError, lambda: ConditionSet(x, x < p, S.Integers).subs(x, nc)) raises(ValueError, lambda: ConditionSet(x, x < p, S.Integers).subs(x, n)) raises(ValueError, lambda: ConditionSet(x + 1, x < 1, S.Integers)) raises(ValueError, lambda: ConditionSet(x + 1, x < 1, s)) assert ConditionSet(n, n < x, Interval(0, oo)).subs(x, p) == Interval(0, oo) assert ConditionSet(n, n < x, Interval(-oo, 0)).subs(x, p) == Interval(-oo, 0) assert ConditionSet(f(x), f(x) < 1, {w, z}).subs(f(x), y) == ConditionSet(y, y < 1, {w, z}) # issue 17341 k = Symbol('k') img1 = ImageSet(Lambda(k, 2 * k * pi + asin(y)), S.Integers) img2 = ImageSet(Lambda(k, 2 * k * pi + asin(S.One / 3)), S.Integers) assert ConditionSet(x, Contains(y, Interval(-1, 1)), img1).subs(y, S.One / 3).dummy_eq(img2)
def test_subs_CondSet_tebr(): # to eventually be removed c = ConditionSet((x, y), {x + 1, x + y}, S.Reals) assert c.subs(x, z) == c
def test_duplicate(): from sympy.core.function import BadSignatureError # test coverage for line 95 in conditionset.py, check for duplicates in symbols dup = symbols('a,a') raises(BadSignatureError, lambda: ConditionSet(dup, x < 0))
def solveset_real(f, symbol): """ Solves a real valued equation. Parameters ========== f : Expr The target equation symbol : Symbol The variable for which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is equal to zero. An `EmptySet` is returned if no solution is found. A `ConditionSet` is returned as unsolved object if algorithms to evaluate complete solutions are not yet implemented. `solveset_real` claims to be complete in the set of the solution it returns. Raises ====== NotImplementedError Algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. See Also ======= solveset_complex : solver for complex domain Examples ======== >>> from sympy import Symbol, exp, sin, sqrt, I >>> from sympy.solvers.solveset import solveset_real >>> x = Symbol('x', real=True) >>> a = Symbol('a', real=True, finite=True, positive=True) >>> solveset_real(x**2 - 1, x) {-1, 1} >>> solveset_real(sqrt(5*x + 6) - 2 - x, x) {-1, 2} >>> solveset_real(x - I, x) EmptySet() >>> solveset_real(x - a, x) {a} >>> solveset_real(exp(x) - a, x) {log(a)} * In case the equation has infinitely many solutions an infinitely indexed `ImageSet` is returned. >>> solveset_real(sin(x) - 1, x) ImageSet(Lambda(_n, 2*_n*pi + pi/2), Integers()) * If the equation is true for any arbitrary value of the symbol a `S.Reals` set is returned. >>> solveset_real(x - x, x) (-oo, oo) """ if not symbol.is_Symbol: raise ValueError(" %s is not a symbol" % (symbol)) f = sympify(f) if not isinstance(f, (Expr, Number)): raise ValueError(" %s is not a valid sympy expression" % (f)) original_eq = f f = together(f) # In this, unlike in solveset_complex, expression should only # be expanded when fraction(f)[1] does not contain the symbol # for which we are solving if not symbol in fraction(f)[1].free_symbols and f.is_rational_function(): f = expand(f) if f.has(Piecewise): f = piecewise_fold(f) result = EmptySet() if f.expand().is_zero: return S.Reals elif not f.has(symbol): return EmptySet() elif f.is_Mul and all([_is_finite_with_finite_vars(m) for m in f.args]): # if f(x) and g(x) are both finite we can say that the solution of # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in # general. g(x) can grow to infinitely large for the values where # f(x) == 0. To be sure that we are not silently allowing any # wrong solutions we are using this technique only if both f and g are # finite for a finite input. result = Union(*[solveset_real(m, symbol) for m in f.args]) elif _is_function_class_equation(TrigonometricFunction, f, symbol) or \ _is_function_class_equation(HyperbolicFunction, f, symbol): result = _solve_real_trig(f, symbol) elif f.is_Piecewise: result = EmptySet() expr_set_pairs = f.as_expr_set_pairs() for (expr, in_set) in expr_set_pairs: solns = solveset_real(expr, symbol).intersect(in_set) result = result + solns else: lhs, rhs_s = invert_real(f, 0, symbol) if lhs == symbol: result = rhs_s elif isinstance(rhs_s, FiniteSet): equations = [lhs - rhs for rhs in rhs_s] for equation in equations: if equation == f: if any( _has_rational_power(g, symbol)[0] for g in equation.args): result += _solve_radical(equation, symbol, solveset_real) elif equation.has(Abs): result += _solve_abs(f, symbol) else: result += _solve_as_rational( equation, symbol, solveset_solver=solveset_real, as_poly_solver=_solve_as_poly_real) else: result += solveset_real(equation, symbol) else: result = ConditionSet(symbol, Eq(f, 0), S.Reals) if isinstance(result, FiniteSet): result = [ s for s in result if isinstance(s, RootOf) or domain_check(original_eq, symbol, s) ] return FiniteSet(*result).intersect(S.Reals) else: return result.intersect(S.Reals)