def test_zoo(): b = Symbol('b', finite=True) nz = Symbol('nz', nonzero=True) p = Symbol('p', positive=True) n = Symbol('n', negative=True) im = Symbol('i', imaginary=True) c = Symbol('c', complex=True) pb = Symbol('pb', positive=True, finite=True) nb = Symbol('nb', negative=True, finite=True) imb = Symbol('ib', imaginary=True, finite=True) for i in [I, S.Infinity, S.NegativeInfinity, S.Zero, S.One, S.Pi, S.Half, S(3), log(3), b, nz, p, n, im, pb, nb, imb, c]: if i.is_finite and (i.is_real or i.is_imaginary): assert i + zoo is zoo assert i - zoo is zoo assert zoo + i is zoo assert zoo - i is zoo elif i.is_finite is not False: assert (i + zoo).is_Add assert (i - zoo).is_Add assert (zoo + i).is_Add assert (zoo - i).is_Add else: assert (i + zoo) is S.NaN assert (i - zoo) is S.NaN assert (zoo + i) is S.NaN assert (zoo - i) is S.NaN if fuzzy_not(i.is_zero) and (i.is_real or i.is_imaginary): assert i*zoo is zoo assert zoo*i is zoo elif i.is_zero: assert i*zoo is S.NaN assert zoo*i is S.NaN else: assert (i*zoo).is_Mul assert (zoo*i).is_Mul if fuzzy_not((1/i).is_zero) and (i.is_real or i.is_imaginary): assert zoo/i is zoo elif (1/i).is_zero: assert zoo/i is S.NaN elif i.is_zero: assert zoo/i is zoo else: assert (zoo/i).is_Mul assert (I*oo).is_Mul # allow directed infinity assert zoo + zoo is S.NaN assert zoo * zoo is zoo assert zoo - zoo is S.NaN assert zoo/zoo is S.NaN assert zoo**zoo is S.NaN assert zoo**0 is S.One assert zoo**2 is zoo assert 1/zoo is S.Zero assert Mul.flatten([S(-1), oo, S(0)]) == ([S.NaN], [], None)
def __new__(cls, *args): n = args[BinomialDistribution._argnames.index('n')] p = args[BinomialDistribution._argnames.index('p')] n_sym = sympify(n) p_sym = sympify(p) if fuzzy_not(fuzzy_and((n_sym.is_integer, n_sym.is_nonnegative))): raise ValueError("'n' must be positive integer. n = %s." % str(n)) elif fuzzy_not(fuzzy_and((p_sym.is_nonnegative, (p_sym - 1).is_nonpositive))): raise ValueError("'p' must be: 0 <= p <= 1 . p = %s" % str(p)) else: return super(BinomialDistribution, cls).__new__(cls, *args)
def eval(cls, x, k=None): if k is S.Zero: return cls(x) elif k is None: k = S.Zero if k is S.Zero: if x is S.Zero: return S.Zero if x is S.Exp1: return S.One if x == -1/S.Exp1: return S.NegativeOne if x == -log(2)/2: return -log(2) if x is S.Infinity: return S.Infinity if fuzzy_not(k.is_zero): if x is S.Zero: return S.NegativeInfinity if k is S.NegativeOne: if x == -S.Pi/2: return -S.ImaginaryUnit*S.Pi/2 elif x == -1/S.Exp1: return S.NegativeOne elif x == -2*exp(-2): return -Integer(2)
def _eval_is_algebraic(self): s = self.func(*self.args) if s.func == self.func: if fuzzy_not(self.args[0].is_zero) and self.args[0].is_algebraic: return False else: return s.is_algebraic
def Basic(expr, assumptions): if expr.is_number: notpositive = fuzzy_not(AskPositiveHandler._number(expr, assumptions)) if notpositive: return ask(Q.real(expr), assumptions) else: return notpositive
def _eval_power(self, other): if ( fuzzy_not(self.args[0].is_zero) and other.is_integer and other.is_even ): return S.One
def refine_abs(expr, assumptions): """ Handler for the absolute value. Examples ======== >>> from sympy import Symbol, Q, refine, Abs >>> from sympy.assumptions.refine import refine_abs >>> from sympy.abc import x >>> refine_abs(Abs(x), Q.real(x)) >>> refine_abs(Abs(x), Q.positive(x)) x >>> refine_abs(Abs(x), Q.negative(x)) -x """ from sympy.core.logic import fuzzy_not arg = expr.args[0] if ask(Q.real(arg), assumptions) and fuzzy_not(ask(Q.negative(arg), assumptions)): # if it's nonnegative return arg if ask(Q.negative(arg), assumptions): return -arg
def eval(cls, arg, k=0): """ Returns a simplified form or a value of DiracDelta depending on the argument passed by the DiracDelta object. The ``eval()`` method is automatically called when the ``DiracDelta`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import DiracDelta, S, Subs >>> from sympy.abc import x >>> DiracDelta(x) DiracDelta(x) >>> DiracDelta(x,1) DiracDelta(x, 1) >>> DiracDelta(1) 0 >>> DiracDelta(5,1) 0 >>> DiracDelta(0) DiracDelta(0) >>> DiracDelta(-1) 0 >>> DiracDelta(S.NaN) nan >>> DiracDelta(x).eval(1) 0 >>> DiracDelta(x - 100).subs(x, 5) 0 >>> DiracDelta(x - 100).subs(x, 100) DiracDelta(0) """ k = sympify(k) if not k.is_Integer or k.is_negative: raise ValueError("Error: the second argument of DiracDelta must be \ a non-negative integer, %s given instead." % (k,)) arg = sympify(arg) if arg is S.NaN: return S.NaN if arg.is_nonzero: return S.Zero if fuzzy_not(im(arg).is_zero): raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) )
def __new__(cls, *args): p = args[BernoulliDistribution._argnames.index('p')] p_sym = sympify(p) if fuzzy_not(fuzzy_and((p_sym.is_nonnegative, (p_sym - 1).is_nonpositive))): raise ValueError("p = %s is not in range [0, 1]." % str(p)) else: return super(BernoulliDistribution, cls).__new__(cls, *args)
def _eval_is_even(self): is_integer = self.is_integer if is_integer: return fuzzy_not(self._eval_is_odd()) elif is_integer is False: return False
def eval(cls, arg, H0=None): """ Returns a simplified form or a value of Heaviside depending on the argument passed by the Heaviside object. The ``eval()`` method is automatically called when the ``Heaviside`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import Heaviside, S >>> from sympy.abc import x >>> Heaviside(x) Heaviside(x) >>> Heaviside(19) 1 >>> Heaviside(0) Heaviside(0) >>> Heaviside(0, 1) 1 >>> Heaviside(-5) 0 >>> Heaviside(S.NaN) nan >>> Heaviside(x).eval(100) 1 >>> Heaviside(x - 100).subs(x, 5) 0 >>> Heaviside(x - 100).subs(x, 105) 1 """ H0 = sympify(H0) arg = sympify(arg) if arg.is_negative: return S.Zero elif arg.is_positive: return S.One elif arg.is_zero: return H0 elif arg is S.NaN: return S.NaN elif fuzzy_not(im(arg).is_zero): raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) )
def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if s.exp is S.Zero: return True elif s.exp.is_rational and fuzzy_not(s.exp.is_zero): return False else: return s.is_rational
def substitution_rule(integral): integrand, symbol = integral u_var = sympy.Dummy("u") substitutions = find_substitutions(integrand, symbol, u_var) if substitutions: ways = [] for u_func, c, substituted in substitutions: subrule = integral_steps(substituted, u_var) if contains_dont_know(subrule): continue if sympy.simplify(c - 1) != 0: _, denom = c.as_numer_denom() if subrule: subrule = ConstantTimesRule(c, substituted, subrule, substituted, u_var) if denom.free_symbols: piecewise = [] could_be_zero = [] if isinstance(denom, sympy.Mul): could_be_zero = denom.args else: could_be_zero.append(denom) for expr in could_be_zero: if not fuzzy_not(expr.is_zero): substep = integral_steps(integrand.subs(expr, 0), symbol) if substep: piecewise.append(( substep, sympy.Eq(expr, 0) )) piecewise.append((subrule, True)) subrule = PiecewiseRule(piecewise, substituted, symbol) ways.append(URule(u_var, u_func, c, subrule, integrand, symbol)) if len(ways) > 1: return AlternativeRule(ways, integrand, symbol) elif ways: return ways[0] elif integrand.has(sympy.exp): u_func = sympy.exp(symbol) c = 1 substituted = integrand / u_func.diff(symbol) substituted = substituted.subs(u_func, u_var) if symbol not in substituted.free_symbols: return URule(u_var, u_func, c, integral_steps(substituted, u_var), integrand, symbol)
def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if (self.args[0] - 1).is_zero: return True if s.args[0].is_rational and fuzzy_not((self.args[0] - 1).is_zero): return False else: return s.is_rational
def _eval_is_algebraic(self): s = self.func(*self.args) if s.func == self.func: if (self.args[0] - 1).is_zero: return True elif fuzzy_not((self.args[0] - 1).is_zero): if self.args[0].is_algebraic: return False else: return s.is_algebraic
def __new__(cls, density): density = Dict(density) for k in density.values(): k_sym = sympify(k) if fuzzy_not(fuzzy_and((k_sym.is_nonnegative, (k_sym - 1).is_nonpositive))): raise ValueError("Probability at a point must be between 0 and 1.") sum_sym = sum(density.values()) if sum_sym != 1: raise ValueError("Total Probability must be equal to 1.") return Basic.__new__(cls, density)
def _eval_is_real(self): x = self.args[0] if len(self.args) == 1: k = S.Zero else: k = self.args[1] if k.is_zero: if (x + 1/S.Exp1).is_positive: return True elif (x + 1/S.Exp1).is_nonpositive: return False elif (k + 1).is_zero: if x.is_negative and (x + 1/S.Exp1).is_positive: return True elif x.is_nonpositive or (x + 1/S.Exp1).is_nonnegative: return False elif fuzzy_not(k.is_zero) and fuzzy_not((k + 1).is_zero): if x.is_real: return False
def eval(cls, arg): arg = sympify(arg) if arg is S.NaN: return S.NaN elif fuzzy_not(im(arg).is_zero): raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) ) elif arg.is_negative: return S.Zero elif arg.is_positive: return S.One
def _eval_is_algebraic(self): s = self.func(*self.args) if s.func == self.func: if fuzzy_not(self.exp.is_zero): if self.exp.is_algebraic: return False elif (self.exp/S.Pi).is_rational: return False else: return s.is_algebraic
def power_rule(integral): integrand, symbol = integral base, exp = integrand.as_base_exp() if symbol not in exp.free_symbols and isinstance(base, sympy.Symbol): if sympy.simplify(exp + 1) == 0: return ReciprocalRule(base, integrand, symbol) return PowerRule(base, exp, integrand, symbol) elif symbol not in base.free_symbols and isinstance(exp, sympy.Symbol): rule = ExpRule(base, exp, integrand, symbol) if fuzzy_not(sympy.log(base).is_zero): return rule elif sympy.log(base).is_zero: return ConstantRule(1, 1, symbol) return PiecewiseRule( [(ConstantRule(1, 1, symbol), sympy.Eq(sympy.log(base), 0)), (rule, True)], integrand, symbol )
def eval(cls, i, j): """ Evaluates the discrete delta function. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy.abc import i, j, k >>> KroneckerDelta(i, j) KroneckerDelta(i, j) >>> KroneckerDelta(i, i) 1 >>> KroneckerDelta(i, i + 1) 0 >>> KroneckerDelta(i, i + 1 + k) KroneckerDelta(i, i + k + 1) # indirect doctest """ diff = i - j if diff.is_zero: return S.One elif fuzzy_not(diff.is_zero): return S.Zero if i.assumptions0.get("below_fermi") and \ j.assumptions0.get("above_fermi"): return S.Zero if j.assumptions0.get("below_fermi") and \ i.assumptions0.get("above_fermi"): return S.Zero # to make KroneckerDelta canonical # following lines will check if inputs are in order # if not, will return KroneckerDelta with correct order if i is not min(i, j, key=default_sort_key): return cls(j, i)
def refine_abs(expr, assumptions): """ Handler for the absolute value. Examples ======== >>> from sympy import Symbol, Q, refine, Abs >>> from sympy.assumptions.refine import refine_abs >>> from sympy.abc import x >>> refine_abs(Abs(x), Q.real(x)) >>> refine_abs(Abs(x), Q.positive(x)) x >>> refine_abs(Abs(x), Q.negative(x)) -x """ from sympy.core.logic import fuzzy_not from sympy import Abs arg = expr.args[0] if ask(Q.real(arg), assumptions) and \ fuzzy_not(ask(Q.negative(arg), assumptions)): # if it's nonnegative return arg if ask(Q.negative(arg), assumptions): return -arg # arg is Mul if isinstance(arg, Mul): r = [refine(abs(a), assumptions) for a in arg.args] non_abs = [] in_abs = [] for i in r: if isinstance(i, Abs): in_abs.append(i.args[0]) else: non_abs.append(i) return Mul(*non_abs) * Abs(Mul(*in_abs))
def is_gt(lhs, rhs): """Fuzzy bool for lhs is strictly greater than rhs. See the docstring for is_ge for more """ return fuzzy_not(is_le(lhs, rhs))
def is_gt(lhs, rhs, assumptions=None): """Fuzzy bool for lhs is strictly greater than rhs. See the docstring for :func:`~.is_ge` for more. """ return fuzzy_not(is_le(lhs, rhs, assumptions))
def is_eq(lhs, rhs, assumptions=None): """ Fuzzy bool representing mathematical equality between *lhs* and *rhs*. Parameters ========== lhs : Expr The left-hand side of the expression, must be sympified. rhs : Expr The right-hand side of the expression, must be sympified. assumptions: Boolean, optional Assumptions taken to evaluate the equality. Returns ======= ``True`` if *lhs* is equal to *rhs*, ``False`` is *lhs* is not equal to *rhs*, and ``None`` if the comparison between *lhs* and *rhs* is indeterminate. Explanation =========== This function is intended to give a relatively fast determination and deliberately does not attempt slow calculations that might help in obtaining a determination of True or False in more difficult cases. :func:`~.is_neq` calls this function to return its value, so supporting new type with this function will ensure correct behavior for ``is_neq`` as well. Examples ======== >>> from sympy import Q, S >>> from sympy.core.relational import is_eq, is_neq >>> from sympy.abc import x >>> is_eq(S(0), S(0)) True >>> is_neq(S(0), S(0)) False >>> is_eq(S(0), S(2)) False >>> is_neq(S(0), S(2)) True Assumptions can be passed to evaluate the equality which is otherwise indeterminate. >>> print(is_eq(x, S(0))) None >>> is_eq(x, S(0), assumptions=Q.zero(x)) True New types can be supported by dispatching to ``_eval_is_eq``. >>> from sympy import Basic, sympify >>> from sympy.multipledispatch import dispatch >>> class MyBasic(Basic): ... def __new__(cls, arg): ... return Basic.__new__(cls, sympify(arg)) ... @property ... def value(self): ... return self.args[0] ... >>> @dispatch(MyBasic, MyBasic) ... def _eval_is_eq(a, b): ... return is_eq(a.value, b.value) ... >>> a = MyBasic(1) >>> b = MyBasic(1) >>> is_eq(a, b) True >>> is_neq(a, b) False """ from sympy.assumptions.wrapper import (AssumptionsWrapper, is_infinite, is_extended_real) from sympy.core.add import Add from sympy.functions.elementary.complexes import arg from sympy.simplify.simplify import clear_coefficients from sympy.utilities.iterables import sift # here, _eval_Eq is only called for backwards compatibility # new code should use is_eq with multiple dispatch as # outlined in the docstring for side1, side2 in (lhs, rhs), (rhs, lhs): eval_func = getattr(side1, '_eval_Eq', None) if eval_func is not None: retval = eval_func(side2) if retval is not None: return retval retval = _eval_is_eq(lhs, rhs) if retval is not None: return retval if dispatch(type(lhs), type(rhs)) != dispatch(type(rhs), type(lhs)): retval = _eval_is_eq(rhs, lhs) if retval is not None: return retval # retval is still None, so go through the equality logic # If expressions have the same structure, they must be equal. if lhs == rhs: return True # e.g. True == True elif all(isinstance(i, BooleanAtom) for i in (rhs, lhs)): return False # True != False elif not (lhs.is_Symbol or rhs.is_Symbol) and (isinstance(lhs, Boolean) != isinstance(rhs, Boolean)): return False # only Booleans can equal Booleans _lhs = AssumptionsWrapper(lhs, assumptions) _rhs = AssumptionsWrapper(rhs, assumptions) if _lhs.is_infinite or _rhs.is_infinite: if fuzzy_xor([_lhs.is_infinite, _rhs.is_infinite]): return False if fuzzy_xor([_lhs.is_extended_real, _rhs.is_extended_real]): return False if fuzzy_and([_lhs.is_extended_real, _rhs.is_extended_real]): return fuzzy_xor([ _lhs.is_extended_positive, fuzzy_not(_rhs.is_extended_positive) ]) # Try to split real/imaginary parts and equate them I = S.ImaginaryUnit def split_real_imag(expr): real_imag = lambda t: ( 'real' if is_extended_real(t, assumptions) else 'imag' if is_extended_real(I * t, assumptions) else None) return sift(Add.make_args(expr), real_imag) lhs_ri = split_real_imag(lhs) if not lhs_ri[None]: rhs_ri = split_real_imag(rhs) if not rhs_ri[None]: eq_real = is_eq(Add(*lhs_ri['real']), Add(*rhs_ri['real']), assumptions) eq_imag = is_eq(I * Add(*lhs_ri['imag']), I * Add(*rhs_ri['imag']), assumptions) return fuzzy_and(map(fuzzy_bool, [eq_real, eq_imag])) # Compare e.g. zoo with 1+I*oo by comparing args arglhs = arg(lhs) argrhs = arg(rhs) # Guard against Eq(nan, nan) -> False if not (arglhs == S.NaN and argrhs == S.NaN): return fuzzy_bool(is_eq(arglhs, argrhs, assumptions)) if all(isinstance(i, Expr) for i in (lhs, rhs)): # see if the difference evaluates dif = lhs - rhs _dif = AssumptionsWrapper(dif, assumptions) z = _dif.is_zero if z is not None: if z is False and _dif.is_commutative: # issue 10728 return False if z: return True n2 = _n2(lhs, rhs) if n2 is not None: return _sympify(n2 == 0) # see if the ratio evaluates n, d = dif.as_numer_denom() rv = None _n = AssumptionsWrapper(n, assumptions) _d = AssumptionsWrapper(d, assumptions) if _n.is_zero: rv = _d.is_nonzero elif _n.is_finite: if _d.is_infinite: rv = True elif _n.is_zero is False: rv = _d.is_infinite if rv is None: # if the condition that makes the denominator # infinite does not make the original expression # True then False can be returned l, r = clear_coefficients(d, S.Infinity) args = [_.subs(l, r) for _ in (lhs, rhs)] if args != [lhs, rhs]: rv = fuzzy_bool(is_eq(*args, assumptions)) if rv is True: rv = None elif any(is_infinite(a, assumptions) for a in Add.make_args(n)): # (inf or nan)/x != 0 rv = False if rv is not None: return rv
def _contains(self, other): from sympy.solvers.solveset import _solveset_multi def get_symsetmap(signature, base_sets): '''Attempt to get a map of symbols to base_sets''' queue = list(zip(signature, base_sets)) symsetmap = {} for sig, base_set in queue: if sig.is_symbol: symsetmap[sig] = base_set elif base_set.is_ProductSet: sets = base_set.sets if len(sig) != len(sets): raise ValueError("Incompatible signature") # Recurse queue.extend(zip(sig, sets)) else: # If we get here then we have something like sig = (x, y) and # base_set = {(1, 2), (3, 4)}. For now we give up. return None return symsetmap def get_equations(expr, candidate): '''Find the equations relating symbols in expr and candidate.''' queue = [(expr, candidate)] for e, c in queue: if not isinstance(e, Tuple): yield Eq(e, c) elif not isinstance(c, Tuple) or len(e) != len(c): yield False return else: queue.extend(zip(e, c)) # Get the basic objects together: other = _sympify(other) expr = self.lamda.expr sig = self.lamda.signature variables = self.lamda.variables base_sets = self.base_sets # Use dummy symbols for ImageSet parameters so they don't match # anything in other rep = {v: Dummy(v.name) for v in variables} variables = [v.subs(rep) for v in variables] sig = sig.subs(rep) expr = expr.subs(rep) # Map the parts of other to those in the Lambda expr equations = [] for eq in get_equations(expr, other): # Unsatisfiable equation? if eq is False: return False equations.append(eq) # Map the symbols in the signature to the corresponding domains symsetmap = get_symsetmap(sig, base_sets) if symsetmap is None: # Can't factor the base sets to a ProductSet return None # Which of the variables in the Lambda signature need to be solved for? symss = (eq.free_symbols for eq in equations) variables = set(variables) & reduce(set.union, symss, set()) # Use internal multivariate solveset variables = tuple(variables) base_sets = [symsetmap[v] for v in variables] solnset = _solveset_multi(equations, variables, base_sets) if solnset is None: return None return fuzzy_not(solnset.is_empty)
def __new__(cls, lhs, rhs=None, **options): from sympy.core.add import Add from sympy.core.logic import fuzzy_bool, fuzzy_xor, fuzzy_and, fuzzy_not from sympy.core.expr import _n2 from sympy.functions.elementary.complexes import arg from sympy.simplify.simplify import clear_coefficients from sympy.utilities.iterables import sift if rhs is None: SymPyDeprecationWarning( feature="Eq(expr) with rhs default to 0", useinstead="Eq(expr, 0)", issue=16587, deprecated_since_version="1.5" ).warn() rhs = 0 lhs = _sympify(lhs) rhs = _sympify(rhs) evaluate = options.pop('evaluate', global_parameters.evaluate) if evaluate: if isinstance(lhs, Boolean) != isinstance(lhs, Boolean): # e.g. 0/1 not recognized as Boolean in SymPy return S.false # If one expression has an _eval_Eq, return its results. if hasattr(lhs, '_eval_Eq'): r = lhs._eval_Eq(rhs) if r is not None: return r if hasattr(rhs, '_eval_Eq'): r = rhs._eval_Eq(lhs) if r is not None: return r # If expressions have the same structure, they must be equal. if lhs == rhs: return S.true # e.g. True == True elif all(isinstance(i, BooleanAtom) for i in (rhs, lhs)): return S.false # True != False elif not (lhs.is_Symbol or rhs.is_Symbol) and ( isinstance(lhs, Boolean) != isinstance(rhs, Boolean)): return S.false # only Booleans can equal Booleans if lhs.is_infinite or rhs.is_infinite: if fuzzy_xor([lhs.is_infinite, rhs.is_infinite]): return S.false if fuzzy_xor([lhs.is_extended_real, rhs.is_extended_real]): return S.false if fuzzy_and([lhs.is_extended_real, rhs.is_extended_real]): r = fuzzy_xor([lhs.is_extended_positive, fuzzy_not(rhs.is_extended_positive)]) return S(r) # Try to split real/imaginary parts and equate them I = S.ImaginaryUnit def split_real_imag(expr): real_imag = lambda t: ( 'real' if t.is_extended_real else 'imag' if (I*t).is_extended_real else None) return sift(Add.make_args(expr), real_imag) lhs_ri = split_real_imag(lhs) if not lhs_ri[None]: rhs_ri = split_real_imag(rhs) if not rhs_ri[None]: eq_real = Eq(Add(*lhs_ri['real']), Add(*rhs_ri['real'])) eq_imag = Eq(I*Add(*lhs_ri['imag']), I*Add(*rhs_ri['imag'])) res = fuzzy_and(map(fuzzy_bool, [eq_real, eq_imag])) if res is not None: return S(res) # Compare e.g. zoo with 1+I*oo by comparing args arglhs = arg(lhs) argrhs = arg(rhs) # Guard against Eq(nan, nan) -> False if not (arglhs == S.NaN and argrhs == S.NaN): res = fuzzy_bool(Eq(arglhs, argrhs)) if res is not None: return S(res) return Relational.__new__(cls, lhs, rhs, **options) if all(isinstance(i, Expr) for i in (lhs, rhs)): # see if the difference evaluates dif = lhs - rhs z = dif.is_zero if z is not None: if z is False and dif.is_commutative: # issue 10728 return S.false if z: return S.true # evaluate numerically if possible n2 = _n2(lhs, rhs) if n2 is not None: return _sympify(n2 == 0) # see if the ratio evaluates n, d = dif.as_numer_denom() rv = None if n.is_zero: rv = d.is_nonzero elif n.is_finite: if d.is_infinite: rv = S.true elif n.is_zero is False: rv = d.is_infinite if rv is None: # if the condition that makes the denominator # infinite does not make the original expression # True then False can be returned l, r = clear_coefficients(d, S.Infinity) args = [_.subs(l, r) for _ in (lhs, rhs)] if args != [lhs, rhs]: rv = fuzzy_bool(Eq(*args)) if rv is True: rv = None elif any(a.is_infinite for a in Add.make_args(n)): # (inf or nan)/x != 0 rv = S.false if rv is not None: return _sympify(rv) return Relational.__new__(cls, lhs, rhs, **options)
def _eval_is_complex(self): z = self.args[1] is_negative_integer = fuzzy_and([z.is_negative, z.is_integer]) return fuzzy_and([z.is_complex, fuzzy_not(is_negative_integer)])
def is_eq(lhs, rhs): """ Fuzzy bool representing mathematical equality between lhs and rhs. Parameters ========== lhs: Expr The left-hand side of the expression, must be sympified. rhs: Expr The right-hand side of the expression, must be sympified. Returns ======= True if lhs is equal to rhs, false is lhs is not equal to rhs, and None if the comparison between lhs and rhs is indeterminate. Explanation =========== This function is intended to give a relatively fast determination and deliberately does not attempt slow calculations that might help in obtaining a determination of True or False in more difficult cases. InEquality classes, such as Lt, Gt, etc. Use one of is_ge, is_le, etc. To implement comparisons with ``Gt(a, b)`` or ``a > b`` etc for an ``Expr`` subclass it is only necessary to define a dispatcher method for ``_eval_is_ge`` like >>> from sympy.core.relational import is_eq >>> from sympy.core.relational import is_neq >>> from sympy import S, Basic, Eq, sympify >>> from sympy.abc import x >>> from sympy.multipledispatch import dispatch >>> class MyBasic(Basic): ... def __new__(cls, arg): ... return Basic.__new__(cls, sympify(arg)) ... @property ... def value(self): ... return self.args[0] ... >>> @dispatch(MyBasic, MyBasic) ... def _eval_is_eq(a, b): ... return is_eq(a.value, b.value) ... >>> a = MyBasic(1) >>> b = MyBasic(1) >>> a == b True >>> Eq(a, b) True >>> a != b False >>> is_eq(a, b) True Examples ======== >>> is_eq(S(0), S(0)) True >>> Eq(0, 0) True >>> is_neq(S(0), S(0)) False >>> is_eq(S(0), S(2)) False >>> Eq(0, 2) False >>> is_neq(S(0), S(2)) True >>> is_eq(S(0), x) >>> Eq(S(0), x) Eq(0, x) """ from sympy.core.add import Add from sympy.functions.elementary.complexes import arg from sympy.simplify.simplify import clear_coefficients from sympy.utilities.iterables import sift # here, _eval_Eq is only called for backwards compatibility # new code should use is_eq with multiple dispatch as # outlined in the docstring for side1, side2 in (lhs, rhs), (rhs, lhs): eval_func = getattr(side1, '_eval_Eq', None) if eval_func is not None: retval = eval_func(side2) if retval is not None: return retval retval = _eval_is_eq(lhs, rhs) if retval is not None: return retval if dispatch(type(lhs), type(rhs)) != dispatch(type(rhs), type(lhs)): retval = _eval_is_eq(rhs, lhs) if retval is not None: return retval # retval is still None, so go through the equality logic # If expressions have the same structure, they must be equal. if lhs == rhs: return True # e.g. True == True elif all(isinstance(i, BooleanAtom) for i in (rhs, lhs)): return False # True != False elif not (lhs.is_Symbol or rhs.is_Symbol) and (isinstance(lhs, Boolean) != isinstance(rhs, Boolean)): return False # only Booleans can equal Booleans if lhs.is_infinite or rhs.is_infinite: if fuzzy_xor([lhs.is_infinite, rhs.is_infinite]): return False if fuzzy_xor([lhs.is_extended_real, rhs.is_extended_real]): return False if fuzzy_and([lhs.is_extended_real, rhs.is_extended_real]): return fuzzy_xor([ lhs.is_extended_positive, fuzzy_not(rhs.is_extended_positive) ]) # Try to split real/imaginary parts and equate them I = S.ImaginaryUnit def split_real_imag(expr): real_imag = lambda t: ('real' if t.is_extended_real else 'imag' if (I * t).is_extended_real else None) return sift(Add.make_args(expr), real_imag) lhs_ri = split_real_imag(lhs) if not lhs_ri[None]: rhs_ri = split_real_imag(rhs) if not rhs_ri[None]: eq_real = Eq(Add(*lhs_ri['real']), Add(*rhs_ri['real'])) eq_imag = Eq(I * Add(*lhs_ri['imag']), I * Add(*rhs_ri['imag'])) return fuzzy_and(map(fuzzy_bool, [eq_real, eq_imag])) # Compare e.g. zoo with 1+I*oo by comparing args arglhs = arg(lhs) argrhs = arg(rhs) # Guard against Eq(nan, nan) -> Falsesymp if not (arglhs == S.NaN and argrhs == S.NaN): return fuzzy_bool(Eq(arglhs, argrhs)) if all(isinstance(i, Expr) for i in (lhs, rhs)): # see if the difference evaluates dif = lhs - rhs z = dif.is_zero if z is not None: if z is False and dif.is_commutative: # issue 10728 return False if z: return True n2 = _n2(lhs, rhs) if n2 is not None: return _sympify(n2 == 0) # see if the ratio evaluates n, d = dif.as_numer_denom() rv = None if n.is_zero: rv = d.is_nonzero elif n.is_finite: if d.is_infinite: rv = True elif n.is_zero is False: rv = d.is_infinite if rv is None: # if the condition that makes the denominator # infinite does not make the original expression # True then False can be returned l, r = clear_coefficients(d, S.Infinity) args = [_.subs(l, r) for _ in (lhs, rhs)] if args != [lhs, rhs]: rv = fuzzy_bool(Eq(*args)) if rv is True: rv = None elif any(a.is_infinite for a in Add.make_args(n)): # (inf or nan)/x != 0 rv = False if rv is not None: return rv
def eval(cls, arg, H0=S.Half): """ Returns a simplified form or a value of Heaviside depending on the argument passed by the Heaviside object. Explanation =========== The ``eval()`` method is automatically called when the ``Heaviside`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import Heaviside, S >>> from sympy.abc import x >>> Heaviside(x) Heaviside(x) >>> Heaviside(19) 1 >>> Heaviside(0) 1/2 >>> Heaviside(0, 1) 1 >>> Heaviside(-5) 0 >>> Heaviside(S.NaN) nan >>> Heaviside(x).eval(42) 1 >>> Heaviside(x - 100).subs(x, 5) 0 >>> Heaviside(x - 100).subs(x, 105) 1 Parameters ========== arg : argument passed by Heaviside object H0 : value of Heaviside(0) """ H0 = sympify(H0) arg = sympify(arg) if arg.is_extended_negative: return S.Zero elif arg.is_extended_positive: return S.One elif arg.is_zero: return H0 elif arg is S.NaN: return S.NaN elif fuzzy_not(im(arg).is_zero): raise ValueError( "Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)))
def _eval_is_nonzero(self): return fuzzy_not(self._args[0].is_zero)
def _eval_power(self, other): if (fuzzy_not(self.args[0].is_zero) and other.is_integer and other.is_even): return S.One
def _eval_Abs(self): if fuzzy_not(self.args[0].is_zero): return S.One
def __new__(cls, sides): sides_sym = sympify(sides) if fuzzy_not(fuzzy_and((sides_sym.is_integer, sides_sym.is_positive))): raise ValueError("'sides' must be a positive integer.") else: return super(DieDistribution, cls).__new__(cls, sides)
def roots_quartic(f): r""" Returns a list of roots of a quartic polynomial. There are many references for solving quartic expressions available [1-5]. This reviewer has found that many of them require one to select from among 2 or more possible sets of solutions and that some solutions work when one is searching for real roots but don't work when searching for complex roots (though this is not always stated clearly). The following routine has been tested and found to be correct for 0, 2 or 4 complex roots. The quasisymmetric case solution [6] looks for quartics that have the form `x**4 + A*x**3 + B*x**2 + C*x + D = 0` where `(C/A)**2 = D`. Although no general solution that is always applicable for all coefficients is known to this reviewer, certain conditions are tested to determine the simplest 4 expressions that can be returned: 1) `f = c + a*(a**2/8 - b/2) == 0` 2) `g = d - a*(a*(3*a**2/256 - b/16) + c/4) = 0` 3) if `f != 0` and `g != 0` and `p = -d + a*c/4 - b**2/12` then a) `p == 0` b) `p != 0` Examples ======== >>> from sympy import Poly, symbols, I >>> from sympy.polys.polyroots import roots_quartic >>> r = roots_quartic(Poly('x**4-6*x**3+17*x**2-26*x+20')) >>> # 4 complex roots: 1+-I*sqrt(3), 2+-I >>> sorted(str(tmp.evalf(n=2)) for tmp in r) ['1.0 + 1.7*I', '1.0 - 1.7*I', '2.0 + 1.0*I', '2.0 - 1.0*I'] References ========== 1. http://mathforum.org/dr.math/faq/faq.cubic.equations.html 2. https://en.wikipedia.org/wiki/Quartic_function#Summary_of_Ferrari.27s_method 3. http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html 4. http://staff.bath.ac.uk/masjhd/JHD-CA.pdf 5. http://www.albmath.org/files/Math_5713.pdf 6. http://www.statemaster.com/encyclopedia/Quartic-equation 7. eqworld.ipmnet.ru/en/solutions/ae/ae0108.pdf """ _, a, b, c, d = f.monic().all_coeffs() if not d: return [S.Zero] + roots([1, a, b, c], multiple=True) elif (c / a)**2 == d: x, m = f.gen, c / a g = Poly(x**2 + a * x + b - 2 * m, x) z1, z2 = roots_quadratic(g) h1 = Poly(x**2 - z1 * x + m, x) h2 = Poly(x**2 - z2 * x + m, x) r1 = roots_quadratic(h1) r2 = roots_quadratic(h2) return r1 + r2 else: a2 = a**2 e = b - 3 * a2 / 8 f = _mexpand(c + a * (a2 / 8 - b / 2)) g = _mexpand(d - a * (a * (3 * a2 / 256 - b / 16) + c / 4)) aon4 = a / 4 if f is S.Zero: y1, y2 = [sqrt(tmp) for tmp in roots([1, e, g], multiple=True)] return [tmp - aon4 for tmp in [-y1, -y2, y1, y2]] if g is S.Zero: y = [S.Zero] + roots([1, 0, e, f], multiple=True) return [tmp - aon4 for tmp in y] else: # Descartes-Euler method, see [7] sols = _roots_quartic_euler(e, f, g, aon4) if sols: return sols # Ferrari method, see [1, 2] a2 = a**2 e = b - 3 * a2 / 8 f = c + a * (a2 / 8 - b / 2) g = d - a * (a * (3 * a2 / 256 - b / 16) + c / 4) p = -e**2 / 12 - g q = -e**3 / 108 + e * g / 3 - f**2 / 8 TH = Rational(1, 3) def _ans(y): w = sqrt(e + 2 * y) arg1 = 3 * e + 2 * y arg2 = 2 * f / w ans = [] for s in [-1, 1]: root = sqrt(-(arg1 + s * arg2)) for t in [-1, 1]: ans.append((s * w - t * root) / 2 - aon4) return ans # p == 0 case y1 = -5 * e / 6 - q**TH if p.is_zero: return _ans(y1) # if p != 0 then u below is not 0 root = sqrt(q**2 / 4 + p**3 / 27) r = -q / 2 + root # or -q/2 - root u = r**TH # primary root of solve(x**3 - r, x) y2 = -5 * e / 6 + u - p / u / 3 if fuzzy_not(p.is_zero): return _ans(y2) # sort it out once they know the values of the coefficients return [ Piecewise((a1, Eq(p, 0)), (a2, True)) for a1, a2 in zip(_ans(y1), _ans(y2)) ]
def __invert__(self): a, b = self return intervalMembership(fuzzy_not(a), b)
def test_fuzzy_nand(): for args in [(1, 0), (1, 1), (0, 0)]: assert fuzzy_nand(args) == fuzzy_not(fuzzy_and(args))
def _contains(self, other): from sympy.matrices import Matrix from sympy.solvers.solveset import solveset, linsolve from sympy.solvers.solvers import solve from sympy.utilities.iterables import is_sequence, cartes L = self.lamda if is_sequence(other) != is_sequence(L.expr): return False elif is_sequence(other) and len(L.expr) != len(other): return False if self._is_multivariate(): if not is_sequence(L.expr): # exprs -> (numer, denom) and check again # XXX this is a bad idea -- make the user # remap self to desired form return other.as_numer_denom() in self.func( Lambda(L.signature, L.expr.as_numer_denom()), self.base_set) eqs = [expr - val for val, expr in zip(other, L.expr)] variables = L.variables free = set(variables) if all(i.is_number for i in list(Matrix(eqs).jacobian(variables))): solns = list(linsolve([e - val for e, val in zip(L.expr, other)], variables)) else: try: syms = [e.free_symbols & free for e in eqs] solns = {} for i, (e, s, v) in enumerate(zip(eqs, syms, other)): if not s: if e != v: return S.false solns[vars[i]] = [v] continue elif len(s) == 1: sy = s.pop() sol = solveset(e, sy) if sol is S.EmptySet: return S.false elif isinstance(sol, FiniteSet): solns[sy] = list(sol) else: raise NotImplementedError else: # if there is more than 1 symbol from # variables in expr than this is a # coupled system raise NotImplementedError solns = cartes(*[solns[s] for s in variables]) except NotImplementedError: solns = solve([e - val for e, val in zip(L.expr, other)], variables, set=True) if solns: _v, solns = solns # watch for infinite solutions like solving # for x, y and getting (x, 0), (0, y), (0, 0) solns = [i for i in solns if not any( s in i for s in variables)] if not solns: return False else: # not sure if [] means no solution or # couldn't find one return else: x = L.variables[0] if isinstance(L.expr, Expr): # scalar -> scalar mapping solnsSet = solveset(L.expr - other, x) if solnsSet.is_FiniteSet: solns = list(solnsSet) else: msgset = solnsSet else: # scalar -> vector # note: it is not necessary for components of other # to be in the corresponding base set unless the # computed component is always in the corresponding # domain. e.g. 1/2 is in imageset(x, x/2, Integers) # while it cannot be in imageset(x, x + 2, Integers). # So when the base set is comprised of integers or reals # perhaps a pre-check could be done to see if the computed # values are still in the set. dom = self.base_set for e, o in zip(L.expr, other): dom = dom.intersection(solveset(e - o, x, domain=dom)) if dom.is_empty: # there is no solution in common return False return fuzzy_not(dom.is_empty) for soln in solns: try: if soln in self.base_set: return True except TypeError: return return S.false
def _eval_is_integer(self): from sympy.core.logic import fuzzy_and, fuzzy_not p, q = self.args if fuzzy_and([p.is_integer, q.is_integer, fuzzy_not(q.is_zero)]): return True
def is_subset_sets(a_interval, b_fs): # noqa:F811 # An Interval can only be a subset of a finite set if it is finite # which can only happen if it has zero measure. if fuzzy_not(a_interval.measure.is_zero): return False
def test_fuzzy_not(): assert fuzzy_not(T) == F assert fuzzy_not(F) == T assert fuzzy_not(U) == U
def test_zoo(): b = Symbol('b', finite=True) nz = Symbol('nz', nonzero=True) p = Symbol('p', positive=True) n = Symbol('n', negative=True) im = Symbol('i', imaginary=True) c = Symbol('c', complex=True) pb = Symbol('pb', positive=True, finite=True) nb = Symbol('nb', negative=True, finite=True) imb = Symbol('ib', imaginary=True, finite=True) for i in [ I, S.Infinity, S.NegativeInfinity, S.Zero, S.One, S.Pi, S.Half, S(3), log(3), b, nz, p, n, im, pb, nb, imb, c ]: if i.is_finite and (i.is_real or i.is_imaginary): assert i + zoo is zoo assert i - zoo is zoo assert zoo + i is zoo assert zoo - i is zoo elif i.is_finite is not False: assert (i + zoo).is_Add assert (i - zoo).is_Add assert (zoo + i).is_Add assert (zoo - i).is_Add else: assert (i + zoo) is S.NaN assert (i - zoo) is S.NaN assert (zoo + i) is S.NaN assert (zoo - i) is S.NaN if fuzzy_not(i.is_zero) and (i.is_real or i.is_imaginary): assert i * zoo is zoo assert zoo * i is zoo elif i.is_zero: assert i * zoo is S.NaN assert zoo * i is S.NaN else: assert (i * zoo).is_Mul assert (zoo * i).is_Mul if fuzzy_not((1 / i).is_zero) and (i.is_real or i.is_imaginary): assert zoo / i is zoo elif (1 / i).is_zero: assert zoo / i is S.NaN elif i.is_zero: assert zoo / i is zoo else: assert (zoo / i).is_Mul assert (I * oo).is_Mul # allow directed infinity assert zoo + zoo is S.NaN assert zoo * zoo is zoo assert zoo - zoo is S.NaN assert zoo / zoo is S.NaN assert zoo**zoo is S.NaN assert zoo**0 is S.One assert zoo**2 is zoo assert 1 / zoo is S.Zero assert Mul.flatten([S(-1), oo, S(0)]) == ([S.NaN], [], None)
def Basic(expr, assumptions): return fuzzy_and([fuzzy_not(ask(Q.nonzero(expr), assumptions)), ask(Q.real(expr), assumptions)])
def is_neq(lhs, rhs, assumptions=None): """Fuzzy bool for lhs does not equal rhs. See the docstring for :func:`~.is_eq` for more. """ return fuzzy_not(is_eq(lhs, rhs, assumptions))
def eval(cls, arg, k=0): """ Returns a simplified form or a value of DiracDelta depending on the argument passed by the DiracDelta object. The ``eval()`` method is automatically called when the ``DiracDelta`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import DiracDelta, S, Subs >>> from sympy.abc import x >>> DiracDelta(x) DiracDelta(x) >>> DiracDelta(x,1) DiracDelta(x, 1) >>> DiracDelta(1) 0 >>> DiracDelta(5,1) 0 >>> DiracDelta(0) DiracDelta(0) >>> DiracDelta(-1) 0 >>> DiracDelta(S.NaN) nan >>> DiracDelta(x).eval(1) 0 >>> DiracDelta(x - 100).subs(x, 5) 0 >>> DiracDelta(x - 100).subs(x, 100) DiracDelta(0) """ k = sympify(k) if not k.is_Integer or k.is_negative: raise ValueError( "Error: the second argument of DiracDelta must be \ a non-negative integer, %s given instead." % (k, )) arg = sympify(arg) if arg is S.NaN: return S.NaN if arg.is_positive or arg.is_negative: return S.Zero if fuzzy_not(im(arg).is_zero): raise ValueError( "Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)))
def is_neq(lhs, rhs): """Fuzzy bool for lhs does not equal rhs. See the docstring for is_eq for more """ return fuzzy_not(is_eq(lhs, rhs))
def eval(cls, variable, offset, exponent): """ Returns a simplified form or a value of Singularity Function depending on the argument passed by the object. The ``eval()`` method is automatically called when the ``SingularityFunction`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import SingularityFunction, Symbol, nan >>> from sympy.abc import x, a, n >>> SingularityFunction(x, a, n) SingularityFunction(x, a, n) >>> SingularityFunction(5, 3, 2) 4 >>> SingularityFunction(x, a, nan) nan >>> SingularityFunction(x, 3, 0).subs(x, 3) 1 >>> SingularityFunction(x, a, n).eval(3, 5, 1) 0 >>> SingularityFunction(x, a, n).eval(4, 1, 5) 243 >>> x = Symbol('x', positive = True) >>> a = Symbol('a', negative = True) >>> n = Symbol('n', nonnegative = True) >>> SingularityFunction(x, a, n) (-a + x)**n >>> x = Symbol('x', negative = True) >>> a = Symbol('a', positive = True) >>> SingularityFunction(x, a, n) 0 """ x = sympify(variable) a = sympify(offset) n = sympify(exponent) shift = (x - a) if fuzzy_not(im(shift).is_zero): raise ValueError("Singularity Functions are defined only for Real Numbers.") if fuzzy_not(im(n).is_zero): raise ValueError("Singularity Functions are not defined for imaginary exponents.") if shift is S.NaN or n is S.NaN: return S.NaN if (n + 2).is_negative: raise ValueError("Singularity Functions are not defined for exponents less than -2.") if shift.is_negative: return S.Zero if n.is_nonnegative and shift.is_nonnegative: return (x - a)**n if n == -1 or n == -2: if shift.is_negative or shift.is_positive: return S.Zero if shift.is_zero: return S.Infinity
def eval(cls, arg, k=0): """ Returns a simplified form or a value of DiracDelta depending on the argument passed by the DiracDelta object. The ``eval()`` method is automatically called when the ``DiracDelta`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import DiracDelta, S, Subs >>> from sympy.abc import x >>> DiracDelta(x) DiracDelta(x) >>> DiracDelta(-x, 1) -DiracDelta(x, 1) >>> DiracDelta(1) 0 >>> DiracDelta(5, 1) 0 >>> DiracDelta(0) DiracDelta(0) >>> DiracDelta(-1) 0 >>> DiracDelta(S.NaN) nan >>> DiracDelta(x).eval(1) 0 >>> DiracDelta(x - 100).subs(x, 5) 0 >>> DiracDelta(x - 100).subs(x, 100) DiracDelta(0) """ k = sympify(k) if not k.is_Integer or k.is_negative: raise ValueError( "Error: the second argument of DiracDelta must be \ a non-negative integer, %s given instead." % (k, )) arg = sympify(arg) if arg is S.NaN: return S.NaN if arg.is_nonzero: return S.Zero if fuzzy_not(im(arg).is_zero): raise ValueError( filldedent(''' Function defined only for Real Values. Complex part: %s found in %s .''' % (repr(im(arg)), repr(arg)))) c, nc = arg.args_cnc() if c and c[0] == -1: # keep this fast and simple instead of using # could_extract_minus_sign if k % 2 == 1: return -cls(-arg, k) elif k % 2 == 0: return cls(-arg, k) if k else cls(-arg)
def _eval_is_complex(self): z = self.args[0] return fuzzy_and([z.is_complex, fuzzy_not(z.is_zero)])
def eval(cls, variable, offset, exponent): """ Returns a simplified form or a value of Singularity Function depending on the argument passed by the object. Explanation =========== The ``eval()`` method is automatically called when the ``SingularityFunction`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import SingularityFunction, Symbol, nan >>> from sympy.abc import x, a, n >>> SingularityFunction(x, a, n) SingularityFunction(x, a, n) >>> SingularityFunction(5, 3, 2) 4 >>> SingularityFunction(x, a, nan) nan >>> SingularityFunction(x, 3, 0).subs(x, 3) 1 >>> SingularityFunction(x, a, n).eval(3, 5, 1) 0 >>> SingularityFunction(x, a, n).eval(4, 1, 5) 243 >>> x = Symbol('x', positive = True) >>> a = Symbol('a', negative = True) >>> n = Symbol('n', nonnegative = True) >>> SingularityFunction(x, a, n) (-a + x)**n >>> x = Symbol('x', negative = True) >>> a = Symbol('a', positive = True) >>> SingularityFunction(x, a, n) 0 """ x = sympify(variable) a = sympify(offset) n = sympify(exponent) shift = (x - a) if fuzzy_not(im(shift).is_zero): raise ValueError( "Singularity Functions are defined only for Real Numbers.") if fuzzy_not(im(n).is_zero): raise ValueError( "Singularity Functions are not defined for imaginary exponents." ) if shift is S.NaN or n is S.NaN: return S.NaN if (n + 2).is_negative: raise ValueError( "Singularity Functions are not defined for exponents less than -2." ) if shift.is_extended_negative: return S.Zero if n.is_nonnegative and shift.is_extended_nonnegative: return (x - a)**n if n == -1 or n == -2: if shift.is_negative or shift.is_extended_positive: return S.Zero if shift.is_zero: return S.Infinity
def Basic(expr, assumptions): return fuzzy_and([ fuzzy_not(ask(Q.nonzero(expr), assumptions)), ask(Q.real(expr), assumptions) ])
def roots_quartic(f): r""" Returns a list of roots of a quartic polynomial. There are many references for solving quartic expressions available [1-5]. This reviewer has found that many of them require one to select from among 2 or more possible sets of solutions and that some solutions work when one is searching for real roots but don't work when searching for complex roots (though this is not always stated clearly). The following routine has been tested and found to be correct for 0, 2 or 4 complex roots. The quasisymmetric case solution [6] looks for quartics that have the form `x**4 + A*x**3 + B*x**2 + C*x + D = 0` where `(C/A)**2 = D`. Although no general solution that is always applicable for all coefficients is known to this reviewer, certain conditions are tested to determine the simplest 4 expressions that can be returned: 1) `f = c + a*(a**2/8 - b/2) == 0` 2) `g = d - a*(a*(3*a**2/256 - b/16) + c/4) = 0` 3) if `f != 0` and `g != 0` and `p = -d + a*c/4 - b**2/12` then a) `p == 0` b) `p != 0` Examples ======== >>> from sympy import Poly, symbols, I >>> from sympy.polys.polyroots import roots_quartic >>> r = roots_quartic(Poly('x**4-6*x**3+17*x**2-26*x+20')) >>> # 4 complex roots: 1+-I*sqrt(3), 2+-I >>> sorted(str(tmp.evalf(n=2)) for tmp in r) ['1.0 + 1.7*I', '1.0 - 1.7*I', '2.0 + 1.0*I', '2.0 - 1.0*I'] References ========== 1. http://mathforum.org/dr.math/faq/faq.cubic.equations.html 2. https://en.wikipedia.org/wiki/Quartic_function#Summary_of_Ferrari.27s_method 3. http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html 4. http://staff.bath.ac.uk/masjhd/JHD-CA.pdf 5. http://www.albmath.org/files/Math_5713.pdf 6. http://www.statemaster.com/encyclopedia/Quartic-equation 7. eqworld.ipmnet.ru/en/solutions/ae/ae0108.pdf """ _, a, b, c, d = f.monic().all_coeffs() if not d: return [S.Zero] + roots([1, a, b, c], multiple=True) elif (c/a)**2 == d: x, m = f.gen, c/a g = Poly(x**2 + a*x + b - 2*m, x) z1, z2 = roots_quadratic(g) h1 = Poly(x**2 - z1*x + m, x) h2 = Poly(x**2 - z2*x + m, x) r1 = roots_quadratic(h1) r2 = roots_quadratic(h2) return r1 + r2 else: a2 = a**2 e = b - 3*a2/8 f = _mexpand(c + a*(a2/8 - b/2)) g = _mexpand(d - a*(a*(3*a2/256 - b/16) + c/4)) aon4 = a/4 if f is S.Zero: y1, y2 = [sqrt(tmp) for tmp in roots([1, e, g], multiple=True)] return [tmp - aon4 for tmp in [-y1, -y2, y1, y2]] if g is S.Zero: y = [S.Zero] + roots([1, 0, e, f], multiple=True) return [tmp - aon4 for tmp in y] else: # Descartes-Euler method, see [7] sols = _roots_quartic_euler(e, f, g, aon4) if sols: return sols # Ferrari method, see [1, 2] a2 = a**2 e = b - 3*a2/8 f = c + a*(a2/8 - b/2) g = d - a*(a*(3*a2/256 - b/16) + c/4) p = -e**2/12 - g q = -e**3/108 + e*g/3 - f**2/8 TH = Rational(1, 3) def _ans(y): w = sqrt(e + 2*y) arg1 = 3*e + 2*y arg2 = 2*f/w ans = [] for s in [-1, 1]: root = sqrt(-(arg1 + s*arg2)) for t in [-1, 1]: ans.append((s*w - t*root)/2 - aon4) return ans # p == 0 case y1 = -5*e/6 - q**TH if p.is_zero: return _ans(y1) # if p != 0 then u below is not 0 root = sqrt(q**2/4 + p**3/27) r = -q/2 + root # or -q/2 - root u = r**TH # primary root of solve(x**3 - r, x) y2 = -5*e/6 + u - p/u/3 if fuzzy_not(p.is_zero): return _ans(y2) # sort it out once they know the values of the coefficients return [Piecewise((a1, Eq(p, 0)), (a2, True)) for a1, a2 in zip(_ans(y1), _ans(y2))]
def _eval_is_extended_positive(self): return fuzzy_not(self._args[0].is_zero)