예제 #1
0
from typing import Type

import pytest
import torch
import torch.nn as nn
from torch import Tensor

import lqsvg.torch.named as nt
from lqsvg.envs import lqr
from lqsvg.envs.lqr import pack_obs, unpack_obs
from lqsvg.envs.lqr.modules.dynamics.gauss import InitStateDynamics
from lqsvg.testing.fixture import standard_fixture
from lqsvg.torch.modules import CholeskyFactor

dim = standard_fixture((2, 4, 8), "Dim")


@pytest.fixture
def module_cls() -> Type[InitStateDynamics]:
    return InitStateDynamics


@pytest.fixture
def module(module_cls: Type[InitStateDynamics], dim: int) -> InitStateDynamics:
    return module_cls(dim)


@pytest.fixture
def state(dim: int, batch_shape: tuple[int, ...]) -> Tensor:
    return nt.vector(torch.randn(batch_shape + (dim, )))
예제 #2
0
# pylint:disable=invalid-name
from __future__ import annotations

import pytest
import torch
from torch import Tensor

import lqsvg.torch.named as nt
from lqsvg.envs import lqr
from lqsvg.envs.lqr.generators import make_lindynamics, make_linsdynamics
from lqsvg.np_util import RNG
from lqsvg.policy.modules import TVLinearFeedback, TVLinearPolicy
from lqsvg.testing.fixture import standard_fixture

frozen = standard_fixture((True, False), "Frozen")


