Pendulum

Classic swing-up control task. Apply torque to swing the pendulum from hanging to upright position.

Physics

Pure dynamics for the simple pendulum, decoupled from task logic.

Pure stateless physics for the Pendulum system.

This module contains the ground truth dynamics for the simple pendulum, completely decoupled from any task-specific logic (rewards, terminations, observations).

The physics can be reused by different tasks (control, system ID, etc.) and can be directly accessed by model-based methods like MPC planners or Neural ODEs.

class myriad.envs.classic.pendulum.physics.PhysicsState(theta, theta_dot)[source]

Bases: NamedTuple

Pure physical state of the pendulum system.

Variables:
  • theta (jax.jaxlib._jax.Array) – Angle from vertical down (rad, 0 = hanging down, pi = upright)

  • theta_dot (jax.jaxlib._jax.Array) – Angular velocity (rad/s)

theta: Array

Alias for field number 0

theta_dot: Array

Alias for field number 1

to_array()[source]

Convert to flat array for NN-based agents.

Returns:

Array of shape (2,) with [theta, theta_dot]

Return type:

Array

classmethod from_array(arr)[source]

Create state from flat array.

Parameters:

arr (Array) – Array of shape (2,) with [theta, theta_dot]

Returns:

PhysicsState instance

Return type:

PhysicsState

class myriad.envs.classic.pendulum.physics.PhysicsConfig(gravity=9.8, mass=1.0, length=1.0, dt=0.05, max_torque=2.0, max_speed=8.0)[source]

Bases: object

Static physics constants for the pendulum system.

These are compile-time constants passed as static_argnames to jit. Changing these values requires recompilation but enables better optimization.

gravity: float = 9.8
mass: float = 1.0
length: float = 1.0
dt: float = 0.05
max_torque: float = 2.0
max_speed: float = 8.0
__init__(gravity=9.8, mass=1.0, length=1.0, dt=0.05, max_torque=2.0, max_speed=8.0)
replace(**updates)

Returns a new object replacing the specified fields with new values.

class myriad.envs.classic.pendulum.physics.PhysicsParams[source]

Bases: object

Dynamic physics parameters for domain randomization.

Currently empty for Pendulum, but maintained for protocol consistency and future domain randomization support (e.g., varying masses/lengths per episode).

__init__()
replace(**updates)

Returns a new object replacing the specified fields with new values.

myriad.envs.classic.pendulum.physics.step_physics(state, action, params, config)[source]

Pure physics step using Euler integration.

The pendulum dynamics follow the standard equation: theta_ddot = (3g/2l)*sin(theta) + (3/ml^2)*tau

where theta=0 is hanging down and tau is the applied torque.

Parameters:
  • state (PhysicsState) – Current physical state (theta, theta_dot)

  • action (Array) – Continuous torque in [-max_torque, max_torque]

  • params (PhysicsParams) – Dynamic parameters (unused, reserved for future randomization)

  • config (PhysicsConfig) – Static physics constants

Returns:

Next physical state after one dt timestep

Return type:

PhysicsState

myriad.envs.classic.pendulum.physics.create_physics_params(**kwargs)[source]

Factory function to create PhysicsParams.

Parameters:

**kwargs – Reserved for future domain randomization parameters

Returns:

PhysicsParams instance

Return type:

PhysicsParams

Control Task

Standard swing-up task with continuous torque control.

Control task wrapper for Pendulum.

Standard swing-up task: Swing the pendulum to the upright position and balance. Reward: -(theta_from_up^2 + 0.1*theta_dot^2 + 0.001*torque^2)

class myriad.envs.classic.pendulum.tasks.control.ControlTaskState(physics, t)[source]

Bases: NamedTuple

State for the control task.

Variables:
physics: PhysicsState

Alias for field number 0

t: Array

Alias for field number 1

class myriad.envs.classic.pendulum.tasks.control.ControlTaskConfig(physics=<factory>, task=<factory>)[source]

Bases: object

Configuration for the Pendulum control task.

Composed of physics config and task config for clean separation.

physics: PhysicsConfig
task: TaskConfig
property dt: float

Timestep duration in seconds.

property max_steps: int

Required by EnvironmentConfig protocol.

__init__(physics=<factory>, task=<factory>)
replace(**updates)

Returns a new object replacing the specified fields with new values.

class myriad.envs.classic.pendulum.tasks.control.ControlTaskParams(physics=<factory>)[source]

Bases: object

Parameters for the control task.

physics: PhysicsParams
__init__(physics=<factory>)
replace(**updates)

Returns a new object replacing the specified fields with new values.

myriad.envs.classic.pendulum.tasks.control.step(key, state, action, params, config)

Step the control task forward one timestep.

