|
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 |
|
|
|
sleft = s2 |
|
else: |
|
|
|
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) |
|
|
|
|
|
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): |
|
|
|
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) |
|
|