diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 032ddc616..073c3272e 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - PYTHON_VERSION: ['3.10', '3.11', '3.12'] + PYTHON_VERSION: ['3.10', '3.11', '3.12', '3.13'] BUILD_TYPE: ['Release'] include: - PYTHON_VERSION: '3.12' @@ -69,10 +69,9 @@ jobs: git config --global advice.detachedHead false - name: Install pre-compiled binaries for additional gym-jiminy dependencies - if: matrix.PYTHON_VERSION != '3.13' run: | - "${PYTHON_EXECUTABLE}" -m pip install "torch" -f https://download.pytorch.org/whl/torch - "${PYTHON_EXECUTABLE}" -m pip install "gymnasium>=0.28,<=1.0" "stable_baselines3>=2.0,<2.5" + "${PYTHON_EXECUTABLE}" -m pip install torch -f https://download.pytorch.org/whl/torch + "${PYTHON_EXECUTABLE}" -m pip install "gymnasium>=0.28,<1.1" "stable_baselines3>=2.0,<2.5" - name: Install latest numpy version at build-time for run-time binary compatibility run: | "${PYTHON_EXECUTABLE}" -m pip install --upgrade "numpy>=1.24" numba torch @@ -95,7 +94,6 @@ jobs: -DBoost_NO_SYSTEM_PATHS=TRUE -DBoost_NO_BOOST_CMAKE=TRUE -DBoost_USE_STATIC_LIBS=ON \ -DPYTHON_EXECUTABLE="${PYTHON_EXECUTABLE}" \ -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_PYTHON_INTERFACE=ON \ - -DINSTALL_GYM_JIMINY=${{ (matrix.PYTHON_VERSION == '3.13' && 'OFF') || 'ON' }} \ -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_BUILD_TYPE="${{ matrix.BUILD_TYPE }}" make install -j4 @@ -133,7 +131,7 @@ jobs: "${PYTHON_EXECUTABLE}" -m unittest discover -s "${RootDir}/python/gym_jiminy/unit_py" -v - name: Run examples for gym jiminy add-on modules - if: matrix.BUILD_TYPE != 'Debug' + if: matrix.BUILD_TYPE != 'Debug' && matrix.PYTHON_VERSION != '3.13' run: | cd "${RootDir}/python/gym_jiminy/examples/rllib" "${PYTHON_EXECUTABLE}" acrobot_ppo.py diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 054a2cc69..49feb7d0a 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: OS: ['macos-15'] # 'macos-13': Intel (x86), 'macos-14+': Apple Silicon (arm64) - PYTHON_VERSION: ['3.10', '3.11', '3.12'] # `setup-python` does not support Python<3.10 on Apple Silicon + PYTHON_VERSION: ['3.10', '3.11', '3.12', '3.13'] # `setup-python` does not support Python<3.10 on Apple Silicon BUILD_TYPE: ['Release'] include: - OS: 'macos-13' @@ -72,10 +72,14 @@ jobs: "${PYTHON_EXECUTABLE}" -m pip install setuptools wheel "pip>=20.3" "${PYTHON_EXECUTABLE}" -m pip install delocate twine - name: Install pre-compiled binaries for additional gym-jiminy dependencies - if: matrix.PYTHON_VERSION != '3.13' run: | - "${PYTHON_EXECUTABLE}" -m pip install "torch" -f https://download.pytorch.org/whl/torch - "${PYTHON_EXECUTABLE}" -m pip install "gymnasium>=0.28,<=1.0" "stable_baselines3>=2.0,<2.5" + # FIXME: Pre-release 2.6 is needed to install torch for Python 3.13 on MacOS + if [[ "${{ matrix.OS }}" != 'macos-13' ]] ; then + "${PYTHON_EXECUTABLE}" -m pip install --pre torch --index-url https://download.pytorch.org/whl/nightly/cpu + else + "${PYTHON_EXECUTABLE}" -m pip install "torch" -f https://download.pytorch.org/whl/torch + fi + "${PYTHON_EXECUTABLE}" -m pip install "gymnasium>=0.28,<1.1" "stable_baselines3>=2.0,<2.5" - name: Install latest numpy version at build-time for run-time binary compatibility run: | if [[ "${{ matrix.BUILD_TYPE }}" != 'Debug' && "${{ matrix.OS }}" != 'macos-13' ]] ; then @@ -114,7 +118,6 @@ jobs: -DBoost_NO_SYSTEM_PATHS=TRUE -DBoost_NO_BOOST_CMAKE=TRUE \ -DBoost_USE_STATIC_LIBS=ON -DPYTHON_EXECUTABLE="${PYTHON_EXECUTABLE}" \ -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_PYTHON_INTERFACE=ON \ - -DINSTALL_GYM_JIMINY=${{ (matrix.PYTHON_VERSION == '3.13' && 'OFF') || 'ON' }} \ -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_BUILD_TYPE="${{ matrix.BUILD_TYPE }}" make -j4 @@ -214,7 +217,7 @@ jobs: "${PYTHON_EXECUTABLE}" -m unittest discover -s "${RootDir}/python/gym_jiminy/unit_py" -v - name: Run examples for gym jiminy add-on modules - if: matrix.BUILD_TYPE != 'Debug' + if: matrix.BUILD_TYPE != 'Debug' && matrix.PYTHON_VERSION != '3.13' run: | export LD_LIBRARY_PATH="${InstallDir}/lib/:/usr/local/lib" diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index e001351af..21694bdba 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - PYTHON_VERSION: ['cp310', 'cp311', 'cp312'] + PYTHON_VERSION: ['cp310', 'cp311', 'cp312', 'cp313'] OS: [ubuntu-24.04] include: - OS: ubuntu-24.04 @@ -87,7 +87,6 @@ jobs: -DBoost_NO_SYSTEM_PATHS=TRUE -DBoost_NO_BOOST_CMAKE=TRUE \ -DBoost_USE_STATIC_LIBS=ON -DPYTHON_EXECUTABLE="${PYTHON_EXECUTABLE}" \ -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_PYTHON_INTERFACE=ON \ - -DINSTALL_GYM_JIMINY=${{ (matrix.PYTHON_VERSION == 'cp313' && 'OFF') || 'ON' }} \ -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" make -j4 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 90a1c2313..f0087e75e 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -75,8 +75,8 @@ jobs: if [[ "${{ matrix.GENERATOR }}" == 'Ninja' ]] ; then sudo apt install ninja-build fi - "${PYTHON_EXECUTABLE}" -m pip install "torch" -f https://download.pytorch.org/whl/torch - "${PYTHON_EXECUTABLE}" -m pip install "gymnasium>=0.28,<=1.0" "stable_baselines3>=2.0,<2.5" + "${PYTHON_EXECUTABLE}" -m pip install torch -f https://download.pytorch.org/whl/torch + "${PYTHON_EXECUTABLE}" -m pip install "gymnasium>=0.28,<1.1" "stable_baselines3>=2.0,<2.5" ##################################################################################### diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml index 2cb887f96..b1b18ee18 100644 --- a/.github/workflows/win.yml +++ b/.github/workflows/win.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: - PYTHON_VERSION: ['3.10', '3.11', '3.12'] + PYTHON_VERSION: ['3.10', '3.11', '3.12', '3.13'] BUILD_TYPE: ['Release'] include: - PYTHON_VERSION: '3.12' @@ -58,10 +58,10 @@ jobs: python -m pip install setuptools wheel "pip>=20.3" python -m pip install pefile machomachomangler - name: Install pre-compiled binaries for additional gym-jiminy dependencies - if: matrix.PYTHON_VERSION != '3.13' run: | - python -m pip install "torch" -f https://download.pytorch.org/whl/torch - python -m pip install "gymnasium>=0.28,<=1.0" "stable_baselines3>=2.0,<2.5" + # FIXME: Pre-release 2.6 is needed to install torch for Python 3.13 on Windows + python -m pip install --pre torch --index-url https://download.pytorch.org/whl/nightly/cpu + python -m pip install "gymnasium>=0.28,<1.1" "stable_baselines3>=2.0,<2.5" - name: Install latest numpy version at build-time for run-time binary compatibility run: | python -m pip install --upgrade "numpy>=1.24" numba torch @@ -100,7 +100,6 @@ jobs: -DBoost_NO_SYSTEM_PATHS=TRUE -DBoost_NO_BOOST_CMAKE=TRUE ` -DBoost_USE_STATIC_LIBS=ON -DPYTHON_REQUIRED_VERSION="${{ matrix.PYTHON_VERSION }}" ` -DBUILD_TESTING=ON -DBUILD_EXAMPLES=ON -DBUILD_PYTHON_INTERFACE=ON ` - -DINSTALL_GYM_JIMINY=${{ ((matrix.PYTHON_VERSION == '3.13') && 'OFF') || 'ON' }} ` -DCMAKE_CXX_FLAGS="${env:CXX_FLAGS} $( ) -DBOOST_ALL_NO_LIB -DBOOST_LIB_DIAGNOSTIC -DBOOST_CORE_USE_GENERIC_CMATH $( ) -DEIGENPY_STATIC -DURDFDOM_STATIC -DHPP_FCL_STATIC -DPINOCCHIO_STATIC" @@ -124,15 +123,17 @@ jobs: ${env:Path} += ";$InstallDir/lib" # Generate stubs - # FIXME: stubgen does not work with Numpy 2.X - # (see https://github.com/python/mypy/issues/17396) - python -m pip install "numpy<2.0" - stubgen -p jiminy_py -o $RootDir/build/pypi/jiminy_py/src - python "$RootDir/build_tools/stubgen.py" ` - -o $RootDir/build/stubs --ignore-invalid=all jiminy_py - Copy-Item -Force -Path "$RootDir/build/stubs/jiminy_py-stubs/core/__init__.pyi" ` - -Destination "$RootDir/build/pypi/jiminy_py/src/jiminy_py/core/core.pyi" - python -m pip install --upgrade "numpy>=1.24" numba torch + if ("${{ matrix.PYTHON_VERSION }}" -ne "3.13") { + # FIXME: stubgen does not work with Numpy 2.X + # (see https://github.com/python/mypy/issues/17396) + python -m pip install "numpy<2.0" + stubgen -p jiminy_py -o $RootDir/build/pypi/jiminy_py/src + python "$RootDir/build_tools/stubgen.py" ` + -o $RootDir/build/stubs --ignore-invalid=all jiminy_py + Copy-Item -Force -Path "$RootDir/build/stubs/jiminy_py-stubs/core/__init__.pyi" ` + -Destination "$RootDir/build/pypi/jiminy_py/src/jiminy_py/core/core.pyi" + python -m pip install --upgrade "numpy>=1.24" numba torch + fi # Generate wheels Set-Location -Path "$RootDir/build" @@ -202,7 +203,7 @@ jobs: python -m unittest discover -s "$RootDir/python/gym_jiminy/unit_py" -v - name: Run examples for gym jiminy add-on modules - if: matrix.BUILD_TYPE != 'Debug' + if: matrix.BUILD_TYPE != 'Debug' && matrix.PYTHON_VERSION != '3.13' run: | $RootDir = "${env:GITHUB_WORKSPACE}/workspace" -replace '\\', '/' diff --git a/core/src/engine/engine.cc b/core/src/engine/engine.cc index 3469c6146..efa21788c 100644 --- a/core/src/engine/engine.cc +++ b/core/src/engine/engine.cc @@ -1505,11 +1505,12 @@ namespace jiminy telemetrySender_->registerConstant(key, saveToBinary(robot, isPersistent)); } - // Log the ground profile if requested + // Log the (simplified) ground profile if requested if (engineOptions_->telemetry.isPersistent) { - hpp::fcl::CollisionGeometryPtr_t heightmap = discretizeHeightmap( - engineOptions_->world.groundProfile, -10.0, 10.0, 0.04, -10.0, 10.0, 0.04); + const HeightmapFunction & groundProfile = engineOptions_->world.groundProfile; + hpp::fcl::CollisionGeometryPtr_t heightmap = + discretizeHeightmap(groundProfile, -10.0, 10.0, 0.04, -10.0, 10.0, 0.04, true); telemetrySender_->registerConstant("groundProfile", saveToBinary(heightmap)); } diff --git a/python/gym_jiminy/common/gym_jiminy/common/quantities/generic.py b/python/gym_jiminy/common/gym_jiminy/common/quantities/generic.py index 42fd6732d..ed5e148da 100644 --- a/python/gym_jiminy/common/gym_jiminy/common/quantities/generic.py +++ b/python/gym_jiminy/common/gym_jiminy/common/quantities/generic.py @@ -1633,7 +1633,10 @@ def initialize(self) -> None: joint_to_motor_ratios = [] self.kinematic_indices.clear() for motor in self.robot.motors: - joint = self.pinocchio_model.joints[motor.joint_index] + # Note that pinocchio model may be theoretical or extended, which + # means that `motor.joint_index` cannot be used reliably. + joint_index = self.pinocchio_model.getJointId(motor.joint_name) + joint = self.pinocchio_model.joints[joint_index] joint_type = jiminy.get_joint_type(joint) if joint_type == jiminy.JointModelType.ROTARY_UNBOUNDED: raise ValueError( diff --git a/python/gym_jiminy/common/gym_jiminy/common/wrappers/scale.py b/python/gym_jiminy/common/gym_jiminy/common/wrappers/scale.py index 4965ed42c..232361a5f 100644 --- a/python/gym_jiminy/common/gym_jiminy/common/wrappers/scale.py +++ b/python/gym_jiminy/common/gym_jiminy/common/wrappers/scale.py @@ -217,6 +217,8 @@ def __init__(self, copy_ops.append((dst, src)) observation_flat.append(dst) if copy_ops: + # FIXME: Could be optimized by avoiding copying fields for which + # the union of extracted slices is covering the whole subspace. self._copyto_dst, self._copyto_src = map(tuple, zip(*copy_ops)) else: self._copyto_dst, self._copyto_src = (), () @@ -234,7 +236,7 @@ def _initialize_observation_space(self) -> None: def transform_observation(self) -> None: # First, copy the value of some leaves. # Guarding function call is faster than calling no-op python bindings. - if not self._copyto_dst: + if self._copyto_dst: multi_array_copyto(self._copyto_dst, self._copyto_src) # Apply scaling factor sequentially on some chunks diff --git a/python/gym_jiminy/common/setup.py b/python/gym_jiminy/common/setup.py index c751e96ff..5fc85ba21 100644 --- a/python/gym_jiminy/common/setup.py +++ b/python/gym_jiminy/common/setup.py @@ -31,7 +31,7 @@ "@PROJECT_VERSION@.tar.gz"), maintainer="Alexis Duburcq", license="MIT", - python_requires=">=3.10,<3.13", + python_requires=">=3.10,<3.14", classifiers=[ "Development Status :: 3 - Alpha", "Intended Audience :: Science/Research", @@ -40,7 +40,8 @@ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12" + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13" ], keywords="reinforcement-learning robotics gym jiminy", packages=find_namespace_packages(), diff --git a/python/gym_jiminy/envs/setup.py b/python/gym_jiminy/envs/setup.py index 35e261ae6..d4bc41f19 100644 --- a/python/gym_jiminy/envs/setup.py +++ b/python/gym_jiminy/envs/setup.py @@ -13,7 +13,7 @@ author_email="alexis.duburcq@gmail.com", maintainer="Alexis Duburcq", license="MIT", - python_requires=">=3.10,<3.13", + python_requires=">=3.10,<3.14", classifiers=[ "Development Status :: 3 - Alpha", "Intended Audience :: Science/Research", @@ -22,7 +22,8 @@ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12" + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13" ], keywords="reinforcement-learning robotics gym jiminy", packages=find_namespace_packages(), diff --git a/python/gym_jiminy/rllib/setup.py b/python/gym_jiminy/rllib/setup.py index b89276b22..d91340b42 100644 --- a/python/gym_jiminy/rllib/setup.py +++ b/python/gym_jiminy/rllib/setup.py @@ -14,7 +14,7 @@ author_email="alexis.duburcq@gmail.com", maintainer="Alexis Duburcq", license="MIT", - python_requires=">=3.10,<3.13", + python_requires=">=3.10,<3.14", classifiers=[ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Science/Research", @@ -23,7 +23,8 @@ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12" + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13" ], keywords="reinforcement-learning robotics gym jiminy", packages=find_namespace_packages(), diff --git a/python/gym_jiminy/toolbox/setup.py b/python/gym_jiminy/toolbox/setup.py index eb4baa4ea..373f6c75e 100644 --- a/python/gym_jiminy/toolbox/setup.py +++ b/python/gym_jiminy/toolbox/setup.py @@ -14,7 +14,7 @@ author_email="alexis.duburcq@gmail.com", maintainer="Alexis Duburcq", license="MIT", - python_requires=">=3.10,<3.13", + python_requires=">=3.10,<3.14", classifiers=[ "Development Status :: 3 - Alpha", "Intended Audience :: Science/Research", @@ -23,7 +23,8 @@ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12" + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13" ], keywords="reinforcement-learning robotics gym jiminy", packages=find_namespace_packages(), diff --git a/python/gym_jiminy/unit_py/test_task_curriculum.py b/python/gym_jiminy/unit_py/test_task_curriculum.py index 292cd0192..2eb765525 100644 --- a/python/gym_jiminy/unit_py/test_task_curriculum.py +++ b/python/gym_jiminy/unit_py/test_task_curriculum.py @@ -11,16 +11,21 @@ import numpy as np import gymnasium as gym -import ray -from ray.tune.registry import register_env -from ray.rllib.algorithms import PPOConfig -from ray.rllib.core.rl_module.default_model_config import DefaultModelConfig +try: + import ray + from ray.tune.registry import register_env + from ray.rllib.algorithms import PPOConfig + from ray.rllib.core.rl_module.default_model_config import DefaultModelConfig + IS_RAY_AVAILABLE = True +except ImportError: + IS_RAY_AVAILABLE = False from gym_jiminy.common.wrappers import FlattenObservation from gym_jiminy.envs import AcrobotJiminyEnv from gym_jiminy.toolbox.wrappers.meta_envs import BaseTaskSettableWrapper -from gym_jiminy.rllib.utilities import initialize, train -from gym_jiminy.rllib.curriculum import build_task_scheduling_callback +if IS_RAY_AVAILABLE: + from gym_jiminy.rllib.utilities import initialize, train + from gym_jiminy.rllib.curriculum import build_task_scheduling_callback # Fix the seed for CI stability @@ -62,6 +67,7 @@ def get_score(self) -> float: return float(score) +@unittest.skipIf(not IS_RAY_AVAILABLE, "Ray is not available.") class AcrobotTaskCurriculum(unittest.TestCase): """ TODO: Write documentation. """ diff --git a/python/jiminy_py/setup.py b/python/jiminy_py/setup.py index b69220479..732e9d889 100644 --- a/python/jiminy_py/setup.py +++ b/python/jiminy_py/setup.py @@ -60,7 +60,7 @@ def finalize_options(self) -> None: author_email="alexis.duburcq@gmail.com", maintainer="Alexis Duburcq", license="MIT", - python_requires=">=3.10,<3.13", + python_requires=">=3.10,<3.14", classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Science/Research", @@ -69,7 +69,8 @@ def finalize_options(self) -> None: "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12" + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13" ], keywords="robotics physics simulator", distclass=BinaryDistribution,