예제 #1
0
 def test_floats_with_step(self):
     interval = FloatInterval((0, 0.5), step=0.5)
     assert interval.lower == 0
     assert interval.upper == 0.5
     assert not interval.lower_inc
     assert not interval.upper_inc
     assert interval.step
예제 #2
0
 def test_string_as_constructor_param(self):
     with raises(TypeError) as e:
         FloatInterval('(0.2, 0.5)')
     assert str(e.value) == (
         'First argument should be a list or tuple. If you wish to '
         'initialize an interval from string, use from_string factory '
         'method.'
     )
예제 #3
0
 def __init__(self, _type, const):
     super(Constnode, self).__init__(_type)
     self.const = const
     val = float(const)
     if val == int(val) and not const.endswith('.0'):
         self.I = IntInterval([int(val), int(val)])  #TODO: float
     else:
         self.I = FloatInterval([val, val])  #TODO: float
예제 #4
0
 def __init__(self, var_type, interval=None):
     super(Var, self).__init__()
     self.var_type = var_type
     self.interval = {}
     if var_type == 'int':
         if interval == None:
             self.interval['int'] = IntInterval.all()
         else:
             self.interval['int'] = IntInterval(interval)
     elif var_type == 'float':
         if interval == None:
             self.interval['float'] = FloatInterval.all()
         else:
             self.interval['float'] = FloatInterval(interval)
예제 #5
0
class TestComparisonOperators(object):
    @mark.parametrize(('comparison', 'result'), (
        (IntInterval([1, 3]) == IntInterval([1, 3]), True),
        (IntInterval([1, 3]) == IntInterval([1, 4]), False),
        (IntInterval([inf, inf]) == inf, True),
        (IntInterval([3, 3]) == 3, True),
        (IntInterval([3, 3]) == 5, False),
        (IntInterval('(,)') == None, False)
    ))
    def test_eq_operator(self, comparison, result):
        assert comparison is result

    @mark.parametrize(('comparison', 'result'), (
        (IntInterval([1, 3]) != IntInterval([1, 3]), False),
        (IntInterval([1, 3]) != IntInterval([1, 4]), True),
        (IntInterval([inf, inf]) != inf, False),
        (IntInterval([3, 3]) != 3, False),
        (IntInterval([3, 3]) != 5, True),
        (IntInterval('(,)') != None, True)
    ))
    def test_ne_operator(self, comparison, result):
        assert comparison is result

    @mark.parametrize(('comparison', 'result'), (
        (IntInterval([1, 3]) > IntInterval([0, 2]), True),
        (IntInterval((1, 4)) > 1, False),
        (IntInterval((1, 6)) > [1, 6], False),
        (IntInterval((1, 6)) > 0, True)
    ))
    def test_gt_operator(self, comparison, result):
        assert comparison is result

    @mark.parametrize(('comparison', 'result'), (
        (IntInterval([1, 3]) >= IntInterval([0, 2]), True),
        (IntInterval((1, 4)) >= 1, False),
        (IntInterval((1, 6)) >= [1, 6], False),
        (IntInterval((1, 6)) >= 0, True)
    ))
    def test_ge_operator(self, comparison, result):
        assert comparison is result

    @mark.parametrize(('comparison', 'result'), (
        (IntInterval([0, 2]) < IntInterval([1, 3]), True),
        (IntInterval([2, 3]) < IntInterval([2, 3]), False),
        (IntInterval([2, 5]) < 6, True),
        (IntInterval([2, 5]) < 5, False),
        (IntInterval([2, 5]) < inf, True)
    ))
    def test_lt_operator(self, comparison, result):
        assert comparison is result

    @mark.parametrize(('comparison', 'result'), (
        (IntInterval([0, 2]) <= IntInterval([1, 3]), True),
        (IntInterval([1, 3]) <= IntInterval([1, 3]), True),
        (IntInterval([1, 7]) <= 8, True),
        (IntInterval([1, 6]) <= 5, False),
        (IntInterval([1, 5]) <= inf, True)
    ))
    def test_le_operator(self, comparison, result):
        assert comparison is result

    def test_integer_comparison(self):
        assert IntInterval([2, 2]) <= 3
        assert IntInterval([1, 3]) >= 0
        assert IntInterval([2, 2]) == 2
        assert IntInterval([2, 2]) != 3

    @mark.parametrize('value', (
        IntInterval([0, 2]),
        1,
        (-1, 1),
    ))
    def test_contains_operator_for_inclusive_interval(self, value):
        assert value in IntInterval([-1, 2])

    @mark.parametrize('value', (
        IntInterval([0, 2]),
        2,
        '[-1, 1]',
    ))
    def test_contains_operator_for_non_inclusive_interval(self, value):
        assert value not in IntInterval((-1, 2))

    @mark.parametrize(('interval1', 'interval2', 'expected'), (
        (IntInterval((0, 2)), IntInterval((0, 2)), True),
        (IntInterval([0, 2]), IntInterval([0, 2]), True),
        (IntInterval('[0, 2)'), IntInterval('[0, 2)'), True),
        (IntInterval('(0, 2]'), IntInterval('(0, 2]'), True),
        (IntInterval((0, 2)), IntInterval((1, 2)), False),
        (IntInterval((0, 2)), IntInterval((0, 1)), False),
        (IntInterval((0, 2)), IntInterval([0, 1]), False),
        (IntInterval((0, 2)), FloatInterval((0, 1)), False),
    ))
    def test_hash_operator_with_interval_attributes(self, interval1, interval2, expected):
        actual = (interval1.__hash__() == interval2.__hash__())
        assert actual == expected

    @mark.parametrize(('contains_check', 'expected'), (
        (IntInterval([0, 2]) in {IntInterval([0, 2]): ''}, True),
        (IntInterval([0, 2]) in {IntInterval((0, 2)): ''}, False),
        (IntInterval([0, 2]) in set([IntInterval([0, 2])]), True),
    ))
    def test_hash_operator_with_collections(self, contains_check, expected):
        assert contains_check is expected
