def cond(): d = self._smat yield self.is_square if len(d) <= self.rows: yield fuzzy_and(d[i, i].is_real for i, j in d if i == j) else: yield fuzzy_and(d[i, i].is_real for i in range(self.rows) if (i, i) in d) yield fuzzy_and(((self[i, j] - self[j, i].conjugate()).is_zero if (j, i) in d else False) for (i, j) in d)
def test_fuzzy_and(): assert fuzzy_and([T, T]) == T assert fuzzy_and([T, F]) == F assert fuzzy_and([T, U]) == U assert fuzzy_and([F, F]) == F assert fuzzy_and([F, U]) == F assert fuzzy_and([U, U]) == U assert [fuzzy_and([w]) for w in [U, T, F]] == [U, T, F] assert fuzzy_and([T, F, U]) == F assert fuzzy_and([]) == T raises(TypeError, lambda: fuzzy_and())
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 __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 _old_assump_replacer(obj): # Things to be careful of: # - real means real or infinite in the old assumptions. # - nonzero does not imply real in the old assumptions. # - finite means finite and not zero in the old assumptions. if not isinstance(obj, AppliedPredicate): return obj e = obj.args[0] ret = None if obj.func == Q.positive: ret = fuzzy_and([e.is_finite, e.is_positive]) if obj.func == Q.zero: ret = e.is_zero if obj.func == Q.negative: ret = fuzzy_and([e.is_finite, e.is_negative]) if obj.func == Q.nonpositive: ret = fuzzy_and([e.is_finite, e.is_nonpositive]) if obj.func == Q.nonzero: ret = fuzzy_and([e.is_nonzero, e.is_finite]) if obj.func == Q.nonnegative: ret = fuzzy_and([fuzzy_or([e.is_zero, e.is_finite]), e.is_nonnegative]) if obj.func == Q.rational: ret = e.is_rational if obj.func == Q.irrational: ret = e.is_irrational if obj.func == Q.even: ret = e.is_even if obj.func == Q.odd: ret = e.is_odd if obj.func == Q.integer: ret = e.is_integer if obj.func == Q.imaginary: ret = e.is_imaginary if obj.func == Q.commutative: ret = e.is_commutative if ret is None: return obj return ret
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 _from_args(cls, args, is_commutative=None): """Create new instance with already-processed args""" if len(args) == 0: return cls.identity elif len(args) == 1: return args[0] obj = super(AssocOp, cls).__new__(cls, *args) if is_commutative is None: is_commutative = fuzzy_and(a.is_commutative for a in args) obj.is_commutative = is_commutative return obj
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: return (x + 1/S.Exp1).is_positive elif (k + 1).is_zero: from sympy.core.logic import fuzzy_and return fuzzy_and([x.is_negative, (x + 1/S.Exp1).is_positive]) elif k.is_nonzero and (k + 1).is_nonzero: return False
def is_hermitian(self): """Checks if the matrix is Hermitian. In a Hermitian matrix element i,j is the complex conjugate of element j,i. Examples ======== >>> from sympy.matrices import SparseMatrix >>> from sympy import I >>> from sympy.abc import x >>> a = SparseMatrix([[1, I], [-I, 1]]) >>> a Matrix([ [ 1, I], [-I, 1]]) >>> a.is_hermitian True >>> a[0, 0] = 2*I >>> a.is_hermitian False >>> a[0, 0] = x >>> a.is_hermitian >>> a[0, 1] = a[1, 0]*I >>> a.is_hermitian False """ def cond(): d = self._smat yield self.is_square if len(d) <= self.rows: yield fuzzy_and( d[i, i].is_real for i, j in d if i == j) else: yield fuzzy_and( d[i, i].is_real for i in range(self.rows) if (i, i) in d) yield fuzzy_and( ((self[i, j] - self[j, i].conjugate()).is_zero if (j, i) in d else False) for (i, j) in d) return fuzzy_and(i for i in cond())
def _eval_is_integer(self): return fuzzy_and([self.args[0].is_integer, self.args[0].is_positive])
def _(a, b): if a.step == b.step == 1: return fuzzy_and( [fuzzy_bool(a.start >= b.start), fuzzy_bool(a.stop <= b.stop)])
def MatMul_elements(matrix_predicate, scalar_predicate, expr, assumptions): d = sift(expr.args, lambda x: isinstance(x, MatrixExpr)) factors, matrices = d[False], d[True] return fuzzy_and([ test_closed_group(Basic(*factors), assumptions, scalar_predicate), test_closed_group(Basic(*matrices), assumptions, matrix_predicate)])
def _eval_is_positive(self): return fuzzy_and(a.is_positive for a in self.args)
def _eval_is_eq(lhs, rhs): # noqa: F811 if len(lhs.sets) != len(rhs.sets): return False eqs = (is_eq(x, y) for x, y in zip(lhs.sets, rhs.sets)) return tfn[fuzzy_and(map(fuzzy_bool, eqs))]
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 _eval_is_extended_negative(self): return fuzzy_and(arg.is_extended_negative for arg in self.args)
def _eval_is_extended_real(self): return fuzzy_and(arg.is_extended_real for arg in self.args)
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_eq(lhs, rhs): """ Fuzzy bool representing mathematical equality between lhs and rhs. :param lhs: the left-hand side of the expression, must be sympified :param rhs: the right-hand side of the expression, must be sympified :return: 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 Notes: 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_is_eq(lhs, rhs): # noqa: F811 return tfn[fuzzy_and(a.is_subset(b) for a, b in [(lhs, rhs), (rhs, lhs)])]
def __getitem__(self, i): from sympy.functions.elementary.integers import ceiling ooslice = "cannot slice from the end with an infinite value" zerostep = "slice step cannot be zero" infinite = "slicing not possible on range with infinite start" # if we had to take every other element in the following # oo, ..., 6, 4, 2, 0 # we might get oo, ..., 4, 0 or oo, ..., 6, 2 ambiguous = "cannot unambiguously re-stride from the end " + \ "with an infinite value" if isinstance(i, slice): if self.size.is_finite: # validates, too if self.start == self.stop: return Range(0) start, stop, step = i.indices(self.size) n = ceiling((stop - start)/step) if n <= 0: return Range(0) canonical_stop = start + n*step end = canonical_stop - step ss = step*self.step return Range(self[start], self[end] + ss, ss) else: # infinite Range start = i.start stop = i.stop if i.step == 0: raise ValueError(zerostep) step = i.step or 1 ss = step*self.step #--------------------- # handle infinite Range # i.e. Range(-oo, oo) or Range(oo, -oo, -1) # -------------------- if self.start.is_infinite and self.stop.is_infinite: raise ValueError(infinite) #--------------------- # handle infinite on right # e.g. Range(0, oo) or Range(0, -oo, -1) # -------------------- if self.stop.is_infinite: # start and stop are not interdependent -- # they only depend on step --so we use the # equivalent reversed values return self.reversed[ stop if stop is None else -stop + 1: start if start is None else -start: step].reversed #--------------------- # handle infinite on the left # e.g. Range(oo, 0, -1) or Range(-oo, 0) # -------------------- # consider combinations of # start/stop {== None, < 0, == 0, > 0} and # step {< 0, > 0} if start is None: if stop is None: if step < 0: return Range(self[-1], self.start, ss) elif step > 1: raise ValueError(ambiguous) else: # == 1 return self elif stop < 0: if step < 0: return Range(self[-1], self[stop], ss) else: # > 0 return Range(self.start, self[stop], ss) elif stop == 0: if step > 0: return Range(0) else: # < 0 raise ValueError(ooslice) elif stop == 1: if step > 0: raise ValueError(ooslice) # infinite singleton else: # < 0 raise ValueError(ooslice) else: # > 1 raise ValueError(ooslice) elif start < 0: if stop is None: if step < 0: return Range(self[start], self.start, ss) else: # > 0 return Range(self[start], self.stop, ss) elif stop < 0: return Range(self[start], self[stop], ss) elif stop == 0: if step < 0: raise ValueError(ooslice) else: # > 0 return Range(0) elif stop > 0: raise ValueError(ooslice) elif start == 0: if stop is None: if step < 0: raise ValueError(ooslice) # infinite singleton elif step > 1: raise ValueError(ambiguous) else: # == 1 return self elif stop < 0: if step > 1: raise ValueError(ambiguous) elif step == 1: return Range(self.start, self[stop], ss) else: # < 0 return Range(0) else: # >= 0 raise ValueError(ooslice) elif start > 0: raise ValueError(ooslice) else: if self.start == self.stop: raise IndexError('Range index out of range') if not (all(i.is_integer or i.is_infinite for i in self.args) and ((self.stop - self.start)/ self.step).is_extended_positive): raise ValueError('Invalid method for symbolic Range') if i == 0: if self.start.is_infinite: raise ValueError(ooslice) return self.start if i == -1: if self.stop.is_infinite: raise ValueError(ooslice) return self.stop - self.step n = self.size # must be known for any other index rv = (self.stop if i < 0 else self.start) + i*self.step if rv.is_infinite: raise ValueError(ooslice) val = (rv - self.start)/self.step rel = fuzzy_or([val.is_infinite, fuzzy_and([val.is_nonnegative, (n-val).is_nonnegative])]) if rel: return rv if rel is None: raise ValueError('Invalid method for symbolic Range') raise IndexError("Range index out of range")
def _(expr, assumptions): if expr.rowblocksizes != expr.colblocksizes: return None return fuzzy_and([ask(Q.invertible(a), assumptions) for a in expr.diag])
def _eval_is_eq(lhs, rhs): # noqa:F811 if len(lhs) != len(rhs): return False return fuzzy_and(fuzzy_bool(is_eq(s, o)) for s, o in zip(lhs, rhs))
def _eval_is_finite(self): return fuzzy_and(arg.is_finite for arg in self.args)
def all_in_both(): s_set = set(lhs.args) o_set = set(rhs.args) yield fuzzy_and(lhs._contains(e) for e in o_set - s_set) yield fuzzy_and(rhs._contains(e) for e in s_set - o_set)
def _eval_is_complex(self): z = self.args[0] return fuzzy_and([z.is_complex, fuzzy_not(z.is_zero)])
def _eval_is_integer(self): from sympy.core.logic import fuzzy_and p, q = self.args return fuzzy_and([p.is_integer, q.is_integer, q.is_nonzero])
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) -> Falsesymp 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 __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 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_nonnegative(self): return fuzzy_and(a.is_nonnegative for a in self.args)
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_subset_sets(a, b): # noqa:F811 if a.step == b.step == 1: return fuzzy_and( [fuzzy_bool(a.start >= b.start), fuzzy_bool(a.stop <= b.stop)])
def _(a_ps, b_fs): return fuzzy_and(b_fs.contains(x) for x in a_ps)
def test_fuzzy_and(): assert fuzzy_and(*[T, T]) == T assert fuzzy_and(*[T, F]) == F assert fuzzy_and(*[T, U]) == U assert fuzzy_and(*[F, F]) == F assert fuzzy_and(*[F, U]) == F assert fuzzy_and(*[U, U]) == U assert fuzzy_and([T, T]) == T assert fuzzy_and([T, F]) == F assert fuzzy_and([T, U]) == U assert fuzzy_and([F, F]) == F assert fuzzy_and([F, U]) == F assert fuzzy_and([U, U]) == U
def _eval_is_positive(self): return fuzzy_and((self.args[0].is_integer, (self.args[0] + 1).is_nonnegative))
def is_real(self): return fuzzy_and(arg.is_real for arg in self.args)
def _eval_is_zero(self): x = self.args[0] if len(self.args) == 1: return x.is_zero else: return fuzzy_and([x.is_zero, self.args[1].is_zero])
def _eval_is_ge(lhs, rhs): if type(lhs) == PowTest and type(rhs) == PowTest: return fuzzy_and([ is_ge(lhs.args[0], rhs.args[0]), is_ge(lhs.args[1], rhs.args[1]) ])
def test_fuzzy_and(): assert fuzzy_and(*[T, T]) == T assert fuzzy_and(*[T, F]) == F assert fuzzy_and(*[T, U]) == U assert fuzzy_and(*[F, F]) == F assert fuzzy_and(*[F, U]) == F assert fuzzy_and(*[U, U]) == U assert fuzzy_and([T, T]) == T assert fuzzy_and([T, F]) == F assert fuzzy_and([T, U]) == U assert fuzzy_and([F, F]) == F assert fuzzy_and([F, U]) == F assert fuzzy_and([U, U]) == U assert [fuzzy_and(w) for w in [U, T, F]] == [U, T, F] raises(ValueError, lambda: fuzzy_and([])) raises(ValueError, lambda: fuzzy_and())
def Basic(expr, assumptions): return fuzzy_and([fuzzy_not(ask(Q.nonzero(expr), assumptions)), ask(Q.real(expr), assumptions)])
def _eval_is_integer(self): return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer, self.args[1].is_nonnegative))
def _(expr, assumptions): return fuzzy_and([fuzzy_not(ask(Q.nonzero(expr), assumptions)), ask(Q.real(expr), assumptions)])