copp 0.2.2

Convex-objective path parameterization for robotic trajectory planning.
Documentation
import numpy as np
import pytest

import copp_py as copp


def _build_robot_with_jerk_constraints(n_samples=5, dim=2):
    s = np.linspace(0.0, 1.0, n_samples, dtype=np.float64)
    q = np.empty((n_samples, dim), dtype=np.float64)
    dq = np.empty_like(q)
    ddq = np.empty_like(q)
    dddq = np.empty_like(q)

    for col in range(dim):
        scale = float(col + 1)
        q[:, col] = scale * s
        dq[:, col] = scale
        ddq[:, col] = 0.25 * scale
        dddq[:, col] = 0.1 * scale

    robot = copp.Robot(dim, capacity=n_samples)
    robot.append_s(s)
    robot.set_q(q, dq, ddq, 0, dddq=dddq)
    upper = np.full(dim, 10.0, dtype=np.float64)
    robot.add_jerk_limits(upper, -upper, start_idx_s=0)
    return robot


def test_topp3_problem_constructs_and_copies_linearization():
    robot = _build_robot_with_jerk_constraints()
    a_linearization = np.ones(len(robot), dtype=np.float64)

    problem = copp.solver.topp3_lp.Problem(
        robot.constraints,
        a_linearization,
        idx_s_start=0,
        a_boundary=(0.0, 0.0),
        b_boundary=(0.0, 0.0),
        num_stationary_max=1,
    )

    assert problem.constraints.len == len(robot)
    assert problem.idx_s_start == 0
    assert problem.idx_s_final == len(robot) - 1
    assert problem.s_len == len(robot)
    assert problem.a_boundary == (0.0, 0.0)
    assert problem.b_boundary == (0.0, 0.0)
    assert problem.num_stationary_max == (1, 1)
    assert np.isclose(problem.a_linearization_floor, 1.0e-10)
    assert np.allclose(problem.a_linearization, 1.0)

    a_linearization[0] = 7.0
    copied = problem.a_linearization
    copied[1] = 9.0
    assert np.allclose(problem.a_linearization, 1.0)

    problem.validate()


def test_topp3_problem_accepts_stationary_pair():
    robot = _build_robot_with_jerk_constraints()
    a_linearization = np.ones(len(robot), dtype=np.float64)

    problem = copp.solver.topp3_lp.Problem(
        robot.constraints,
        a_linearization,
        num_stationary_max=(2, 3),
    )

    assert problem.num_stationary_max == (2, 3)


def test_topp3_problem_rejects_invalid_python_arguments():
    robot = _build_robot_with_jerk_constraints()
    a_linearization = np.ones(len(robot), dtype=np.float64)

    with pytest.raises(ValueError, match="num_stationary_max"):
        copp.solver.topp3_lp.Problem(
            robot.constraints,
            a_linearization,
            num_stationary_max="bad",
        )

    with pytest.raises(ValueError, match="a_linearization"):
        copp.solver.topp3_lp.Problem(
            robot.constraints,
            [a_linearization.tolist()],
        )


def test_topp3_problem_rejects_invalid_core_arguments():
    robot = _build_robot_with_jerk_constraints()
    a_linearization = np.ones(len(robot), dtype=np.float64)

    with pytest.raises(copp.CoppError, match="a_linearization_floor"):
        copp.solver.topp3_lp.Problem(
            robot.constraints,
            a_linearization,
            a_linearization_floor=0.0,
        )