예제 #6
0
class TestIntervalProperties(object):
    @mark.parametrize(('number_range', 'length'), (
        ([1, 4], 3),
        ([-1, 1], 2),
        ((-inf, inf), inf),
        ((1, inf), inf),
    ))
    def test_length(self, number_range, length):
        assert IntInterval(number_range).length == length

    @mark.parametrize(('number_range', 'radius'), (
        ([1, 4], 1.5),
        ([-1, 1], 1.0),
        ([-4, -1], 1.5),
        ((-inf, inf), inf),
        ((1, inf), inf),
    ))
    def test_radius(self, number_range, radius):
        assert IntInterval(number_range).radius == radius

    @mark.parametrize(('number_range', 'centre'), (
        ([1, 4], 2.5),
        ([-1, 1], 0),
        ([-4, -1], -2.5),
        ((1, inf), inf),
    ))
    def test_centre(self, number_range, centre):
        assert IntInterval(number_range).centre == centre

    @mark.parametrize(('number_range', 'is_open'),
                      (((2, 3), True), ('(2, 5)', True), ('[3, 4)', False),
                       ('(4, 5]', False), ('3 - 4', False), ([4, 5], False),
                       ('[4, 5]', False)))
    def test_open(self, number_range, is_open):
        assert IntInterval(number_range).open == is_open

    @mark.parametrize(
        ('number_range', 'is_closed'),
        (((2, 3), False), ('(2, 5)', False), ('[3, 4)', False),
         ('(4, 5]', False), ('3 - 4', True), ([4, 5], True), ('[4, 5]', True)))
    def test_closed(self, number_range, is_closed):
        assert IntInterval(number_range).closed == is_closed

    @mark.parametrize(('number_range', 'empty'), (
        ((2, 3), True),
        ([2, 3], False),
        ([2, 2], False),
        ((2, 2), True),
        ('[2, 2)', True),
        ('(2, 2]', True),
        ('[2, 3)', False),
        ((2, 10), False),
    ))
    def test_empty(self, number_range, empty):
        assert IntInterval(number_range).empty == empty

    @mark.parametrize(('number_range', 'degenerate'), (
        ((2, 4), False),
        ('(2, 2)', True),
        ('[0, 0)', True),
    ))
    def test_degenerate(self, number_range, degenerate):
        assert IntInterval(number_range).degenerate == degenerate

    @mark.parametrize(
        ('interval', 'discrete'),
        ((IntInterval((2, 3)), True), (IntInterval(5), True),
         (FloatInterval(3.5), False), (DecimalInterval(Decimal('2.4')), False),
         (DateTimeInterval(datetime(2002, 1, 1)), False),
         (DateInterval(date(2002, 1, 1)), True)))
    def test_discrete(self, interval, discrete):
        assert interval.discrete == discrete
