示例#1
0
class TestCos(object):
    def _result_with_mono_bounds(self, visitor, g, mono_g, bounds_g):
        mono = ComponentMap()
        mono[g] = mono_g
        bounds = ComponentMap()
        bounds[g] = bounds_g
        expr = pe.cos(g)
        matched, result = visitor.visit_expression(expr, mono, bounds)
        assert matched
        return result

    @given(expressions(), nonnegative_sin_bounds())
    def test_nonincreasing_nonnegative_sin(self, visitor, g, bounds):
        mono = self._result_with_mono_bounds(visitor, g, M.Nonincreasing, bounds)
        assert mono.is_nondecreasing()

    @given(expressions(), nonnegative_sin_bounds())
    def test_nondecreasing_nonnegative_sin(self, visitor, g, bounds):
        mono = self._result_with_mono_bounds(visitor, g, M.Nondecreasing, bounds)
        assert mono.is_nonincreasing()

    @given(expressions(), nonpositive_sin_bounds())
    def test_nondecreasing_nonpositive_sin(self, visitor, g, bounds):
        mono = self._result_with_mono_bounds(visitor, g, M.Nondecreasing, bounds)
        assert mono.is_nondecreasing()

    @given(expressions(), nonpositive_sin_bounds())
    def test_nonincreasing_nonpositive_sin(self, visitor, g, bounds):
        mono = self._result_with_mono_bounds(visitor, g, M.Nonincreasing, bounds)
        assert mono.is_nonincreasing()
示例#2
0
class TestAtan(UnaryFunctionTest):
    @given(child=expressions())
    def test_is_concave(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Concave, M.Unknown,
                                I(0, None), pe.atan)
        assert cvx == C.Concave

    @pytest.mark.parametrize('bounds', [I(None, 0), I(None, None)])
    @given(child=expressions())
    def test_is_not_concave(self, visitor, child, bounds):
        cvx = self._rule_result(visitor, child, C.Concave, M.Unknown, bounds,
                                pe.atan)
        assert cvx == C.Unknown

    @given(child=expressions())
    def test_is_convex(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Convex, M.Unknown,
                                I(None, 0), pe.atan)
        assert cvx == C.Convex

    @pytest.mark.parametrize('bounds', [I(0, None), I(None, None)])
    @given(child=expressions())
    def test_is_not_convex(self, visitor, child, bounds):
        cvx = self._rule_result(visitor, child, C.Convex, C.Unknown, bounds,
                                pe.atan)
        assert cvx == C.Unknown
示例#3
0
class TestAbs(UnaryFunctionTest):
    @pytest.mark.parametrize(
        'mono,bounds',
        itertools.product(
            [M.Nondecreasing, M.Nonincreasing, M.Constant],
            [I(None, 0), I(0, None), I(None, None)]))
    @given(child=expressions())
    def test_linear_child(self, visitor, child, mono, bounds):
        cvx = self._rule_result(visitor, child, C.Linear, mono, bounds, abs)
        assert cvx == C.Convex

    @pytest.mark.parametrize('mono,bounds,expected', [
        (M.Unknown, I(0, None), C.Convex),
        (M.Unknown, I(None, 0), C.Concave),
    ])
    @given(child=expressions())
    def test_convex_child(self, visitor, child, mono, bounds, expected):
        cvx = self._rule_result(visitor, child, C.Convex, mono, bounds, abs)
        assert cvx == expected

    @pytest.mark.parametrize('mono,bounds,expected', [
        (M.Unknown, I(0, None), C.Concave),
        (M.Unknown, I(None, 0), C.Convex),
    ])
    @given(child=expressions())
    def test_concave_child(self, visitor, child, mono, bounds, expected):
        cvx = self._rule_result(visitor, child, C.Concave, mono, bounds, abs)
        assert cvx == expected
示例#4
0
class TestExp(UnaryFunctionTest):
    @pytest.mark.parametrize(
        'cvx,mono,bounds',
        itertools.product(
            [C.Convex, C.Linear],
            [M.Nondecreasing, M.Nonincreasing, M.Constant, M.Unknown],
            [I(0, None), I(None, 0), I(None, None)],
        )
    )
    @given(child=expressions())
    def test_convex_child(self, visitor, child, cvx, mono, bounds):
        cvx = self._rule_result(visitor, child, cvx, mono, bounds, pe.exp)
        assert cvx == C.Convex

    @pytest.mark.parametrize(
        'cvx,mono,bounds',
        itertools.product(
            [C.Concave, C.Unknown],
            [M.Nondecreasing, M.Nonincreasing, M.Constant, M.Unknown],
            [I(0, None), I(None, 0), I(None, None)],
        )
    )
    @given(child=expressions())
    def test_convex_child(self, visitor, child, cvx, mono, bounds):
        cvx = self._rule_result(visitor, child, cvx, mono, bounds, pe.exp)
        assert cvx == C.Unknown