Parameters:
  • key (Array) – RNG key (unused for deterministic control task, but part of protocol)

  • state (ControlTaskState) – Current task state

  • action (Array) – Continuous torque in [-max_torque, max_torque]

  • params (ControlTaskParams) – Task parameters

  • config (ControlTaskConfig) – Task configuration (static)

Returns:

Next observation (PendulumObservation) next_state: Next environment state reward: Reward (negative cost) done: Termination flag (1.0 if done, 0.0 otherwise) info: Empty dict (no auxiliary information)

Return type:

obs_next

myriad.envs.classic.pendulum.tasks.control.reset(key, params, config)

Reset the control task to initial state.

Initializes the pendulum with random angle and small velocity.

Parameters:
Returns:

Initial observation (PendulumObservation) state: Initial task state

Return type:

obs

myriad.envs.classic.pendulum.tasks.control.get_obs(state, params, config)[source]

Extract observation from state.

For control task, observation is cos/sin/theta_dot representation. Neural network agents can call .to_array() for flat array representation.

Parameters:
Returns:

PendulumObservation with cos_theta, sin_theta, theta_dot

Return type:

PendulumObservation

myriad.envs.classic.pendulum.tasks.control.get_obs_shape(config)[source]

Get the shape of the observation space.

Parameters:

config (ControlTaskConfig) – Task configuration (unused)

Returns:

Observation shape tuple

Return type:

tuple[int, …]

myriad.envs.classic.pendulum.tasks.control.get_action_space(config)[source]

Get the continuous action space for the environment.

Parameters:

config (ControlTaskConfig) – Task configuration with physics config

Returns:

Box space for torque in [-max_torque, max_torque]

Return type:

Box

myriad.envs.classic.pendulum.tasks.control.make_env(config=None, params=None, **kwargs)[source]

Create a Pendulum control task environment.

Parameters:
  • config (ControlTaskConfig | None) – Custom ControlTaskConfig. If None, uses defaults.

  • params (ControlTaskParams | None) – Custom ControlTaskParams. If None, creates from kwargs.

  • **kwargs – Keyword arguments for creating config/params if not provided.

Returns:

Environment instance for the control task

Return type:

Environment[ControlTaskState, ControlTaskConfig, ControlTaskParams, PendulumObservation]

Shared utilities for Pendulum task wrappers.

class myriad.envs.classic.pendulum.tasks.base.TaskConfig(max_steps=200)[source]

Bases: object

Base configuration shared by all Pendulum tasks.

These define the task-specific episode limits.

max_steps: int = 200
__init__(max_steps=200)
replace(**updates)

Returns a new object replacing the specified fields with new values.

class myriad.envs.classic.pendulum.tasks.base.PendulumObservation(cos_theta, sin_theta, theta_dot)[source]

Bases: NamedTuple

Observation for the pendulum system.

Uses cos/sin representation to avoid angle discontinuity at +/-pi. This provides bounded values suitable for neural network inputs.

Variables:
  • cos_theta (jax.jaxlib._jax.Array) – Cosine of angle from vertical down

  • sin_theta (jax.jaxlib._jax.Array) – Sine of angle from vertical down

  • theta_dot (jax.jaxlib._jax.Array) – Angular velocity (rad/s)

cos_theta: Array

Alias for field number 0

sin_theta: Array

Alias for field number 1

theta_dot: Array

Alias for field number 2

to_array()[source]

Convert to flat array for NN-based agents.

Returns:

Array of shape (3,) with [cos_theta, sin_theta, theta_dot]

Return type:

Array

myriad.envs.classic.pendulum.tasks.base.get_pendulum_obs(physics_state)[source]

Extract standard Pendulum observation from physics state.

Converts angle to cos/sin representation to avoid discontinuity.

Parameters:

physics_state (PhysicsState) – PhysicsState with theta, theta_dot fields

Returns:

PendulumObservation with cos_theta, sin_theta, theta_dot

Return type:

PendulumObservation

myriad.envs.classic.pendulum.tasks.base.get_pendulum_obs_shape()[source]

Get the shape of the Pendulum observation space.

Returns:

Observation shape tuple (3,) for [cos_theta, sin_theta, theta_dot]

Return type:

tuple[int, …]

myriad.envs.classic.pendulum.tasks.base.get_pendulum_action_space(config)[source]

Get the continuous action space for Pendulum.

Parameters:

config (PhysicsConfig) – Physics configuration with max_torque

Returns:

Box space for torque in [-max_torque, max_torque]

Return type:

Box

myriad.envs.classic.pendulum.tasks.base.sample_initial_physics(key)[source]

Sample initial physics state with random angle and velocity.

Initializes the pendulum with random angle in [-pi, pi] and small random velocity.

Parameters:

key (Array) – RNG key for random initialization

Returns:

PhysicsState with random initial conditions

Return type:

PhysicsState