Merge commit '81396a5322a7a48764fcf254d5d933ba1e57bdc5' as 'kiwi'
This commit is contained in:
202
kiwi/py/tests/test_term.py
Normal file
202
kiwi/py/tests/test_term.py
Normal file
@@ -0,0 +1,202 @@
|
||||
# --------------------------------------------------------------------------------------
|
||||
# Copyright (c) 2014-2021, Nucleic Development Team.
|
||||
#
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
#
|
||||
# The full license is in the file LICENSE, distributed with this software.
|
||||
# --------------------------------------------------------------------------------------
|
||||
import gc
|
||||
import math
|
||||
import operator
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from kiwisolver import Constraint, Expression, Term, Variable, strength
|
||||
|
||||
|
||||
def test_term_creation() -> None:
|
||||
"""Test the Term constructor."""
|
||||
v = Variable("foo")
|
||||
t = Term(v)
|
||||
assert t.variable() is v
|
||||
assert t.coefficient() == 1
|
||||
|
||||
t = Term(v, 100)
|
||||
assert t.variable() is v
|
||||
assert t.coefficient() == 100
|
||||
|
||||
assert str(t) == "100 * foo"
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
Term("") # type: ignore
|
||||
assert "Variable" in excinfo.exconly()
|
||||
|
||||
# ensure we test garbage collection
|
||||
del t
|
||||
gc.collect()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def terms():
|
||||
"""Terms for testing."""
|
||||
v = Variable("foo")
|
||||
v2 = Variable("bar")
|
||||
t = Term(v, 10)
|
||||
t2 = Term(v2)
|
||||
|
||||
return t, t2, v, v2
|
||||
|
||||
|
||||
def test_term_neg(terms: Tuple[Term, Term, Variable, Variable]) -> None:
|
||||
"""Test neg on a term."""
|
||||
t, _, v, _ = terms
|
||||
|
||||
neg = -t
|
||||
assert isinstance(neg, Term)
|
||||
assert neg.variable() is v and neg.coefficient() == -10
|
||||
|
||||
|
||||
def test_term_mul(terms: Tuple[Term, Term, Variable, Variable]) -> None:
|
||||
"""Test term multiplications"""
|
||||
t, _, v, _ = terms
|
||||
|
||||
for mul in (t * 2, 2.0 * t):
|
||||
assert isinstance(mul, Term)
|
||||
assert mul.variable() is v and mul.coefficient() == 20
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
t * v # type: ignore
|
||||
|
||||
|
||||
def test_term_div(terms: Tuple[Term, Term, Variable, Variable]) -> None:
|
||||
"""Test term divisions."""
|
||||
t, _, v, v2 = terms
|
||||
|
||||
div = t / 2
|
||||
assert isinstance(div, Term)
|
||||
assert div.variable() is v and div.coefficient() == 5
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
t / v2 # type: ignore
|
||||
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
t / 0
|
||||
|
||||
|
||||
def test_term_add(terms: Tuple[Term, Term, Variable, Variable]) -> None:
|
||||
"""Test term additions."""
|
||||
t, t2, v, v2 = terms
|
||||
|
||||
for add in (t + 2, 2.0 + t):
|
||||
assert isinstance(add, Expression)
|
||||
assert add.constant() == 2
|
||||
terms_ = add.terms()
|
||||
assert (
|
||||
len(terms_) == 1
|
||||
and terms[0].variable() is v
|
||||
and terms_[0].coefficient() == 10
|
||||
)
|
||||
|
||||
for add2, order in zip((t + v2, v2 + t), ((0, 1), (1, 0))):
|
||||
assert isinstance(add2, Expression)
|
||||
assert add2.constant() == 0
|
||||
terms_ = add2.terms()
|
||||
assert (
|
||||
len(terms_) == 2
|
||||
and terms_[order[0]].variable() is v
|
||||
and terms_[order[0]].coefficient() == 10
|
||||
and terms_[order[1]].variable() is v2
|
||||
and terms_[order[1]].coefficient() == 1
|
||||
)
|
||||
|
||||
add2 = t + t2
|
||||
assert isinstance(add2, Expression)
|
||||
assert add2.constant() == 0
|
||||
terms_ = add2.terms()
|
||||
assert (
|
||||
len(terms_) == 2
|
||||
and terms_[0].variable() is v
|
||||
and terms_[0].coefficient() == 10
|
||||
and terms_[1].variable() is v2
|
||||
and terms_[1].coefficient() == 1
|
||||
)
|
||||
|
||||
|
||||
def test_term_sub(terms: Tuple[Term, Term, Variable, Variable]) -> None:
|
||||
"""Test term substractions."""
|
||||
t, t2, v, v2 = terms
|
||||
|
||||
for sub, diff in zip((t - 2, 2.0 - t), (-2, 2)):
|
||||
assert isinstance(sub, Expression)
|
||||
assert sub.constant() == diff
|
||||
terms_ = sub.terms()
|
||||
assert (
|
||||
len(terms_) == 1
|
||||
and terms[0].variable() is v
|
||||
and terms_[0].coefficient() == -math.copysign(10, diff)
|
||||
)
|
||||
|
||||
for sub2, order in zip((t - v2, v2 - t), ((0, 1), (1, 0))):
|
||||
assert isinstance(sub2, Expression)
|
||||
assert sub2.constant() == 0
|
||||
terms_ = sub2.terms()
|
||||
assert (
|
||||
len(terms_) == 2
|
||||
and terms_[order[0]].variable() is v
|
||||
and terms_[order[0]].coefficient() == 10 * (-1) ** order[0]
|
||||
and terms_[order[1]].variable() is v2
|
||||
and terms_[order[1]].coefficient() == -1 * (-1) ** order[0]
|
||||
)
|
||||
|
||||
sub2 = t - t2
|
||||
assert isinstance(sub2, Expression)
|
||||
assert sub2.constant() == 0
|
||||
terms_ = sub2.terms()
|
||||
assert (
|
||||
len(terms_) == 2
|
||||
and terms_[0].variable() is v
|
||||
and terms_[0].coefficient() == 10
|
||||
and terms_[1].variable() is v2
|
||||
and terms_[1].coefficient() == -1
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"op, symbol",
|
||||
[
|
||||
(operator.le, "<="),
|
||||
(operator.eq, "=="),
|
||||
(operator.ge, ">="),
|
||||
(operator.lt, None),
|
||||
(operator.ne, None),
|
||||
(operator.gt, None),
|
||||
],
|
||||
)
|
||||
def test_term_rich_compare_operations(op, symbol):
|
||||
"""Test using comparison on variables."""
|
||||
v = Variable("foo")
|
||||
v2 = Variable("bar")
|
||||
t1 = Term(v, 10)
|
||||
t2 = Term(v2, 20)
|
||||
|
||||
if symbol is not None:
|
||||
c = op(t1, t2 + 1)
|
||||
assert isinstance(c, Constraint)
|
||||
e = c.expression()
|
||||
t = e.terms()
|
||||
assert len(t) == 2
|
||||
if t[0].variable() is not v:
|
||||
t = (t[1], t[0])
|
||||
assert (
|
||||
t[0].variable() is v
|
||||
and t[0].coefficient() == 10
|
||||
and t[1].variable() is v2
|
||||
and t[1].coefficient() == -20
|
||||
)
|
||||
assert e.constant() == -1
|
||||
assert c.op() == symbol and c.strength() == strength.required
|
||||
|
||||
else:
|
||||
with pytest.raises(TypeError):
|
||||
op(t1, t2)
|
||||
Reference in New Issue
Block a user