示例#5
0
class TestPowConstantBase(object):
    def _result_with_base_expo(self, visitor, base, expo, mono_expo, bounds_expo):
        rule = PowerRule()
        mono = ComponentMap()
        mono[base] = M.Constant
        mono[expo] = mono_expo
        bounds = ComponentMap()
        bounds[base] = I(base, base)
        bounds[expo] = bounds_expo
        expr = base ** expo
        assume(isinstance(expr, PowExpression))
        matched, result = visitor.visit_expression(expr, mono, bounds)
        assert matched
        return result

    @pytest.mark.parametrize(
        'mono_expo,bounds_expo',
        itertools.product(
            [M.Nondecreasing, M.Nonincreasing, M.Unknown],
            [I(None, 0), I(0, None), I(None, None)]
        )
    )
    @given(
        base=reals(max_value=-0.01, allow_infinity=False),
        expo=expressions(),
    )
    def test_negative_base(self, visitor, base, expo, mono_expo, bounds_expo):
        mono = self._result_with_base_expo(visitor, base, expo, mono_expo, bounds_expo)
        assert mono == M.Unknown

    @pytest.mark.parametrize('mono_expo,bounds_expo,expected', [
        (M.Nondecreasing, I(None, 0), M.Nondecreasing),
        (M.Nondecreasing, I(0, None), M.Unknown),
        (M.Nonincreasing, I(0, None), M.Nondecreasing),
        (M.Nonincreasing, I(None, 0), M.Unknown),
    ])
    @given(
        base=reals(min_value=0.01, max_value=0.999),
        expo=expressions(),
    )
    def test_base_between_0_and_1(self, visitor, base, expo, mono_expo, bounds_expo, expected):
        mono = self._result_with_base_expo(visitor, base, expo, mono_expo, bounds_expo)
        assert mono == expected

    @pytest.mark.parametrize('mono_expo,bounds_expo,expected', [
        (M.Nondecreasing, I(0, None), M.Nondecreasing),
        (M.Nondecreasing, I(None, 0), M.Unknown),
        (M.Nonincreasing, I(None, 0), M.Nondecreasing),
        (M.Nonincreasing, I(0, None), M.Unknown),
    ])
    @given(
        base=reals(min_value=1.01, allow_infinity=False),
        expo=expressions(),
    )
    def test_base_gt_1(self, visitor, base, expo, mono_expo, bounds_expo, expected):
        mono = self._result_with_base_expo(visitor, base, expo, mono_expo, bounds_expo)
        assert mono == expected
示例#6
0
class TestCos(UnaryFunctionTest):
    @given(expressions())
    def test_bound_size_too_big(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Linear, M.Constant, I(-2, 2), pe.cos)
        assert cvx == C.Unknown

    @given(expressions())
    def test_bound_opposite_sign(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Linear, M.Constant, I(pi/2-0.1, pi/2+0.1), pe.cos)
        assert cvx == C.Unknown

    @given(expressions())
    def test_positive_cos_linear_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Linear, M.Constant, I(0, 0.5*pi), pe.cos)
        assert cvx == C.Concave

    @given(expressions())
    def test_positive_cos_convex_child_but_wrong_interval(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Convex, M.Unknown, I(0, 0.5*pi), pe.cos)
        assert cvx == C.Unknown

    @given(expressions())
    def test_positive_cos_convex_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Convex, M.Unknown, I(1.5*pi, 2*pi), pe.cos)
        assert cvx == C.Concave

    @given(expressions())
    def test_positive_cos_concave_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Concave, M.Unknown, I(0, 0.5*pi), pe.cos)
        assert cvx == C.Concave

    @given(expressions())
    def test_negative_cos_linear_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Linear, M.Constant, I(0.6*pi, 1.4*pi), pe.cos)
        assert cvx == C.Convex

    @given(expressions())
    def test_negative_cos_concave_child_but_wrong_interval(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Concave, M.Unknown, I(0.6*pi, 0.9*pi), pe.cos)
        assert cvx == C.Unknown

    @given(expressions())
    def test_negative_cos_concave_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Concave, M.Unknown, I(1.1*pi, 1.4*pi), pe.cos)
        assert cvx == C.Convex

    @given(expressions())
    def test_negative_cos_convex_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Convex, M.Unknown, I(0.6*pi, 0.9*pi), pe.cos)
        assert cvx == C.Convex
