Skip to content

Commit a272715

Browse files
committed
Cleaner tests
1 parent 76ae4ae commit a272715

13 files changed

Lines changed: 1214 additions & 888 deletions

File tree

oryx/distribution/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,14 @@ def __init__(
172172
tanh = bijectors.Tanh()
173173
self.distribution = distributions.Transformed(normal, tanh)
174174

175+
@property
176+
def loc(self) -> Float[Array, " dims"]:
177+
return self.distribution._distribution.loc
178+
179+
@property
180+
def scale(self) -> Float[Array, " dims"]:
181+
return self.distribution._distribution.scale
182+
175183

176184
class MultivariateNormalDiag(AbstractDistribution[Float[Array, " dims"]]):
177185

@@ -245,6 +253,14 @@ def __init__(
245253
tanh = bijectors.Tanh()
246254
self.distribution = distributions.Transformed(mvn, tanh)
247255

256+
@property
257+
def loc(self) -> Float[Array, " dims"]:
258+
return self.distribution._distribution.loc
259+
260+
@property
261+
def scale_diag(self) -> Float[Array, " dims"]:
262+
return self.distribution._distribution.scale_diag
263+
248264

249265
__all__ = [
250266
"AbstractDistribution",

oryx/policy/actor_critic/custom.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ class CustomActorCriticPolicy[
3737
* Box: MLP(feature_size → action_dim) with Normal + squashing
3838
"""
3939

40-
state_index: eqx.nn.StateIndex[None]
41-
4240
feature_extractor: (
4341
AbstractModel[[ObsType], FeatureType]
4442
| AbstractStatefulModel[[ObsType], FeatureType]
@@ -54,6 +52,7 @@ class CustomActorCriticPolicy[
5452
log_std: Float[Array, " action_size"]
5553

5654
env: AbstractEnvLike[ActType, ObsType]
55+
state_index: eqx.nn.StateIndex[None] = eqx.nn.StateIndex(None)
5756

5857
def __init__(
5958
self,
@@ -134,8 +133,6 @@ def __init__(
134133
else:
135134
self.action_model = action_model
136135

137-
self.state_index = eqx.nn.StateIndex(None)
138-
139136
@property
140137
def action_space(self) -> AbstractSpace[ActType]:
141138
return self.env.action_space

oryx/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def _f(carry_arr, x):
4343
carry, y = f(carry, x)
4444
carry_arr, _static = eqx.partition(carry, eqx.is_array)
4545

46+
# Assert will be omitted from the compiled code
47+
# I tried using `eqx.error(carry_arr, cond)` if but it breaks if the carry includes a key
4648
assert eqx.tree_equal(
4749
static, _static
4850
), "Non-array carry of filter_scan must not change."

oryx/wrapper/transform_reward.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import equinox as eqx
77
from jax import numpy as jnp
88
from jax import random as jr
9-
from jaxtyping import Array, Bool, Float, Key
9+
from jaxtyping import Array, ArrayLike, Bool, Float, Key
1010

1111
from oryx.env import AbstractEnvLike
1212

@@ -93,8 +93,8 @@ class ClipReward[ActType, ObsType](
9393
def __init__(
9494
self,
9595
env: AbstractEnvLike[ActType, ObsType],
96-
min: Float[Array, ""] = jnp.asarray(-1.0),
97-
max: Float[Array, ""] = jnp.asarray(1.0),
96+
min: Float[ArrayLike, ""] = jnp.asarray(-1.0),
97+
max: Float[ArrayLike, ""] = jnp.asarray(1.0),
9898
):
9999
self.env = env
100100
self.min = jnp.asarray(min)

tests/shared/__init__.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1 @@
1-
from .envs import DiscreteActionEnv, DummyEnv, EchoEnv, FiniteEpisodeEnv, PassThroughEnv
21

3-
__all__ = [
4-
"DiscreteActionEnv",
5-
"DummyEnv",
6-
"EchoEnv",
7-
"FiniteEpisodeEnv",
8-
"PassThroughEnv",
9-
]

tests/shared/envs.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class EchoEnv(AbstractEnv[Float[Array, " n"], Float[Array, " n"]]):
1414
Echoes the action back as the observation, never terminates.
1515
"""
1616

17-
state_index: eqx.nn.StateIndex[None]
1817
action_space: Box
1918
observation_space: Box
19+
state_index: eqx.nn.StateIndex[None] = eqx.nn.StateIndex(None)
2020

2121
def __init__(
2222
self,
@@ -25,7 +25,6 @@ def __init__(
2525
):
2626
self.action_space = action_space
2727
self.observation_space = observation_space
28-
self.state_index = eqx.nn.StateIndex(None)
2928

3029
def reset(self, state, *, key):
3130
return state, self.observation_space.sample(key), {}
@@ -92,10 +91,9 @@ class PassThroughEnv(AbstractEnv[Float[Array, ""], Float[Array, ""]]):
9291
always returns observation = 0.0.
9392
"""
9493

95-
state_index: eqx.nn.StateIndex[None]
94+
state_index: eqx.nn.StateIndex[None] = eqx.nn.StateIndex(None)
9695

97-
def __init__(self):
98-
self.state_index = eqx.nn.StateIndex(None)
96+
def __init__(self): ... # Override dataclass init to avoid unused argument warning
9997

10098
def reset(self, state, *, key):
10199
return state, jnp.asarray(0.0), {}
@@ -171,12 +169,11 @@ class DiscreteActionEnv(AbstractEnv[Int[Array, ""], Float[Array, " n"]]):
171169
Never terminates/truncates.
172170
"""
173171

174-
state_index: eqx.nn.StateIndex[None]
172+
state_index: eqx.nn.StateIndex[None] = eqx.nn.StateIndex(None)
175173
observation_space: Box
176174
action_space: Discrete
177175

178176
def __init__(self, *, key, n_actions: int = 4, obs_size: int = 3):
179-
self.state_index = eqx.nn.StateIndex(None)
180177
self.observation_space = Box(-jnp.inf, jnp.inf, shape=(obs_size,))
181178
self.action_space = Discrete(n_actions)
182179

tests/shared/models.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import annotations
2+
3+
import equinox as eqx
4+
from jax import numpy as jnp
5+
from jaxtyping import Array
6+
7+
from oryx.model.base_model import AbstractModel, AbstractStatefulModel
8+
9+
10+
class Doubler(AbstractModel[[Array], Array]):
11+
def __call__(self, x: Array) -> Array:
12+
return 2.0 * x
13+
14+
15+
class StatefulDoubler(AbstractStatefulModel[[Array], Array]):
16+
state_index: eqx.nn.StateIndex[Array]
17+
18+
def __init__(self):
19+
self.state_index = eqx.nn.StateIndex(jnp.array(0.0))
20+
21+
def __call__(self, state, x):
22+
c = state.get(self.state_index)
23+
state = state.set(self.state_index, c + 1.0)
24+
return state, 2.0 * x
25+
26+
def reset(self, state):
27+
return state.set(self.state_index, jnp.array(0.0))

tests/test_buffers.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from oryx.policy import AbstractActorCriticPolicy
1111
from oryx.utils import filter_scan
1212

13-
from .shared import EchoEnv
13+
from .shared.envs import EchoEnv
1414

1515

1616
class TestRolloutBufferBasics:
@@ -111,12 +111,11 @@ def test_batches_handles_non_divisible_batch_size(self):
111111
class TestRolloutBufferWithEnv:
112112

113113
class _SimplePolicy(AbstractActorCriticPolicy):
114-
state_index: eqx.nn.StateIndex[None]
115114
env: EchoEnv
115+
state_index: eqx.nn.StateIndex[None] = eqx.nn.StateIndex(None)
116116

117117
def __init__(self, env: EchoEnv):
118118
self.env = env
119-
self.state_index = eqx.nn.StateIndex(None)
120119

121120
@property
122121
def action_space(self):

0 commit comments

Comments
 (0)