123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- from sympy.core import Basic, Expr
- from sympy.core.function import Lambda
- from sympy.core.numbers import oo, Infinity, NegativeInfinity, Zero, Integer
- from sympy.core.singleton import S
- from sympy.core.symbol import symbols
- from sympy.functions.elementary.miscellaneous import (Max, Min)
- from sympy.sets.fancysets import ImageSet
- from sympy.sets.setexpr import set_div
- from sympy.sets.sets import Set, Interval, FiniteSet, Union
- from sympy.multipledispatch import Dispatcher
- _x, _y = symbols("x y")
- _set_pow = Dispatcher('_set_pow')
- @_set_pow.register(Basic, Basic)
- def _(x, y):
- return None
- @_set_pow.register(Set, Set)
- def _(x, y):
- return ImageSet(Lambda((_x, _y), (_x ** _y)), x, y)
- @_set_pow.register(Expr, Expr)
- def _(x, y):
- return x**y
- @_set_pow.register(Interval, Zero)
- def _(x, z):
- return FiniteSet(S.One)
- @_set_pow.register(Interval, Integer)
- def _(x, exponent):
- """
- Powers in interval arithmetic
- https://en.wikipedia.org/wiki/Interval_arithmetic
- """
- s1 = x.start**exponent
- s2 = x.end**exponent
- if ((s2 > s1) if exponent > 0 else (x.end > -x.start)) == True:
- left_open = x.left_open
- right_open = x.right_open
- # TODO: handle unevaluated condition.
- sleft = s2
- else:
- # TODO: `s2 > s1` could be unevaluated.
- left_open = x.right_open
- right_open = x.left_open
- sleft = s1
- if x.start.is_positive:
- return Interval(
- Min(s1, s2),
- Max(s1, s2), left_open, right_open)
- elif x.end.is_negative:
- return Interval(
- Min(s1, s2),
- Max(s1, s2), left_open, right_open)
- # Case where x.start < 0 and x.end > 0:
- if exponent.is_odd:
- if exponent.is_negative:
- if x.start.is_zero:
- return Interval(s2, oo, x.right_open)
- if x.end.is_zero:
- return Interval(-oo, s1, True, x.left_open)
- return Union(Interval(-oo, s1, True, x.left_open), Interval(s2, oo, x.right_open))
- else:
- return Interval(s1, s2, x.left_open, x.right_open)
- elif exponent.is_even:
- if exponent.is_negative:
- if x.start.is_zero:
- return Interval(s2, oo, x.right_open)
- if x.end.is_zero:
- return Interval(s1, oo, x.left_open)
- return Interval(0, oo)
- else:
- return Interval(S.Zero, sleft, S.Zero not in x, left_open)
- @_set_pow.register(Interval, Infinity)
- def _(b, e):
- # TODO: add logic for open intervals?
- if b.start.is_nonnegative:
- if b.end < 1:
- return FiniteSet(S.Zero)
- if b.start > 1:
- return FiniteSet(S.Infinity)
- return Interval(0, oo)
- elif b.end.is_negative:
- if b.start > -1:
- return FiniteSet(S.Zero)
- if b.end < -1:
- return FiniteSet(-oo, oo)
- return Interval(-oo, oo)
- else:
- if b.start > -1:
- if b.end < 1:
- return FiniteSet(S.Zero)
- return Interval(0, oo)
- return Interval(-oo, oo)
- @_set_pow.register(Interval, NegativeInfinity)
- def _(b, e):
- return _set_pow(set_div(S.One, b), oo)
|