Source code for embodichain.cli.sim

# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------

"""Simulation CLI options independent of Gym configuration loading.

Seed registration is opt-in. Parsing never initializes a simulator or random
stream; callers explicitly apply the resolved seed to their owned generators.
"""

from __future__ import annotations

import argparse
import secrets

__all__ = ["add_sim_args_to_parser", "add_seed_arg_to_parser", "resolve_seed"]


[docs] def add_sim_args_to_parser(parser: argparse.ArgumentParser) -> None: """Register standalone simulation and visualization options. Args: parser: Parser receiving the options. Device omission preserves the backend default; the other standalone defaults are concrete. """ parser.add_argument( "--num_envs", "--num-envs", help="Number of parallel environments; omission uses launcher/config defaults.", default=1, type=int, ) parser.add_argument( "--device", type=str, default=None, help="Device used by environment tensors and the selected physics " "backend, e.g. 'cpu' or 'cuda:0'. When omitted, the selected backend " "default is preserved unless this option is set.", ) parser.add_argument( "--headless", help="Whether to perform the simulation in headless mode.", default=False, action=argparse.BooleanOptionalAction, ) parser.add_argument( "--renderer", type=str, choices=["auto", "no-render", "hybrid", "fast-rt", "rt"], default="auto", help="Renderer backend; auto uses no-render for task environments without " "native render consumers, otherwise selects by GPU (run-task " "uses fast-rt on every platform). Omission preserves the launcher/config default.", ) parser.add_argument( "--physics", type=str, choices=["default", "newton"], default="default", help="Physics backend. For Gym configs, this may only confirm the file-owned backend.", ) parser.add_argument( "--arena_space", "--arena-space", help="The size of the arena space.", default=5.0, type=float, ) parser.add_argument( "--gpu_id", "--gpu-id", help="The GPU ID to use for the simulation.", default=0, type=int, ) from ._visualization import add_viser_args_to_parser add_viser_args_to_parser(parser)
def _parse_seed(value: str) -> int: try: seed = int(value) except ValueError as exc: raise argparse.ArgumentTypeError("Seed must be an integer.") from exc if not -1 <= seed < 2**32: raise argparse.ArgumentTypeError("Seed must be -1 or in [0, 2**32).") return seed
[docs] def add_seed_arg_to_parser( parser: argparse.ArgumentParser, *, default: int | None = 0, scope: str = "random sampling", ) -> None: """Register one seed option for a caller that actually consumes it. Args: parser: Parser receiving the seed option. default: Seed when omitted; None preserves a Gym config's seed. scope: User-facing description of the random streams controlled. """ if default is not None: _parse_seed(str(default)) parser.add_argument( "--seed", type=_parse_seed, default=default, help=f"Seed for {scope}; -1 selects a random seed. " + ( "Omission preserves the task config." if default is None else f"Default: {default}." ), )
[docs] def resolve_seed(seed: int) -> int: """Resolve the random-run sentinel without changing global RNG state. Args: seed: A non-negative 32-bit seed, or -1 to generate a fresh seed. Returns: Effective seed to log and pass to the caller's random generators. Raises: ValueError: If seed is outside the portable 32-bit range. """ if not -1 <= seed < 2**32: raise ValueError("Seed must be -1 or in [0, 2**32).") return secrets.randbits(32) if seed == -1 else seed