示例#7
0
class TestSum(object):
    def _result_with_terms(self, visitor, expr_with_monos):
        children = [c for c, _ in expr_with_monos]
        monos = [m for _, m in expr_with_monos]
        monotonicity = ComponentMap()
        for child, mono in expr_with_monos:
            monotonicity[child] = mono
        expr = SumExpression(children)
        matched, result = visitor.visit_expression(expr, monotonicity, None)
        assert matched
        return result

    @given(
        st.lists(
            st.tuples(expressions(), st.just(M.Nondecreasing)),
            min_size=1,
        ),
        st.lists(
            st.tuples(expressions(),
                      st.one_of(st.just(M.Nondecreasing),
                                st.just(M.Constant)))),
    )
    def test_nondecreasing(self, visitor, a, b):
        mono = self._result_with_terms(visitor, a + b)
        assert mono.is_nondecreasing()

    @given(
        st.lists(st.tuples(expressions(), st.just(M.Nonincreasing)),
                 min_size=1),
        st.lists(
            st.tuples(expressions(),
                      st.one_of(st.just(M.Nonincreasing),
                                st.just(M.Constant)))),
    )
    def test_nonincreasing(self, visitor, a, b):
        mono = self._result_with_terms(visitor, a + b)
        assert mono.is_nonincreasing()

    @given(
        st.lists(st.tuples(expressions(), st.just(M.Constant)), min_size=1), )
    def test_constant(self, visitor, a):
        mono = self._result_with_terms(visitor, a)
        assert mono.is_constant()

    @given(
        st.lists(st.tuples(expressions(), st.just(M.Nondecreasing)),
                 min_size=1),
        st.lists(st.tuples(
            expressions(),
            st.just(M.Nonincreasing),
        ),
                 min_size=1),
    )
    def test_unknown(self, visitor, a, b):
        mono = self._result_with_terms(visitor, a + b)
        assert mono.is_unknown()
示例#8
0
class TestTan(UnaryFunctionTest):
    @given(expressions())
    def test_bound_size_too_big(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Linear, M.Constant, I(-2, 2), pe.tan)
        assert cvx == C.Unknown

    @given(expressions())
    def test_bound_opposite_sign(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Linear, M.Constant, I(-0.1, 0.1), pe.tan)
        assert cvx == C.Unknown

    @given(expressions())
    def test_positive_tan_convex_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Convex, M.Unknown, I(pi, 1.5*pi), pe.tan)
        assert cvx == C.Convex

    @given(expressions())
    def test_positive_tan_concave_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Concave, M.Unknown, I(pi, 1.5*pi), pe.tan)
        assert cvx == C.Unknown

    @given(expressions())
    def test_negative_tan_convex_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Convex, M.Unknown, I(-1.5*pi, -pi), pe.tan)
        assert cvx == C.Unknown

    @given(expressions())
    def test_negative_tan_concave_child(self, visitor, child):
        cvx = self._rule_result(visitor, child, C.Concave, M.Unknown, I(-0.49*pi, -0.1), pe.tan)
        assert cvx == C.Concave
示例#9
0
class TestLog(UnaryFunctionTest):
    @pytest.mark.parametrize(
        'cvx,mono',
        itertools.product(
            [C.Concave, C.Linear],
            [M.Nondecreasing, M.Nonincreasing, M.Constant, M.Unknown],
        ))
    @given(child=expressions())
    def test_concave_child(self, visitor, child, cvx, mono):
        cvx = self._rule_result(visitor, child, cvx, mono, I(0, None), pe.log)
        assert cvx == C.Concave

    @pytest.mark.parametrize(
        'cvx,mono',
        itertools.product(
            [C.Convex, C.Unknown],
            [M.Nondecreasing, M.Nonincreasing, M.Constant, M.Unknown],
        ),
    )
    @given(child=expressions())
    def test_non_concave_child(self, visitor, child, cvx, mono):
        cvx = self._rule_result(visitor, child, cvx, mono, I(0, None), pe.log)
        assert cvx == C.Unknown