@pytest.fixture
def dynamics(n_state: int, n_ctrl: int, horizon: int,
             rng: RNG) -> lqr.LinSDynamics:
    return make_linsdynamics(
        make_lindynamics(
            n_state,
            n_ctrl,
            horizon,
            stationary=True,
            passive_eigval_range=(0.5, 1.5),
            rng=rng,
        ),
        stationary=True,
        rng=rng,
예제 #3
0
@pytest.fixture(autouse=True)
def torch_generator_state(seed: int):
    with default_generator_seed(seed):
        yield


@pytest.fixture
def n_state() -> int:
    return 2


@pytest.fixture
def n_ctrl() -> int:
    return 2


@pytest.fixture
def horizon() -> int:
    return 20


stationary = standard_fixture((True, False), "Stationary")


@pytest.fixture
def lqg_generator(
    n_state: int, n_ctrl: int, horizon: int, stationary: bool, seed: int
) -> LQGGenerator:
    return LQGGenerator(n_state, n_ctrl, horizon, stationary=stationary, rng=seed)
예제 #4
0
    def test_init(self, n_state: int, n_ctrl: int, horizon: int, stationary: bool):
        module = LinearTransitionModel(n_state, n_ctrl, horizon, stationary)
        assert isinstance(module, LinearDynamicsModule)
        assert all(
            list(hasattr(module, attr) for attr in "n_state n_ctrl horizon".split())
        )


class TestLinearDiagDynamicsModel(DynamicsModuleTests, LinearParamsTestMixin):
    @pytest.fixture
    def module(self, n_state: int, n_ctrl: int, horizon: int, stationary: bool):
        return LinearDiagDynamicsModel(n_state, n_ctrl, horizon, stationary)


hunits = standard_fixture([(), (10,), (32, 32)], "HiddenUnits")
activation = standard_fixture((None, "ReLU", "ELU", "Tanh"), "Activation")


@pytest.mark.skip(reason="Unimplemented")
class TestMLPTransitionModel(DynamicsModuleTests):
    @pytest.fixture
    def module(
        self,
        n_state: int,
        n_ctrl: int,
        horizon: int,
        hunits: tuple[int, ...],
        activation: str,
    ) -> MLPDynamicsModel:
        # pylint:disable=too-many-arguments
예제 #5
0
import pytest
from ray.rllib import RolloutWorker
from torch import Tensor

import lqsvg.torch.named as nt
from lqsvg.experiment.data import DataModuleSpec, TrajectoryData, TransitionData
from lqsvg.experiment.worker import make_worker
from lqsvg.testing.fixture import standard_fixture

n_state = standard_fixture((2, 3), "NState")
n_ctrl = standard_fixture((2, 3), "NCtrl")
horizon = standard_fixture((1, 7, 10), "Horizon")


@pytest.fixture
def worker(n_state: int, n_ctrl: int, horizon: int) -> RolloutWorker:
    with nt.suppress_named_tensor_warning():
        worker = make_worker(
            env_config=dict(n_state=n_state,
                            n_ctrl=n_ctrl,
                            horizon=horizon,
                            num_envs=2),
            log_level="WARNING",
        )
    return worker


def test_trajectory_data(worker: RolloutWorker, n_state: int, n_ctrl: int,
                         horizon: int):
    data_spec = DataModuleSpec(total_trajs=100)
    datamodule = TrajectoryData(worker, data_spec)
예제 #6
0
from __future__ import annotations

import pytest
from torch import Tensor

import lqsvg.torch.named as nt
from lqsvg.testing.fixture import standard_fixture
from lqsvg.torch.utils import make_spd_matrix

n_row = standard_fixture((1, 2, 4), "Rows")


@pytest.fixture
def spdm(n_row: int, seed: int) -> Tensor:
    return nt.matrix(make_spd_matrix(n_row, sample_shape=(), rng=seed))


def test_cholesky(spdm: Tensor):
    scale_tril = nt.cholesky(spdm)

    assert scale_tril.shape == spdm.shape
    assert scale_tril.names == spdm.names
    assert scale_tril.dtype == spdm.dtype
    assert (nt.diagonal(scale_tril) >= 0).all()
    assert nt.allclose(scale_tril @ nt.transpose(scale_tril), spdm)
예제 #7
0
    env = RandomLQGEnv(config)

    env.reset()
    act = env.action_space.sample()
    new_obs, rew, done, info = env.step(act)

    # pylint:disable=unsupported-membership-test
    assert new_obs in env.observation_space
    assert isinstance(rew, float)
    assert isinstance(done, bool)
    assert isinstance(info, dict)


# ==============================================================================

num_envs = standard_fixture((1, 2, 4), "NEnvs")


@pytest.fixture
def vector_config(config: dict, num_envs: int) -> dict:
    config["num_envs"] = num_envs
    return config


# Test RandomVectorLQG =========================================================
def test_vector_init(vector_config: dict):
    env = RandomVectorLQG(vector_config)

    assert env.num_envs == vector_config["num_envs"]
    assert hasattr(env, "curr_states")
    assert env.curr_states is None
예제 #8
0
from lqsvg.envs import lqr
from lqsvg.envs.lqr.generators import make_lindynamics, make_linsdynamics
from lqsvg.envs.lqr.utils import (
    ctrb,
    minimal_sample_shape,
    random_mat_with_eigval_range,
    random_matrix_from_eigs,
    wrap_sample_shape_to_size,
)
from lqsvg.np_util import RNG
from lqsvg.testing.fixture import standard_fixture

from .utils import scalar_to_matrix, sort_eigfactors, vector_to_matrix

mat_dim = standard_fixture((2, 3, 4), "MatDim")
eigval_range = standard_fixture([(0, 1), (0.5, 1.5)], "EigvalRange")
n_batch = standard_fixture((None, 1, 4), "NBatch")
vec_dim = standard_fixture((2, 3, 4), "VecDim")
batch_shape = standard_fixture([(), (1, ), (2, ), (2, 1)], "BatchShape")


@pytest.fixture(params=(0, 2))
def dim(request) -> int:
    return request.param


@pytest.fixture
def sampler(dim: int) -> Callable[[int], np.ndarray]:
    call = normal.rvs if dim == 0 else partial(ortho_group.rvs, dim=3)
예제 #9
0

def squared(x: np.ndarray) -> np.ndarray:
    return x**2


def dot_2d(x: np.ndarray) -> np.ndarray:
    return x.dot(np.array([1, 1]))


def dot_3d(x: np.ndarray) -> np.ndarray:
    return x.dot(np.array([1, 1, 1]))


FUNCTIONS = {1: squared, 2: dot_2d, 3: dot_3d}
dim = standard_fixture((1, 2, 3), "Dim")
max_scaling = standard_fixture((0.1, 1.0, 3.0), "MaxScaling")
steps = standard_fixture((2, 5, 10), "Steps")


@pytest.fixture
def rng(seed: int) -> Generator:
    return np.random.default_rng(seed)


@pytest.fixture
def f_delta(dim: int) -> Callable[[np.ndarray], np.ndarray]:
    return FUNCTIONS[dim]


@pytest.fixture
예제 #10
0
from __future__ import annotations

import pytest
import torch
from torch import Tensor

import lqsvg.torch.named as nt
from lqsvg.envs import lqr
from lqsvg.envs.lqr.modules.reward.quadratic import QuadraticReward
from lqsvg.envs.lqr.utils import pack_obs, unpack_obs
from lqsvg.testing.fixture import standard_fixture

batch_shape = standard_fixture([(), (1,), (4,), (2, 2)], "BatchShape")


class TestQuadraticReward:
    @pytest.fixture
    def module(self, n_state: int, n_ctrl: int, horizon: int) -> QuadraticReward:
        return QuadraticReward(n_state + n_ctrl, horizon)

    @pytest.fixture
    def state(self, n_state: int, batch_shape: tuple[int, ...]) -> Tensor:
        return nt.vector(torch.randn(batch_shape + (n_state,)))

    @pytest.fixture
    def obs(self, state: Tensor, horizon: int, batch_shape: tuple[int, ...]) -> Tensor:
        time = torch.randint(low=0, high=horizon, size=batch_shape + (1,))
        return pack_obs(state, nt.vector(time)).requires_grad_(True)

    @pytest.fixture
    def act(self, n_ctrl: int, batch_shape) -> Tensor:
예제 #11
0
import pytest

from lqsvg.testing.fixture import standard_fixture
from lqsvg.torch.utils import default_generator_seed

seed = standard_fixture((1, 2, 3), "Seed")


@pytest.fixture(autouse=True)
def torch_generator_state(seed: int):
    with default_generator_seed(seed):
        yield
예제 #12
0
    LQGGenerator,
    box_ddp_random_lqr,
    make_lindynamics,
    make_linsdynamics,
    make_lqr,
    make_lqr_linear_navigation,
    make_quadcost,
    stack_lqs,
)
from lqsvg.envs.lqr.types import LinDynamics, LinSDynamics, QuadCost
from lqsvg.envs.lqr.utils import stationary_dynamics_factors
from lqsvg.testing.fixture import standard_fixture

