Ejemplo n.º 1
0
    total_angle = sum(angles)
    fellswoop = initial.rotate(total_angle)
    note(f"One Fell Swoop: {fellswoop}")

    stepwise = initial
    for angle in angles:
        stepwise = stepwise.rotate(angle)
    note(f"Step-wise: {stepwise}")

    # Increase the tolerance on this comparison,
    # as stepwise rotations induce rounding errors
    assert fellswoop.isclose(stepwise, rel_tol=1e-6)
    assert math.isclose(fellswoop.length, initial.length, rel_tol=1e-15)


@given(x=vectors(), y=vectors(), scalar=floats(), angle=angles())
# In this example:
# * x * l == -y
# * Rotation must not be an multiple of 90deg
# * Must be sufficiently large
@example(x=Vector(1e10, 1e10), y=Vector(1e19, 1e19), scalar=-1e9, angle=45)
def test_rotation_linearity(x, y, scalar, angle):
    """(l*x + y).rotate is equivalent to l*x.rotate + y.rotate"""
    inner = (scalar * x + y).rotate(angle)
    outer = scalar * x.rotate(angle) + y.rotate(angle)
    note(f"scalar * x + y: {scalar * x + y}")
    note(f"scalar * x.rotate(): {scalar * x.rotate(angle)}")
    note(f"y.rotate(): {y.rotate(angle)}")
    note(f"Inner: {inner}")
    note(f"Outer: {outer}")
    assert inner.isclose(outer, rel_to=[x, scalar * x, y])
Ejemplo n.º 2
0
from hypothesis import given

from ppb_vector import Vector
from utils import floats, vectors


@given(x=floats(), y=floats())
def test_class_member_access(x: float, y: float):
    v = Vector(x, y)
    assert v.x == x
    assert v.y == y


@given(v=vectors())
def test_index_access(v: Vector):
    assert v[0] == v.x
    assert v[1] == v.y


@given(v=vectors())
def test_key_access(v: Vector):
    assert v["x"] == v.x
    assert v["y"] == v.y
Ejemplo n.º 3
0
from hypothesis import given

from ppb_vector import Vector
from utils import floats, vectors


@given(v=vectors(), x=floats())
def test_update_x(v: Vector, x: float):
    assert v.update(x=x) == (x, v.y)


@given(v=vectors(), y=floats())
def test_update_y(v: Vector, y: float):
    assert v.update(y=y) == (v.x, y)


@given(v=vectors(), x=floats(), y=floats())
def test_update_xy(v: Vector, x: float, y: float):
    assert v.update(x=x, y=y) == (x, y)
Ejemplo n.º 4
0
    # Exclude near-orthogonal test inputs
    assume(abs(cos_t) > 1e-6)
    assert isclose(x * y,
                   x.rotate(angle) * y.rotate(angle),
                   rel_to=(x, y),
                   rel_exp=2)


MAGNITUDE = 1e10


@given(
    x=vectors(max_magnitude=MAGNITUDE),
    z=vectors(max_magnitude=MAGNITUDE),
    y=vectors(max_magnitude=sqrt(MAGNITUDE)),
    scalar=floats(max_magnitude=sqrt(MAGNITUDE)),
)
def test_dot_linear(x: Vector, y: Vector, z: Vector, scalar: float):
    """Test that x · (λ y + z) = λ x·y + x·z"""
    inner, outer = x * (scalar * y + z), scalar * x * y + x * z
    note(f"inner: {inner}")
    note(f"outer: {outer}")
    assert isclose(inner, outer, rel_to=(x, scalar, y, z), rel_exp=2)


@given(x=vectors(max_magnitude=1e7), y=vectors(max_magnitude=1e7))
def test_dot_from_angle(x: Vector, y: Vector):
    """Test x · y == |x| · |y| · cos(θ)"""
    t = x.angle(y)
    cos_t, _ = Vector._trig(t)
from hypothesis import assume, given, strategies as st
from pytest import raises  # type: ignore

from ppb_vector import Vector
from utils import floats, isclose, vectors


@given(scalar=floats(), v=vectors())
def test_scalar_coordinates(scalar: float, v: Vector):
    assert scalar * v.x == (scalar * v).x
    assert scalar * v.y == (scalar * v).y


@given(scalar1=floats(), scalar2=floats(), v=vectors())
def test_scalar_associative(scalar1: float, scalar2: float, v: Vector):
    """(scalar1 * scalar2) * v == scalar1 * (scalar2 * v)"""
    left = (scalar1 * scalar2) * v
    right = scalar1 * (scalar2 * v)
    assert left.isclose(right)


@given(scalar=floats(), v=vectors(), w=vectors())
def test_scalar_linear(scalar: float, v: Vector, w: Vector):
    assert (scalar * (v + w)).isclose(
        scalar * v + scalar * w,
        rel_to=[v, w, scalar * v, scalar * w],
    )


@given(scalar=floats(), v=vectors())
def test_scalar_length(scalar: float, v: Vector):
Ejemplo n.º 6
0

@given(left=vectors(), right=vectors())
def test_angle_range(left, right):
    """Vector.angle produces values in [-180; 180] and is antisymmetric.

    Antisymmetry means that left.angle(right) == - right.angle(left).
    """
    lr = left.angle(right)
    rl = right.angle(left)
    assert -180 < lr <= 180
    assert -180 < rl <= 180
    assert angle_isclose(lr, -rl)


@given(left=vectors(), middle=vectors(), right=vectors())
def test_angle_additive(left, middle, right):
    """left.angle(middle) + middle.angle(right) == left.angle(right)"""
    lm = left.angle(middle)
    mr = middle.angle(right)
    lr = left.angle(right)
    assert angle_isclose(lm + mr, lr)


@given(x=vectors(), scalar=floats())
def test_angle_aligned(x: Vector, scalar: float):
    """x.angle(scalar * x) is 0 or 180, depending on whether scalar > 0"""
    assume(scalar != 0)
    y = scalar * x
    assert angle_isclose(x.angle(y), 0 if scalar > 0 else 180)
Ejemplo n.º 7
0
from ppb_vector import Vector
from utils import floats, lengths, vectors


@given(x=vectors(), max_length=lengths())
def test_truncate_length(x: Vector, max_length: float):
    assert x.truncate(max_length).length <= (1 + 1e-14) * max_length


@given(x=vectors(), max_length=lengths(max_value=1e150))
def test_truncate_invariant(x: Vector, max_length: float):
    assume(x.length <= max_length)
    assert x.truncate(max_length) == x


@given(x=vectors(max_magnitude=1e150), max_length=floats())
@example(  # Large example where x.length == max_length but 1 * x != x
    x=Vector(0.0, 7.1e62),
    max_length=7.1e62,
)
def test_truncate_equivalent_to_scale(x: Vector, max_length: float):
    """Vector.scale_to and truncate are equivalent when max_length <= x.length"""
    assume(max_length <= x.length)
    note(f"x.length = {x.length}")
    if max_length > 0:
        note(f"x.length = {x.length / max_length} * max_length")

    scale: Union[Vector, Type[Exception]]
    truncate: Union[Vector, Type[Exception]]

    try: