%PDF- %PDF-
| Direktori : /lib/python3/dist-packages/pythran/ |
| Current File : //lib/python3/dist-packages/pythran/interval.py |
""" Module with facilities to represent range values. """
from math import isinf, isnan
import itertools
import numpy
class Interval(object):
""" Representation for a range of values. """
def __init__(self, low, high):
""" Set initial bound of the range object. """
if isnan(low):
low = -float('inf')
if isnan(high):
high = +float('inf')
self._low = low
self._high = high
@property
def low(self):
return self._low
@property
def high(self):
return self._high
def __repr__(self):
""" Return a nicely formatted representation string. """
return "Interval(low={low}, high={high})".format(low=self.low,
high=self.high)
def bounds(self):
return self.low, self.high
def __contains__(self, value):
return self.low <= value <= self.high
def union(self, other):
""" Intersect current range with other."""
return Interval(min(self.low, other.low), max(self.high, other.high))
def intersect(self, other):
return Interval(max(self.low, other.low), min(self.high, other.high))
def copy(self):
return Interval(self.low, self.high)
def widen(self, other):
""" Widen current range. """
if self.low < other.low:
low = -float("inf")
else:
low = self.low
if self.high > other.high:
high = float("inf")
else:
high = self.high
return Interval(low, high)
def __mul__(self, other):
"""
Combiner for Multiplication operation.
>>> Interval(1, 5) * Interval(-5, -4)
Interval(low=-25, high=-4)
>>> Interval(-1, 5) * Interval(-5, 3)
Interval(low=-25, high=15)
>>> Interval(1, 5) * Interval(3, 8)
Interval(low=3, high=40)
"""
def all_bounds():
return itertools.chain(self.bounds(), other.bounds())
if any(map(isinf, all_bounds())) and any(x == 0 for x in all_bounds()):
return UNKNOWN_RANGE
res = [v1 * v2 for v1, v2 in
itertools.product(self.bounds(), other.bounds())]
return Interval(min(res), max(res))
__mult__ = __mul__
def __div__(self, other):
"""
Combiner for Divide operation.
>>> Interval(-1, 5) / Interval(3, 8)
Interval(low=-1, high=1)
>>> Interval(-1, 5) / Interval(-5, -4)
Interval(low=-2, high=0)
>>> Interval(-1, 5) / Interval(-5, 3)
Interval(low=-inf, high=inf)
"""
if other.low <= 0 and other.high >= 0:
return UNKNOWN_RANGE
if other.low == 0:
return UNKNOWN_RANGE
def all_bounds():
return itertools.chain(self.bounds(), other.bounds())
if any(isinf(x) for x in all_bounds()):
return UNKNOWN_RANGE
res = [v1 // v2 for v1, v2 in
itertools.product(self.bounds(), other.bounds())]
return Interval(min(res), max(res))
__truediv__ = __div__
def __add__(self, other):
"""
Combiner for Addition operation.
>>> Interval(-12, 5) + Interval(-5, -3)
Interval(low=-17, high=2)
"""
if isinstance(other, IntervalTuple):
return UNKNOWN_RANGE
sl, sh, ol, oh = self.low, self.high, other.low, other.high
if isinf(sl) and isinf(ol) and sl * ol < 0:
return UNKNOWN_RANGE
if isinf(sh) and isinf(oh) and sh * oh < 0:
return UNKNOWN_RANGE
return Interval(sl + ol, sh + oh)
def __sub__(self, other):
"""
Combiner for Subtraction operation.
>>> Interval(1, 5) - Interval(-5, -4)
Interval(low=5, high=10)
"""
sl, sh, ol, oh = self.low, self.high, other.low, other.high
if isinf(sl) and isinf(oh):
return UNKNOWN_RANGE
if isinf(sh) and isinf(ol):
return UNKNOWN_RANGE
return Interval(sl - oh, sh - ol)
def __rshift__(range1, range2):
"""
Combiner for Right shift operation.
>>> Interval(10, 100) >> Interval(3, 8)
Interval(low=0, high=12)
>>> Interval(10, float("inf")) >> Interval(3, 8)
Interval(low=0, high=inf)
>>> Interval(-float("inf"), 0) >> Interval(3, 8)
Interval(low=-inf, high=0)
>>> Interval(-30, 10) >> Interval(3, float('inf'))
Interval(low=-4, high=1)
"""
if range1.low <= 0:
if isinf(range1.low):
min_ = range1.low
else:
min_ = range1.low >> range2.low
elif isinf(range2.high):
min_ = 0
else:
min_ = range1.low >> range2.high
if isinf(range1.high):
max_ = range1.high
elif isinf(range2.low):
max_ = 0
else:
max_ = range1.high >> range2.low
return Interval(min_, max_)
def __mod__(range1, range2):
""" Combiner for Modulo operation.
>>> Interval(-1, 5) % Interval(1, 13)
Interval(low=0, high=5)
>>> Interval(-21, 5) % Interval(1, 13)
Interval(low=0, high=13)
"""
return Interval(0, min(range2.high,
max(abs(range1.high), abs(range1.low))))
def __pow__(range1, range2):
"""
Combiner for Power operation.
>>> Interval(1, 5) ** Interval(-5, -4)
Interval(low=1.0, high=1.0)
>>> Interval(-1, 5) ** Interval(-5, 3)
Interval(low=-1.0, high=125.0)
>>> Interval(1, 5) ** Interval(3, 8)
Interval(low=1.0, high=390625.0)
"""
res = [v1 ** v2 for v1, v2 in
itertools.product(range1.bounds(), range2.bounds())]
return Interval(numpy.ceil(min(res)), numpy.floor(max(res)))
def __lshift__(range1, range2):
"""
Combiner for Left shift operation.
>>> Interval(1, 5) << Interval(3, 8)
Interval(low=8, high=1280)
>>> Interval(1, float("inf")) << Interval(3, 8)
Interval(low=8, high=inf)
>>> Interval(-float("inf"), 0) << Interval(3, 8)
Interval(low=-inf, high=0)
>>> Interval(-3, 1) << Interval(3, float('inf'))
Interval(low=-24, high=inf)
"""
min_inf = isinf(range1.low) or isinf(range2.low)
max_inf = isinf(range1.high) or isinf(range2.high)
min_ = -float("inf") if min_inf else (range1.low << range2.low)
max_ = float("inf") if max_inf else (range1.high << range2.high)
return Interval(min_, max_)
def __floordiv__(range1, range2):
"""
Combiner for Floor divide operation.
>>> Interval(-1, 5) // Interval(3, 8)
Interval(low=-1, high=1)
>>> Interval(-1, 5) // Interval(-5, -4)
Interval(low=-2, high=0)
>>> Interval(-1, 5) // Interval(-5, 3)
Interval(low=-inf, high=inf)
"""
if range2.low <= 0 and range2.high >= 0:
return UNKNOWN_RANGE
if range2.low == 0:
return UNKNOWN_RANGE
res = [v1 if isinf(v1) else (v1 // v2) for v1, v2 in
itertools.product(range1.bounds(), range2.bounds())]
return Interval(min(res), max(res))
def __lt__(self, other):
"""
Combiner for lower than operation.
>>> Interval(-1, 5) < Interval(6, 7)
Interval(low=1, high=1)
>>> Interval(-1, 5) < Interval(5, 7)
Interval(low=0, high=1)
>>> Interval(-1, 5) < Interval(-16, -7)
Interval(low=0, high=0)
>>> Interval(1, 5) < Interval(3, 7)
Interval(low=0, high=1)
"""
if self.high < other.low:
return Interval(1, 1)
if self.low >= other.high:
return Interval(0, 0)
return Interval(0, 1)
def __le__(self, other):
"""
Combiner for lower than or equal operation.
>>> Interval(-1, 5) <= Interval(6, 7)
Interval(low=1, high=1)
>>> Interval(-1, 5) <= Interval(5, 7)
Interval(low=1, high=1)
>>> Interval(-1, 5) <= Interval(-16, -7)
Interval(low=0, high=0)
>>> Interval(1, 5) <= Interval(3, 7)
Interval(low=0, high=1)
"""
if self.high <= other.low:
return Interval(1, 1)
if self.low > other.high:
return Interval(0, 0)
return Interval(0, 1)
def __gt__(self, other):
"""
Combiner for greater than operation.
>>> Interval(-5, 1) > Interval(-7, -6)
Interval(low=1, high=1)
>>> Interval(-5, 1) > Interval(-7, -5)
Interval(low=0, high=1)
>>> Interval(-1, 5) > Interval(6, 7)
Interval(low=0, high=0)
>>> Interval(1, 5) > Interval(3, 7)
Interval(low=0, high=1)
"""
if self.low > other.high:
return Interval(1, 1)
if self.high <= other.low:
return Interval(0, 0)
return Interval(0, 1)
def __ge__(self, other):
"""
Combiner for greater than or equal operation.
>>> Interval(-5, 1) >= Interval(-7, -6)
Interval(low=1, high=1)
>>> Interval(-5, 1) >= Interval(-7, -5)
Interval(low=1, high=1)
>>> Interval(-1, 5) >= Interval(6, 7)
Interval(low=0, high=0)
>>> Interval(1, 5) >= Interval(3, 7)
Interval(low=0, high=1)
"""
if self.low >= other.high:
return Interval(1, 1)
if self.high < other.low:
return Interval(0, 0)
return Interval(0, 1)
def __eq__(self, other):
"""
Combiner for equal operation.
>>> Interval(-5, 1) == Interval(-7, -6)
Interval(low=0, high=0)
>>> Interval(-5, 1) == Interval(-7, -5)
Interval(low=0, high=1)
>>> Interval(-1, 5) == Interval(6, 7)
Interval(low=0, high=0)
"""
if isinf(self.low):
return Interval(0, 1)
elif self.low == self.high == other.low == other.high:
return Interval(1, 1)
elif (self < other) or (self > other):
return Interval(0, 0)
else:
return Interval(0, 1)
def __ne__(self, other):
"""
Combiner for not equal operation.
>>> Interval(-5, 1) != Interval(-7, -6)
Interval(low=1, high=1)
>>> Interval(-5, 1) != Interval(-7, -5)
Interval(low=0, high=1)
>>> Interval(-1, 5) != Interval(6, 7)
Interval(low=1, high=1)
"""
if isinf(self.low):
return Interval(0, 1)
elif self.low == self.high == other.low == other.high:
return Interval(1, 1)
elif (self < other) or (self > other):
return Interval(1, 1)
else:
return Interval(0, 1)
def __nonzero__(self):
return not isinf(self.high) and self.low == self.high and self .low > 0
def __getitem__(self, index):
return UNKNOWN_RANGE
__bool__ = __nonzero__
class IntervalTuple(object):
def __init__(self, values):
self.values = tuple(values)
def union(self, other):
if isinstance(other, Interval):
return UNKNOWN_TUPLE_RANGE
return IntervalTuple(x.union(y) for x, y in zip(self.values,
other.values))
def intersect(self, other):
if isinstance(other, Interval):
return UNKNOWN_TUPLE_RANGE
return IntervalTuple(x.intersect(y) for x, y in zip(self.values,
other.values))
@property
def high(self):
return UNKNOWN_RANGE.high
@property
def low(self):
return UNKNOWN_RANGE.low
def __getitem__(self, index):
out = None
low = max(0, index.low)
high = min(len(self.values) - 1, index.high)
for i in range(low, high + 1):
if out is None:
out = self.values[i]
else:
out = out.union(self.values[i])
return out or UNKNOWN_RANGE
def widen(self, other):
if isinstance(other, Interval):
return UNKNOWN_TUPLE_RANGE
return IntervalTuple(s.widen(o) for s, o in zip(self.values,
other.values))
def __add__(self, other):
if isinstance(other, Interval):
return UNKNOWN_TUPLE_RANGE
return IntervalTuple(self.values + other.values)
UNKNOWN_RANGE = Interval(-float("inf"), float("inf"))
UNKNOWN_TUPLE_RANGE = IntervalTuple([UNKNOWN_RANGE])
def range_values(args):
""" Function used to compute returned range value of [x]range function. """
if len(args) == 1:
return Interval(0, args[0].high)
elif len(args) == 2:
return Interval(args[0].low, args[1].high)
elif len(args) == 3:
is_neg = args[2].low < 0
is_pos = args[2].high > 0
if is_neg and is_pos:
return UNKNOWN_RANGE
elif is_neg:
return Interval(args[1].low, args[0].high - 1)
else:
return Interval(args[0].low, args[1].high - 1)
def bool_values(_):
""" Return the range of a boolean value, i.e. [0, 1]. """
return Interval(0, 1)
def cmp_values(_):
""" Return the range of a comparison value, i.e. [-1, 1]. """
return Interval(-1, 1)
def positive_values(_):
""" Return a positive range without upper bound. """
return Interval(0, float("inf"))
def max_values(args):
""" Return possible range for max function. """
return Interval(max(x.low for x in args), max(x.high for x in args))
def min_values(args):
""" Return possible range for min function. """
return Interval(min(x.low for x in args), min(x.high for x in args))
def ord_values(_):
""" Return possible range for ord function. """
return Interval(0, 255)