示例#10
0
class TestSum:
    def _rule_result(self, visitor, children_with_cvx):
        children = [c for c, _ in children_with_cvx]

        convexity = ComponentMap()
        for child, cvx in children_with_cvx:
            convexity[child] = cvx
        expr = SumExpression(children)
        matched, result = visitor.visit_expression(expr, convexity, None, None)
        assert matched
        return result

    @given(
        st.lists(st.tuples(expressions(), st.just(C.Convex)), min_size=1),
        st.lists(st.tuples(expressions(), st.just(C.Linear)), ),
    )
    def test_convex(self, visitor, a, b):
        cvx = self._rule_result(visitor, a + b)
        assert cvx.is_convex()

    @given(
        st.lists(st.tuples(expressions(), st.just(C.Concave)), min_size=1),
        st.lists(st.tuples(expressions(), st.just(C.Linear))),
    )
    def test_concave(self, visitor, a, b):
        cvx = self._rule_result(visitor, a + b)
        assert cvx.is_concave()

    @given(
        st.lists(st.tuples(expressions(), st.just(C.Linear)), min_size=1), )
    def test_linear(self, visitor, a):
        cvx = self._rule_result(visitor, a)
        assert cvx.is_linear()

    @given(
        st.lists(st.tuples(expressions(), st.just(C.Concave)), min_size=1),
        st.lists(st.tuples(expressions(), st.just(C.Convex)), min_size=1),
    )
    def test_unknown(self, visitor, a, b):
        cvx = self._rule_result(visitor, a + b)
        assert cvx.is_unknown()
示例#11
0
class TestProduct:
    def _rule_result(self, visitor, f, g, cvx_f, cvx_g, mono_f, mono_g,
                     bounds_f, bounds_g):
        convexity = ComponentMap()
        convexity[f] = cvx_f
        convexity[g] = cvx_g
        mono = ComponentMap()
        mono[f] = mono_f
        mono[g] = mono_g
        bounds = ComponentMap()
        bounds[f] = bounds_f
        bounds[g] = bounds_g
        expr = f * g
        assume(isinstance(expr, ProductExpression))
        matched, result = visitor.visit_expression(expr, convexity, mono,
                                                   bounds)
        assert matched
        return result

    @pytest.mark.parametrize('cvx_f,bounds_g,expected', [
        (C.Convex, I(0, None), C.Convex),
        (C.Convex, I(None, 0), C.Concave),
        (C.Concave, I(0, None), C.Concave),
        (C.Concave, I(None, 0), C.Convex),
        (C.Linear, I(0, None), C.Linear),
        (C.Linear, I(None, 0), C.Linear),
        (C.Unknown, I(0, None), C.Unknown),
        (C.Unknown, I(None, 0), C.Unknown),
    ])
    @given(f=expressions(), g=constants())
    def test_product_with_constant(self, visitor, f, g, cvx_f, bounds_g,
                                   expected):
        assume(f.is_expression_type()
               and not isinstance(f, MonomialTermExpression))
        cvx_g = C.Linear  # g is constant
        mono_f = M.Unknown
        mono_g = M.Constant
        bounds_f = I(None, None)
        assert self._rule_result(visitor, f, g, cvx_f, cvx_g, mono_f, mono_g,
                                 bounds_f, bounds_g) == expected
        assert self._rule_result(visitor, g, f, cvx_g, cvx_f, mono_g, mono_f,
                                 bounds_g, bounds_f) == expected

    @pytest.mark.parametrize('cvx_f,bounds_f,expected', [
        (C.Linear, I(None, None), C.Convex),
        (C.Linear, I(0, None), C.Convex),
        (C.Linear, I(None, 0), C.Convex),
        (C.Convex, I(None, None), C.Unknown),
        (C.Convex, I(0, None), C.Convex),
        (C.Convex, I(None, 0), C.Unknown),
        (C.Concave, I(None, None), C.Unknown),
        (C.Concave, I(0, None), C.Unknown),
        (C.Concave, I(None, 0), C.Convex),
    ])
    @given(f=expressions())
    def test_product_with_itself(self, visitor, f, cvx_f, bounds_f, expected):
        convexity = ComponentMap()
        convexity[f] = cvx_f
        bounds = ComponentMap()
        bounds[f] = bounds_f
        expr = f * f
        matched, result = visitor.visit_expression(expr, convexity, None,
                                                   bounds)
        assert matched
        assert result == expected

    @given(var=variables(), coef=reals())
    def test_product_with_itself_with_coeff(self, visitor, var, coef):
        if coef > 0:
            expected = C.Convex
        else:
            expected = C.Concave
        rule = ProductRule()
        g = coef * var
        assume(isinstance(g, ProductExpression))
        matched, result = visitor.visit_expression(ProductExpression([var, g]),
                                                   None, None, None)
        assert result == expected
        matched, result = visitor.visit_expression(ProductExpression([g, var]),
                                                   None, None, None)
        assert result == expected

    @given(var=variables(),
           vars_with_coef=st.lists(st.tuples(
               variables(),
               constants(),
           ), ))
    def test_product_linear_by_var(self, visitor, var, vars_with_coef):
        rule = ProductRule()
        mono = ComponentMap()
        lin = sum(v * c for v, c in vars_with_coef)
        mono[var] = M.Nondecreasing
        mono[lin] = M.Nondecreasing
        matched, result = visitor.visit_expression(
            ProductExpression([var, lin]), None, mono, None)
        assert result == C.Unknown
        matched, result = visitor.visit_expression(
            ProductExpression([lin, var]), None, mono, None)
        assert result == C.Unknown
