Environment
The Environment class and the Timestep it produces.
An Environment is a frozen JAX pytree: it holds the grid geometry
(height, width, max_steps) and a set of pluggable functions -
observation_fn, reward_fn, termination_fn, transitions_fn,
action_set - that together define the task. reset and step are pure
functions of (key) / (timestep, action), so they compose with
jax.jit, jax.vmap (a batch of environments) and jax.lax.scan (a
whole rollout in one compiled loop).
Concrete environments (navix.environments.Empty, DoorKey, ...)
subclass Environment and implement _reset to lay out their grid;
everything else is inherited. Build one with navix.make(id) or
SomeEnv.create(...).
Environment
Bases: PyTreeNode
A gridworld task as a frozen JAX pytree.
The task is defined by five pluggable pieces, each a plain function
you can override per-make/create call:
observation_fn(state) -> Array- what the agent sees.transitions_fn(state, action, action_set) -> State- the world dynamics (appliesaction_set[action], then any stochastic entity updates).reward_fn(prev_state, action, state) -> f32[]- the reward for a transition. The(prev_state, action, state)triple is the convention acrossnavix.rewards/terminations/events:prev_stateis $s_t$,stateis $s_{t+1}$.termination_fn(prev_state, action, state) -> bool[]- whether $s_{t+1}$ is a genuine terminal state (truncation atmax_stepsis added on top automatically).action_set- the tuple ofstate -> stateprimitives an integer action indexes into.
Subclasses only implement _reset (the initial grid layout);
reset/step are inherited. Instances are immutable - use
env.replace(...) (from flax.struct) to get a modified copy.
Attributes:
| Name | Type | Description |
|---|---|---|
height |
int
|
grid height in cells, including the surrounding wall. |
width |
int
|
grid width in cells, including the surrounding wall. |
max_steps |
int
|
truncation horizon - |
observation_space |
Space
|
|
action_space |
Space
|
|
reward_space |
Space
|
|
disable_autoreset |
bool
|
if |
gamma |
float
|
discount factor. Not used by |
penalty_coeff |
float
|
if non-zero, a terminating reward is reduced by
|
observation_fn |
Callable[[State], Array]
|
|
reward_fn |
Callable[[State, Array, State], Array]
|
|
termination_fn |
Callable[[State, Array, State], Array]
|
|
transitions_fn |
Callable[[State, Array, Tuple[Callable[[State], State], ...]], State]
|
|
action_set |
Tuple[Callable[[State], State], ...]
|
tuple of |
penality_coeff
property
Deprecated misspelling of penalty_coeff. Reads still work
(with a warning); pass penalty_coeff to create going
forward.
create(height, width, max_steps=None, observation_fn=observations.symbolic, reward_fn=rewards.DEFAULT_TASK, termination_fn=terminations.DEFAULT_TERMINATION, transitions_fn=transitions.DEFAULT_TRANSITION, action_set=DEFAULT_ACTION_SET, observation_space=None, action_space=None, reward_space=None, disable_autoreset=False, **kwargs)
classmethod
Builds an environment, filling in the spaces and max_steps
that weren't given.
This is the shared constructor concrete environments call from
their own create; navix.make(id, **kwargs) ends up here too.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
height
|
int
|
grid height in cells (walls included). |
required |
width
|
int
|
grid width in cells (walls included). |
required |
max_steps
|
int | None
|
truncation horizon. |
None
|
observation_fn
|
Callable
|
|
symbolic
|
reward_fn
|
Callable
|
|
DEFAULT_TASK
|
termination_fn
|
Callable
|
|
DEFAULT_TERMINATION
|
transitions_fn
|
Callable
|
|
DEFAULT_TRANSITION
|
action_set
|
tuple[Callable, ...]
|
|
DEFAULT_ACTION_SET
|
observation_space
|
Space | None
|
|
None
|
action_space
|
Space | None
|
|
None
|
reward_space
|
Space | None
|
|
None
|
disable_autoreset
|
bool
|
see the class attribute. |
False
|
**kwargs
|
extra fields forwarded to the subclass constructor
(e.g. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
Environment |
Environment
|
the constructed environment. |
reset(key, cache=None)
Starts a new episode.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
Array
|
a |
required |
cache
|
RenderingCache | None
|
optional pre-built rendering
cache (see |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Timestep |
Timestep
|
the first timestep - |
Timestep
|
|
|
Timestep
|
from |
|
Timestep
|
reproducible from the single seed you pass here. |
step(timestep, action)
Advances one timestep, or auto-resets at an episode boundary.
If timestep already ended an episode (its step_type > 0) and
disable_autoreset is False, this ignores action and returns
a fresh reset seeded from timestep.state.key. Otherwise it
applies action via transitions_fn, then evaluates
reward_fn, termination_fn and observation_fn on the result.
Autoreset is deferred by one call: the terminal timestep is
returned as-is (so you can read its final reward), and the reset
happens on the next step. Detect a fresh episode with
timestep.is_start(), not by looking back at is_done().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timestep
|
Timestep
|
the current timestep (from |
required |
action
|
Array
|
an integer action, |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Timestep |
Timestep
|
the next timestep. |
Timestep
|
undiscounted episodic reward. |
termination(prev_state, action, state, t)
Combines the task's termination_fn with the max_steps
truncation into a single StepType.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prev_state
|
State
|
$s_t$. |
required |
action
|
Array
|
$a_t$. |
required |
state
|
State
|
$s_{t+1}$. |
required |
t
|
Array
|
the step count of |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Array |
Array
|
a |
Array
|
fired, else |
|
Array
|
|
StepType
Bases: PyTreeNode
The three kinds of timestep, stored as Timestep.step_type. The
distinction between the two "episode over" cases matters for
bootstrapping a value function: bootstrap through a TRUNCATION,
but not through a TERMINATION.
TERMINATION = jnp.asarray(2)
class-attribute
instance-attribute
The episode reached a genuine terminal (absorbing) state - the goal, lava, a wrong toggle, etc. Its value is 0; do not bootstrap.
TRANSITION = jnp.asarray(0)
class-attribute
instance-attribute
The episode continues; step will keep advancing it.
TRUNCATION = jnp.asarray(1)
class-attribute
instance-attribute
The episode was cut off at max_steps while still ongoing. The
final state is not absorbing - its value is non-zero - so a value
estimate should bootstrap through it.
Timestep
Bases: PyTreeNode
What Environment.reset and Environment.step return - one moment
in a trajectory.
Read it as the result of the transition that produced it: state
and t describe the world now, and action / reward / step_type
are the action that got here and its consequences. So after
ts_next = env.step(ts, a): ts_next.state is $s_{t+1}$,
ts_next.action is $a$ (ts.action is discarded), ts_next.reward
is $R(s_t, a, s_{t+1})$, and ts_next.observation is the observation
of $s_{t+1}$.
Every field is a JAX array (or a pytree of them), so a Timestep
vmaps over a batch of environments and scans over time.
Attributes:
| Name | Type | Description |
|---|---|---|
t |
Array
|
steps since the last reset, |
observation |
Array
|
the agent's view of |
action |
Array
|
the action that led to this timestep, |
reward |
Array
|
the scalar reward for the transition into this timestep,
|
step_type |
Array
|
a |
state |
State
|
the full |
info |
Dict[str, Any]
|
a plain dict for extra per-step quantities. navix populates
|
is_done()
True where the episode has ended for either reason -
truncation or termination. This is the mask you use to segment
trajectories or to stop bootstrapping a return.
is_start()
True on the first timestep of an episode (t == 0) - both
the initial reset and every post-autoreset step. Robust to
navix deferring autoreset by one step call, unlike checking a
previous step's is_done().
is_termination()
True where step_type == StepType.TERMINATION (genuine
absorbing terminal state). Boolean, same batch shape as
step_type.
is_transition()
True where the episode is still ongoing
(step_type == StepType.TRANSITION). Boolean.
is_truncation()
True where step_type == StepType.TRUNCATION (episode cut off
at max_steps). Boolean, same batch shape as step_type.