Advanced Usage
Changing the emission rate and environment speed
By default, any RxEnvironment
emits an observation to any subscribed agents every 1000
milliseconds, or whenever any agent in the environment conducts an action. To change this, one can use the emit_every_ms
keyword argument to the RxEnvironment
function. Taking the environment from the example:
environment = RxEnvironment(BayesianThermostat(0.0, -10, 10); emit_every_ms = 10)
Will emit an observation to any agents in the environment every 10
milliseconds.
By adjusting the real_time_factor
keyword argument to the RxEnvironment
function, one can play with the amount of computation time we give to agents to conduct their actions. For example:
environment = RxEnvironment(BayesianThermostat(0.0, -10, 10); emit_every_ms = 1000, real_time_factor=2)
Will emit an observation to every subscribed agent every 1000 milliseconds. However, the environment will only have moved 500 milliseconds forward, giving any subscribed agent twice as much time to choose an action than that it would have in a real-time setting.
Discrete Environments
RxEnvironments
natively represents any environment as a continuous environment. However, discrete environments are also supported. By including the keyword argument discrete=true
to the RxEnvironment
function, we convert the environment to a discrete environment. There are 2 major differences between a discrete RxEnvironment
and a continuous one:
- A discrete environment waits until all agents in the environment have conducted an action, and only then takes the last action emitted by every agent into account. I.e. if we have an environment with
agent_1
andagent_2
as agents. Ifagent_1
emits two actions beforeagent_2
emits, the environment will only incorporate the second action emitted byagent_1
wheneveragent_2
emits. - A discrete environment has a fixed time between state transitions, which can be set by implementing
RxEnvironments.time_interval(::YourEntityType)
. This function should return the time interval between state transitions in seconds, which by default is 1.0.
Note that by "Discrete", we mean that the environment is discrete in time, not in state space. The state space can still be continuous. Note, however, that for more complex entity interactions, the fact that a discrete entity waits for all subscribers to emit before transitioning to the next state can lead to undesired behavior.
Animating Environments
Animating an environment is done using the GLMakie
package. In order to animate your custom environments, please implement RxEnvironments.plot_state(ax, ::EnvironmentType)
, where ax
is the GLMakie
axis object that you can plot towards. If you need access to other agents or entities in order to plot your environments, you can extend RxEnvironments.add_to_state!(::EnvironmentType, ::AgentType)
to make sure you have access to subscribed agents in the state.
By calling RxEnvironments.animate_state(::RxEnvironment; fps)
, RxEnvironments
animates the plots you generate in the plot_state
function to accurately reflect the state of your environment in real time.
Multi-Agent Environments
RxEnvironments natively supports multi-agent environments, similarly to how we call add!(environment, agent)
in the example page, we can call add!
with additional agents in order to create a multi-agent environment.
Inspecting Observations
By using RxEnvironments.subscribe_to_observations!
we can subscribe any Rocket
actor to the observations of any entity. Note that these observations will be of type Observation
, that also contains a reference to the entity that emitted the observation. In order to retrieve the value of the observation, you can call RxEnvironments.data
on the Observation
instance.