示例#12
0
        (C.Concave, True, True, C.Unknown),
        (C.Unknown, True, True, C.Unknown),

        # g(x) <= u is the same as g(x)
        (C.Linear, False, True, C.Linear),
        (C.Convex, False, True, C.Convex),
        (C.Concave, False, True, C.Concave),
        (C.Unknown, False, True, C.Unknown),

        # l <= g(x) is the negation of g(x)
        (C.Linear, True, False, C.Linear),
        (C.Convex, True, False, C.Concave),
        (C.Concave, True, False, C.Convex),
        (C.Unknown, True, False, C.Unknown),
    ])
@given(child=expressions())
def test_constraint(visitor, child, cvx_child, bounded_below, bounded_above,
                    expected):
    if bounded_below:
        lower_bound = 0.0
    else:
        lower_bound = None

    if bounded_above:
        upper_bound = 1.0
    else:
        upper_bound = None

    expr = Constraint('constr', lower_bound, upper_bound, children=[child])

    convexity = ComponentMap()
示例#13
0
class TestPowConstantExponent(object):
    def _result_with_base_expo(self, visitor, base, mono_base, bounds_base, expo):
        mono = ComponentMap()
        mono[base] = mono_base
        mono[expo] = M.Constant
        bounds = ComponentMap()
        bounds[base] = bounds_base
        bounds[expo] = I(expo, expo)
        expr = PowExpression([base, expo])
        matched, result = visitor.visit_expression(expr, mono, bounds)
        assert matched
        return result

    @pytest.mark.parametrize(
        'mono_base,bounds_base',
        itertools.product([M.Nonincreasing, M.Nondecreasing],
                          [I(None, 0), I(0, None), I(None, None)])
    )
    @given(base=expressions())
    def test_exponent_equals_1(self, visitor, base, mono_base, bounds_base):
        mono = self._result_with_base_expo(visitor, base, mono_base, bounds_base, 1.0)
        assert mono == mono_base

    @pytest.mark.parametrize(
        'mono_base,bounds_base',
        itertools.product([M.Nonincreasing, M.Nondecreasing],
                          [I(None, 0), I(0, None), I(None, None)])
    )
    @given(base=expressions())
    def test_exponent_equals_0(self, visitor, base, mono_base, bounds_base):
        mono = self._result_with_base_expo(visitor, base, mono_base, bounds_base, 0.0)
        assert mono == M.Constant

    @pytest.mark.parametrize('mono_base,bounds_base,expected', [
        (M.Nondecreasing, I(0, None), M.Nondecreasing),
        (M.Nonincreasing, I(None, 0), M.Nondecreasing),

        (M.Nondecreasing, I(None, 0), M.Nonincreasing),
        (M.Nonincreasing, I(0, None), M.Nonincreasing),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1, max_value=1000),
    )
    def test_positive_even_integer(self, visitor, base, expo, mono_base, bounds_base, expected):
        mono = self._result_with_base_expo(visitor, base, mono_base, bounds_base, 2*expo)
        assert mono == expected

    @pytest.mark.parametrize('mono_base,bounds_base,expected', [
        (M.Nondecreasing, I(0, None), M.Nonincreasing),
        (M.Nonincreasing, I(None, 0), M.Nonincreasing),

        (M.Nondecreasing, I(None, 0), M.Nondecreasing),
        (M.Nonincreasing, I(0, None), M.Nondecreasing),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1, max_value=1000)
    )
    def test_negative_even_integer(self, visitor, base, expo, mono_base, bounds_base, expected):
        mono = self._result_with_base_expo(visitor, base, mono_base, bounds_base, -2*expo)
        assert mono == expected

    @pytest.mark.parametrize('mono_base,expected', [
        (M.Nondecreasing, M.Nondecreasing),
        (M.Nonincreasing, M.Nonincreasing),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1, max_value=1000)
    )
    def test_positive_odd_integer(self, visitor, base, expo, mono_base, expected):
        mono = self._result_with_base_expo(visitor, base, mono_base, I(None, None), 2*expo+1)
        assert mono == expected

    @pytest.mark.parametrize('mono_base,expected', [
        (M.Nondecreasing, M.Nonincreasing),
        (M.Nonincreasing, M.Nondecreasing),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1, max_value=1000)
    )
    def test_negative_odd_integer(self, visitor, base, expo, mono_base, expected):
        mono = self._result_with_base_expo(
            visitor, base, mono_base, I(None, None), -2*expo+1
        )
        assert mono == expected

    @pytest.mark.parametrize('mono_base', [M.Nondecreasing, M.Nondecreasing])
    @given(
        base=expressions(),
        expo=reals(allow_infinity=False, min_value=-1e5, max_value=1e5),
    )
    def test_noninteger_negative_base(self, visitor, base, expo, mono_base):
        assume(not almosteq(expo,  0))
        assume(not almosteq(expo, int(expo)))
        mono = self._result_with_base_expo(
            visitor, base, mono_base, I(None, 0), expo
        )
        assert mono == M.Unknown

    @pytest.mark.parametrize('mono_base,expected', [
        (M.Nondecreasing, M.Nondecreasing),
        (M.Nonincreasing, M.Nonincreasing)
    ])
    @given(
        base=expressions(),
        expo=reals(allow_infinity=False, min_value=1e-5, max_value=1e-5)
    )
    def test_positive_noninteger(self, visitor, base, expo, mono_base, expected):
        mono = self._result_with_base_expo(visitor, base, mono_base, I(0, None), expo)
        assert mono == expected

    @pytest.mark.parametrize('mono_base,expected', [
        (M.Nonincreasing, M.Nondecreasing),
        (M.Nondecreasing, M.Nonincreasing)
    ])
    @given(
        base=expressions(),
        expo=reals(allow_infinity=False, min_value=-1e5, max_value=-1e-5)
    )
    def test_negative_noninteger(self, visitor, base, expo, mono_base, expected):
        mono = self._result_with_base_expo(visitor, base, mono_base, I(0, None), expo)
        assert mono == expected
