Skip to content

Variable Morphology

jax-evogym supports two mechanisms for varying robot morphology:

  1. robot_override — swap the robot’s body within a fixed template frame
  2. Dense grid pipeline — build simulation data from scratch in pure JAX, vmap-able across populations

Compile a template once, then instantiate it with different morphologies:

import numpy as np
from jax_evogym import (
EvoWorld, FIXED, H_ACT, SOFT, V_ACT, CONTRACTILE, EMPTY, RIGID,
compile_world_template, instantiate_world,
)
# Compile once
world = EvoWorld()
world.add_from_array("ground", np.array([[FIXED, FIXED, FIXED, FIXED]]), 0, 0)
world.add_from_array("robot", np.array([[H_ACT, SOFT, V_ACT]]), 1, 2)
template = compile_world_template(world, robot_name="robot")
# Instantiate with different bodies
dense = np.array([[H_ACT, SOFT, V_ACT]])
sparse = np.array([[H_ACT, EMPTY, V_ACT]])
dense_built = instantiate_world(template, robot_override=dense)
sparse_built = instantiate_world(template, robot_override=sparse)
  • Override shape must match the robot template grid exactly
  • Same array orientation as add_from_array
  • EMPTY disables cells within the frame
  • Any dynamic voxel type is allowed (RIGID, SOFT, H_ACT, V_ACT, CONTRACTILE)
  • Slope values are rejected
  • Terrain objects are never affected

instantiate_world does not auto-mirror robot_override. Pass the override explicitly to each template:

from jax_evogym import compile_world_templates
template_set = compile_world_templates(world, robot_name="robot", mirror_mode="paired")
built_primary = instantiate_world(template_set.primary, robot_override=body)
built_mirror = instantiate_world(template_set.mirror, robot_override=body)

If you want a truly mirrored body, construct the mirrored array yourself.

For evolutionary search where you need to evaluate thousands of morphologies in parallel, the dense grid pipeline provides pure JAX, vmap-able construction:

from jax_evogym import precompute_grid, jax_build_sim_state, jax_build_collision_data
# 1. Precompute grid infrastructure (once per grid size)
grid_data = precompute_grid(H=5, W=5)
# 2. Build simulation data (pure JAX, vmap-able)
sim_state = jax_build_sim_state(body_array, grid_data)
collision_data = jax_build_collision_data(body_array, grid_data)

See Dense Grid Pipeline for the full guide.

ScenarioUse
Standard environment usageBuilt-in environments (handle everything internally)
Fixed terrain, varying robot bodyrobot_override on a compiled template
Terrain with multiple objectsObject-separated build (compile_world_template)
Population-level morphology search with vmapDense grid pipeline
Custom terrain + custom morphologyBuild the EvoWorld programmatically, compile, instantiate