예제 #7
0
 def test_floats(self):
     interval = FloatInterval((0.2, 0.5))
     assert interval.lower == 0.2
     assert interval.upper == 0.5
     assert not interval.lower_inc
     assert not interval.upper_inc
예제 #8
0
 def test_invalid_argument(self):
     with raises(IllegalArgument) as e:
         FloatInterval((0, 0))
     assert (
         'The bounds may be equal only if at least one of the bounds is '
         'closed.') in str(e)
예제 #9
0
 def test_step_rounding(self):
     interval = FloatInterval((0.2, 0.8), step=0.5)
     assert interval.lower == 0
     assert interval.upper == 1
예제 #10
0
 def get_evaluate(self, op, arg1, arg2):  #需要判断死分支,所以必须是类内函数
     if type(op) in [Rangenode, Ftrangenode]:
         I1 = arg1.I
         I2 = op.I  #Rangenode有I、且I一定不是None
         #而Ftrangenode一开始的I没有初始化,要等到做完Future Resolution以后才有
     elif type(op) == Opnode:  #op,可能是一元或二元的
         I1 = arg1.I
         if arg2 != None:
             I2 = arg2.I
         else:
             I2 = None
         if type(arg1) == Varnode\
         and (arg1.var.endswith('_t') or arg1.var.endswith('_f'))\
         and arg1.Belong != op.Belong:
             # 如果arg1要参与其他分量节点的区间运算(即出循环)、且它是_t/_f,则要让它的区间收敛
             # print arg1.var, I1
             if I1 != None:  #有可能它是空集;这说明这是一个不可能分支
                 pass  # TODO:应该在这里让区间收敛。但是要解决问题太多了
                 # 问题1、怎么确定收敛结果?因为在分支语句中可能是跟变量比较,收敛的结果可能是一个区间而不是一个点!
             # 问题2、就算能让它正确收敛,因为区间变小了,它也无法再影响传递出去的e了。
             # 问题3、就算一路上的节点成功更新了,还有一个问题:无法区分PHI语句的from是循环初值还是if分支
             # 把循环初值误判成了if分支还造成了其他的问题:不可能分支的误判
         if arg2 != None and type(arg2) == Varnode\
         and (arg2.var.endswith('_t') or arg2.var.endswith('_f'))\
         and arg2.Belong != op.Belong:
             # 如果arg2要参与其他分量节点的区间运算(即出循环)、且它是_t/_f,则要让它的区间收敛
             if I2 != None:  #有可能它是空集;这说明这是一个不可能分支
                 pass  # TODO:同上
     # else:
     # 	pass
     if type(op) in [Rangenode, Ftrangenode]:  #求交集
         if I1 == None:
             e = None  #这里I1为None代表它是空集,而不是未初始化
         elif I2 == None:
             e = copy.deepcopy(I1)
         else:
             try:
                 e = I1 & I2
             except Exception as ex:
                 e = 'Empty'  #没有交集,则取空集
             else:
                 pass
             finally:
                 pass
     # 以下都是opnode。先是一元运算
     elif op.op == '(float)':
         e = FloatInterval([I1.lower, I1.upper])
         e.upper_inc = I1.upper_inc
         e.lower_inc = I1.lower_inc
     elif op.op == '(int)':
         if math.isinf(I1.lower):
             lower = -inf
         else:
             val = round(I1.lower)
             if abs(val - int(val)) <= 1e-6:
                 lower = int(val)  #浮点误差
             else:
                 lower = int(I1.lower)
         if math.isinf(I1.upper):
             upper = inf
         else:
             val = round(I1.upper)
             if abs(val - int(val)) <= 1e-6:
                 upper = int(val)  #浮点误差
             else:
                 upper = int(I1.upper)
         e = IntInterval([lower, upper])
         e.upper_inc = I1.upper_inc
         e.lower_inc = I1.lower_inc  # TODO:整数化以后开闭可能变化!
     elif op.op == '=':
         e = copy.deepcopy(I1)
     # 再是二元运算
     elif op.op == 'PHI':
         # 如果一个arg是同一个分量的,而另一个不是:这是在一个循环内部
         if (arg1.Belong == op.Belong and arg2.Belong != op.Belong)\
         or (arg2.Belong == op.Belong and arg1.Belong != op.Belong):
             # if arg1.Belong == op.Belong or arg2.Belong == op.Belong:
             if arg1.Belong == op.Belong:
                 inner = arg1
                 outer = arg2
             else:
                 inner = arg2
                 outer = arg1
             # 第一次进循环,内部还是None,直接取外部;以后内部不是None了,就取内部
             if inner.I == None:
                 e = copy.deepcopy(outer.I)
             else:
                 e = copy.deepcopy(inner.I)
         else:  #两个都不是另外一个分量的:这是一个if分支,应该取并集
             # 注意:还可能两者都是Inner的,见样例t9那个很复杂的分量。我认为这也算一个if分支?
             # 注意,只对if分支先排除不可能分支,因为对于循环存在误判的可能:
             # 循环一开始范围只有初值,此时因为交集为空而被误判为不可能分支
             # 但是循环几次以后范围扩大了,此时又变成可能分支了
             if op.phi_from_block[arg1.var] in self.last_Unreached:
                 e = copy.deepcopy(arg2.I)
             elif op.phi_from_block[arg2.var] in self.last_Unreached:
                 e = copy.deepcopy(arg1.I)
             # 然后取并集
             elif arg1.I == None:
                 e = copy.deepcopy(arg2.I)
             elif arg2.I == None:
                 e = copy.deepcopy(arg1.I)
             else:
                 inner = arg1  #还是用inner和outer来标记吧
                 outer = arg2
                 e = copy.deepcopy(inner.I)
                 if (outer.I.lower<e.lower) or\
                 (outer.I.lower == e.lower and outer.I.lower_inc==False):
                     #就算一个是(5一个是[6,或者一个是(6一个是[6,改一下也不会错
                     e.lower = outer.I.lower
                     e.lower_inc = outer.I.lower_inc  # 开闭也要修改
                 if (outer.I.upper>e.upper) or\
                 (outer.I.upper == e.upper and outer.I.upper_inc==True):
                     #就算一个是(5一个是[6,或者一个是(6一个是[6,改一下也不会错
                     e.upper = outer.I.upper
                     e.upper_inc = outer.I.upper_inc  # 开闭也要修改
     else:  #op:None参与时直接返回None
         if I1 == None or I2 == None:
             e = None
         elif op.op == '+':
             e = I1 + I2
             e.lower_inc = I1.lower_inc and I2.lower_inc  #只要有一个开,结果就是开
             e.upper_inc = I1.upper_inc and I2.upper_inc  #只要有一个开,结果就是开
             #TODO,对于整数,(1,3)+(3,5)=(4,8)是错的!不过允许有一点误差
         elif op.op == '-':
             # e = I1 - I2 这样写可能会出错
             e = copy.deepcopy(I1)
             e.lower += -I2.upper
             e.upper += -I2.lower  #- -inf不等于+ inf,所以必须这么写……
             e.lower_inc = I1.lower_inc and I2.upper_inc  #只要有一个开,结果就是开
             e.upper_inc = I1.upper_inc and I2.lower_inc  #只要有一个开,结果就是开
             #TODO,对于整数,(1,3)+(3,5)=(4,8)是错的!不过允许有一点误差
         elif op.op == '*':  #TODO: 开闭的问题!!!现在默认是闭!
             L = [
                 mul(I1.lower, I2.lower),
                 mul(I1.lower, I2.upper),
                 mul(I1.upper, I2.lower),
                 mul(I1.upper, I2.upper)
             ]
             if arg1._type == 'int':
                 e = IntInterval([min(L), max(L)])
             else:
                 e = FloatInterval([min(L), max(L)])
         elif op.op == '/':  # TODO 开闭的问题
             L = [div(I1.lower,I2.lower), div(I1.lower,I2.upper),\
             div(I1.upper,I2.lower), div(I1.upper,I2.upper)]
             if arg1._type == 'int':
                 e = IntInterval([min(L), max(L)])
             else:
                 e = FloatInterval([min(L), max(L)])
     return e