GeneratorFn = Callable[..., LQGGenerator]

passive_eigval_range = standard_fixture([None, (0.0, 1.0), (0.5, 1.5)],
                                        "PassiveEigvals")
stat_ctrb = standard_fixture([(True, False), (True, True), (False, False)],
                             "Stationary/Controllable")
transition_bias = standard_fixture((True, False), "TransBias")
sample_covariance = standard_fixture((True, False), "SampleCov")
cost_linear = standard_fixture((True, False), "CostLinear")
cost_cross = standard_fixture((True, False), "CostCross")
n_batch = standard_fixture((None, 1, 4), "NBatch")


@pytest.fixture
def stationary(stat_ctrb: tuple[bool, bool]) -> bool:
    stat, _ = stat_ctrb
    return stat

예제 #13
0
from __future__ import annotations

import numpy as np
import torch

from lqsvg.np_util import make_spd_matrix, random_unit_col_matrix, random_unit_vector
from lqsvg.testing.fixture import standard_fixture

seed = standard_fixture((42, 69, 37), "Seed")
batch_shape = standard_fixture([(), (1, ), (2, ), (2, 1)], "BatchShape")
vec_dim = standard_fixture((2, 3, 4), "VecDim")
n_row = standard_fixture((2, 3, 4), "Rows")
n_col = standard_fixture((2, 3, 4), "Columns")


def test_spd_matrix(n_row: int, batch_shape: tuple[int, ...], seed: int):
    A = make_spd_matrix(n_row, sample_shape=batch_shape, rng=seed)

    assert A.shape == batch_shape + (n_row, n_row)
    B = torch.as_tensor(A)
    assert torch.allclose(B, B.transpose(-2, -1))
    eigval, _ = torch.linalg.eigh(B)
    assert eigval.ge(0).all()


def test_random_unit_vector(vec_dim: int, batch_shape: tuple[int, ...],
                            seed: int):
    vector = random_unit_vector(vec_dim, sample_shape=batch_shape, rng=seed)

    assert isinstance(vector, np.ndarray)
    assert vector.shape == batch_shape + (vec_dim, )
예제 #14
0
from __future__ import annotations

import numpy as np
import pytest
import torch
from numpy.random import Generator
from torch import Tensor

from lqsvg.envs.lqr.utils import pack_obs, unpack_obs
from lqsvg.testing.fixture import standard_fixture
from lqsvg.torch import named as nt
from lqsvg.torch.utils import default_generator_seed

n_state = standard_fixture((2, 3), "NState")
n_ctrl = standard_fixture((2, 3), "NCtrl")
horizon = standard_fixture((1, 3, 10), "Horizon")
stationary = standard_fixture((True, False), "Stationary")
seed = standard_fixture((1, 2, 3), "Seed")
batch_shape = standard_fixture([(), (1, ), (4, )], "BatchShape")


@pytest.fixture
def rng(seed: int) -> Generator:
    return np.random.default_rng(seed)


@pytest.fixture(autouse=True)
def torch_generator_state(seed: int):
    with default_generator_seed(seed):
        yield