示例#14
0
    assert result.is_nondecreasing() and (not result.is_constant())


def test_constant_is_constant():
    rule = ConstantRule()
    result = rule.apply(PE(ET.Constant), None, None)
    assert result.is_constant()


@pytest.mark.parametrize('expr_mono,expected_mono', [
    (M.Nondecreasing, M.Nondecreasing),
    (M.Nonincreasing, M.Nonincreasing),
    (M.Constant, M.Constant),
    (M.Unknown, M.Unknown),
])
@given(child=expressions())
def test_lte_constraint(visitor, child, expr_mono, expected_mono):
    mono = ComponentMap()
    mono[child] = expr_mono
    expr = Constraint('cons', None, 0.0, children=[child])
    matched, result = visitor.visit_expression(expr, mono, None)
    assert matched
    assert result == expected_mono


@pytest.mark.parametrize('expr_mono,expected_mono', [
    (M.Nondecreasing, M.Nonincreasing),
    (M.Nonincreasing, M.Nondecreasing),
    (M.Constant, M.Constant),
    (M.Unknown, M.Unknown),
])
示例#15
0
class TestPowConstantBase:
    def _rule_result(self, visitor, base, expo, cvx_expo, mono_expo,
                     bounds_expo):
        convexity = ComponentMap()
        convexity[expo] = cvx_expo
        convexity[base] = C.Linear
        mono = ComponentMap()
        mono[expo] = mono_expo
        mono[base] = M.Constant
        bounds = ComponentMap()
        bounds[base] = I(base, base)
        bounds[expo] = bounds_expo

        expr = PowExpression([base, expo])
        matched, result = visitor.visit_expression(expr, convexity, mono,
                                                   bounds)
        assert matched
        return result

    @pytest.mark.parametrize(
        'cvx_expo,mono_expo,bounds_expo',
        itertools.product(
            [C.Convex, C.Concave, C.Linear, C.Unknown],
            [M.Nondecreasing, M.Nonincreasing, M.Unknown],
            [I(None, 0), I(0, None), I(None, None)],
        ))
    @given(
        base=reals(max_value=-0.01, allow_infinity=False),
        expo=expressions(),
    )
    def test_negative_base(self, visitor, base, expo, cvx_expo, mono_expo,
                           bounds_expo):
        cvx = self._rule_result(visitor, base, expo, cvx_expo, mono_expo,
                                bounds_expo)
        assert cvx == C.Unknown

    @pytest.mark.parametrize(
        'cvx_expo,mono_expo,bounds_expo',
        itertools.product(
            [C.Convex, C.Concave, C.Linear, C.Unknown],
            [M.Nondecreasing, M.Nonincreasing, M.Unknown],
            [I(None, 0), I(0, None), I(None, None)],
        ))
    @given(
        base=reals(min_value=0.001, max_value=0.999),
        expo=expressions(),
    )
    def test_base_between_0_and_1(self, visitor, base, expo, cvx_expo,
                                  mono_expo, bounds_expo):
        if cvx_expo == C.Concave or cvx_expo == C.Linear:
            expected = C.Convex
        else:
            expected = C.Unknown
        cvx = self._rule_result(visitor, base, expo, cvx_expo, mono_expo,
                                bounds_expo)
        assert cvx == expected

    @pytest.mark.parametrize(
        'cvx_expo,mono_expo,bounds_expo',
        itertools.product(
            [C.Convex, C.Concave, C.Linear, C.Unknown],
            [M.Nondecreasing, M.Nonincreasing, M.Unknown],
            [I(None, 0), I(0, None), I(None, None)],
        ))
    @given(
        base=reals(min_value=1, allow_infinity=False),
        expo=expressions(),
    )
    def test_base_gt_1(self, visitor, base, expo, cvx_expo, mono_expo,
                       bounds_expo):
        if cvx_expo == C.Convex or cvx_expo == C.Linear:
            expected = C.Convex
        else:
            expected = C.Unknown
        cvx = self._rule_result(visitor, base, expo, cvx_expo, mono_expo,
                                bounds_expo)
        assert cvx == expected
示例#16
0
class TestPowConstantExponent(object):
    def _rule_result(self, visitor, base, cvx_base, mono_base, bounds_base,
                     expo):
        convexity = ComponentMap()
        convexity[base] = cvx_base
        convexity[expo] = C.Linear
        mono = ComponentMap()
        mono[base] = mono_base
        mono[expo] = M.Constant
        bounds = ComponentMap()
        bounds[base] = bounds_base
        bounds[expo] = I(expo, expo)
        expr = PowExpression([base, expo])
        matched, result = visitor.visit_expression(expr, convexity, mono,
                                                   bounds)
        assert matched
        return result

    @pytest.mark.parametrize(
        'cvx_base,mono_base,bounds_base',
        itertools.product(
            [C.Convex, C.Concave, C.Linear, C.Unknown],
            [M.Nondecreasing, M.Nonincreasing, M.Unknown],
            [I(None, 0), I(0, None), I(None, None)],
        ))
    @given(base=expressions())
    def test_exponent_equals_0(self, visitor, base, cvx_base, mono_base,
                               bounds_base):
        cvx = self._rule_result(visitor, base, cvx_base, mono_base,
                                bounds_base, 0.0)
        assert cvx == C.Linear

    @pytest.mark.parametrize(
        'cvx_base,mono_base,bounds_base',
        itertools.product(
            [C.Convex, C.Concave, C.Linear, C.Unknown],
            [M.Nondecreasing, M.Nonincreasing, M.Unknown],
            [I(None, 0), I(0, None), I(None, None)],
        ))
    @given(base=expressions())
    def test_exponent_equals_1(self, visitor, base, cvx_base, mono_base,
                               bounds_base):
        cvx = self._rule_result(visitor, base, cvx_base, mono_base,
                                bounds_base, 1.0)
        assert cvx == cvx_base

    @pytest.mark.parametrize('cvx_base,mono_base,bounds_base,expected', [
        (C.Linear, M.Nondecreasing, I(None, None), C.Convex),
        (C.Convex, M.Unknown, I(0, None), C.Convex),
        (C.Convex, M.Unknown, I(None, 0), C.Unknown),
        (C.Concave, M.Unknown, I(0, None), C.Unknown),
        (C.Concave, M.Unknown, I(None, 0), C.Convex),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1),
    )
    def test_positive_even_integer(self, visitor, base, expo, cvx_base,
                                   mono_base, bounds_base, expected):
        cvx = self._rule_result(visitor, base, cvx_base, mono_base,
                                bounds_base, 2 * expo)
        assert cvx == expected

    @pytest.mark.parametrize('cvx_base,mono_base,bounds_base,expected', [
        (C.Convex, M.Unknown, I(None, 0), C.Convex),
        (C.Convex, M.Unknown, I(0, None), C.Concave),
        (C.Concave, M.Unknown, I(0, None), C.Convex),
        (C.Concave, M.Unknown, I(None, 0), C.Concave),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1),
    )
    def test_negative_even_integer(self, visitor, base, expo, cvx_base,
                                   mono_base, bounds_base, expected):
        cvx = self._rule_result(visitor, base, cvx_base, mono_base,
                                bounds_base, -2 * expo)
        assert cvx == expected

    @pytest.mark.parametrize('cvx_base,mono_base,bounds_base,expected', [
        (C.Convex, M.Unknown, I(0, None), C.Convex),
        (C.Convex, M.Unknown, I(None, 0), C.Unknown),
        (C.Concave, M.Unknown, I(None, 0), C.Concave),
        (C.Concave, M.Unknown, I(0, None), C.Unknown),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1),
    )
    def test_positive_odd_integer(self, visitor, base, expo, cvx_base,
                                  mono_base, bounds_base, expected):
        cvx = self._rule_result(visitor, base, cvx_base, mono_base,
                                bounds_base, 2 * expo + 1)
        assert cvx == expected

    @pytest.mark.parametrize('cvx_base,mono_base,bounds_base,expected', [
        (C.Concave, M.Unknown, I(0, None), C.Convex),
        (C.Concave, M.Unknown, I(None, 0), C.Unknown),
        (C.Convex, M.Unknown, I(None, 0), C.Concave),
        (C.Convex, M.Unknown, I(0, None), C.Unknown),
    ])
    @given(
        base=expressions(),
        expo=st.integers(min_value=1),
    )
    def test_negative_odd_integer(self, visitor, base, expo, cvx_base,
                                  mono_base, bounds_base, expected):
        cvx = self._rule_result(visitor, base, cvx_base, mono_base,
                                bounds_base, -2 * expo + 1)
        assert cvx == expected

    @given(
        base=expressions(),
        expo=reals(min_value=1, allow_infinity=False),
    )
    def test_positive_gt_1_non_integer_negative_base(self, visitor, base,
                                                     expo):
        expo = expo + 1e-6
        assume(expo != int(expo))
        cvx = self._rule_result(visitor, base, C.Convex, M.Unknown,
                                I(None, -1), expo)
        assert cvx == C.Unknown

    @given(
        base=expressions(),
        expo=reals(min_value=1, allow_infinity=False),
    )
    def test_positive_gt_1_non_integer(self, visitor, base, expo):
        expo = expo + 1e-5  # make it positive
        assume(expo != int(expo))
        cvx = self._rule_result(visitor, base, C.Convex, M.Unknown, I(0, None),
                                expo)
        assert cvx == C.Convex

    @pytest.mark.parametrize('cvx,expected', [(C.Convex, C.Concave),
                                              (C.Concave, C.Convex)])
    @given(
        base=expressions(),
        expo=reals(max_value=0, allow_infinity=False),
    )
    def test_positive_lt_0_non_integer(self, visitor, base, expo, cvx,
                                       expected):
        expo = expo - 1e-5  # make it negative
        assume(not almosteq(expo, int(expo)))
        cvx = self._rule_result(visitor, base, cvx, M.Unknown, I(0, None),
                                expo)
        assert cvx == expected

    @given(
        base=expressions(),
        expo=reals(min_value=0, max_value=1, allow_infinity=False),
    )
    def test_positive_0_1_non_integer(self, visitor, base, expo):
        assume(not almosteq(expo, int(expo)))
        cvx = self._rule_result(visitor, base, C.Concave, M.Unknown,
                                I(0, None), expo)
        assert cvx == C.Concave
示例#17
0
    return PolynomialDegree(degree)


def test_variable_is_always_1(visitor):
    matched, result = visitor.visit_expression(pe.Var(), None)
    assert matched
    assert result.degree == 1


def test_constant_is_always_0(visitor):
    matched, result = visitor.visit_expression(123.0, None)
    assert matched
    assert result.degree == 0


@given(expressions(), polynomial_degrees())
def test_objective(visitor, child, child_degree):
    expr = Objective('obj', children=[child])
    poly = ComponentMap()
    poly[child] = child_degree
    matched, result = visitor.visit_expression(expr, poly)
    assert matched
    assert result == child_degree


@given(expressions(), polynomial_degrees())
def test_constraint(visitor, child, child_degree):
    expr = Constraint('cons', 0.0, None, children=[child])
    poly = ComponentMap()
    poly[child] = child_degree
    matched, result = visitor.visit_expression(expr, poly)