From 07f27f80e7abe97ba174f27192009d0f72a75bd4 Mon Sep 17 00:00:00 2001 From: David Yuan <47169162+DaivdYuan@users.noreply.github.com> Date: Mon, 10 Aug 2026 21:10:59 -0700 Subject: [PATCH] Release the SpeedTuning simulation reproduction --- .github/workflows/sim-tests.yml | 58 ++ .gitignore | 35 + .python-version | 1 + CHANGELOG.md | 28 + CITATION.cff | 25 + CONTRIBUTING.md | 21 + LICENSE | 22 + MANIFEST.in | 7 + NOTICE.md | 22 + README.md | 246 ++++- act_integration.py | 242 +++++ assets/__init__.py | 1 + assets/bimanual_viperx_ee_insertion.xml | 59 ++ assets/bimanual_viperx_ee_transfer_cube.xml | 48 + .../bimanual_viperx_ee_transfer_tea_bag.xml | 103 ++ assets/bimanual_viperx_insertion.xml | 53 + assets/bimanual_viperx_transfer_cube.xml | 42 + assets/bimanual_viperx_transfer_tea_bag.xml | 97 ++ assets/scene.xml | 38 + assets/tabletop.stl | Bin 0 -> 684 bytes assets/vx300s_10_custom_finger_left.stl | Bin 0 -> 83384 bytes assets/vx300s_10_custom_finger_right.stl | Bin 0 -> 83384 bytes assets/vx300s_1_base.stl | Bin 0 -> 99984 bytes assets/vx300s_2_shoulder.stl | Bin 0 -> 63884 bytes assets/vx300s_3_upper_arm.stl | Bin 0 -> 102984 bytes assets/vx300s_4_upper_forearm.stl | Bin 0 -> 49584 bytes assets/vx300s_5_lower_forearm.stl | Bin 0 -> 99884 bytes assets/vx300s_6_wrist.stl | Bin 0 -> 70784 bytes assets/vx300s_7_gripper.stl | Bin 0 -> 450084 bytes assets/vx300s_8_gripper_prop.stl | Bin 0 -> 31684 bytes assets/vx300s_9_gripper_bar.stl | Bin 0 -> 379484 bytes assets/vx300s_dependencies.xml | 17 + assets/vx300s_left.xml | 59 ++ assets/vx300s_right.xml | 59 ++ benchmarks/README.md | 18 + benchmarks/scripted_results.json | 59 ++ chunked_policy.py | 324 +++++++ configs/README.md | 39 + configs/__init__.py | 1 + configs/ablations/act_encoder.json | 8 + configs/ablations/frame_skip_25.json | 5 + configs/ablations/frame_skip_5.json | 5 + configs/ablations/no_image.json | 11 + configs/ablations/random_resnet.json | 5 + configs/ablations/reward_beta_0.json | 5 + configs/ablations/reward_beta_1.json | 5 + configs/ablations/reward_beta_3.json | 5 + configs/ablations/scripted_policy.json | 5 + configs/paper_sim.json | 49 + configs/scripted_insertion.json | 15 + configs/scripted_pick_and_place.json | 15 + configs/scripted_tea_bag.json | 47 + configs/scripted_tea_bag_randomized.json | 12 + constants.py | 46 + detr/LICENSE | 201 ++++ detr/README.md | 9 + detr/__init__.py | 1 + detr/main.py | 77 ++ detr/models/__init__.py | 9 + detr/models/backbone.py | 127 +++ detr/models/detr_vae.py | 274 ++++++ detr/models/position_encoding.py | 90 ++ detr/models/transformer.py | 311 ++++++ detr/util/__init__.py | 1 + detr/util/misc.py | 468 +++++++++ docs/EXTERNAL_POLICIES.md | 147 +++ docs/SCRIPTED_REPRODUCTION.md | 154 +++ docs/assets/speedtuning_teaser.png | Bin 0 -> 219511 bytes ee_sim_env.py | 235 +++++ experiment_config.py | 73 ++ policy.py | 81 ++ policy_loader.py | 97 ++ policy_speed_env.py | 515 ++++++++++ pyproject.toml | 92 ++ requirements-sim.txt | 6 + rl/__init__.py | 1 + rl/rainbowDQN/__init__.py | 0 rl/rainbowDQN/dqnAgent.py | 289 ++++++ rl/rainbowDQN/network.py | 196 ++++ rl/rainbowDQN/replayBuffer.py | 234 +++++ rl/rainbowDQN/segment_tree.py | 142 +++ scripted_policy.py | 233 +++++ scripts/__init__.py | 1 + scripts/check_chunked_policy.py | 25 + scripts/eval_speed_policy.py | 147 +++ scripts/policy_cli.py | 179 ++++ scripts/rainbow_poc.py | 157 +++ scripts/run_sim.py | 108 +++ scripts/sweep_speed_policy.py | 158 +++ scripts/train_speed_policy.py | 189 ++++ sim_env.py | 221 +++++ sim_tasks.py | 181 ++++ speed_evaluation.py | 93 ++ speed_observation.py | 284 ++++++ speed_policy.py | 322 +++++++ speed_training.py | 298 ++++++ tests/test_chunked_policies.py | 98 ++ tests/test_paper_parity.py | 241 +++++ tests/test_sim_envs.py | 107 ++ tests/test_speed_infrastructure.py | 158 +++ uv.lock | 911 ++++++++++++++++++ 101 files changed, 9900 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/sim-tests.yml create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 CHANGELOG.md create mode 100644 CITATION.cff create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 MANIFEST.in create mode 100644 NOTICE.md create mode 100644 act_integration.py create mode 100644 assets/__init__.py create mode 100644 assets/bimanual_viperx_ee_insertion.xml create mode 100644 assets/bimanual_viperx_ee_transfer_cube.xml create mode 100644 assets/bimanual_viperx_ee_transfer_tea_bag.xml create mode 100644 assets/bimanual_viperx_insertion.xml create mode 100644 assets/bimanual_viperx_transfer_cube.xml create mode 100644 assets/bimanual_viperx_transfer_tea_bag.xml create mode 100644 assets/scene.xml create mode 100644 assets/tabletop.stl create mode 100644 assets/vx300s_10_custom_finger_left.stl create mode 100644 assets/vx300s_10_custom_finger_right.stl create mode 100644 assets/vx300s_1_base.stl create mode 100644 assets/vx300s_2_shoulder.stl create mode 100644 assets/vx300s_3_upper_arm.stl create mode 100644 assets/vx300s_4_upper_forearm.stl create mode 100644 assets/vx300s_5_lower_forearm.stl create mode 100644 assets/vx300s_6_wrist.stl create mode 100644 assets/vx300s_7_gripper.stl create mode 100644 assets/vx300s_8_gripper_prop.stl create mode 100644 assets/vx300s_9_gripper_bar.stl create mode 100644 assets/vx300s_dependencies.xml create mode 100644 assets/vx300s_left.xml create mode 100644 assets/vx300s_right.xml create mode 100644 benchmarks/README.md create mode 100644 benchmarks/scripted_results.json create mode 100644 chunked_policy.py create mode 100644 configs/README.md create mode 100644 configs/__init__.py create mode 100644 configs/ablations/act_encoder.json create mode 100644 configs/ablations/frame_skip_25.json create mode 100644 configs/ablations/frame_skip_5.json create mode 100644 configs/ablations/no_image.json create mode 100644 configs/ablations/random_resnet.json create mode 100644 configs/ablations/reward_beta_0.json create mode 100644 configs/ablations/reward_beta_1.json create mode 100644 configs/ablations/reward_beta_3.json create mode 100644 configs/ablations/scripted_policy.json create mode 100644 configs/paper_sim.json create mode 100644 configs/scripted_insertion.json create mode 100644 configs/scripted_pick_and_place.json create mode 100644 configs/scripted_tea_bag.json create mode 100644 configs/scripted_tea_bag_randomized.json create mode 100644 constants.py create mode 100644 detr/LICENSE create mode 100644 detr/README.md create mode 100644 detr/__init__.py create mode 100644 detr/main.py create mode 100644 detr/models/__init__.py create mode 100644 detr/models/backbone.py create mode 100644 detr/models/detr_vae.py create mode 100644 detr/models/position_encoding.py create mode 100644 detr/models/transformer.py create mode 100644 detr/util/__init__.py create mode 100644 detr/util/misc.py create mode 100644 docs/EXTERNAL_POLICIES.md create mode 100644 docs/SCRIPTED_REPRODUCTION.md create mode 100644 docs/assets/speedtuning_teaser.png create mode 100644 ee_sim_env.py create mode 100644 experiment_config.py create mode 100644 policy.py create mode 100644 policy_loader.py create mode 100644 policy_speed_env.py create mode 100644 pyproject.toml create mode 100644 requirements-sim.txt create mode 100644 rl/__init__.py create mode 100644 rl/rainbowDQN/__init__.py create mode 100644 rl/rainbowDQN/dqnAgent.py create mode 100644 rl/rainbowDQN/network.py create mode 100644 rl/rainbowDQN/replayBuffer.py create mode 100644 rl/rainbowDQN/segment_tree.py create mode 100644 scripted_policy.py create mode 100644 scripts/__init__.py create mode 100644 scripts/check_chunked_policy.py create mode 100644 scripts/eval_speed_policy.py create mode 100644 scripts/policy_cli.py create mode 100644 scripts/rainbow_poc.py create mode 100644 scripts/run_sim.py create mode 100644 scripts/sweep_speed_policy.py create mode 100644 scripts/train_speed_policy.py create mode 100644 sim_env.py create mode 100644 sim_tasks.py create mode 100644 speed_evaluation.py create mode 100644 speed_observation.py create mode 100644 speed_policy.py create mode 100644 speed_training.py create mode 100644 tests/test_chunked_policies.py create mode 100644 tests/test_paper_parity.py create mode 100644 tests/test_sim_envs.py create mode 100644 tests/test_speed_infrastructure.py create mode 100644 uv.lock diff --git a/.github/workflows/sim-tests.yml b/.github/workflows/sim-tests.yml new file mode 100644 index 0000000..6a2f840 --- /dev/null +++ b/.github/workflows/sim-tests.yml @@ -0,0 +1,58 @@ +name: Simulation tests + +on: + push: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + MUJOCO_GL: osmesa + PYOPENGL_PLATFORM: osmesa + steps: + - uses: actions/checkout@v4 + - name: Verify checkpoint-free release contents + run: | + forbidden="$(git ls-files | grep -E '(^|/)(outputs|checkpoints|runs|wandb)/|\.(pt|pth|ckpt|onnx|h5|hdf5|pkl|pickle)$' || true)" + if [ -n "$forbidden" ]; then + echo "Generated model artifacts must not be tracked:" + echo "$forbidden" + exit 1 + fi + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: pip + - name: Install headless MuJoCo rendering libraries + run: | + sudo apt-get update + sudo apt-get install --yes libgl1 libosmesa6 + - name: Install public package and test dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -e ".[rl,learned,test]" build twine + - name: Run tests + run: pytest -q + - name: Run supported integration commands + run: | + speedtuning-sim + speedtuning-sim --speed 1.5 + speedtuning-check-chunks + speedtuning-rainbow-poc + speedtuning-eval-speed --task tea_bag --base-policy recorded-chunk --episodes 1 + speedtuning-sweep --task tea_bag --base-policy scripted --speed-start 1.0 --speed-stop 1.1 --episodes-per-speed 1 --output /tmp/sweep.json + - name: Build source and wheel distributions + run: | + python -m build + python -m twine check dist/* + tar -tzf dist/*.tar.gz | grep 'docs/SCRIPTED_REPRODUCTION.md' + tar -tzf dist/*.tar.gz | grep 'benchmarks/scripted_results.json' + - name: Verify the wheel and packaged MuJoCo assets + run: | + python -m venv /tmp/speedtuning-package-check + /tmp/speedtuning-package-check/bin/python -m pip install dist/*.whl + cd /tmp + /tmp/speedtuning-package-check/bin/python -c "from experiment_config import load_experiment_config; assert load_experiment_config('scripted-pick-and-place')[0]['decisions'] == 100000" + /tmp/speedtuning-package-check/bin/speedtuning-sim --task tea_bag diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f39a8db --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Python +__pycache__/ +*.py[cod] +.pytest_cache/ +.coverage +htmlcov/ +.mypy_cache/ +.ruff_cache/ + +# Environments and editors +.venv/ +.venv-legacy/ +.vscode/ +.idea/ +**/.DS_Store + +# Packaging +build/ +dist/ +*.egg-info/ + +# Generated research artifacts +outputs/ +results/ +logs/ +tmp/ +.tmp/ +data/ +data_local/ +checkpoints/ +*.pt +*.pth +*.ckpt +wandb/ +_wandb/ diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..c8cfe39 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.10 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..96b7602 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +## 0.1.0 + +- Released pick-and-place, insertion, and tea-bag MuJoCo tasks. +- Added parameterized execution speed for retained waypoint policies. +- Added a model-agnostic variable-speed action-chunk interface. +- Added external chunk-policy and speed-policy factory loading. +- Added supported Rainbow DQN speed-policy training, checkpoints, and evaluation. +- Added decision-level speed execution with fresh receding-horizon chunks and + shared frame-skip semantics for training and evaluation. +- Added stacked proprioceptive/visual speed observations with pretrained, random, + and external image-encoder support. +- Added retained ACT checkpoint/backbone adapters, checkpointed preprocessing, + seeded physical-acceleration metrics, fixed-speed sweeps, and plotting. +- Added an archival paper configuration and manifests for every published + simulation ablation. +- Added runnable scripted-policy presets for pick-and-place, insertion, and tea + bag, including the retained reward and Rainbow update schedule. +- Added from-scratch reproduction instructions and machine-readable reference + results for all three simulated tasks. +- Added seeded tea-bag pose randomization as a separately labeled robustness + protocol while preserving the fixed-pose historical environment. +- Added periodic training snapshots, task/protocol metadata validation, and safe + loading for locally generated speed-policy checkpoints. +- Added clean-install packaging, continuous integration, and release tests. +- Removed real-robot, private-path, scratch-output, and trained-checkpoint + artifacts from the public surface. diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..4f7c297 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,25 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite the SpeedTuning paper." +title: "SpeedTuning simulation and speed-policy infrastructure" +type: software +version: 0.1.0 +authors: + - family-names: Yuan + given-names: David D. +license: MIT +repository-code: "https://github.com/DaivdYuan/SpeedTuning" +preferred-citation: + type: conference-paper + title: "SpeedTuning: Speeding Up Policy Execution with Lightweight Reinforcement Learning" + authors: + - family-names: Yuan + given-names: David D. + - family-names: Zhao + given-names: Tony Z. + - family-names: Burns + given-names: Kaylee + - family-names: Finn + given-names: Chelsea + collection-title: "2025 IEEE International Conference on Robotics and Automation (ICRA)" + year: 2025 + doi: "10.1109/ICRA55743.2025.11128753" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6386907 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,21 @@ +# Contributing + +Bug reports and focused pull requests for the supported simulation surface are +welcome. Before opening a pull request: + +1. Install Python 3.10 and the development extras with + `uv sync --extra rl --extra learned --extra test`. +2. Run `uv run pytest -q`. +3. Run `uv run speedtuning-sim` and `uv run speedtuning-check-chunks` when + changing tasks, policies, interpolation, or physics assets. +4. Run `uv run speedtuning-rainbow-poc` when changing speed-policy learning. +5. Run a two-point `speedtuning-sweep` smoke test when changing metrics, + decision timing, or experiment manifests. + +Please keep real-robot dependencies, private checkpoints, datasets, machine-local +paths, and generated outputs outside this repository. New external policy support +should use the public adapters instead of adding a dependency on another research +repository to the core environment. + +By contributing, you agree that your contribution may be distributed under the +license applicable to the directory you modify. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..686d48e --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2023 Tony Z. Zhao +Copyright (c) 2024-2026 David D. Yuan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..cab13be --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,7 @@ +include CHANGELOG.md +include CITATION.cff +include CONTRIBUTING.md +include NOTICE.md +include requirements-sim.txt +recursive-include benchmarks *.json *.md +recursive-include docs *.md *.png diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000..5c5eace --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,22 @@ +# Notices and attribution + +SpeedTuning simulation and speed-policy infrastructure includes code and assets +derived from [Action Chunking with Transformers +(ACT)](https://github.com/tonyzhaozh/act), originally released under the MIT +License. The original Tony Z. Zhao copyright notice is retained in `LICENSE`. + +The files under `detr/` are modified from +[DETR](https://github.com/facebookresearch/detr) and are distributed under the +Apache License 2.0 included at `detr/LICENSE`. + +The ALOHA/ViperX MuJoCo XML files and meshes under `assets/` were inherited from +the MIT-licensed ACT repository history. Task-specific tea-bag environment files +were added in the SpeedTuning development history and are distributed under this +repository's MIT License. + +SpeedTuning simulator recovery, public integration, and release engineering: +Copyright (c) 2024-2026 David D. Yuan. + +The README teaser image is rendered from the SpeedTuning project-page figure, +Copyright (c) the SpeedTuning authors and shared under CC BY-SA 4.0. The source +project page is https://daivdyuan.github.io/speed-tuning/. diff --git a/README.md b/README.md index fa59c36..ec65482 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,245 @@ -# SpeedTuning +
-This repository contains the code for *SpeedTuning: Speeding Up Policy Execution with Lightweight Reinforcement Learning* +# SpeedTuning: Speeding Up Policy Execution with Lightweight Reinforcement Learning -Note: This is a work in progress. The official release is expected by late September. +[David D. Yuan](https://www.linkedin.com/in/dewei-yuan) · +[Tony Z. Zhao](https://tonyzhaozh.github.io/) · +[Kaylee Burns](https://kayburns.github.io/) · +[Chelsea Finn](https://ai.stanford.edu/~cbfinn/) + +Stanford University · ICRA 2025 + +[Project Page](https://daivdyuan.github.io/speed-tuning/) · +[arXiv](https://arxiv.org/abs/2608.09138) · +[Conference Paper](https://daivdyuan.github.io/speed-tuning/static/pdfs/speedtuning_icra.pdf) · +[Video](https://daivdyuan.github.io/speed-tuning/static/videos/icra2025_final.mp4) · +[Simulation Reproduction](docs/SCRIPTED_REPRODUCTION.md) + +[![Tests](https://github.com/DaivdYuan/SpeedTuning/actions/workflows/sim-tests.yml/badge.svg)](https://github.com/DaivdYuan/SpeedTuning/actions/workflows/sim-tests.yml) + +
+ +

+ + SpeedTuning method and adaptive speed profile + +

+ +

+SpeedTuning keeps a base manipulation policy fixed and learns a lightweight +speed policy that accelerates safe phases while preserving precision around +critical interactions. +

+ +> [!NOTE] +> This repository is the simulation reproduction release. It provides complete +> from-scratch speed-policy training with bundled scripted task policies. + +## Overview + +Imitation-learned manipulation policies often inherit the operator's pace and +the hardware constraints present during data collection. Applying one global +interpolation factor can make execution faster, but it cannot distinguish +between transit phases that tolerate aggressive acceleration and contact-rich +phases that require precision. + +SpeedTuning adds a small reinforcement-learning policy on top of a frozen base +policy. At each decision, it selects a speed multiplier from the current robot +and task observation. The base policy continues to predict actions; SpeedTuning +only changes how quickly those actions are executed. + +This release supports the full simulation loop: + +1. run a task with a fixed scripted base policy; +2. train a Rainbow DQN policy over discrete speed multipliers; +3. evaluate success against physical acceleration; +4. compare the adaptive policy with matched fixed-speed baselines. + +## Included tasks + +| Task | Simulator objective | Public preset | +| --- | --- | --- | +| Pick-and-place | Transfer a cube between grippers | `scripted-pick-and-place` | +| Insertion | Insert a peg into a socket | `scripted-insertion` | +| Tea bag | Move a tea bag into a cup | `scripted-tea-bag` | + +An additional `scripted-tea-bag-randomized` preset samples initial tea-bag poses +for distributional evaluation. The retained fixed-pose environment remains +available for historical parity. + +## Installation + +Python 3.10 is required. MuJoCo and DM Control are pinned because contact +dynamics affect the scripted policies. + +Using `uv`: + +```bash +git clone https://github.com/DaivdYuan/SpeedTuning.git +cd SpeedTuning + +uv sync --extra test +uv run speedtuning-sim +``` + +Using `pip`: + +```bash +python3.10 -m venv .venv +source .venv/bin/activate +python -m pip install -e ".[test]" +speedtuning-sim +``` + +On a headless Linux machine, prefix simulator commands with `MUJOCO_GL=egl`. + +## Quick simulation check + +Run all three scripted tasks at nominal speed: + +```bash +uv run speedtuning-sim +``` + +Run one task with a fixed `1.5x` speed multiplier: + +```bash +uv run speedtuning-sim --task insertion --speed 1.5 +``` + +Each command prints a JSON summary and exits nonzero if the task fails. + +## Train a speed policy + +Install the reinforcement-learning extra and run a short CPU smoke test: + +```bash +uv sync --extra rl --extra test + +uv run speedtuning-train-speed \ + --config scripted-tea-bag \ + --task tea_bag \ + --decisions 1000 \ + --checkpoint-interval 0 \ + --output outputs/smoke_test.pt +``` + +For a full 100,000-decision run, use the preset without the smoke-test +overrides: + +```bash +uv run speedtuning-train-speed \ + --config scripted-tea-bag \ + --task tea_bag \ + --output outputs/tea_bag_speed.pt \ + --report outputs/tea_bag_speed.training.json +``` + +Training defaults to CPU. Add `--device cuda` when CUDA is available. Hardware +changes wall-clock time, not the simulation protocol or acceleration metric. + +Every full preset trains a separate task-specific policy. Generated checkpoints +and reports are written under the ignored `outputs/` directory; no pretrained +artifact is required or distributed. + +## Evaluate + +Evaluate the learned speed policy: + +```bash +uv run speedtuning-eval-speed \ + --config scripted-tea-bag \ + --task tea_bag \ + --speed-policy rainbow \ + --speed-checkpoint outputs/tea_bag_speed.pt \ + --episodes 20 +``` + +Measure a fixed-speed frontier: + +```bash +uv run speedtuning-sweep \ + --config scripted-tea-bag \ + --task tea_bag \ + --speed-start 1.0 --speed-stop 3.0 --speed-step 0.25 \ + --episodes-per-speed 20 \ + --output outputs/tea_bag_sweep.json +``` + +Physical acceleration is the nominal task horizon divided by the number of +executed MuJoCo steps. It is not the arithmetic mean of commanded multipliers. + +## Simulation reference results + +One seeded run using the final checkpoint from each 100,000-decision training +run produced: + +| Protocol | Adaptive SpeedTuning | Matched fixed speed | +| --- | --- | --- | +| Pick-and-place | 98% success at 3.856x | 66% at 3.846x | +| Insertion | 97% success at 2.387x | 52% at 2.381x | +| Tea bag, randomized poses | 78% success at 2.077x | 24% at 2.075x | + +These are reference points in the pinned simulator, not exact-decimal +guarantees. Reinforcement learning is stochastic; reruns should be compared by +the success/acceleration tradeoff. + +See the [full reproduction guide](docs/SCRIPTED_REPRODUCTION.md) for reward and +update definitions, all-task commands, pose protocols, and seeded evaluation. +The compact machine-readable record is +[`benchmarks/scripted_results.json`](benchmarks/scripted_results.json). + +## Bring your own task policy + +The speed controller can wrap an external policy that returns action chunks with +shape `[time, 14]`. A `module:factory` adapter makes it possible to train or +evaluate another repository's task policy without modifying this codebase. + +See [External task-policy integration](docs/EXTERNAL_POLICIES.md) for: + +- the Python and CLI interfaces; +- ACT checkpoint and normalization support; +- visual, state, and external speed-policy observations; +- the archival learned-policy configuration and ablations. + +## Commands + +| Command | Purpose | +| --- | --- | +| `speedtuning-sim` | Run scripted simulator tasks at a fixed speed | +| `speedtuning-train-speed` | Train a Rainbow speed policy | +| `speedtuning-eval-speed` | Evaluate fixed, profiled, or learned speed policies | +| `speedtuning-sweep` | Build a success-versus-acceleration curve | +| `speedtuning-check-chunks` | Validate action-chunk integration | +| `speedtuning-rainbow-poc` | Run a small Rainbow optimization check | + +## Scope and limitations + +- This release reproduces the methodology with scripted base policies in + simulation; it does not claim to reproduce the paper's learned-ACT table. +- Real-robot execution is not part of the supported API. +- External task policies remain responsible for their architectures, + preprocessing, normalization statistics, and checkpoint compatibility. +- The physics stack is intentionally pinned for reproducibility. + +## Citation + +If you use this code, please cite: + +```bibtex +@inproceedings{yuan2025speedtuning, + title = {{SpeedTuning}: Speeding Up Policy Execution with Lightweight Reinforcement Learning}, + author = {Yuan, David D. and Zhao, Tony Z. and Burns, Kaylee and Finn, Chelsea}, + booktitle = {2025 IEEE International Conference on Robotics and Automation (ICRA)}, + year = {2025}, + doi = {10.1109/ICRA55743.2025.11128753} +} +``` + +Citation metadata is also available in [`CITATION.cff`](CITATION.cff). + +## License and acknowledgments + +SpeedTuning is released under the MIT License. The ACT-derived DETR code under +`detr/` retains its Apache-2.0 license. Simulator assets and upstream attribution +are documented in [`NOTICE.md`](NOTICE.md). diff --git a/act_integration.py b/act_integration.py new file mode 100644 index 0000000..9ac89c0 --- /dev/null +++ b/act_integration.py @@ -0,0 +1,242 @@ +"""Load retained ACT checkpoints through the public chunk-policy interface.""" + +from __future__ import annotations + +import json +import pickle +from pathlib import Path + +import numpy as np + +from chunked_policy import TorchChunkPredictor + + +REQUIRED_STATS = ("qpos_mean", "qpos_std", "action_mean", "action_std") + + +def _load_mapping(path): + path = Path(path) + if path.suffix == ".npz": + with np.load(path) as values: + return {key: values[key] for key in values.files} + if path.suffix == ".json": + return json.loads(path.read_text()) + if path.suffix in {".pkl", ".pickle"}: + with path.open("rb") as stream: + return pickle.load(stream) + raise ValueError("ACT stats must use .npz, .json, .pkl, or .pickle") + + +def _checkpoint_parts(checkpoint, device): + try: + import torch + except ImportError as exc: + raise RuntimeError("ACT integration requires: uv sync --extra learned") from exc + if checkpoint is None: + raise ValueError("An ACT checkpoint path is required") + # ACT checkpoints may include NumPy normalization arrays and legacy config + # objects. They therefore require pickle loading and must come from a + # trusted source (normally the user's own task-policy training run). + payload = torch.load( + Path(checkpoint), map_location=device, weights_only=False + ) + if not isinstance(payload, dict): + raise ValueError("ACT checkpoint must contain a state dictionary or payload") + for key in ("model_state_dict", "policy_state_dict", "state_dict"): + if key in payload: + return payload, payload[key] + # A raw torch state dictionary maps names to tensors. + if payload and all(isinstance(key, str) for key in payload): + return {}, payload + raise ValueError("ACT checkpoint does not contain recognizable model weights") + + +def _resolve_config(payload, policy_config, camera_names, device): + config = dict(payload.get("policy_config", {})) + config.update(policy_config or {}) + if camera_names is not None: + config["camera_names"] = list(camera_names) + if not config.get("camera_names"): + raise ValueError("ACT policy_config must provide camera_names") + required = ("num_queries", "hidden_dim", "dim_feedforward", "enc_layers", "dec_layers", "nheads") + missing = [key for key in required if key not in config] + if missing: + raise ValueError(f"ACT policy_config is missing: {', '.join(missing)}") + config.setdefault("lr", 1e-4) + config.setdefault("lr_backbone", 0.0) + config.setdefault("kl_weight", 10.0) + config.setdefault("backbone", "resnet18") + config.setdefault("pretrained_backbone", False) + config["device"] = device + return config + + +def _resolve_stats(payload, stats_path): + stats = dict(payload.get("stats", {})) + if stats_path is not None: + stats.update(_load_mapping(stats_path)) + missing = [key for key in REQUIRED_STATS if key not in stats] + if missing: + raise ValueError( + "ACT normalization stats are missing: " + ", ".join(missing) + ) + return {key: np.asarray(stats[key], dtype=np.float32) for key in REQUIRED_STATS} + + +def load_act_policy( + checkpoint, + device="cpu", + stats_path=None, + policy_config=None, + camera_names=None, + strict=True, +): + """Return the ACT module, resolved configuration, and normalization stats.""" + + from policy import ACTPolicy + + payload, state_dict = _checkpoint_parts(checkpoint, device) + config = _resolve_config(payload, policy_config, camera_names, device) + stats = _resolve_stats(payload, stats_path) + model = ACTPolicy(config) + incompatible = model.load_state_dict(state_dict, strict=bool(strict)) + if not strict and (incompatible.missing_keys or incompatible.unexpected_keys): + # Keep the information available to callers without printing during imports. + model.checkpoint_incompatibilities = { + "missing_keys": list(incompatible.missing_keys), + "unexpected_keys": list(incompatible.unexpected_keys), + } + model.eval() + return model, config, stats + + +def build_act_chunk_predictor( + task_name, + checkpoint, + device="cpu", + stats_path=None, + policy_config=None, + camera_names=None, + strict=True, +): + """Factory usable as ``act_integration:build_act_chunk_predictor``.""" + + del task_name + model, config, stats = load_act_policy( + checkpoint=checkpoint, + device=device, + stats_path=stats_path, + policy_config=policy_config, + camera_names=camera_names, + strict=strict, + ) + return TorchChunkPredictor( + model=model, + camera_names=config["camera_names"], + qpos_mean=stats["qpos_mean"], + qpos_std=stats["qpos_std"], + action_mean=stats["action_mean"], + action_std=stats["action_std"], + device=device, + ) + + +class ACTBackboneObservationEncoder: + """Use a supplied ACT task policy's ResNet backbone for speed features.""" + + requires_images = True + + def __init__(self, model, camera_names, include_qvel=True, device="cpu"): + import torch + + self.torch = torch + self.device = torch.device(device) + self.camera_names = tuple(camera_names) + self.include_qvel = bool(include_qvel) + self.backbone = model.model.backbones[0] + self.backbone.to(self.device).eval() + self.feature_dim = int(self.backbone.num_channels) + self.mean = torch.tensor( + [0.485, 0.456, 0.406], dtype=torch.float32, device=self.device + ).view(1, 3, 1, 1) + self.std = torch.tensor( + [0.229, 0.224, 0.225], dtype=torch.float32, device=self.device + ).view(1, 3, 1, 1) + + def reset(self): + return None + + def __call__(self, observation): + torch = self.torch + if "images" not in observation: + raise ValueError("ACT-backbone speed observations require images") + images = np.stack( + [observation["images"][name] for name in self.camera_names] + ).transpose(0, 3, 1, 2) + tensor = torch.as_tensor(images, dtype=torch.float32, device=self.device) / 255.0 + tensor = (tensor - self.mean) / self.std + features = [] + with torch.inference_mode(): + for image in tensor: + backbone_features, _ = self.backbone(image.unsqueeze(0)) + feature_map = backbone_features[-1] + features.append(feature_map.mean(dim=(2, 3)).squeeze(0)) + proprioception = [np.asarray(observation["qpos"], dtype=np.float32)] + if self.include_qvel: + proprioception.append(np.asarray(observation["qvel"], dtype=np.float32)) + return np.concatenate( + proprioception + + [torch.cat(features).detach().cpu().numpy().astype(np.float32)] + ) + + def output_dim(self, env_state_dim): + del env_state_dim + return 14 + (14 if self.include_qvel else 0) + len(self.camera_names) * self.feature_dim + + def spec(self): + return { + "type": "act_backbone", + "camera_names": list(self.camera_names), + "include_qpos": True, + "include_qvel": self.include_qvel, + "include_env_state": False, + "feature_dim": self.feature_dim, + } + + def state_dict(self): + return { + key: value.detach().cpu() + for key, value in self.backbone.state_dict().items() + } + + def load_state_dict(self, state_dict): + self.backbone.load_state_dict(state_dict) + + +def build_act_observation_encoder( + task_name, + checkpoint, + device="cpu", + stats_path=None, + policy_config=None, + camera_names=None, + include_qvel=True, + strict=True, +): + """Factory for the task-policy image-encoder ablation.""" + + del task_name + model, config, _ = load_act_policy( + checkpoint=checkpoint, + device=device, + stats_path=stats_path, + policy_config=policy_config, + camera_names=camera_names, + strict=strict, + ) + return ACTBackboneObservationEncoder( + model, + config["camera_names"], + include_qvel=include_qvel, + device=device, + ) diff --git a/assets/__init__.py b/assets/__init__.py new file mode 100644 index 0000000..9d30322 --- /dev/null +++ b/assets/__init__.py @@ -0,0 +1 @@ +"""Packaged MuJoCo models and meshes for the simulation tasks.""" diff --git a/assets/bimanual_viperx_ee_insertion.xml b/assets/bimanual_viperx_ee_insertion.xml new file mode 100644 index 0000000..700aaac --- /dev/null +++ b/assets/bimanual_viperx_ee_insertion.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/bimanual_viperx_ee_transfer_cube.xml b/assets/bimanual_viperx_ee_transfer_cube.xml new file mode 100644 index 0000000..2589384 --- /dev/null +++ b/assets/bimanual_viperx_ee_transfer_cube.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/bimanual_viperx_ee_transfer_tea_bag.xml b/assets/bimanual_viperx_ee_transfer_tea_bag.xml new file mode 100644 index 0000000..3358ebc --- /dev/null +++ b/assets/bimanual_viperx_ee_transfer_tea_bag.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/bimanual_viperx_insertion.xml b/assets/bimanual_viperx_insertion.xml new file mode 100644 index 0000000..f701d70 --- /dev/null +++ b/assets/bimanual_viperx_insertion.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/bimanual_viperx_transfer_cube.xml b/assets/bimanual_viperx_transfer_cube.xml new file mode 100644 index 0000000..bdc9e64 --- /dev/null +++ b/assets/bimanual_viperx_transfer_cube.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/bimanual_viperx_transfer_tea_bag.xml b/assets/bimanual_viperx_transfer_tea_bag.xml new file mode 100644 index 0000000..51974c8 --- /dev/null +++ b/assets/bimanual_viperx_transfer_tea_bag.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/scene.xml b/assets/scene.xml new file mode 100644 index 0000000..ae59450 --- /dev/null +++ b/assets/scene.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/tabletop.stl b/assets/tabletop.stl new file mode 100644 index 0000000000000000000000000000000000000000..ab35cdf76426b2dddc433afa11af96ebe0e07c17 GIT binary patch literal 684 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 L5+uyeJY(`Nju%Ka literal 0 HcmV?d00001 diff --git a/assets/vx300s_10_custom_finger_right.stl b/assets/vx300s_10_custom_finger_right.stl new file mode 100644 index 0000000000000000000000000000000000000000..d6a492c2046d3850ce7c7d650e951701b93bb87d GIT binary patch literal 83384 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 literal 0 HcmV?d00001 diff --git a/assets/vx300s_1_base.stl b/assets/vx300s_1_base.stl new file mode 100644 index 0000000000000000000000000000000000000000..5a7efda2fe330aeadad63ee4ce29e996ebdf2195 GIT binary patch literal 99984 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 z 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 literal 0 HcmV?d00001 diff --git a/assets/vx300s_2_shoulder.stl b/assets/vx300s_2_shoulder.stl new file mode 100644 index 0000000000000000000000000000000000000000..dc22aa7e51355a0a8d0439f85be356c6aa9e1c3c GIT binary patch literal 63884 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 IQab+s0B?#a?f?J) literal 0 HcmV?d00001 diff --git a/assets/vx300s_3_upper_arm.stl b/assets/vx300s_3_upper_arm.stl new file mode 100644 index 0000000000000000000000000000000000000000..111c586e18fb0f44cee7e4593d24c71382a6e9b4 GIT binary patch literal 102984 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 Qg}}QoCNx_X0=Dn|ANIr_wEzGB literal 0 HcmV?d00001 diff --git a/assets/vx300s_6_wrist.stl b/assets/vx300s_6_wrist.stl new file mode 100644 index 0000000000000000000000000000000000000000..ab8423e99da86cb9e13c197f8137b670f789ea2a GIT binary patch literal 70784 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 literal 0 HcmV?d00001 diff --git a/assets/vx300s_7_gripper.stl b/assets/vx300s_7_gripper.stl new file mode 100644 index 0000000000000000000000000000000000000000..043db9caeaa59dcb0a6bf570956b0904eb60ba63 GIT binary patch literal 450084 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

+Hgr>qo{?*1^}%qZ;2qh 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

mev-9LM@Y2(F?th1J! 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 z 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�N{IX^OwNSRi8J}H} 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


<34N!sL?C*sEm+4vn_wLn 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 literal 0 HcmV?d00001 diff --git a/assets/vx300s_dependencies.xml b/assets/vx300s_dependencies.xml new file mode 100644 index 0000000..c75d3ad --- /dev/null +++ b/assets/vx300s_dependencies.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/vx300s_left.xml b/assets/vx300s_left.xml new file mode 100644 index 0000000..61e6219 --- /dev/null +++ b/assets/vx300s_left.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/vx300s_right.xml b/assets/vx300s_right.xml new file mode 100644 index 0000000..2c6f007 --- /dev/null +++ b/assets/vx300s_right.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 0000000..5dbccc8 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,18 @@ +# Reference results + +[`scripted_results.json`](scripted_results.json) records one seeded run of the +from-scratch scripted-policy protocol. The record is hardware-neutral: it +reports simulator success and physical acceleration, not training time. + +| Protocol | Learned speed | Matched fixed speed | +| --- | --- | --- | +| Pick-and-place | 98% at 3.856x | 66% at 3.846x | +| Insertion | 97% at 2.387x | 52% at 2.381x | +| Tea bag, randomized poses | 78% at 2.077x | 24% at 2.075x | + +The JSON includes the preset, training seed, and episode count needed to +interpret each result. Training is stochastic, so these values +are reference points rather than exact-decimal guarantees. + +See the [reproduction guide](../docs/SCRIPTED_REPRODUCTION.md) for commands and +protocol details. No trained checkpoint is distributed with the repository. diff --git a/benchmarks/scripted_results.json b/benchmarks/scripted_results.json new file mode 100644 index 0000000..02610bc --- /dev/null +++ b/benchmarks/scripted_results.json @@ -0,0 +1,59 @@ +{ + "schema_version": 1, + "description": "Reference results for from-scratch scripted-policy training", + "protocol": { + "base_policy": "bundled scripted policy", + "training_decisions": 100000, + "evaluation_checkpoint": "final training output", + "held_out_seeds": [100, 199], + "episodes_per_task": 100, + "metric": "physical_acceleration=nominal_horizon/executed_physics_steps" + }, + "results": { + "pick_and_place": { + "preset": "scripted-pick-and-place", + "training_seed": 0, + "learned_speed": { + "successes": 98, + "success_rate": 0.98, + "mean_physical_acceleration": 3.856 + }, + "matched_fixed_speed": { + "commanded_speed": 3.856, + "successes": 66, + "success_rate": 0.66, + "mean_physical_acceleration": 3.846 + } + }, + "insertion": { + "preset": "scripted-insertion", + "training_seed": 0, + "learned_speed": { + "successes": 97, + "success_rate": 0.97, + "mean_physical_acceleration": 2.387 + }, + "matched_fixed_speed": { + "commanded_speed": 2.387, + "successes": 52, + "success_rate": 0.52, + "mean_physical_acceleration": 2.381 + } + }, + "tea_bag": { + "preset": "scripted-tea-bag-randomized", + "training_seed": 1, + "learned_speed": { + "successes": 78, + "success_rate": 0.78, + "mean_physical_acceleration": 2.077 + }, + "matched_fixed_speed": { + "commanded_speed": 2.075, + "successes": 24, + "success_rate": 0.24, + "mean_physical_acceleration": 2.075 + } + } + } +} diff --git a/chunked_policy.py b/chunked_policy.py new file mode 100644 index 0000000..e22efad --- /dev/null +++ b/chunked_policy.py @@ -0,0 +1,324 @@ +"""Adapters for upstream policies that predict joint-action chunks. + +The public contract is intentionally model-agnostic: a predictor receives one +DM Control observation dictionary and returns one or more 14D joint actions. +``ChunkPredictorAdapter`` handles common NumPy, PyTorch, tuple, and dictionary +outputs, while ``ChunkedPolicyRunner`` turns those chunks into individual +simulator actions at a parameterized execution speed. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Callable + +import numpy as np + +from constants import PUPPET_GRIPPER_POSITION_NORMALIZE_FN +from ee_sim_env import make_ee_sim_env +from scripted_policy import make_scripted_policy +from sim_env import make_sim_env +from sim_tasks import get_task_spec, normalize_task_name + + +def _to_numpy(value: Any) -> np.ndarray: + """Convert common model outputs without importing a framework eagerly.""" + + detach = getattr(value, "detach", None) + if detach is not None: + value = detach() + cpu = getattr(value, "cpu", None) + if cpu is not None: + value = cpu() + numpy = getattr(value, "numpy", None) + if numpy is not None: + value = numpy() + return np.asarray(value, dtype=np.float64) + + +def as_action_chunk(output: Any) -> np.ndarray: + """Normalize an upstream policy output to a finite ``[time, 14]`` array.""" + + if isinstance(output, dict): + for key in ("actions", "action", "chunk"): + if key in output: + output = output[key] + break + else: + raise ValueError( + "Chunk dictionaries must contain an 'actions', 'action', or 'chunk' key" + ) + if isinstance(output, (tuple, list)): + if not output: + raise ValueError("A chunked policy returned an empty sequence") + output = output[0] + + actions = _to_numpy(output) + if actions.ndim == 3 and actions.shape[0] == 1: + actions = actions[0] + if actions.ndim == 1 and actions.shape[0] == 14: + actions = actions[None] + if actions.ndim != 2 or actions.shape[1] != 14 or len(actions) == 0: + raise ValueError("Chunked policy output must have shape [time, 14]") + if not np.all(np.isfinite(actions)): + raise ValueError("Chunked policy produced a non-finite action") + return actions + + +class ChunkPredictorAdapter: + """Adapt an arbitrary upstream chunk predictor to the public contract. + + ``predictor`` can be callable or expose ``predict_chunk(observation)``. + Optional adapters make it possible to translate repository-specific + observations and outputs without changing the simulator integration. + """ + + def __init__( + self, + predictor: Any, + observation_adapter: Callable[[dict], Any] | None = None, + output_adapter: Callable[[Any], Any] | None = None, + ): + predict = getattr(predictor, "predict_chunk", None) + if predict is None and callable(predictor): + predict = predictor + if predict is None: + raise TypeError("predictor must be callable or define predict_chunk()") + self.predictor = predictor + self._predict = predict + self.observation_adapter = observation_adapter or (lambda observation: observation) + self.output_adapter = output_adapter or (lambda output: output) + + def reset(self): + reset = getattr(self.predictor, "reset", None) + if reset is not None: + reset() + + def advance(self, nominal_steps): + """Notify predictors that explicitly track nominal demonstration time.""" + + advance = getattr(self.predictor, "advance", None) + if advance is not None: + advance(float(nominal_steps)) + + def __call__(self, observation): + model_input = self.observation_adapter(observation) + output = self.output_adapter(self._predict(model_input)) + return as_action_chunk(output) + + +def interpolate_action_chunk(actions, speed=1.0): + """Resample a ``[time, 14]`` action chunk at a new execution speed.""" + + actions = as_action_chunk(actions) + if speed <= 0: + raise ValueError("speed must be positive") + sample_times = np.arange(0.0, len(actions), speed) + lower = np.floor(sample_times).astype(int) + upper = np.minimum(lower + 1, len(actions) - 1) + fraction = (sample_times - lower)[:, None] + return actions[lower] + fraction * (actions[upper] - actions[lower]) + + +class ChunkedPolicyRunner: + """Turn a chunk-predicting policy into one joint action per simulator step. + + Speed is expressed in nominal policy timesteps per physics step. It may be + fixed at construction or supplied for every call, allowing a learned speed + policy to change acceleration online without modifying the upstream model. + """ + + def __init__(self, predictor, speed=1.0): + self.predictor = ( + predictor + if isinstance(predictor, ChunkPredictorAdapter) + else ChunkPredictorAdapter(predictor) + ) + self.speed = self._validate_speed(speed) + self._chunk = None + self._chunk_index = 0.0 + + @staticmethod + def _validate_speed(speed): + speed = float(speed) + if not np.isfinite(speed) or speed <= 0: + raise ValueError("speed must be a finite positive value") + return speed + + def reset(self): + self._chunk = None + self._chunk_index = 0.0 + reset = getattr(self.predictor, "reset", None) + if reset is not None: + reset() + + def begin_decision(self, observation, speed=None): + """Predict a fresh receding-horizon chunk for one speed decision.""" + + speed = self.speed if speed is None else self._validate_speed(speed) + self._chunk = self.predictor(observation) + self._chunk_index = 0.0 + self._decision_speed = speed + return self._chunk + + def action(self, observation, speed=None): + speed = self.speed if speed is None else self._validate_speed(speed) + if self._chunk is None or self._chunk_index >= len(self._chunk): + self.begin_decision(observation, speed=speed) + + lower = int(np.floor(self._chunk_index)) + upper = min(lower + 1, len(self._chunk) - 1) + fraction = self._chunk_index - lower + action = self._chunk[lower] + fraction * ( + self._chunk[upper] - self._chunk[lower] + ) + self._chunk_index += speed + self.predictor.advance(speed) + return action.copy() + + +class TorchChunkPredictor: + """Pre/post-processing adapter for ACT-compatible PyTorch policies. + + The wrapped model must accept normalized ``qpos`` with shape ``[1, 14]`` and + RGB images with shape ``[1, cameras, 3, height, width]``, and return an action + tensor with shape ``[1, chunk, 14]``. + """ + + def __init__( + self, + model, + camera_names, + qpos_mean, + qpos_std, + action_mean, + action_std, + device=None, + ): + try: + import torch + except ImportError as exc: + raise RuntimeError("Learned policies require: uv sync --extra learned") from exc + self.torch = torch + self.model = model + self.camera_names = tuple(camera_names) + self.device = torch.device( + device or ("cuda" if torch.cuda.is_available() else "cpu") + ) + self.qpos_mean = np.asarray(qpos_mean) + self.qpos_std = np.maximum(np.asarray(qpos_std), 1e-6) + self.action_mean = np.asarray(action_mean) + self.action_std = np.asarray(action_std) + for value, name in ( + (self.qpos_mean, "qpos_mean"), + (self.qpos_std, "qpos_std"), + (self.action_mean, "action_mean"), + (self.action_std, "action_std"), + ): + if value.shape != (14,): + raise ValueError(f"{name} must have shape (14,)") + self.model.to(self.device) + self.model.eval() + + def __call__(self, observation): + torch = self.torch + if "images" not in observation: + raise ValueError("The environment must be created with render_images=True") + qpos = (np.asarray(observation["qpos"]) - self.qpos_mean) / self.qpos_std + images = np.stack( + [observation["images"][name] for name in self.camera_names], axis=0 + ).transpose(0, 3, 1, 2) + qpos_tensor = torch.as_tensor(qpos, dtype=torch.float32, device=self.device)[None] + image_tensor = torch.as_tensor( + images / 255.0, dtype=torch.float32, device=self.device + )[None] + with torch.inference_mode(): + output = self.model(qpos_tensor, image_tensor) + chunk = as_action_chunk(output) + return chunk * self.action_std + self.action_mean + + +@dataclass +class JointDemonstration: + actions: np.ndarray + object_pose: np.ndarray + + +def collect_scripted_joint_demonstration(task_name, seed=0): + """Convert the retained EE scripted rollout into joint commands.""" + + task_name = normalize_task_name(task_name) + spec = get_task_spec(task_name) + env = make_ee_sim_env(task_name, render_images=False, seed=seed) + timestep = env.reset() + episode = [timestep] + policy = make_scripted_policy(task_name) + for _ in range(spec.episode_len): + timestep = env.step(policy(timestep)) + episode.append(timestep) + + actions = [] + for item in episode: + action = item.observation["qpos"].copy() + gripper_ctrl = item.observation["gripper_ctrl"] + action[6] = PUPPET_GRIPPER_POSITION_NORMALIZE_FN(gripper_ctrl[0]) + action[13] = PUPPET_GRIPPER_POSITION_NORMALIZE_FN(gripper_ctrl[2]) + actions.append(action) + return JointDemonstration( + actions=np.asarray(actions), + object_pose=episode[0].observation["env_state"].copy(), + ) + + +class RecordedChunkPredictor: + """Deterministic chunk oracle used to validate the learned-policy contract.""" + + def __init__(self, actions, chunk_size): + self.actions = np.asarray(actions) + self.chunk_size = chunk_size + self.cursor = 0.0 + + def reset(self): + self.cursor = 0.0 + + def advance(self, nominal_steps): + self.cursor = min(self.cursor + float(nominal_steps), len(self.actions) - 1) + + def __call__(self, observation): + del observation + start = int(np.floor(self.cursor)) + end = min(start + self.chunk_size, len(self.actions)) + chunk = self.actions[start:end] + if len(chunk) < self.chunk_size: + chunk = np.concatenate( + [chunk, np.repeat(chunk[-1:], self.chunk_size - len(chunk), axis=0)] + ) + return chunk + + +def replay_recorded_chunks(task_name, chunk_size=25, seed=0): + """Validate chunked-policy replay through the joint-control environment.""" + + task_name = normalize_task_name(task_name) + demonstration = collect_scripted_joint_demonstration(task_name, seed=seed) + env = make_sim_env( + task_name, + render_images=False, + seed=seed, + object_pose=demonstration.object_pose, + ) + timestep = env.reset() + predictor = RecordedChunkPredictor(demonstration.actions, chunk_size) + runner = ChunkedPolicyRunner(predictor) + rewards = [] + for _ in range(len(demonstration.actions)): + timestep = env.step(runner.action(timestep.observation)) + rewards.append(int(timestep.reward or 0)) + return { + "task": task_name, + "success": max(rewards, default=0) == env.task.max_reward, + "max_reward": max(rewards, default=0), + "target_reward": env.task.max_reward, + "chunk_size": chunk_size, + "steps": len(demonstration.actions), + } diff --git a/configs/README.md b/configs/README.md new file mode 100644 index 0000000..bb1f71c --- /dev/null +++ b/configs/README.md @@ -0,0 +1,39 @@ +# Experiment manifests + +`paper_sim.json` is the best simulation configuration recoverable from the +published paper and the retained `SpeedTuningViz` experiment directory names. It +is an archival preset, not a guarantee of exact numerical reproduction. + +`scripted_tea_bag.json` is the fully runnable public reproduction. It uses the +included tea-bag waypoint policy and the latest retained training recipe from +the repository history: five speed actions, state observations, quadratic speed +reward, 100k decisions, and episode-boundary Rainbow updates. Load it with +`--config scripted-tea-bag`. + +`scripted_tea_bag_randomized.json` inherits that recipe and samples the tea bag +within the original ACT cube-position range at every reset. This opt-in variant +is the appropriate preset for reporting success rates across simulator seeds; +the exact historical tea-bag environment uses one fixed initial pose. + +`scripted_pick_and_place.json` and `scripted_insertion.json` apply the same +scripted-base Rainbow recipe to the other reconstructed tasks. Pick-and-place +includes speed actions through 4.5x because its transport phase tolerates the +paper's higher acceleration range; insertion retains the denser historical +1.0x-3.0x actions for contact-sensitive control. + +The main recovered choices are: + +- discrete speeds: 1.5, 2.0, 3.0, and 4.5; +- frame skip 10 and observation stack 5; +- proprioception plus top-camera features from pretrained ResNet-18; +- no privileged simulator object state; +- quadratic speed reward and hidden dimension 1024. + +The exact original task-policy checkpoints, speed-policy checkpoints, datasets, +and full training command were not recovered. Values retained only in the old +trainer, such as gamma and replay capacity, are included to make the preset +concrete and are identified by the manifest's archival status. + +Files in `ablations/` inherit the paper preset and override one experimental +factor. They can be passed directly to `--config`; command-line arguments may +override any value. diff --git a/configs/__init__.py b/configs/__init__.py new file mode 100644 index 0000000..042db17 --- /dev/null +++ b/configs/__init__.py @@ -0,0 +1 @@ +"""Packaged SpeedTuning experiment manifests.""" diff --git a/configs/ablations/act_encoder.json b/configs/ablations/act_encoder.json new file mode 100644 index 0000000..2a8aef3 --- /dev/null +++ b/configs/ablations/act_encoder.json @@ -0,0 +1,8 @@ +{ + "name": "act-task-policy-encoder", + "inherits": "paper-sim", + "observation": { + "speed_observation": "external", + "observation_encoder_loader": "act_integration:build_act_observation_encoder" + } +} diff --git a/configs/ablations/frame_skip_25.json b/configs/ablations/frame_skip_25.json new file mode 100644 index 0000000..0668c91 --- /dev/null +++ b/configs/ablations/frame_skip_25.json @@ -0,0 +1,5 @@ +{ + "name": "frame-skip-25", + "inherits": "paper-sim", + "environment": {"frame_skip": 25} +} diff --git a/configs/ablations/frame_skip_5.json b/configs/ablations/frame_skip_5.json new file mode 100644 index 0000000..fcdab6b --- /dev/null +++ b/configs/ablations/frame_skip_5.json @@ -0,0 +1,5 @@ +{ + "name": "frame-skip-5", + "inherits": "paper-sim", + "environment": {"frame_skip": 5} +} diff --git a/configs/ablations/no_image.json b/configs/ablations/no_image.json new file mode 100644 index 0000000..3402632 --- /dev/null +++ b/configs/ablations/no_image.json @@ -0,0 +1,11 @@ +{ + "name": "no-image", + "inherits": "paper-sim", + "observation": { + "speed_observation": "state", + "include_env_state": false, + "include_qpos": true, + "include_qvel": true, + "frame_stack": 5 + } +} diff --git a/configs/ablations/random_resnet.json b/configs/ablations/random_resnet.json new file mode 100644 index 0000000..5056f4b --- /dev/null +++ b/configs/ablations/random_resnet.json @@ -0,0 +1,5 @@ +{ + "name": "random-resnet18", + "inherits": "paper-sim", + "observation": {"image_encoder": "resnet18-random"} +} diff --git a/configs/ablations/reward_beta_0.json b/configs/ablations/reward_beta_0.json new file mode 100644 index 0000000..d2f31fe --- /dev/null +++ b/configs/ablations/reward_beta_0.json @@ -0,0 +1,5 @@ +{ + "name": "reward-beta-0", + "inherits": "paper-sim", + "reward": {"speed_power": 0.0, "speed_weight": 0.0} +} diff --git a/configs/ablations/reward_beta_1.json b/configs/ablations/reward_beta_1.json new file mode 100644 index 0000000..7a0ceef --- /dev/null +++ b/configs/ablations/reward_beta_1.json @@ -0,0 +1,5 @@ +{ + "name": "reward-beta-1", + "inherits": "paper-sim", + "reward": {"speed_power": 1.0} +} diff --git a/configs/ablations/reward_beta_3.json b/configs/ablations/reward_beta_3.json new file mode 100644 index 0000000..fc3bf4d --- /dev/null +++ b/configs/ablations/reward_beta_3.json @@ -0,0 +1,5 @@ +{ + "name": "reward-beta-3", + "inherits": "paper-sim", + "reward": {"speed_power": 3.0} +} diff --git a/configs/ablations/scripted_policy.json b/configs/ablations/scripted_policy.json new file mode 100644 index 0000000..c7d84b7 --- /dev/null +++ b/configs/ablations/scripted_policy.json @@ -0,0 +1,5 @@ +{ + "name": "scripted-policy", + "inherits": "paper-sim", + "base_policy": {"base_policy": "scripted"} +} diff --git a/configs/paper_sim.json b/configs/paper_sim.json new file mode 100644 index 0000000..a1be8dd --- /dev/null +++ b/configs/paper_sim.json @@ -0,0 +1,49 @@ +{ + "name": "paper-sim", + "status": "best-recovered archival configuration; checkpoints and data are not included", + "evidence": "Published paper plus retained SpeedTuningViz experiment names", + "base_policy": { + "base_policy": "external-chunk", + "chunk_size": 100 + }, + "environment": { + "speed_values": [1.5, 2.0, 3.0, 4.5], + "frame_skip": 10 + }, + "observation": { + "speed_observation": "visual", + "camera_names": ["top"], + "image_encoder": "resnet18-pretrained", + "image_size": 224, + "include_env_state": false, + "include_qpos": true, + "include_qvel": true, + "frame_stack": 5 + }, + "reward": { + "success_bonus": 100.0, + "speed_weight": 0.01, + "speed_power": 2.0 + }, + "training": { + "decisions": 100000, + "memory_size": 1000000, + "batch_size": 128, + "learning_starts": 512, + "gradient_steps": 1, + "update_schedule": "episode", + "checkpoint_interval": 10000, + "hidden_dim": 1024, + "gamma": 0.99, + "target_update": 50, + "beta_schedule": "legacy" + }, + "evaluation": { + "episodes": 2000, + "adaptive_episodes": 2000, + "episodes_per_speed": 100, + "speed_start": 1.0, + "speed_stop": 4.5, + "speed_step": 0.1 + } +} diff --git a/configs/scripted_insertion.json b/configs/scripted_insertion.json new file mode 100644 index 0000000..4e0fc94 --- /dev/null +++ b/configs/scripted_insertion.json @@ -0,0 +1,15 @@ +{ + "name": "scripted-insertion", + "inherits": "scripted-tea-bag", + "status": "fully runnable scripted-policy insertion reproduction", + "environment": { + "speed_values": [1.0, 1.5, 2.0, 2.5, 3.0] + }, + "evaluation": { + "episodes": 100, + "episodes_per_speed": 100, + "speed_start": 1.0, + "speed_stop": 3.0, + "speed_step": 0.25 + } +} diff --git a/configs/scripted_pick_and_place.json b/configs/scripted_pick_and_place.json new file mode 100644 index 0000000..a4bbd12 --- /dev/null +++ b/configs/scripted_pick_and_place.json @@ -0,0 +1,15 @@ +{ + "name": "scripted-pick-and-place", + "inherits": "scripted-tea-bag", + "status": "fully runnable scripted-policy pick-and-place reproduction", + "environment": { + "speed_values": [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5] + }, + "evaluation": { + "episodes": 100, + "episodes_per_speed": 100, + "speed_start": 1.0, + "speed_stop": 4.5, + "speed_step": 0.25 + } +} diff --git a/configs/scripted_tea_bag.json b/configs/scripted_tea_bag.json new file mode 100644 index 0000000..25211fa --- /dev/null +++ b/configs/scripted_tea_bag.json @@ -0,0 +1,47 @@ +{ + "name": "scripted-tea-bag", + "status": "fully runnable scripted-policy reproduction", + "evidence": "Retained run_speed_rl.py at commit 097a46f plus the ICRA 2025 paper", + "base_policy": { + "base_policy": "scripted" + }, + "environment": { + "speed_values": [1.0, 1.5, 2.0, 2.5, 3.0], + "frame_skip": 10 + }, + "observation": { + "speed_observation": "state", + "include_env_state": true, + "include_qpos": true, + "include_qvel": true, + "frame_stack": 1 + }, + "reward": { + "success_bonus": 100.0, + "speed_weight": 0.01, + "speed_power": 2.0 + }, + "training": { + "decisions": 100000, + "memory_size": 1000000, + "batch_size": 128, + "learning_starts": 128, + "gradient_steps": 1, + "update_schedule": "episode", + "checkpoint_interval": 10000, + "hidden_dim": 256, + "gamma": 0.99, + "target_update": 50, + "beta_schedule": "legacy", + "epsilon": 0.0, + "min_epsilon": 0.0, + "exploration_steps": 0 + }, + "evaluation": { + "episodes": 20, + "episodes_per_speed": 50, + "speed_start": 1.0, + "speed_stop": 3.0, + "speed_step": 0.25 + } +} diff --git a/configs/scripted_tea_bag_randomized.json b/configs/scripted_tea_bag_randomized.json new file mode 100644 index 0000000..5e03f73 --- /dev/null +++ b/configs/scripted_tea_bag_randomized.json @@ -0,0 +1,12 @@ +{ + "name": "scripted-tea-bag-randomized", + "inherits": "scripted-tea-bag", + "status": "scripted-policy reproduction with seeded pose variation", + "environment": { + "randomize_object_pose": true + }, + "evaluation": { + "episodes": 100, + "episodes_per_speed": 100 + } +} diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..e6f3853 --- /dev/null +++ b/constants.py @@ -0,0 +1,46 @@ +import os +from importlib import resources + +### Task parameters +### Simulation envs fixed constants +DT = 0.02 +JOINT_NAMES = ["waist", "shoulder", "elbow", "forearm_roll", "wrist_angle", "wrist_rotate"] +START_ARM_POSE = [0, -0.96, 1.16, 0, -0.3, 0, 0.02239, -0.02239, 0, -0.96, 1.16, 0, -0.3, 0, 0.02239, -0.02239] + +XML_DIR = str(resources.files("assets")) + os.sep + +# Left finger position limits (qpos[7]), right_finger = -1 * left_finger +MASTER_GRIPPER_POSITION_OPEN = 0.02417 +MASTER_GRIPPER_POSITION_CLOSE = 0.01244 +PUPPET_GRIPPER_POSITION_OPEN = 0.05800 +PUPPET_GRIPPER_POSITION_CLOSE = 0.01844 + +# Gripper joint limits (qpos[6]) +MASTER_GRIPPER_JOINT_OPEN = 0.3083 +MASTER_GRIPPER_JOINT_CLOSE = -0.6842 +PUPPET_GRIPPER_JOINT_OPEN = 1.4910 +PUPPET_GRIPPER_JOINT_CLOSE = -0.6213 + +############################ Helper functions ############################ + +MASTER_GRIPPER_POSITION_NORMALIZE_FN = lambda x: (x - MASTER_GRIPPER_POSITION_CLOSE) / (MASTER_GRIPPER_POSITION_OPEN - MASTER_GRIPPER_POSITION_CLOSE) +PUPPET_GRIPPER_POSITION_NORMALIZE_FN = lambda x: (x - PUPPET_GRIPPER_POSITION_CLOSE) / (PUPPET_GRIPPER_POSITION_OPEN - PUPPET_GRIPPER_POSITION_CLOSE) +MASTER_GRIPPER_POSITION_UNNORMALIZE_FN = lambda x: x * (MASTER_GRIPPER_POSITION_OPEN - MASTER_GRIPPER_POSITION_CLOSE) + MASTER_GRIPPER_POSITION_CLOSE +PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN = lambda x: x * (PUPPET_GRIPPER_POSITION_OPEN - PUPPET_GRIPPER_POSITION_CLOSE) + PUPPET_GRIPPER_POSITION_CLOSE +MASTER2PUPPET_POSITION_FN = lambda x: PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN(MASTER_GRIPPER_POSITION_NORMALIZE_FN(x)) + +MASTER_GRIPPER_JOINT_NORMALIZE_FN = lambda x: (x - MASTER_GRIPPER_JOINT_CLOSE) / (MASTER_GRIPPER_JOINT_OPEN - MASTER_GRIPPER_JOINT_CLOSE) +PUPPET_GRIPPER_JOINT_NORMALIZE_FN = lambda x: (x - PUPPET_GRIPPER_JOINT_CLOSE) / (PUPPET_GRIPPER_JOINT_OPEN - PUPPET_GRIPPER_JOINT_CLOSE) +MASTER_GRIPPER_JOINT_UNNORMALIZE_FN = lambda x: x * (MASTER_GRIPPER_JOINT_OPEN - MASTER_GRIPPER_JOINT_CLOSE) + MASTER_GRIPPER_JOINT_CLOSE +PUPPET_GRIPPER_JOINT_UNNORMALIZE_FN = lambda x: x * (PUPPET_GRIPPER_JOINT_OPEN - PUPPET_GRIPPER_JOINT_CLOSE) + PUPPET_GRIPPER_JOINT_CLOSE +MASTER2PUPPET_JOINT_FN = lambda x: PUPPET_GRIPPER_JOINT_UNNORMALIZE_FN(MASTER_GRIPPER_JOINT_NORMALIZE_FN(x)) + +MASTER_GRIPPER_VELOCITY_NORMALIZE_FN = lambda x: x / (MASTER_GRIPPER_POSITION_OPEN - MASTER_GRIPPER_POSITION_CLOSE) +PUPPET_GRIPPER_VELOCITY_NORMALIZE_FN = lambda x: x / (PUPPET_GRIPPER_POSITION_OPEN - PUPPET_GRIPPER_POSITION_CLOSE) + +MASTER_POS2JOINT = lambda x: MASTER_GRIPPER_POSITION_NORMALIZE_FN(x) * (MASTER_GRIPPER_JOINT_OPEN - MASTER_GRIPPER_JOINT_CLOSE) + MASTER_GRIPPER_JOINT_CLOSE +MASTER_JOINT2POS = lambda x: MASTER_GRIPPER_POSITION_UNNORMALIZE_FN((x - MASTER_GRIPPER_JOINT_CLOSE) / (MASTER_GRIPPER_JOINT_OPEN - MASTER_GRIPPER_JOINT_CLOSE)) +PUPPET_POS2JOINT = lambda x: PUPPET_GRIPPER_POSITION_NORMALIZE_FN(x) * (PUPPET_GRIPPER_JOINT_OPEN - PUPPET_GRIPPER_JOINT_CLOSE) + PUPPET_GRIPPER_JOINT_CLOSE +PUPPET_JOINT2POS = lambda x: PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN((x - PUPPET_GRIPPER_JOINT_CLOSE) / (PUPPET_GRIPPER_JOINT_OPEN - PUPPET_GRIPPER_JOINT_CLOSE)) + +MASTER_GRIPPER_JOINT_MID = (MASTER_GRIPPER_JOINT_OPEN + MASTER_GRIPPER_JOINT_CLOSE)/2 diff --git a/detr/LICENSE b/detr/LICENSE new file mode 100644 index 0000000..b1395e9 --- /dev/null +++ b/detr/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 - present, Facebook, Inc + + 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. diff --git a/detr/README.md b/detr/README.md new file mode 100644 index 0000000..500b1b8 --- /dev/null +++ b/detr/README.md @@ -0,0 +1,9 @@ +This part of the codebase is modified from DETR https://github.com/facebookresearch/detr under APACHE 2.0. + + @article{Carion2020EndtoEndOD, + title={End-to-End Object Detection with Transformers}, + author={Nicolas Carion and Francisco Massa and Gabriel Synnaeve and Nicolas Usunier and Alexander Kirillov and Sergey Zagoruyko}, + journal={ArXiv}, + year={2020}, + volume={abs/2005.12872} + } \ No newline at end of file diff --git a/detr/__init__.py b/detr/__init__.py new file mode 100644 index 0000000..089d1af --- /dev/null +++ b/detr/__init__.py @@ -0,0 +1 @@ +"""ACT/DETR model components retained for chunk-policy compatibility.""" diff --git a/detr/main.py b/detr/main.py new file mode 100644 index 0000000..7315bc2 --- /dev/null +++ b/detr/main.py @@ -0,0 +1,77 @@ +"""Construct the retained ACT/DETR models from a dictionary configuration.""" + +from __future__ import annotations + +from types import SimpleNamespace + +import torch + +from .models import build_ACT_model, build_CNNMLP_model + + +MODEL_DEFAULTS = { + "lr": 1e-4, + "lr_backbone": 1e-5, + "weight_decay": 1e-4, + "backbone": "resnet18", + "pretrained_backbone": False, + "dilation": False, + "position_embedding": "sine", + "camera_names": [], + "enc_layers": 4, + "dec_layers": 6, + "dim_feedforward": 2048, + "hidden_dim": 256, + "dropout": 0.1, + "nheads": 8, + "num_queries": 400, + "pre_norm": False, + "masks": False, +} + + +def _model_args(overrides): + values = {**MODEL_DEFAULTS, **overrides} + return SimpleNamespace(**values) + + +def _optimizer(model, args): + parameter_groups = [ + { + "params": [ + parameter + for name, parameter in model.named_parameters() + if "backbone" not in name and parameter.requires_grad + ] + }, + { + "params": [ + parameter + for name, parameter in model.named_parameters() + if "backbone" in name and parameter.requires_grad + ], + "lr": args.lr_backbone, + }, + ] + return torch.optim.AdamW( + parameter_groups, lr=args.lr, weight_decay=args.weight_decay + ) + + +def _device(args): + return torch.device( + getattr(args, "device", None) + or ("cuda" if torch.cuda.is_available() else "cpu") + ) + + +def build_ACT_model_and_optimizer(args_override): + args = _model_args(args_override) + model = build_ACT_model(args).to(_device(args)) + return model, _optimizer(model, args) + + +def build_CNNMLP_model_and_optimizer(args_override): + args = _model_args(args_override) + model = build_CNNMLP_model(args).to(_device(args)) + return model, _optimizer(model, args) diff --git a/detr/models/__init__.py b/detr/models/__init__.py new file mode 100644 index 0000000..cc78db1 --- /dev/null +++ b/detr/models/__init__.py @@ -0,0 +1,9 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +from .detr_vae import build as build_vae +from .detr_vae import build_cnnmlp as build_cnnmlp + +def build_ACT_model(args): + return build_vae(args) + +def build_CNNMLP_model(args): + return build_cnnmlp(args) \ No newline at end of file diff --git a/detr/models/backbone.py b/detr/models/backbone.py new file mode 100644 index 0000000..0fc349a --- /dev/null +++ b/detr/models/backbone.py @@ -0,0 +1,127 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +""" +Backbone modules. +""" +from collections import OrderedDict + +import torch +import torch.nn.functional as F +import torchvision +from torch import nn +from torchvision.models._utils import IntermediateLayerGetter +from typing import Dict, List + +from ..util.misc import NestedTensor, is_main_process + +from .position_encoding import build_position_encoding + +class FrozenBatchNorm2d(torch.nn.Module): + """ + BatchNorm2d where the batch statistics and the affine parameters are fixed. + + Copy-paste from torchvision.misc.ops with added eps before rqsrt, + without which any other policy_models than torchvision.policy_models.resnet[18,34,50,101] + produce nans. + """ + + def __init__(self, n): + super(FrozenBatchNorm2d, self).__init__() + self.register_buffer("weight", torch.ones(n)) + self.register_buffer("bias", torch.zeros(n)) + self.register_buffer("running_mean", torch.zeros(n)) + self.register_buffer("running_var", torch.ones(n)) + + def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict, + missing_keys, unexpected_keys, error_msgs): + num_batches_tracked_key = prefix + 'num_batches_tracked' + if num_batches_tracked_key in state_dict: + del state_dict[num_batches_tracked_key] + + super(FrozenBatchNorm2d, self)._load_from_state_dict( + state_dict, prefix, local_metadata, strict, + missing_keys, unexpected_keys, error_msgs) + + def forward(self, x): + # move reshapes to the beginning + # to make it fuser-friendly + w = self.weight.reshape(1, -1, 1, 1) + b = self.bias.reshape(1, -1, 1, 1) + rv = self.running_var.reshape(1, -1, 1, 1) + rm = self.running_mean.reshape(1, -1, 1, 1) + eps = 1e-5 + scale = w * (rv + eps).rsqrt() + bias = b - rm * scale + return x * scale + bias + + +class BackboneBase(nn.Module): + + def __init__(self, backbone: nn.Module, train_backbone: bool, num_channels: int, return_interm_layers: bool): + super().__init__() + # for name, parameter in backbone.named_parameters(): # only train later layers # TODO do we want this? + # if not train_backbone or 'layer2' not in name and 'layer3' not in name and 'layer4' not in name: + # parameter.requires_grad_(False) + if return_interm_layers: + return_layers = {"layer1": "0", "layer2": "1", "layer3": "2", "layer4": "3"} + else: + return_layers = {'layer4': "0"} + self.body = IntermediateLayerGetter(backbone, return_layers=return_layers) + self.num_channels = num_channels + + def forward(self, tensor): + xs = self.body(tensor) + return xs + # out: Dict[str, NestedTensor] = {} + # for name, x in xs.items(): + # m = tensor_list.mask + # assert m is not None + # mask = F.interpolate(m[None].float(), size=x.shape[-2:]).to(torch.bool)[0] + # out[name] = NestedTensor(x, mask) + # return out + + +class Backbone(BackboneBase): + """ResNet backbone with frozen BatchNorm.""" + def __init__(self, name: str, + train_backbone: bool, + return_interm_layers: bool, + dilation: bool, + pretrained: bool = True): + backbone = getattr(torchvision.models, name)( + replace_stride_with_dilation=[False, False, dilation], + weights="DEFAULT" if pretrained and is_main_process() else None, + norm_layer=FrozenBatchNorm2d) + num_channels = 512 if name in ('resnet18', 'resnet34') else 2048 + super().__init__(backbone, train_backbone, num_channels, return_interm_layers) + + +class Joiner(nn.Sequential): + def __init__(self, backbone, position_embedding): + super().__init__(backbone, position_embedding) + + def forward(self, tensor_list: NestedTensor): + xs = self[0](tensor_list) + out: List[NestedTensor] = [] + pos = [] + for name, x in xs.items(): + out.append(x) + # position encoding + pos.append(self[1](x).to(x.dtype)) + + return out, pos + + +def build_backbone(args): + position_embedding = build_position_encoding(args) + train_backbone = args.lr_backbone > 0 + return_interm_layers = args.masks + backbone = Backbone( + args.backbone, + train_backbone, + return_interm_layers, + args.dilation, + pretrained=getattr(args, "pretrained_backbone", True), + ) + model = Joiner(backbone, position_embedding) + model.num_channels = backbone.num_channels + return model diff --git a/detr/models/detr_vae.py b/detr/models/detr_vae.py new file mode 100644 index 0000000..69e999c --- /dev/null +++ b/detr/models/detr_vae.py @@ -0,0 +1,274 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +""" +DETR model and criterion classes. +""" +import torch +from torch import nn +from torch.autograd import Variable +from .backbone import build_backbone +from .transformer import build_transformer, TransformerEncoder, TransformerEncoderLayer + +import numpy as np + + +def reparametrize(mu, logvar): + std = logvar.div(2).exp() + eps = Variable(std.data.new(std.size()).normal_()) + return mu + std * eps + + +def get_sinusoid_encoding_table(n_position, d_hid): + def get_position_angle_vec(position): + return [position / np.power(10000, 2 * (hid_j // 2) / d_hid) for hid_j in range(d_hid)] + + sinusoid_table = np.array([get_position_angle_vec(pos_i) for pos_i in range(n_position)]) + sinusoid_table[:, 0::2] = np.sin(sinusoid_table[:, 0::2]) # dim 2i + sinusoid_table[:, 1::2] = np.cos(sinusoid_table[:, 1::2]) # dim 2i+1 + + return torch.FloatTensor(sinusoid_table).unsqueeze(0) + + +class DETRVAE(nn.Module): + """ This is the DETR module that performs object detection """ + def __init__(self, backbones, transformer, encoder, state_dim, num_queries, camera_names): + """ Initializes the model. + Parameters: + backbones: torch module of the backbone to be used. See backbone.py + transformer: torch module of the transformer architecture. See transformer.py + state_dim: robot state dimension of the environment + num_queries: number of object queries, ie detection slot. This is the maximal number of objects + DETR can detect in a single image. For COCO, we recommend 100 queries. + aux_loss: True if auxiliary decoding losses (loss at each decoder layer) are to be used. + """ + super().__init__() + self.num_queries = num_queries + self.camera_names = camera_names + self.transformer = transformer + self.encoder = encoder + hidden_dim = transformer.d_model + self.action_head = nn.Linear(hidden_dim, state_dim) + self.is_pad_head = nn.Linear(hidden_dim, 1) + self.query_embed = nn.Embedding(num_queries, hidden_dim) + if backbones is not None: + self.input_proj = nn.Conv2d(backbones[0].num_channels, hidden_dim, kernel_size=1) + self.backbones = nn.ModuleList(backbones) + self.input_proj_robot_state = nn.Linear(14, hidden_dim) + else: + # input_dim = 14 + 7 # robot_state + env_state + self.input_proj_robot_state = nn.Linear(14, hidden_dim) + self.input_proj_env_state = nn.Linear(7, hidden_dim) + self.pos = torch.nn.Embedding(2, hidden_dim) + self.backbones = None + + # encoder extra parameters + self.latent_dim = 32 # final size of latent z # TODO tune + self.cls_embed = nn.Embedding(1, hidden_dim) # extra cls token embedding + self.encoder_action_proj = nn.Linear(14, hidden_dim) # project action to embedding + self.encoder_joint_proj = nn.Linear(14, hidden_dim) # project qpos to embedding + self.latent_proj = nn.Linear(hidden_dim, self.latent_dim*2) # project hidden state to latent std, var + self.register_buffer('pos_table', get_sinusoid_encoding_table(1+1+num_queries, hidden_dim)) # [CLS], qpos, a_seq + + # decoder extra parameters + self.latent_out_proj = nn.Linear(self.latent_dim, hidden_dim) # project latent sample to embedding + self.additional_pos_embed = nn.Embedding(2, hidden_dim) # learned position embedding for proprio and latent + + def forward(self, qpos, image, env_state, actions=None, is_pad=None): + """ + qpos: batch, qpos_dim + image: batch, num_cam, channel, height, width + env_state: None + actions: batch, seq, action_dim + """ + is_training = actions is not None # train or val + bs, _ = qpos.shape + ### Obtain latent z from action sequence + if is_training: + # project action sequence to embedding dim, and concat with a CLS token + action_embed = self.encoder_action_proj(actions) # (bs, seq, hidden_dim) + qpos_embed = self.encoder_joint_proj(qpos) # (bs, hidden_dim) + qpos_embed = torch.unsqueeze(qpos_embed, axis=1) # (bs, 1, hidden_dim) + cls_embed = self.cls_embed.weight # (1, hidden_dim) + cls_embed = torch.unsqueeze(cls_embed, axis=0).repeat(bs, 1, 1) # (bs, 1, hidden_dim) + encoder_input = torch.cat([cls_embed, qpos_embed, action_embed], axis=1) # (bs, seq+1, hidden_dim) + encoder_input = encoder_input.permute(1, 0, 2) # (seq+1, bs, hidden_dim) + # do not mask cls token + cls_joint_is_pad = torch.full((bs, 2), False).to(qpos.device) # False: not a padding + is_pad = torch.cat([cls_joint_is_pad, is_pad], axis=1) # (bs, seq+1) + # obtain position embedding + pos_embed = self.pos_table.clone().detach() + pos_embed = pos_embed.permute(1, 0, 2) # (seq+1, 1, hidden_dim) + # query model + encoder_output = self.encoder(encoder_input, pos=pos_embed, src_key_padding_mask=is_pad) + encoder_output = encoder_output[0] # take cls output only + latent_info = self.latent_proj(encoder_output) + mu = latent_info[:, :self.latent_dim] + logvar = latent_info[:, self.latent_dim:] + latent_sample = reparametrize(mu, logvar) + latent_input = self.latent_out_proj(latent_sample) + else: + mu = logvar = None + latent_sample = torch.zeros([bs, self.latent_dim], dtype=torch.float32).to(qpos.device) + latent_input = self.latent_out_proj(latent_sample) + + if self.backbones is not None: + # Image observation features and position embeddings + all_cam_features = [] + all_cam_pos = [] + for cam_id, cam_name in enumerate(self.camera_names): + features, pos = self.backbones[0](image[:, cam_id]) # HARDCODED + features = features[0] # take the last layer feature + pos = pos[0] + all_cam_features.append(self.input_proj(features)) + all_cam_pos.append(pos) + # proprioception features + proprio_input = self.input_proj_robot_state(qpos) + # fold camera dimension into width dimension + src = torch.cat(all_cam_features, axis=3) + pos = torch.cat(all_cam_pos, axis=3) + hs = self.transformer(src, None, self.query_embed.weight, pos, latent_input, proprio_input, self.additional_pos_embed.weight)[0] + else: + qpos = self.input_proj_robot_state(qpos) + env_state = self.input_proj_env_state(env_state) + transformer_input = torch.cat([qpos, env_state], axis=1) # seq length = 2 + hs = self.transformer(transformer_input, None, self.query_embed.weight, self.pos.weight)[0] + a_hat = self.action_head(hs) + is_pad_hat = self.is_pad_head(hs) + return a_hat, is_pad_hat, [mu, logvar] + + + +class CNNMLP(nn.Module): + def __init__(self, backbones, state_dim, camera_names): + """ Initializes the model. + Parameters: + backbones: torch module of the backbone to be used. See backbone.py + transformer: torch module of the transformer architecture. See transformer.py + state_dim: robot state dimension of the environment + num_queries: number of object queries, ie detection slot. This is the maximal number of objects + DETR can detect in a single image. For COCO, we recommend 100 queries. + aux_loss: True if auxiliary decoding losses (loss at each decoder layer) are to be used. + """ + super().__init__() + self.camera_names = camera_names + self.action_head = nn.Linear(1000, state_dim) # TODO add more + if backbones is not None: + self.backbones = nn.ModuleList(backbones) + backbone_down_projs = [] + for backbone in backbones: + down_proj = nn.Sequential( + nn.Conv2d(backbone.num_channels, 128, kernel_size=5), + nn.Conv2d(128, 64, kernel_size=5), + nn.Conv2d(64, 32, kernel_size=5) + ) + backbone_down_projs.append(down_proj) + self.backbone_down_projs = nn.ModuleList(backbone_down_projs) + + mlp_in_dim = 768 * len(backbones) + 14 + self.mlp = mlp(input_dim=mlp_in_dim, hidden_dim=1024, output_dim=14, hidden_depth=2) + else: + raise NotImplementedError + + def forward(self, qpos, image, env_state, actions=None): + """ + qpos: batch, qpos_dim + image: batch, num_cam, channel, height, width + env_state: None + actions: batch, seq, action_dim + """ + is_training = actions is not None # train or val + bs, _ = qpos.shape + # Image observation features and position embeddings + all_cam_features = [] + for cam_id, cam_name in enumerate(self.camera_names): + features, pos = self.backbones[cam_id](image[:, cam_id]) + features = features[0] # take the last layer feature + pos = pos[0] # not used + all_cam_features.append(self.backbone_down_projs[cam_id](features)) + # flatten everything + flattened_features = [] + for cam_feature in all_cam_features: + flattened_features.append(cam_feature.reshape([bs, -1])) + flattened_features = torch.cat(flattened_features, axis=1) # 768 each + features = torch.cat([flattened_features, qpos], axis=1) # qpos: 14 + a_hat = self.mlp(features) + return a_hat + + +def mlp(input_dim, hidden_dim, output_dim, hidden_depth): + if hidden_depth == 0: + mods = [nn.Linear(input_dim, output_dim)] + else: + mods = [nn.Linear(input_dim, hidden_dim), nn.ReLU(inplace=True)] + for i in range(hidden_depth - 1): + mods += [nn.Linear(hidden_dim, hidden_dim), nn.ReLU(inplace=True)] + mods.append(nn.Linear(hidden_dim, output_dim)) + trunk = nn.Sequential(*mods) + return trunk + + +def build_encoder(args): + d_model = args.hidden_dim # 256 + dropout = args.dropout # 0.1 + nhead = args.nheads # 8 + dim_feedforward = args.dim_feedforward # 2048 + num_encoder_layers = args.enc_layers # 4 # TODO shared with VAE decoder + normalize_before = args.pre_norm # False + activation = "relu" + + encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward, + dropout, activation, normalize_before) + encoder_norm = nn.LayerNorm(d_model) if normalize_before else None + encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm) + + return encoder + + +def build(args): + state_dim = 14 # TODO hardcode + + # From state + # backbone = None # from state for now, no need for conv nets + # From image + backbones = [] + backbone = build_backbone(args) + backbones.append(backbone) + + transformer = build_transformer(args) + + encoder = build_encoder(args) + + model = DETRVAE( + backbones, + transformer, + encoder, + state_dim=state_dim, + num_queries=args.num_queries, + camera_names=args.camera_names, + ) + + n_parameters = sum(p.numel() for p in model.parameters() if p.requires_grad) + print("number of parameters: %.2fM" % (n_parameters/1e6,)) + + return model + +def build_cnnmlp(args): + state_dim = 14 # TODO hardcode + + # From state + # backbone = None # from state for now, no need for conv nets + # From image + backbones = [] + for _ in args.camera_names: + backbone = build_backbone(args) + backbones.append(backbone) + + model = CNNMLP( + backbones, + state_dim=state_dim, + camera_names=args.camera_names, + ) + + n_parameters = sum(p.numel() for p in model.parameters() if p.requires_grad) + print("number of parameters: %.2fM" % (n_parameters/1e6,)) + + return model diff --git a/detr/models/position_encoding.py b/detr/models/position_encoding.py new file mode 100644 index 0000000..db455d9 --- /dev/null +++ b/detr/models/position_encoding.py @@ -0,0 +1,90 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +""" +Various positional encodings for the transformer. +""" +import math +import torch +from torch import nn + +from ..util.misc import NestedTensor + +class PositionEmbeddingSine(nn.Module): + """ + This is a more standard version of the position embedding, very similar to the one + used by the Attention is all you need paper, generalized to work on images. + """ + def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None): + super().__init__() + self.num_pos_feats = num_pos_feats + self.temperature = temperature + self.normalize = normalize + if scale is not None and normalize is False: + raise ValueError("normalize should be True if scale is passed") + if scale is None: + scale = 2 * math.pi + self.scale = scale + + def forward(self, tensor): + x = tensor + # mask = tensor_list.mask + # assert mask is not None + # not_mask = ~mask + + not_mask = torch.ones_like(x[0, [0]]) + y_embed = not_mask.cumsum(1, dtype=torch.float32) + x_embed = not_mask.cumsum(2, dtype=torch.float32) + if self.normalize: + eps = 1e-6 + y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale + x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale + + dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device) + dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats) + + pos_x = x_embed[:, :, :, None] / dim_t + pos_y = y_embed[:, :, :, None] / dim_t + pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3) + pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3) + pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2) + return pos + + +class PositionEmbeddingLearned(nn.Module): + """ + Absolute pos embedding, learned. + """ + def __init__(self, num_pos_feats=256): + super().__init__() + self.row_embed = nn.Embedding(50, num_pos_feats) + self.col_embed = nn.Embedding(50, num_pos_feats) + self.reset_parameters() + + def reset_parameters(self): + nn.init.uniform_(self.row_embed.weight) + nn.init.uniform_(self.col_embed.weight) + + def forward(self, tensor_list: NestedTensor): + x = tensor_list.tensors + h, w = x.shape[-2:] + i = torch.arange(w, device=x.device) + j = torch.arange(h, device=x.device) + x_emb = self.col_embed(i) + y_emb = self.row_embed(j) + pos = torch.cat([ + x_emb.unsqueeze(0).repeat(h, 1, 1), + y_emb.unsqueeze(1).repeat(1, w, 1), + ], dim=-1).permute(2, 0, 1).unsqueeze(0).repeat(x.shape[0], 1, 1, 1) + return pos + + +def build_position_encoding(args): + N_steps = args.hidden_dim // 2 + if args.position_embedding in ('v2', 'sine'): + # TODO find a better way of exposing other arguments + position_embedding = PositionEmbeddingSine(N_steps, normalize=True) + elif args.position_embedding in ('v3', 'learned'): + position_embedding = PositionEmbeddingLearned(N_steps) + else: + raise ValueError(f"not supported {args.position_embedding}") + + return position_embedding diff --git a/detr/models/transformer.py b/detr/models/transformer.py new file mode 100644 index 0000000..f14278e --- /dev/null +++ b/detr/models/transformer.py @@ -0,0 +1,311 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +""" +DETR Transformer class. + +Copy-paste from torch.nn.Transformer with modifications: + * positional encodings are passed in MHattention + * extra LN at the end of encoder is removed + * decoder returns a stack of activations from all decoding layers +""" +import copy +from typing import Optional, List + +import torch +import torch.nn.functional as F +from torch import nn, Tensor + +class Transformer(nn.Module): + + def __init__(self, d_model=512, nhead=8, num_encoder_layers=6, + num_decoder_layers=6, dim_feedforward=2048, dropout=0.1, + activation="relu", normalize_before=False, + return_intermediate_dec=False): + super().__init__() + + encoder_layer = TransformerEncoderLayer(d_model, nhead, dim_feedforward, + dropout, activation, normalize_before) + encoder_norm = nn.LayerNorm(d_model) if normalize_before else None + self.encoder = TransformerEncoder(encoder_layer, num_encoder_layers, encoder_norm) + + decoder_layer = TransformerDecoderLayer(d_model, nhead, dim_feedforward, + dropout, activation, normalize_before) + decoder_norm = nn.LayerNorm(d_model) + self.decoder = TransformerDecoder(decoder_layer, num_decoder_layers, decoder_norm, + return_intermediate=return_intermediate_dec) + + self._reset_parameters() + + self.d_model = d_model + self.nhead = nhead + + def _reset_parameters(self): + for p in self.parameters(): + if p.dim() > 1: + nn.init.xavier_uniform_(p) + + def forward(self, src, mask, query_embed, pos_embed, latent_input=None, proprio_input=None, additional_pos_embed=None): + # TODO flatten only when input has H and W + if len(src.shape) == 4: # has H and W + # flatten NxCxHxW to HWxNxC + bs, c, h, w = src.shape + src = src.flatten(2).permute(2, 0, 1) + pos_embed = pos_embed.flatten(2).permute(2, 0, 1).repeat(1, bs, 1) + query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1) + # mask = mask.flatten(1) + + additional_pos_embed = additional_pos_embed.unsqueeze(1).repeat(1, bs, 1) # seq, bs, dim + pos_embed = torch.cat([additional_pos_embed, pos_embed], axis=0) + + addition_input = torch.stack([latent_input, proprio_input], axis=0) + src = torch.cat([addition_input, src], axis=0) + else: + assert len(src.shape) == 3 + # flatten NxHWxC to HWxNxC + bs, hw, c = src.shape + src = src.permute(1, 0, 2) + pos_embed = pos_embed.unsqueeze(1).repeat(1, bs, 1) + query_embed = query_embed.unsqueeze(1).repeat(1, bs, 1) + + tgt = torch.zeros_like(query_embed) + memory = self.encoder(src, src_key_padding_mask=mask, pos=pos_embed) + hs = self.decoder(tgt, memory, memory_key_padding_mask=mask, + pos=pos_embed, query_pos=query_embed) + hs = hs.transpose(1, 2) + return hs + +class TransformerEncoder(nn.Module): + + def __init__(self, encoder_layer, num_layers, norm=None): + super().__init__() + self.layers = _get_clones(encoder_layer, num_layers) + self.num_layers = num_layers + self.norm = norm + + def forward(self, src, + mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + output = src + + for layer in self.layers: + output = layer(output, src_mask=mask, + src_key_padding_mask=src_key_padding_mask, pos=pos) + + if self.norm is not None: + output = self.norm(output) + + return output + + +class TransformerDecoder(nn.Module): + + def __init__(self, decoder_layer, num_layers, norm=None, return_intermediate=False): + super().__init__() + self.layers = _get_clones(decoder_layer, num_layers) + self.num_layers = num_layers + self.norm = norm + self.return_intermediate = return_intermediate + + def forward(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + output = tgt + + intermediate = [] + + for layer in self.layers: + output = layer(output, memory, tgt_mask=tgt_mask, + memory_mask=memory_mask, + tgt_key_padding_mask=tgt_key_padding_mask, + memory_key_padding_mask=memory_key_padding_mask, + pos=pos, query_pos=query_pos) + if self.return_intermediate: + intermediate.append(self.norm(output)) + + if self.norm is not None: + output = self.norm(output) + if self.return_intermediate: + intermediate.pop() + intermediate.append(output) + + if self.return_intermediate: + return torch.stack(intermediate) + + return output.unsqueeze(0) + + +class TransformerEncoderLayer(nn.Module): + + def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1, + activation="relu", normalize_before=False): + super().__init__() + self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) + # Implementation of Feedforward model + self.linear1 = nn.Linear(d_model, dim_feedforward) + self.dropout = nn.Dropout(dropout) + self.linear2 = nn.Linear(dim_feedforward, d_model) + + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.dropout1 = nn.Dropout(dropout) + self.dropout2 = nn.Dropout(dropout) + + self.activation = _get_activation_fn(activation) + self.normalize_before = normalize_before + + def with_pos_embed(self, tensor, pos: Optional[Tensor]): + return tensor if pos is None else tensor + pos + + def forward_post(self, + src, + src_mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + q = k = self.with_pos_embed(src, pos) + src2 = self.self_attn(q, k, value=src, attn_mask=src_mask, + key_padding_mask=src_key_padding_mask)[0] + src = src + self.dropout1(src2) + src = self.norm1(src) + src2 = self.linear2(self.dropout(self.activation(self.linear1(src)))) + src = src + self.dropout2(src2) + src = self.norm2(src) + return src + + def forward_pre(self, src, + src_mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + src2 = self.norm1(src) + q = k = self.with_pos_embed(src2, pos) + src2 = self.self_attn(q, k, value=src2, attn_mask=src_mask, + key_padding_mask=src_key_padding_mask)[0] + src = src + self.dropout1(src2) + src2 = self.norm2(src) + src2 = self.linear2(self.dropout(self.activation(self.linear1(src2)))) + src = src + self.dropout2(src2) + return src + + def forward(self, src, + src_mask: Optional[Tensor] = None, + src_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None): + if self.normalize_before: + return self.forward_pre(src, src_mask, src_key_padding_mask, pos) + return self.forward_post(src, src_mask, src_key_padding_mask, pos) + + +class TransformerDecoderLayer(nn.Module): + + def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1, + activation="relu", normalize_before=False): + super().__init__() + self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) + self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout) + # Implementation of Feedforward model + self.linear1 = nn.Linear(d_model, dim_feedforward) + self.dropout = nn.Dropout(dropout) + self.linear2 = nn.Linear(dim_feedforward, d_model) + + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.norm3 = nn.LayerNorm(d_model) + self.dropout1 = nn.Dropout(dropout) + self.dropout2 = nn.Dropout(dropout) + self.dropout3 = nn.Dropout(dropout) + + self.activation = _get_activation_fn(activation) + self.normalize_before = normalize_before + + def with_pos_embed(self, tensor, pos: Optional[Tensor]): + return tensor if pos is None else tensor + pos + + def forward_post(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + q = k = self.with_pos_embed(tgt, query_pos) + tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask, + key_padding_mask=tgt_key_padding_mask)[0] + tgt = tgt + self.dropout1(tgt2) + tgt = self.norm1(tgt) + tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos), + key=self.with_pos_embed(memory, pos), + value=memory, attn_mask=memory_mask, + key_padding_mask=memory_key_padding_mask)[0] + tgt = tgt + self.dropout2(tgt2) + tgt = self.norm2(tgt) + tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt)))) + tgt = tgt + self.dropout3(tgt2) + tgt = self.norm3(tgt) + return tgt + + def forward_pre(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + tgt2 = self.norm1(tgt) + q = k = self.with_pos_embed(tgt2, query_pos) + tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask, + key_padding_mask=tgt_key_padding_mask)[0] + tgt = tgt + self.dropout1(tgt2) + tgt2 = self.norm2(tgt) + tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt2, query_pos), + key=self.with_pos_embed(memory, pos), + value=memory, attn_mask=memory_mask, + key_padding_mask=memory_key_padding_mask)[0] + tgt = tgt + self.dropout2(tgt2) + tgt2 = self.norm3(tgt) + tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2)))) + tgt = tgt + self.dropout3(tgt2) + return tgt + + def forward(self, tgt, memory, + tgt_mask: Optional[Tensor] = None, + memory_mask: Optional[Tensor] = None, + tgt_key_padding_mask: Optional[Tensor] = None, + memory_key_padding_mask: Optional[Tensor] = None, + pos: Optional[Tensor] = None, + query_pos: Optional[Tensor] = None): + if self.normalize_before: + return self.forward_pre(tgt, memory, tgt_mask, memory_mask, + tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos) + return self.forward_post(tgt, memory, tgt_mask, memory_mask, + tgt_key_padding_mask, memory_key_padding_mask, pos, query_pos) + + +def _get_clones(module, N): + return nn.ModuleList([copy.deepcopy(module) for i in range(N)]) + + +def build_transformer(args): + return Transformer( + d_model=args.hidden_dim, + dropout=args.dropout, + nhead=args.nheads, + dim_feedforward=args.dim_feedforward, + num_encoder_layers=args.enc_layers, + num_decoder_layers=args.dec_layers, + normalize_before=args.pre_norm, + return_intermediate_dec=True, + ) + + +def _get_activation_fn(activation): + """Return an activation function given a string""" + if activation == "relu": + return F.relu + if activation == "gelu": + return F.gelu + if activation == "glu": + return F.glu + raise RuntimeError(F"activation should be relu/gelu, not {activation}.") diff --git a/detr/util/__init__.py b/detr/util/__init__.py new file mode 100644 index 0000000..168f997 --- /dev/null +++ b/detr/util/__init__.py @@ -0,0 +1 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved diff --git a/detr/util/misc.py b/detr/util/misc.py new file mode 100644 index 0000000..dfa9fb5 --- /dev/null +++ b/detr/util/misc.py @@ -0,0 +1,468 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +""" +Misc functions, including distributed helpers. + +Mostly copy-paste from torchvision references. +""" +import os +import subprocess +import time +from collections import defaultdict, deque +import datetime +import pickle +from packaging import version +from typing import Optional, List + +import torch +import torch.distributed as dist +from torch import Tensor + +# needed due to empty tensor bug in pytorch and torchvision 0.5 +import torchvision +if version.parse(torchvision.__version__) < version.parse('0.7'): + from torchvision.ops import _new_empty_tensor + from torchvision.ops.misc import _output_size + + +class SmoothedValue(object): + """Track a series of values and provide access to smoothed values over a + window or the global series average. + """ + + def __init__(self, window_size=20, fmt=None): + if fmt is None: + fmt = "{median:.4f} ({global_avg:.4f})" + self.deque = deque(maxlen=window_size) + self.total = 0.0 + self.count = 0 + self.fmt = fmt + + def update(self, value, n=1): + self.deque.append(value) + self.count += n + self.total += value * n + + def synchronize_between_processes(self): + """ + Warning: does not synchronize the deque! + """ + if not is_dist_avail_and_initialized(): + return + t = torch.tensor([self.count, self.total], dtype=torch.float64, device='cuda') + dist.barrier() + dist.all_reduce(t) + t = t.tolist() + self.count = int(t[0]) + self.total = t[1] + + @property + def median(self): + d = torch.tensor(list(self.deque)) + return d.median().item() + + @property + def avg(self): + d = torch.tensor(list(self.deque), dtype=torch.float32) + return d.mean().item() + + @property + def global_avg(self): + return self.total / self.count + + @property + def max(self): + return max(self.deque) + + @property + def value(self): + return self.deque[-1] + + def __str__(self): + return self.fmt.format( + median=self.median, + avg=self.avg, + global_avg=self.global_avg, + max=self.max, + value=self.value) + + +def all_gather(data): + """ + Run all_gather on arbitrary picklable data (not necessarily tensors) + Args: + data: any picklable object + Returns: + list[data]: list of data gathered from each rank + """ + world_size = get_world_size() + if world_size == 1: + return [data] + + # serialized to a Tensor + buffer = pickle.dumps(data) + storage = torch.ByteStorage.from_buffer(buffer) + tensor = torch.ByteTensor(storage).to("cuda") + + # obtain Tensor size of each rank + local_size = torch.tensor([tensor.numel()], device="cuda") + size_list = [torch.tensor([0], device="cuda") for _ in range(world_size)] + dist.all_gather(size_list, local_size) + size_list = [int(size.item()) for size in size_list] + max_size = max(size_list) + + # receiving Tensor from all ranks + # we pad the tensor because torch all_gather does not support + # gathering tensors of different shapes + tensor_list = [] + for _ in size_list: + tensor_list.append(torch.empty((max_size,), dtype=torch.uint8, device="cuda")) + if local_size != max_size: + padding = torch.empty(size=(max_size - local_size,), dtype=torch.uint8, device="cuda") + tensor = torch.cat((tensor, padding), dim=0) + dist.all_gather(tensor_list, tensor) + + data_list = [] + for size, tensor in zip(size_list, tensor_list): + buffer = tensor.cpu().numpy().tobytes()[:size] + data_list.append(pickle.loads(buffer)) + + return data_list + + +def reduce_dict(input_dict, average=True): + """ + Args: + input_dict (dict): all the values will be reduced + average (bool): whether to do average or sum + Reduce the values in the dictionary from all processes so that all processes + have the averaged results. Returns a dict with the same fields as + input_dict, after reduction. + """ + world_size = get_world_size() + if world_size < 2: + return input_dict + with torch.no_grad(): + names = [] + values = [] + # sort the keys so that they are consistent across processes + for k in sorted(input_dict.keys()): + names.append(k) + values.append(input_dict[k]) + values = torch.stack(values, dim=0) + dist.all_reduce(values) + if average: + values /= world_size + reduced_dict = {k: v for k, v in zip(names, values)} + return reduced_dict + + +class MetricLogger(object): + def __init__(self, delimiter="\t"): + self.meters = defaultdict(SmoothedValue) + self.delimiter = delimiter + + def update(self, **kwargs): + for k, v in kwargs.items(): + if isinstance(v, torch.Tensor): + v = v.item() + assert isinstance(v, (float, int)) + self.meters[k].update(v) + + def __getattr__(self, attr): + if attr in self.meters: + return self.meters[attr] + if attr in self.__dict__: + return self.__dict__[attr] + raise AttributeError("'{}' object has no attribute '{}'".format( + type(self).__name__, attr)) + + def __str__(self): + loss_str = [] + for name, meter in self.meters.items(): + loss_str.append( + "{}: {}".format(name, str(meter)) + ) + return self.delimiter.join(loss_str) + + def synchronize_between_processes(self): + for meter in self.meters.values(): + meter.synchronize_between_processes() + + def add_meter(self, name, meter): + self.meters[name] = meter + + def log_every(self, iterable, print_freq, header=None): + i = 0 + if not header: + header = '' + start_time = time.time() + end = time.time() + iter_time = SmoothedValue(fmt='{avg:.4f}') + data_time = SmoothedValue(fmt='{avg:.4f}') + space_fmt = ':' + str(len(str(len(iterable)))) + 'd' + if torch.cuda.is_available(): + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}', + 'max mem: {memory:.0f}' + ]) + else: + log_msg = self.delimiter.join([ + header, + '[{0' + space_fmt + '}/{1}]', + 'eta: {eta}', + '{meters}', + 'time: {time}', + 'data: {data}' + ]) + MB = 1024.0 * 1024.0 + for obj in iterable: + data_time.update(time.time() - end) + yield obj + iter_time.update(time.time() - end) + if i % print_freq == 0 or i == len(iterable) - 1: + eta_seconds = iter_time.global_avg * (len(iterable) - i) + eta_string = str(datetime.timedelta(seconds=int(eta_seconds))) + if torch.cuda.is_available(): + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time), + memory=torch.cuda.max_memory_allocated() / MB)) + else: + print(log_msg.format( + i, len(iterable), eta=eta_string, + meters=str(self), + time=str(iter_time), data=str(data_time))) + i += 1 + end = time.time() + total_time = time.time() - start_time + total_time_str = str(datetime.timedelta(seconds=int(total_time))) + print('{} Total time: {} ({:.4f} s / it)'.format( + header, total_time_str, total_time / len(iterable))) + + +def get_sha(): + cwd = os.path.dirname(os.path.abspath(__file__)) + + def _run(command): + return subprocess.check_output(command, cwd=cwd).decode('ascii').strip() + sha = 'N/A' + diff = "clean" + branch = 'N/A' + try: + sha = _run(['git', 'rev-parse', 'HEAD']) + subprocess.check_output(['git', 'diff'], cwd=cwd) + diff = _run(['git', 'diff-index', 'HEAD']) + diff = "has uncommited changes" if diff else "clean" + branch = _run(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) + except Exception: + pass + message = f"sha: {sha}, status: {diff}, branch: {branch}" + return message + + +def collate_fn(batch): + batch = list(zip(*batch)) + batch[0] = nested_tensor_from_tensor_list(batch[0]) + return tuple(batch) + + +def _max_by_axis(the_list): + # type: (List[List[int]]) -> List[int] + maxes = the_list[0] + for sublist in the_list[1:]: + for index, item in enumerate(sublist): + maxes[index] = max(maxes[index], item) + return maxes + + +class NestedTensor(object): + def __init__(self, tensors, mask: Optional[Tensor]): + self.tensors = tensors + self.mask = mask + + def to(self, device): + # type: (Device) -> NestedTensor # noqa + cast_tensor = self.tensors.to(device) + mask = self.mask + if mask is not None: + assert mask is not None + cast_mask = mask.to(device) + else: + cast_mask = None + return NestedTensor(cast_tensor, cast_mask) + + def decompose(self): + return self.tensors, self.mask + + def __repr__(self): + return str(self.tensors) + + +def nested_tensor_from_tensor_list(tensor_list: List[Tensor]): + # TODO make this more general + if tensor_list[0].ndim == 3: + if torchvision._is_tracing(): + # nested_tensor_from_tensor_list() does not export well to ONNX + # call _onnx_nested_tensor_from_tensor_list() instead + return _onnx_nested_tensor_from_tensor_list(tensor_list) + + # TODO make it support different-sized images + max_size = _max_by_axis([list(img.shape) for img in tensor_list]) + # min_size = tuple(min(s) for s in zip(*[img.shape for img in tensor_list])) + batch_shape = [len(tensor_list)] + max_size + b, c, h, w = batch_shape + dtype = tensor_list[0].dtype + device = tensor_list[0].device + tensor = torch.zeros(batch_shape, dtype=dtype, device=device) + mask = torch.ones((b, h, w), dtype=torch.bool, device=device) + for img, pad_img, m in zip(tensor_list, tensor, mask): + pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img) + m[: img.shape[1], :img.shape[2]] = False + else: + raise ValueError('not supported') + return NestedTensor(tensor, mask) + + +# _onnx_nested_tensor_from_tensor_list() is an implementation of +# nested_tensor_from_tensor_list() that is supported by ONNX tracing. +@torch.jit.unused +def _onnx_nested_tensor_from_tensor_list(tensor_list: List[Tensor]) -> NestedTensor: + max_size = [] + for i in range(tensor_list[0].dim()): + max_size_i = torch.max(torch.stack([img.shape[i] for img in tensor_list]).to(torch.float32)).to(torch.int64) + max_size.append(max_size_i) + max_size = tuple(max_size) + + # work around for + # pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img) + # m[: img.shape[1], :img.shape[2]] = False + # which is not yet supported in onnx + padded_imgs = [] + padded_masks = [] + for img in tensor_list: + padding = [(s1 - s2) for s1, s2 in zip(max_size, tuple(img.shape))] + padded_img = torch.nn.functional.pad(img, (0, padding[2], 0, padding[1], 0, padding[0])) + padded_imgs.append(padded_img) + + m = torch.zeros_like(img[0], dtype=torch.int, device=img.device) + padded_mask = torch.nn.functional.pad(m, (0, padding[2], 0, padding[1]), "constant", 1) + padded_masks.append(padded_mask.to(torch.bool)) + + tensor = torch.stack(padded_imgs) + mask = torch.stack(padded_masks) + + return NestedTensor(tensor, mask=mask) + + +def setup_for_distributed(is_master): + """ + This function disables printing when not in master process + """ + import builtins as __builtin__ + builtin_print = __builtin__.print + + def print(*args, **kwargs): + force = kwargs.pop('force', False) + if is_master or force: + builtin_print(*args, **kwargs) + + __builtin__.print = print + + +def is_dist_avail_and_initialized(): + if not dist.is_available(): + return False + if not dist.is_initialized(): + return False + return True + + +def get_world_size(): + if not is_dist_avail_and_initialized(): + return 1 + return dist.get_world_size() + + +def get_rank(): + if not is_dist_avail_and_initialized(): + return 0 + return dist.get_rank() + + +def is_main_process(): + return get_rank() == 0 + + +def save_on_master(*args, **kwargs): + if is_main_process(): + torch.save(*args, **kwargs) + + +def init_distributed_mode(args): + if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ: + args.rank = int(os.environ["RANK"]) + args.world_size = int(os.environ['WORLD_SIZE']) + args.gpu = int(os.environ['LOCAL_RANK']) + elif 'SLURM_PROCID' in os.environ: + args.rank = int(os.environ['SLURM_PROCID']) + args.gpu = args.rank % torch.cuda.device_count() + else: + print('Not using distributed mode') + args.distributed = False + return + + args.distributed = True + + torch.cuda.set_device(args.gpu) + args.dist_backend = 'nccl' + print('| distributed init (rank {}): {}'.format( + args.rank, args.dist_url), flush=True) + torch.distributed.init_process_group(backend=args.dist_backend, init_method=args.dist_url, + world_size=args.world_size, rank=args.rank) + torch.distributed.barrier() + setup_for_distributed(args.rank == 0) + + +@torch.no_grad() +def accuracy(output, target, topk=(1,)): + """Computes the precision@k for the specified values of k""" + if target.numel() == 0: + return [torch.zeros([], device=output.device)] + maxk = max(topk) + batch_size = target.size(0) + + _, pred = output.topk(maxk, 1, True, True) + pred = pred.t() + correct = pred.eq(target.view(1, -1).expand_as(pred)) + + res = [] + for k in topk: + correct_k = correct[:k].view(-1).float().sum(0) + res.append(correct_k.mul_(100.0 / batch_size)) + return res + + +def interpolate(input, size=None, scale_factor=None, mode="nearest", align_corners=None): + # type: (Tensor, Optional[List[int]], Optional[float], str, Optional[bool]) -> Tensor + """ + Equivalent to nn.functional.interpolate, but with support for empty batch sizes. + This will eventually be supported natively by PyTorch, and this + class can go away. + """ + if version.parse(torchvision.__version__) < version.parse('0.7'): + if input.numel() > 0: + return torch.nn.functional.interpolate( + input, size, scale_factor, mode, align_corners + ) + + output_shape = _output_size(2, input, size, scale_factor) + output_shape = list(input.shape[:-2]) + list(output_shape) + return _new_empty_tensor(input, output_shape) + else: + return torchvision.ops.misc.interpolate(input, size, scale_factor, mode, align_corners) diff --git a/docs/EXTERNAL_POLICIES.md b/docs/EXTERNAL_POLICIES.md new file mode 100644 index 0000000..d85f0f0 --- /dev/null +++ b/docs/EXTERNAL_POLICIES.md @@ -0,0 +1,147 @@ +# External task-policy integration + +SpeedTuning treats the task policy and speed policy as independent components. +An external task policy supplies robot action chunks; the speed policy chooses +how quickly those chunks are executed. + +This integration is optional. The bundled scripted policies are sufficient for +the from-scratch simulation reproduction. + +## Python interface + +A task policy must be callable, or define `predict_chunk(observation)`, and +return joint actions with shape `[time, 14]`. Outputs shaped `[1, time, 14]`, +PyTorch tensors, and dictionaries containing `actions`, `action`, or `chunk` are +normalized automatically. + +```python +from policy_speed_env import create_speed_env +from speed_policy import FixedSpeedPolicy, rollout_speed_policy + + +class MyChunkPolicy: + def reset(self): + pass + + def predict_chunk(self, observation): + return model(observation) + + +env = create_speed_env( + "insertion", + chunk_predictor=MyChunkPolicy(), + seed=0, +) +result = rollout_speed_policy(env, FixedSpeedPolicy(1.5)) +``` + +At each speed-policy decision, the environment requests a fresh receding-horizon +chunk, interpolates it at the selected speed, and holds that speed for the +configured frame-skip block. A short chunk is safely replanned as needed. + +`TorchChunkPredictor` in `chunked_policy.py` provides normalization and tensor +handling for ACT-style models. + +## CLI factory + +Expose a factory in the external policy package: + +```python +# my_policy/integration.py +def build_policy(task_name, checkpoint, device): + return MyChunkPolicy.load(checkpoint, task=task_name, device=device) +``` + +Install that package in the SpeedTuning environment, then reference the factory +as `module:attribute`: + +```bash +uv run speedtuning-eval-speed \ + --task insertion \ + --base-policy external-chunk \ + --chunk-policy my_policy.integration:build_policy \ + --upstream-checkpoint /path/to/upstream.pt \ + --speed-policy fixed --speed 1.5 \ + --episodes 10 +``` + +The factory may accept any subset of `task_name`, `checkpoint`, `device`, and +keys supplied through `--factory-kwargs`. + +Training uses the same task-policy flags: + +```bash +uv run speedtuning-train-speed \ + --task insertion \ + --base-policy external-chunk \ + --chunk-policy my_policy.integration:build_policy \ + --upstream-checkpoint /path/to/upstream.pt \ + --output outputs/insertion_speed.pt +``` + +## Retained ACT integration + +Install the learned-policy dependencies: + +```bash +uv sync --extra rl --extra learned +``` + +The retained ACT loader accepts checkpoints containing `model_state_dict`, +`policy_config`, and normalization arrays under `stats`. The required statistics +are `qpos_mean`, `qpos_std`, `action_mean`, and `action_std`. They may instead be +provided in an `.npz`, JSON, or legacy pickle file. + +```bash +uv run speedtuning-eval-speed \ + --task insertion \ + --base-policy external-chunk \ + --chunk-policy act_integration:build_act_chunk_predictor \ + --upstream-checkpoint /path/to/act.pt \ + --factory-kwargs '{"stats_path":"/path/to/dataset_stats.npz"}' \ + --speed-policy fixed --speed 1.5 \ + --episodes 10 +``` + +ACT checkpoints and legacy pickle statistics require Python pickle loading. Only +load files created locally or obtained from a trusted source. Rainbow speed +checkpoints produced by this repository use PyTorch's restricted weight loader. + +## Speed-policy observations + +The speed learner supports: + +- `--speed-observation state` for selected simulator and proprioceptive fields; +- `--speed-observation visual` for joint state plus encoded camera images; +- `--speed-observation external` for a custom feature encoder. + +Use `--no-env-state` to remove privileged simulator state. Visual runs support +pretrained or randomly initialized ResNet-18 encoders, configurable cameras, and +frame stacking. Encoder state and preprocessing metadata are saved in the local +Rainbow checkpoint so evaluation cannot silently change them. + +The retained ACT backbone can be used through: + +```text +--speed-observation external \ +--observation-encoder-loader act_integration:build_act_observation_encoder +``` + +## Archival paper configuration + +The `paper-sim` preset records the visual observation and speed-action settings +recoverable from the paper and retained experiment names. It requires an +external task-policy checkpoint and is provided as an archival starting point, +not an exact numerical reproduction claim. + +```bash +uv run speedtuning-train-speed \ + --config paper-sim \ + --task tea_bag \ + --chunk-policy my_policy.integration:build_policy \ + --upstream-checkpoint /path/to/task_policy.pt \ + --output outputs/tea_bag_speed.pt +``` + +The JSON manifests under `configs/ablations/` cover the observation, reward, +frame-skip, image-encoder, and task-policy ablations retained for research use. diff --git a/docs/SCRIPTED_REPRODUCTION.md b/docs/SCRIPTED_REPRODUCTION.md new file mode 100644 index 0000000..cd172c1 --- /dev/null +++ b/docs/SCRIPTED_REPRODUCTION.md @@ -0,0 +1,154 @@ +# Scripted-policy simulation reproduction + +This guide reproduces the simulation methodology from *SpeedTuning: Speeding Up +Policy Execution with Lightweight Reinforcement Learning* using the three task +policies included in the repository. + +No pretrained model is required. Rainbow DQN learns the execution-speed policy +from scratch, and all generated checkpoints and reports stay under the ignored +`outputs/` directory. + +## Method + +The public presets use the retained scripted-policy training recipe: + +- state observations containing object state, joint position, and joint velocity; +- one speed decision every 10 MuJoCo physics steps; +- reward `0.01 * speed**2` per physics step and 100 for terminal success; +- categorical dueling Double DQN with NoisyNet, prioritized replay, and 3-step + returns; +- one optimizer update per speed decision, applied at episode boundaries; +- 100,000 speed decisions with periodic local checkpoints. + +Task-specific presets expose appropriate discrete speed ranges: + +| Task | Preset | Speed range | +| --- | --- | --- | +| Pick-and-place | `scripted-pick-and-place` | 1.0x-4.5x | +| Insertion | `scripted-insertion` | 1.0x-3.0x | +| Tea bag | `scripted-tea-bag` | 1.0x-3.0x | +| Tea bag, randomized poses | `scripted-tea-bag-randomized` | 1.0x-3.0x | + +The complete hyperparameters are versioned in `configs/`. Command-line options +can override them for ablations or short smoke runs. + +## Install and verify + +```bash +uv sync --extra rl --extra test +MUJOCO_GL=egl uv run pytest -q +MUJOCO_GL=egl uv run speedtuning-sim +``` + +`MUJOCO_GL=egl` enables headless rendering on Linux. Depending on the platform, +DM Control may select a suitable backend without it. + +## Train + +Run each task separately because every task has its own speed policy: + +```bash +MUJOCO_GL=egl uv run speedtuning-train-speed \ + --config scripted-pick-and-place --task pick_and_place \ + --output outputs/pick_and_place_speed.pt \ + --report outputs/pick_and_place_speed.training.json --quiet + +MUJOCO_GL=egl uv run speedtuning-train-speed \ + --config scripted-insertion --task insertion \ + --output outputs/insertion_speed.pt \ + --report outputs/insertion_speed.training.json --quiet + +MUJOCO_GL=egl uv run speedtuning-train-speed \ + --config scripted-tea-bag --task tea_bag \ + --output outputs/tea_bag_speed.pt \ + --report outputs/tea_bag_speed.training.json --quiet +``` + +Training defaults to CPU. Add `--device cuda` on a CUDA machine. Hardware changes +runtime, but it does not change the simulator protocol or reported acceleration +metric. + +The presets write a snapshot every 10,000 decisions. Checkpoint metadata records +the task, pose protocol, speed actions, observation preprocessing, and training +configuration. Evaluation rejects an incompatible task or protocol. + +## Evaluate + +Evaluate held-out initial poses by choosing a starting seed and episode count: + +```bash +MUJOCO_GL=egl uv run speedtuning-eval-speed \ + --config scripted-pick-and-place --task pick_and_place \ + --speed-policy rainbow \ + --speed-checkpoint outputs/pick_and_place_speed.pt \ + --seed 100 --episodes 100 +``` + +Compare against a fixed speed on the same seeds: + +```bash +MUJOCO_GL=egl uv run speedtuning-eval-speed \ + --config scripted-pick-and-place --task pick_and_place \ + --speed-policy fixed --speed 3.856 \ + --seed 100 --episodes 100 +``` + +For a complete fixed-speed frontier: + +```bash +MUJOCO_GL=egl uv run speedtuning-sweep \ + --config scripted-pick-and-place --task pick_and_place \ + --speed-start 1.0 --speed-stop 4.5 --speed-step 0.25 \ + --episodes-per-speed 100 \ + --output outputs/pick_and_place_sweep.json +``` + +Physical acceleration is the nominal task horizon divided by executed MuJoCo +steps. Failed rollouts remain in the success-rate and acceleration summaries. + +## Tea-bag protocols + +The retained tea-bag environment has one fixed initial object pose. It is useful +for matching the historical scripted-policy experiment, but repeated seeds are +intentionally identical. + +Use `scripted-tea-bag-randomized` when a distribution of initial poses is needed: + +```bash +MUJOCO_GL=egl uv run speedtuning-train-speed \ + --config scripted-tea-bag-randomized --task tea_bag --seed 1 \ + --output outputs/tea_bag_randomized_speed.pt --quiet + +MUJOCO_GL=egl uv run speedtuning-eval-speed \ + --config scripted-tea-bag-randomized --task tea_bag \ + --speed-policy rainbow \ + --speed-checkpoint outputs/tea_bag_randomized_speed.pt \ + --seed 100 --episodes 100 +``` + +Do not evaluate a fixed-pose checkpoint under the randomized protocol or vice +versa; the observation distribution and normalization differ. + +## Reference results + +One seeded run using the protocol above produced: + +| Protocol | Learned speed | Matched fixed speed | +| --- | --- | --- | +| Pick-and-place, seeds 100-199 | 98% at 3.856x | 66% at 3.846x | +| Insertion, seeds 100-199 | 97% at 2.387x | 52% at 2.381x | +| Tea bag, randomized seeds 100-199 | 78% at 2.077x | 24% at 2.075x | + +The machine-readable record is +[`benchmarks/scripted_results.json`](../benchmarks/scripted_results.json). +Reinforcement learning is stochastic, so compare reruns at the level of success +and acceleration trends rather than exact decimal equality. + +## Scope + +This workflow reproduces speed-policy learning, temporal acceleration, sparse +success, fixed-speed baselines, and seeded simulation evaluation. It does not +include real-robot execution, datasets, or learned task-policy checkpoints. + +See [External task-policy integration](EXTERNAL_POLICIES.md) to wrap ACT or +another action-chunk policy. diff --git a/docs/assets/speedtuning_teaser.png b/docs/assets/speedtuning_teaser.png new file mode 100644 index 0000000000000000000000000000000000000000..bee7b59049054e9218ccf875ea1a470eecce881e GIT binary patch literal 219511 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®2IF5>&0=&wRt#C!=s-s+CcscBY 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

  1. (x*Hg6?O|)&RWx(bhwHGZD5<5bu`BX?#Og#%T&P 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 NNJ+?vSBdHQ|33l&j9&l% literal 0 HcmV?d00001 diff --git a/ee_sim_env.py b/ee_sim_env.py new file mode 100644 index 0000000..8c145af --- /dev/null +++ b/ee_sim_env.py @@ -0,0 +1,235 @@ +"""MuJoCo environments controlled by left and right end-effector poses.""" + +from __future__ import annotations + +import collections +import os + +import numpy as np +from dm_control import mujoco +from dm_control.rl import control +from dm_control.suite import base + +from constants import ( + DT, + PUPPET_GRIPPER_POSITION_CLOSE, + PUPPET_GRIPPER_POSITION_NORMALIZE_FN, + PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN, + PUPPET_GRIPPER_VELOCITY_NORMALIZE_FN, + START_ARM_POSE, + XML_DIR, +) +from sim_tasks import ( + get_task_spec, + insertion_reward, + normalize_task_name, + sample_box_pose, + sample_insertion_pose, + tea_bag_reward, + transfer_cube_reward, +) + + +# Kept for compatibility with the historical scripts. New code should pass +# render_images=False to make_ee_sim_env instead. +DISABLE_RENDER = [False] + + +def make_ee_sim_env( + task_name: str, + render_images: bool = True, + seed: int | None = None, + object_pose=None, + randomize_object_pose: bool = False, +): + """Create an end-effector-control environment for a SpeedTuning sim task. + + Actions contain two 8D commands: xyz, quaternion, and normalized gripper + position for the left arm, followed by the same fields for the right arm. + The factory accepts both the public task names (``pick_and_place``, + ``insertion``, ``tea_bag``) and the task names used by the historical code. + """ + + task_name = normalize_task_name(task_name) + spec = get_task_spec(task_name) + physics = mujoco.Physics.from_xml_path(os.path.join(XML_DIR, spec.ee_xml)) + random_state = np.random.RandomState(seed) + task_classes = { + "pick_and_place": TransferCubeEETask, + "insertion": InsertionEETask, + "tea_bag": TransferTeaBagEETask, + } + task = task_classes[task_name]( + random=random_state, + render_images=render_images, + object_pose=object_pose, + randomize_object_pose=randomize_object_pose, + ) + return control.Environment( + physics, + task, + time_limit=20, + control_timestep=DT, + n_sub_steps=None, + flat_observation=False, + ) + + +class BimanualViperXEETask(base.Task): + def __init__( + self, + random=None, + render_images: bool = True, + object_pose=None, + randomize_object_pose: bool = False, + ): + super().__init__(random=random) + self.render_images = render_images + self.object_pose = ( + None if object_pose is None else np.asarray(object_pose).copy() + ) + self.randomize_object_pose = bool(randomize_object_pose) + + def before_step(self, action, physics): + action = np.asarray(action, dtype=np.float64) + if action.shape != (16,) or not np.all(np.isfinite(action)): + raise ValueError("End-effector actions must be a finite array with shape (16,)") + + action_left = action[:8] + action_right = action[8:] + np.copyto(physics.data.mocap_pos[0], action_left[:3]) + np.copyto(physics.data.mocap_quat[0], action_left[3:7]) + np.copyto(physics.data.mocap_pos[1], action_right[:3]) + np.copyto(physics.data.mocap_quat[1], action_right[3:7]) + + left_gripper = PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN(action_left[7]) + right_gripper = PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN(action_right[7]) + np.copyto( + physics.data.ctrl, + [left_gripper, -left_gripper, right_gripper, -right_gripper], + ) + + def initialize_robots(self, physics): + physics.named.data.qpos[:16] = START_ARM_POSE + np.copyto(physics.data.mocap_pos[0], [-0.31718881, 0.5, 0.29525084]) + np.copyto(physics.data.mocap_quat[0], [1, 0, 0, 0]) + np.copyto(physics.data.mocap_pos[1], [0.31718881, 0.49999888, 0.29525084]) + np.copyto(physics.data.mocap_quat[1], [1, 0, 0, 0]) + np.copyto( + physics.data.ctrl, + [ + PUPPET_GRIPPER_POSITION_CLOSE, + -PUPPET_GRIPPER_POSITION_CLOSE, + PUPPET_GRIPPER_POSITION_CLOSE, + -PUPPET_GRIPPER_POSITION_CLOSE, + ], + ) + + @staticmethod + def get_qpos(physics): + qpos = physics.data.qpos.copy() + left, right = qpos[:8], qpos[8:16] + return np.concatenate( + [ + left[:6], + [PUPPET_GRIPPER_POSITION_NORMALIZE_FN(left[6])], + right[:6], + [PUPPET_GRIPPER_POSITION_NORMALIZE_FN(right[6])], + ] + ) + + @staticmethod + def get_qvel(physics): + qvel = physics.data.qvel.copy() + left, right = qvel[:8], qvel[8:16] + return np.concatenate( + [ + left[:6], + [PUPPET_GRIPPER_VELOCITY_NORMALIZE_FN(left[6])], + right[:6], + [PUPPET_GRIPPER_VELOCITY_NORMALIZE_FN(right[6])], + ] + ) + + @staticmethod + def get_env_state(physics): + return physics.data.qpos.copy()[16:] + + def get_observation(self, physics): + obs = collections.OrderedDict( + qpos=self.get_qpos(physics), + qvel=self.get_qvel(physics), + env_state=self.get_env_state(physics), + ) + if self.render_images and not DISABLE_RENDER[0]: + obs["images"] = { + "top": physics.render(height=480, width=640, camera_id="top"), + "angle": physics.render(height=480, width=640, camera_id="angle"), + "vis": physics.render(height=480, width=640, camera_id="front_close"), + } + obs["mocap_pose_left"] = np.concatenate( + [physics.data.mocap_pos[0], physics.data.mocap_quat[0]] + ).copy() + obs["mocap_pose_right"] = np.concatenate( + [physics.data.mocap_pos[1], physics.data.mocap_quat[1]] + ).copy() + obs["gripper_ctrl"] = physics.data.ctrl.copy() + return obs + + +class TransferCubeEETask(BimanualViperXEETask): + max_reward = 4 + + def initialize_episode(self, physics): + self.initialize_robots(physics) + pose = ( + sample_box_pose(self.random) + if self.object_pose is None + else self.object_pose + ) + if np.asarray(pose).shape != (7,): + raise ValueError("Pick-and-place object_pose must have shape (7,)") + physics.named.data.qpos["red_box_joint"] = pose + super().initialize_episode(physics) + + def get_reward(self, physics): + return transfer_cube_reward(physics) + + +class InsertionEETask(BimanualViperXEETask): + max_reward = 4 + + def initialize_episode(self, physics): + self.initialize_robots(physics) + if self.object_pose is None: + peg_pose, socket_pose = sample_insertion_pose(self.random) + else: + if self.object_pose.shape != (14,): + raise ValueError("Insertion object_pose must have shape (14,)") + peg_pose, socket_pose = self.object_pose[:7], self.object_pose[7:] + physics.named.data.qpos["red_peg_joint"] = peg_pose + physics.named.data.qpos["blue_socket_joint"] = socket_pose + super().initialize_episode(physics) + + def get_reward(self, physics): + return insertion_reward(physics) + + +class TransferTeaBagEETask(BimanualViperXEETask): + max_reward = 3 + + def initialize_episode(self, physics): + self.initialize_robots(physics) + if self.object_pose is not None: + pose = self.object_pose + elif self.randomize_object_pose: + pose = sample_box_pose(self.random) + else: + pose = [0.15, 0.5, 0.05, 1, 0, 0, 0] + if np.asarray(pose).shape != (7,): + raise ValueError("Tea-bag object_pose must have shape (7,)") + physics.named.data.qpos["red_box_joint"] = pose + super().initialize_episode(physics) + + def get_reward(self, physics): + return tea_bag_reward(physics) diff --git a/experiment_config.py b/experiment_config.py new file mode 100644 index 0000000..14bf749 --- /dev/null +++ b/experiment_config.py @@ -0,0 +1,73 @@ +"""JSON experiment manifests shared by training, evaluation, and sweeps.""" + +from __future__ import annotations + +import argparse +import json +from importlib import resources +from pathlib import Path + + +CONFIG_ROOT = Path(str(resources.files("configs"))) +NAMED_CONFIGS = { + "paper-sim": CONFIG_ROOT / "paper_sim.json", + "scripted-tea-bag": CONFIG_ROOT / "scripted_tea_bag.json", + "scripted-tea-bag-randomized": ( + CONFIG_ROOT / "scripted_tea_bag_randomized.json" + ), + "scripted-pick-and-place": ( + CONFIG_ROOT / "scripted_pick_and_place.json" + ), + "scripted-insertion": CONFIG_ROOT / "scripted_insertion.json", +} +CONFIG_SECTIONS = ( + "base_policy", + "environment", + "observation", + "reward", + "training", + "evaluation", +) + + +def resolve_config_path(value): + if value is None: + return None + if value in NAMED_CONFIGS: + return NAMED_CONFIGS[value] + return Path(value) + + +def load_experiment_config(value): + path = resolve_config_path(value) + if path is None: + return {}, None + if not path.exists(): + raise ValueError(f"Experiment config does not exist: {path}") + payload = json.loads(path.read_text()) + if not isinstance(payload, dict): + raise ValueError("Experiment config must contain a JSON object") + inherited_defaults = {} + inherited_manifest = None + if payload.get("inherits"): + inherited_defaults, inherited_manifest = load_experiment_config( + payload["inherits"] + ) + defaults = dict(inherited_defaults) + for section in CONFIG_SECTIONS: + values = payload.get(section, {}) + if not isinstance(values, dict): + raise ValueError(f"Experiment config section {section!r} must be an object") + defaults.update(values) + return defaults, { + "path": str(path), + "manifest": payload, + "inherits": inherited_manifest, + } + + +def defaults_from_argv(argv=None): + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument("--config") + known, _ = parser.parse_known_args(argv) + return load_experiment_config(known.config) diff --git a/policy.py b/policy.py new file mode 100644 index 0000000..accb743 --- /dev/null +++ b/policy.py @@ -0,0 +1,81 @@ +import torch.nn as nn +from torch.nn import functional as F +import torchvision.transforms as transforms + +from detr.main import build_ACT_model_and_optimizer, build_CNNMLP_model_and_optimizer + +class ACTPolicy(nn.Module): + def __init__(self, args_override): + super().__init__() + model, optimizer = build_ACT_model_and_optimizer(args_override) + self.model = model # CVAE decoder + self.optimizer = optimizer + self.kl_weight = args_override['kl_weight'] + + def __call__(self, qpos, image, actions=None, is_pad=None): + env_state = None + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + image = normalize(image) + if actions is not None: # training time + actions = actions[:, :self.model.num_queries] + is_pad = is_pad[:, :self.model.num_queries] + + a_hat, is_pad_hat, (mu, logvar) = self.model(qpos, image, env_state, actions, is_pad) + total_kld, dim_wise_kld, mean_kld = kl_divergence(mu, logvar) + loss_dict = dict() + all_l1 = F.l1_loss(actions, a_hat, reduction='none') + l1 = (all_l1 * ~is_pad.unsqueeze(-1)).mean() + loss_dict['l1'] = l1 + loss_dict['kl'] = total_kld[0] + loss_dict['loss'] = loss_dict['l1'] + loss_dict['kl'] * self.kl_weight + return loss_dict + else: # inference time + a_hat, _, (_, _) = self.model(qpos, image, env_state) # no action, sample from prior + return a_hat + + def configure_optimizers(self): + return self.optimizer + + +class CNNMLPPolicy(nn.Module): + def __init__(self, args_override): + super().__init__() + model, optimizer = build_CNNMLP_model_and_optimizer(args_override) + self.model = model # decoder + self.optimizer = optimizer + + def __call__(self, qpos, image, actions=None, is_pad=None): + env_state = None # TODO + normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + image = normalize(image) + if actions is not None: # training time + actions = actions[:, 0] + a_hat = self.model(qpos, image, env_state, actions) + mse = F.mse_loss(actions, a_hat) + loss_dict = dict() + loss_dict['mse'] = mse + loss_dict['loss'] = loss_dict['mse'] + return loss_dict + else: # inference time + a_hat = self.model(qpos, image, env_state) # no action, sample from prior + return a_hat + + def configure_optimizers(self): + return self.optimizer + +def kl_divergence(mu, logvar): + batch_size = mu.size(0) + assert batch_size != 0 + if mu.data.ndimension() == 4: + mu = mu.view(mu.size(0), mu.size(1)) + if logvar.data.ndimension() == 4: + logvar = logvar.view(logvar.size(0), logvar.size(1)) + + klds = -0.5 * (1 + logvar - mu.pow(2) - logvar.exp()) + total_kld = klds.sum(1).mean(0, True) + dimension_wise_kld = klds.mean(0) + mean_kld = klds.mean(1).mean(0, True) + + return total_kld, dimension_wise_kld, mean_kld diff --git a/policy_loader.py b/policy_loader.py new file mode 100644 index 0000000..68df88a --- /dev/null +++ b/policy_loader.py @@ -0,0 +1,97 @@ +"""Small entry-point loader for integrating external policy repositories.""" + +from __future__ import annotations + +import importlib +import inspect +from pathlib import Path + +from chunked_policy import ChunkPredictorAdapter +from speed_policy import SpeedPolicyAdapter +from speed_observation import ObservationEncoderAdapter + + +def load_entrypoint(spec: str): + """Load ``module.submodule:attribute`` without modifying ``sys.path``.""" + + if ":" not in spec: + raise ValueError("An entry point must use the form 'module.submodule:attribute'") + module_name, attribute_name = spec.rsplit(":", 1) + if not module_name or not attribute_name: + raise ValueError("An entry point must use the form 'module.submodule:attribute'") + module = importlib.import_module(module_name) + try: + return getattr(module, attribute_name) + except AttributeError as exc: + raise ValueError(f"{module_name!r} has no attribute {attribute_name!r}") from exc + + +def _call_factory(factory, available_kwargs): + if not callable(factory): + return factory + signature = inspect.signature(factory) + accepts_extra = any( + parameter.kind == inspect.Parameter.VAR_KEYWORD + for parameter in signature.parameters.values() + ) + kwargs = { + name: value + for name, value in available_kwargs.items() + if accepts_extra or name in signature.parameters + } + return factory(**kwargs) + + +def load_chunk_predictor( + entrypoint, + task_name, + checkpoint=None, + device="cpu", + factory_kwargs=None, +): + """Instantiate and validate an external joint-action chunk predictor. + + The factory may accept any subset of ``task_name``, ``checkpoint``, + ``device``, and the keys in ``factory_kwargs``. Its result must be callable + or define ``predict_chunk(observation)``. + """ + + factory = load_entrypoint(entrypoint) + available = { + "task_name": task_name, + "checkpoint": None if checkpoint is None else Path(checkpoint), + "device": device, + **(factory_kwargs or {}), + } + return ChunkPredictorAdapter(_call_factory(factory, available)) + + +def load_speed_policy(entrypoint, checkpoint=None, device="cpu", factory_kwargs=None): + """Instantiate and validate an external physical-speed policy.""" + + factory = load_entrypoint(entrypoint) + available = { + "checkpoint": None if checkpoint is None else Path(checkpoint), + "device": device, + **(factory_kwargs or {}), + } + return SpeedPolicyAdapter(_call_factory(factory, available)) + + +def load_observation_encoder( + entrypoint, + task_name, + checkpoint=None, + device="cpu", + factory_kwargs=None, +): + """Instantiate an external speed-observation encoder.""" + + factory = load_entrypoint(entrypoint) + available = { + "task_name": task_name, + "checkpoint": None if checkpoint is None else Path(checkpoint), + "device": device, + **(factory_kwargs or {}), + } + return ObservationEncoderAdapter(_call_factory(factory, available)) diff --git a/policy_speed_env.py b/policy_speed_env.py new file mode 100644 index 0000000..c4e527a --- /dev/null +++ b/policy_speed_env.py @@ -0,0 +1,515 @@ +"""Speed-control environments for scripted and chunked robot policies. + +The speed agent never produces robot actions. It observes simulator state and +chooses how quickly an independent base policy advances through nominal policy +time. This separation lets the same speed learner wrap retained waypoint +controllers, ACT, or another upstream policy that emits 14D action chunks. +""" + +from __future__ import annotations + +from collections import deque +from pathlib import Path +from typing import Callable, Sequence + +import numpy as np +from dm_control.rl import control + +from chunked_policy import ( + ChunkedPolicyRunner, + RecordedChunkPredictor, + collect_scripted_joint_demonstration, +) +from ee_sim_env import make_ee_sim_env +from scripted_policy import make_scripted_policy +from sim_env import make_sim_env +from sim_tasks import get_task_spec, normalize_task_name +from speed_observation import StateObservationEncoder, encoder_spec + + +DEFAULT_SPEEDS = (1.0, 1.5, 2.0, 2.5, 3.0) + + +def terminal_success_reward(speed, done, success): + """Sparse objective used by the initial SpeedTuning experiments.""" + + del speed + return 100.0 if done and success else 0.0 + + +def make_speed_reward(success_bonus=100.0, speed_weight=0.01, speed_power=2.0): + """Build a serializable-style speed objective for public experiments.""" + + if speed_power < 0: + raise ValueError("speed_power must be non-negative") + + def reward_fn(speed, done, success): + reward = speed_weight * float(speed) ** speed_power + if done and success: + reward += success_bonus + return reward + + return reward_fn + + +def encode_state_observation(observation): + """Flatten task state, robot position, and robot velocity for a speed agent.""" + + return StateObservationEncoder()(observation) + + +class WaypointActionSource: + """Advance an end-effector waypoint controller by a requested speed.""" + + def __init__(self, policy): + self.policy = policy + + def reset(self): + reset = getattr(self.policy, "reset", None) + if reset is not None: + reset() + + def begin_decision(self, timestep, speed): + del timestep, speed + + def action(self, timestep, speed): + return self.policy(timestep, step_inc=speed) + + +class ChunkedActionSource: + """Advance an arbitrary joint-action chunk predictor by a requested speed.""" + + def __init__(self, predictor): + self.runner = ChunkedPolicyRunner(predictor) + + def reset(self): + self.runner.reset() + + def begin_decision(self, timestep, speed): + self.runner.begin_decision(timestep.observation, speed=speed) + + def action(self, timestep, speed): + return self.runner.action(timestep.observation, speed=speed) + + +class SpeedPolicyEnv: + """A small RL environment whose actions select base-policy speed. + + The interface follows the classic ``reset() -> observation`` and + ``step(action) -> observation, reward, done, info`` convention used by the + included Rainbow implementation. Discrete action ``i`` maps to + ``speed_values[i]``; callers may also pass a physical speed with + ``quantized=False``. + """ + + def __init__( + self, + env, + action_source, + episode_len, + reward_fn=None, + speed_values: Sequence[float] = DEFAULT_SPEEDS, + observation_encoder: Callable[[dict], np.ndarray] | None = None, + frame_stack=1, + decision_frame_skip=10, + save_video=False, + onscreen_render=False, + video_path="output_video.mp4", + max_physics_steps=None, + terminate_on_success=False, + environment_metadata=None, + ): + self.env = env + self.action_source = action_source + self.reward_fn = reward_fn or terminal_success_reward + self.episode_len = int(episode_len) + self.observation_encoder = observation_encoder or StateObservationEncoder() + self.frame_stack = int(frame_stack) + self.decision_frame_skip = int(decision_frame_skip) + if self.frame_stack <= 0 or self.decision_frame_skip <= 0: + raise ValueError("frame_stack and decision_frame_skip must be positive") + self.save_video = bool(save_video) + self.onscreen_render = bool(onscreen_render) + self.video_path = Path(video_path) + self.terminate_on_success = bool(terminate_on_success) + self._environment_metadata = dict(environment_metadata or {}) + + values = np.asarray(speed_values, dtype=np.float64) + if values.ndim != 1 or len(values) == 0: + raise ValueError("speed_values must be a non-empty one-dimensional sequence") + if not np.all(np.isfinite(values)) or np.any(values <= 0): + raise ValueError("Every speed value must be finite and positive") + self.speed_values = tuple(float(value) for value in values) + self.action_space = len(self.speed_values) + self.max_physics_steps = int( + max_physics_steps + if max_physics_steps is not None + else np.ceil(self.episode_len / min(self.speed_values)) + ) + if self.max_physics_steps <= 0: + raise ValueError("max_physics_steps must be positive") + + env_state_dim = int(self.env.physics.data.qpos[16:].size) + output_dim = getattr(self.observation_encoder, "output_dim", None) + try: + single_observation_dim = int(output_dim(env_state_dim)) + except (AttributeError, TypeError): + single_observation_dim = env_state_dim + 28 + self.obs_space = single_observation_dim * self.frame_stack + self.cur_ts = None + self.cur_success = False + self.policy_time = 0.0 + self.physics_steps = 0 + self.speed_list = [] + self.image_list = [] + self._observation_stack = deque(maxlen=self.frame_stack) + self._figure = None + self._plot_image = None + + def reset(self): + self.cur_ts = self.env.reset() + self.action_source.reset() + reset_encoder = getattr(self.observation_encoder, "reset", None) + if reset_encoder is not None: + reset_encoder() + self.cur_success = False + self.policy_time = 0.0 + self.physics_steps = 0 + self.speed_list = [] + self.image_list = [] + self._observation_stack.clear() + + if self.onscreen_render: + import matplotlib.pyplot as plt + + self._figure, axis = plt.subplots() + self._plot_image = axis.imshow(self.cur_ts.observation["images"]["angle"]) + plt.ion() + encoded = self._encode_observation(self.cur_ts.observation) + for _ in range(self.frame_stack): + self._observation_stack.append(encoded.copy()) + observation = self.get_obs() + self.obs_space = int(observation.size) + return observation + + def speed_from_action(self, action): + if not isinstance(action, (int, np.integer)): + raise ValueError("A discrete speed action must be an integer index") + action = int(action) + if not 0 <= action < self.action_space: + raise ValueError(f"Speed action must be in [0, {self.action_space - 1}]") + return self.speed_values[action] + + @staticmethod + def _validate_continuous_speed(speed): + speed = float(speed) + if not np.isfinite(speed) or speed <= 0: + raise ValueError("Continuous speed must be finite and positive") + return speed + + def _resolve_speed(self, speed, quantized): + return ( + self.speed_from_action(speed) + if quantized + else self._validate_continuous_speed(speed) + ) + + def begin_decision(self, speed, quantized=True): + """Select one speed and force a fresh receding-horizon task chunk.""" + + if self.cur_ts is None: + raise RuntimeError("Call reset() before beginning a decision") + resolved_speed = self._resolve_speed(speed, quantized) + begin = getattr(self.action_source, "begin_decision", None) + if begin is not None: + begin(self.cur_ts, resolved_speed) + return resolved_speed + + def step(self, speed, quantized=True): + """Advance one physics step, retaining legacy low-level behavior.""" + + return self._step_physics(self._resolve_speed(speed, quantized)) + + def step_decision(self, speed, frame_skip=None, quantized=True): + """Execute one speed-policy action for a fixed block of physics steps. + + A fresh task-policy chunk is predicted at the decision boundary. Rewards + inside the block are summed without discounting and one transition is + returned to the speed learner. + """ + + repeats = self.decision_frame_skip if frame_skip is None else int(frame_skip) + if repeats <= 0: + raise ValueError("frame_skip must be positive") + resolved_speed = self.begin_decision(speed, quantized=quantized) + total_reward = 0.0 + executed = 0 + info = {"success": False} + for _ in range(repeats): + observation, reward, done, info = self._step_physics(resolved_speed) + total_reward += float(reward) + executed += 1 + if done: + break + info = dict(info) + info.update( + decision_frame_skip=repeats, + decision_physics_steps=executed, + reward_aggregation="undiscounted_sum", + ) + return observation, total_reward, done, info + + def _step_physics(self, speed): + if self.cur_ts is None: + raise RuntimeError("Call reset() before step()") + if self.policy_time >= self.episode_len or self.physics_steps >= self.max_physics_steps: + raise RuntimeError("The episode has already finished") + + action = self.action_source.action(self.cur_ts, speed) + try: + next_timestep = self.env.step(action) + except control.PhysicsError as exc: + # Aggressive speed exploration can occasionally drive MuJoCo into an + # invalid state. Treat that rollout as a failed terminal transition + # so one unstable sample cannot abort a long reinforcement-learning + # run. The following reset restores the simulator state. + self.policy_time += speed + self.physics_steps += 1 + self.speed_list.append(speed) + done = True + reward = float(self.reward_fn(speed, done, False)) + info = { + "success": False, + "speed": speed, + "policy_time": self.policy_time, + "physics_steps": self.physics_steps, + "task_reward": 0.0, + "target_reward": self.env.task.max_reward, + "physics_error": str(exc), + } + return self.get_obs(), reward, done, info + self.cur_ts = next_timestep + self.policy_time += speed + self.physics_steps += 1 + self.speed_list.append(speed) + self._observation_stack.append( + self._encode_observation(self.cur_ts.observation) + ) + + if self.onscreen_render: + import matplotlib.pyplot as plt + + self._plot_image.set_data(self.cur_ts.observation["images"]["angle"]) + plt.pause(0.002) + if self.save_video: + self.image_list.append(self.cur_ts.observation["images"]["angle"]) + + task_reward = float(self.cur_ts.reward or 0) + if task_reward >= self.env.task.max_reward: + self.cur_success = True + timed_out = ( + self.policy_time >= self.episode_len + or self.physics_steps >= self.max_physics_steps + ) + done = timed_out or (self.terminate_on_success and self.cur_success) + reward = float(self.reward_fn(speed, done, self.cur_success)) + + if done and self.save_video: + self._save_video() + info = { + "success": self.cur_success, + "speed": speed, + "policy_time": self.policy_time, + "physics_steps": self.physics_steps, + "task_reward": task_reward, + "target_reward": self.env.task.max_reward, + } + return self.get_obs(), reward, done, info + + def _encode_observation(self, observation_dict): + observation = np.asarray( + self.observation_encoder(observation_dict), dtype=np.float32 + ) + if observation.ndim != 1 or not np.all(np.isfinite(observation)): + raise ValueError("The speed-policy observation must be a finite 1D array") + return observation + + def get_obs(self): + if self.cur_ts is None or not self._observation_stack: + raise RuntimeError("Call reset() before requesting an observation") + return np.concatenate(tuple(self._observation_stack)).astype( + np.float32, copy=False + ) + + def observation_spec(self): + return { + "encoder": encoder_spec(self.observation_encoder), + "frame_stack": self.frame_stack, + "padding": "repeat_initial", + "observation_dim": int(self.obs_space), + } + + def environment_spec(self): + return dict(self._environment_metadata) + + def observation_encoder_state_dict(self): + state_dict = getattr(self.observation_encoder, "state_dict", None) + return None if state_dict is None else state_dict() + + def load_observation_encoder_state_dict(self, state_dict): + if state_dict is None: + return + load = getattr(self.observation_encoder, "load_state_dict", None) + if load is None: + raise ValueError("Configured observation encoder cannot load checkpoint state") + load(state_dict) + + def _save_video(self): + try: + import imageio.v2 as imageio + except ImportError as exc: + raise RuntimeError("Video export requires: uv sync --extra video") from exc + self.video_path.parent.mkdir(parents=True, exist_ok=True) + imageio.mimsave(self.video_path, self.image_list, fps=50) + + def close(self): + if self._figure is not None: + import matplotlib.pyplot as plt + + plt.close(self._figure) + self._figure = None + close_encoder = getattr(self.observation_encoder, "close", None) + if close_encoder is not None: + close_encoder() + + +def create_speed_env( + task_name="tea_bag", + reward_fn=None, + chunk_predictor=None, + object_pose=None, + onscreen_render=False, + save_video=False, + render_images=None, + seed=None, + speed_values=DEFAULT_SPEEDS, + video_path="output_video.mp4", + observation_encoder=None, + frame_stack=1, + decision_frame_skip=10, + terminate_on_success=False, + randomize_object_pose=False, +): + """Create a speed environment around a scripted or chunked base policy. + + With no ``chunk_predictor`` this uses the retained end-effector waypoint + controller. Supplying any callable chunk predictor switches to the joint + simulator and the generic ``[time, 14]`` action-chunk contract. + """ + + task_name = normalize_task_name(task_name) + spec = get_task_spec(task_name) + observation_encoder = observation_encoder or StateObservationEncoder() + if render_images is None: + render_images = bool( + onscreen_render + or save_video + or chunk_predictor is not None + or getattr(observation_encoder, "requires_images", False) + ) + if getattr(observation_encoder, "requires_images", False) and not render_images: + raise ValueError("The configured speed observation encoder requires images") + + if chunk_predictor is None: + env = make_ee_sim_env( + task_name, + render_images=render_images, + seed=seed, + object_pose=object_pose, + randomize_object_pose=randomize_object_pose, + ) + action_source = WaypointActionSource(make_scripted_policy(task_name)) + else: + env = make_sim_env( + task_name, + render_images=render_images, + seed=seed, + object_pose=object_pose, + randomize_object_pose=randomize_object_pose, + ) + action_source = ChunkedActionSource(chunk_predictor) + + return SpeedPolicyEnv( + env=env, + action_source=action_source, + reward_fn=reward_fn, + episode_len=spec.episode_len, + speed_values=speed_values, + observation_encoder=observation_encoder, + frame_stack=frame_stack, + decision_frame_skip=decision_frame_skip, + onscreen_render=onscreen_render, + save_video=save_video, + video_path=video_path, + terminate_on_success=terminate_on_success, + environment_metadata={ + "task": task_name, + "base_policy": ( + "scripted" if chunk_predictor is None else "chunked" + ), + "randomize_object_pose": bool(randomize_object_pose), + }, + ) + + +def create_recorded_chunk_speed_env( + task_name="tea_bag", + chunk_size=25, + seed=0, + render_images=False, + **kwargs, +): + """Create a checkpoint-free chunk environment for integration testing.""" + + demonstration = collect_scripted_joint_demonstration(task_name, seed=seed) + predictor = RecordedChunkPredictor(demonstration.actions, chunk_size=chunk_size) + return create_speed_env( + task_name=task_name, + chunk_predictor=predictor, + object_pose=demonstration.object_pose, + render_images=render_images, + seed=seed, + **kwargs, + ) + + +def test_speed_env( + task_name="tea_bag", + speed_func=None, + seed=0, + chunk_predictor=None, +): + """Run a continuous speed function and return the maximum wrapper reward.""" + + speed_env = create_speed_env( + task_name=task_name, + chunk_predictor=chunk_predictor, + seed=seed, + ) + observation = speed_env.reset() + done = False + rewards = [] + while not done: + speed = 1.0 if speed_func is None else speed_func( + observation=observation, + policy_time=speed_env.policy_time, + ) + observation, reward, done, _ = speed_env.step(speed, quantized=False) + rewards.append(reward) + speed_env.close() + return max(rewards, default=0.0) + + +if __name__ == "__main__": + for _task_name in ("pick_and_place", "insertion", "tea_bag"): + print(_task_name, test_speed_env(_task_name)) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e765b8b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,92 @@ +[build-system] +requires = ["setuptools>=68", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "speedtuning-sim" +version = "0.1.0" +description = "Simulation tasks and speed-policy infrastructure for SpeedTuning" +readme = "README.md" +requires-python = ">=3.10,<3.11" +license = "MIT" +license-files = ["LICENSE", "NOTICE.md", "detr/LICENSE"] +authors = [{name = "David D. Yuan"}] +keywords = ["robotics", "reinforcement-learning", "mujoco", "action-chunking"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Science/Research", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Topic :: Scientific/Engineering :: Artificial Intelligence", +] +dependencies = [ + "dm-control==1.0.9", + "mujoco==2.3.3", + "numpy>=1.23,<2", + "pyquaternion==0.9.9", +] + +[project.optional-dependencies] +learned = [ + "einops>=0.6,<0.9", + "packaging>=23,<26", + "torch==2.5.1", + "torchvision==0.20.1", +] +rl = ["torch==2.5.1"] +test = ["pytest>=8,<9"] +video = ["imageio>=2.31,<3", "imageio-ffmpeg>=0.4.9,<0.7"] +evaluation = ["matplotlib>=3.7,<4"] + +[project.urls] +Paper = "https://doi.org/10.1109/ICRA55743.2025.11128753" +Preprint = "https://arxiv.org/abs/2608.09138" +"Project Page" = "https://daivdyuan.github.io/speed-tuning/" +Video = "https://daivdyuan.github.io/speed-tuning/static/videos/icra2025_final.mp4" +Repository = "https://github.com/DaivdYuan/SpeedTuning" +Documentation = "https://github.com/DaivdYuan/SpeedTuning/blob/main/docs/SCRIPTED_REPRODUCTION.md" +Issues = "https://github.com/DaivdYuan/SpeedTuning/issues" + +[project.scripts] +speedtuning-sim = "scripts.run_sim:main" +speedtuning-check-chunks = "scripts.check_chunked_policy:main" +speedtuning-rainbow-poc = "scripts.rainbow_poc:main" +speedtuning-train-speed = "scripts.train_speed_policy:main" +speedtuning-eval-speed = "scripts.eval_speed_policy:main" +speedtuning-sweep = "scripts.sweep_speed_policy:main" + +[tool.setuptools] +include-package-data = true +py-modules = [ + "act_integration", + "chunked_policy", + "constants", + "ee_sim_env", + "experiment_config", + "policy", + "policy_loader", + "policy_speed_env", + "scripted_policy", + "sim_env", + "sim_tasks", + "speed_policy", + "speed_evaluation", + "speed_observation", + "speed_training", +] + +[tool.setuptools.packages.find] +include = ["assets", "configs*", "detr*", "rl*", "scripts*"] + +[tool.setuptools.package-data] +assets = ["*.xml", "*.stl", "*.obj"] +configs = ["*.json", "*.md", "ablations/*.json"] + +[tool.pytest.ini_options] +pythonpath = ["."] +testpaths = ["tests"] +markers = [ + "learned: requires the optional PyTorch/torchvision learned-policy stack", + "rl: requires the optional PyTorch Rainbow DQN stack", +] diff --git a/requirements-sim.txt b/requirements-sim.txt new file mode 100644 index 0000000..0b48e80 --- /dev/null +++ b/requirements-sim.txt @@ -0,0 +1,6 @@ +# Physics versions are pinned because the historical waypoint controllers are +# sensitive to MuJoCo contact and solver changes. +dm-control==1.0.9 +mujoco==2.3.3 +numpy>=1.23,<2 +pyquaternion==0.9.9 diff --git a/rl/__init__.py b/rl/__init__.py new file mode 100644 index 0000000..273da96 --- /dev/null +++ b/rl/__init__.py @@ -0,0 +1 @@ +"""Reinforcement-learning components for speed selection.""" diff --git a/rl/rainbowDQN/__init__.py b/rl/rainbowDQN/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rl/rainbowDQN/dqnAgent.py b/rl/rainbowDQN/dqnAgent.py new file mode 100644 index 0000000..dbcc5ee --- /dev/null +++ b/rl/rainbowDQN/dqnAgent.py @@ -0,0 +1,289 @@ +"""Rainbow DQN optimization core used by speed-policy training.""" + +from __future__ import annotations + +import random +from pathlib import Path +from time import perf_counter +from typing import Dict + +import numpy as np +import torch +import torch.optim as optim +from torch.nn.utils import clip_grad_norm_ + +from .network import Network +from .replayBuffer import PrioritizedReplayBuffer, ReplayBuffer + + +class DQNAgent: + """Categorical Double DQN with dueling NoisyNet, PER, and n-step replay. + + The high-level, simulator-specific loop lives in ``speed_training.py``. + This class owns action selection, transition collection, and optimizer + updates so it can also be reused by short integration checks. + """ + + def __init__( + self, + env, + memory_size: int, + batch_size: int, + target_update: int, + seed: int, + lr: float = 1e-4, + gamma: float = 0.97, + tau: float = 0.5, + frame_skip: int = 10, + epsilon: float = 1.0, + epsilon_decay: float = 0.999, + min_epsilon: float = 0.1, + hard_exploration_steps: int = 0, + exploration_steps: int = 0, + alpha: float = 0.2, + beta: float = 0.6, + prior_eps: float = 1e-6, + v_min: float = 0.0, + v_max: float = 120.0, + atom_size: int = 121, + n_step: int = 3, + n_step_alpha: float = 1.0, + hidden_dim: int = 256, + device=None, + **legacy_options, + ): + # Logging/checkpoint options belonged to the unrecovered monolithic + # trainer. Accept them for source compatibility; public loops own I/O. + ignored = {"log_dir", "file_path", "name", "ckpt_save_freq"} + unknown = set(legacy_options).difference(ignored) + if unknown: + raise TypeError(f"Unexpected DQN options: {', '.join(sorted(unknown))}") + if batch_size <= 0 or memory_size < batch_size: + raise ValueError("memory_size must be at least a positive batch_size") + if frame_skip <= 0 or atom_size < 2 or v_max <= v_min: + raise ValueError("Invalid frame skip or categorical support") + + random.seed(seed) + np.random.seed(seed) + self.env = env + self.frame_skip = int(frame_skip) + self.batch_size = int(batch_size) + self.target_update = int(target_update) + self.seed = int(seed) + self.gamma = float(gamma) + self.tau = float(tau) + self.device = torch.device( + device or ("cuda" if torch.cuda.is_available() else "cpu") + ) + + self.epsilon = float(epsilon) + self.epsilon_decay = float(epsilon_decay) + self.exploration_steps = int(exploration_steps) + self.hard_exploration_steps = int(hard_exploration_steps) + self.min_epsilon = float(min_epsilon) + self.beta = float(beta) + self.prior_eps = float(prior_eps) + + obs_dim = int(env.obs_space) + action_dim = int(env.action_space) + self.memory = PrioritizedReplayBuffer( + obs_dim, memory_size, batch_size, alpha=alpha, gamma=gamma + ) + self.use_n_step = n_step > 1 + self.n_step = int(n_step) + self.n_step_alpha = float(n_step_alpha) + if self.use_n_step: + self.memory_n = ReplayBuffer( + obs_dim, + memory_size, + batch_size, + n_step=n_step, + gamma=gamma, + ) + + self.v_min = float(v_min) + self.v_max = float(v_max) + self.atom_size = int(atom_size) + self.support = torch.linspace(v_min, v_max, atom_size).to(self.device) + self.dqn = Network( + obs_dim, action_dim, atom_size, self.support, hidden_dim=hidden_dim + ).to(self.device) + self.dqn_target = Network( + obs_dim, action_dim, atom_size, self.support, hidden_dim=hidden_dim + ).to(self.device) + self.dqn_target.load_state_dict(self.dqn.state_dict()) + self.dqn_target.eval() + self.optimizer = optim.Adam(self.dqn.parameters(), lr=lr) + self.transition = [] + self.is_test = False + + def select_action(self, state: np.ndarray) -> int: + """Select a discrete speed action and start a replay transition.""" + + explore = not self.is_test and np.random.uniform() < self.epsilon + if explore: + action = int(np.random.randint(self.env.action_space)) + else: + state_tensor = torch.as_tensor( + state, dtype=torch.float32, device=self.device + ).unsqueeze(0) + with torch.no_grad(): + action = int(self.dqn(state_tensor).argmax(dim=1).item()) + if not self.is_test: + self.transition = [np.asarray(state, dtype=np.float32).copy(), action] + return action + + def step(self, action: int, frame_skip: int | None = None): + """Execute one decision-level speed action and store one transition.""" + + repeats = self.frame_skip if frame_skip is None else int(frame_skip) + if repeats <= 0: + raise ValueError("frame_skip must be positive") + started = perf_counter() + step_decision = getattr(self.env, "step_decision", None) + if step_decision is not None: + next_state, total_reward, done, info = step_decision( + action, frame_skip=repeats + ) + else: + total_reward = 0.0 + info = {"success": False} + for _ in range(repeats): + next_state, reward, done, info = self.env.step(action) + total_reward += float(reward) + if done: + break + env_step_time = perf_counter() - started + + buffer_started = perf_counter() + if not self.is_test: + if len(self.transition) != 2: + raise RuntimeError("Call select_action() before step() while training") + transition = self.transition + [total_reward, next_state, done] + if self.use_n_step: + one_step_transition = self.memory_n.store(*transition) + else: + one_step_transition = transition + if one_step_transition: + self.memory.store(*one_step_transition) + buffer_time = perf_counter() - buffer_started + result_info = dict(info) + result_info.update( + env_step_time=env_step_time, + add_to_buffer_time=buffer_time, + ) + return next_state, total_reward, done, result_info + + def update_model(self) -> float: + """Perform one prioritized categorical DQN update.""" + + samples = self.memory.sample_batch(self.beta) + weights = torch.as_tensor( + samples["weights"].reshape(-1, 1), + dtype=torch.float32, + device=self.device, + ) + indices = samples["indices"] + elementwise_loss = self._compute_dqn_loss(samples, self.gamma) + if self.use_n_step: + n_step_samples = self.memory_n.sample_batch_from_idxs(indices) + elementwise_loss = elementwise_loss + self.n_step_alpha * self._compute_dqn_loss( + n_step_samples, self.gamma**self.n_step + ) + loss = torch.mean(elementwise_loss * weights) + + self.optimizer.zero_grad() + loss.backward() + clip_grad_norm_(self.dqn.parameters(), 10.0) + self.optimizer.step() + priorities = elementwise_loss.detach().cpu().numpy() + self.prior_eps + self.memory.update_priorities(indices, priorities) + self.dqn.reset_noise() + self.dqn_target.reset_noise() + return float(loss.item()) + + def decay_epsilon(self, step: int): + if step <= self.hard_exploration_steps: + self.epsilon = 1.0 + elif self.exploration_steps <= 0: + self.epsilon = 0.0 + elif step >= self.exploration_steps: + self.epsilon = self.min_epsilon + else: + self.epsilon = max(self.epsilon * self.epsilon_decay, self.min_epsilon) + + def set_eval(self, enabled=True): + self.is_test = bool(enabled) + self.dqn.eval() if enabled else self.dqn.train() + + def _compute_dqn_loss( + self, samples: Dict[str, np.ndarray], gamma: float + ) -> torch.Tensor: + state = torch.as_tensor(samples["obs"], dtype=torch.float32, device=self.device) + next_state = torch.as_tensor( + samples["next_obs"], dtype=torch.float32, device=self.device + ) + action = torch.as_tensor(samples["acts"], dtype=torch.long, device=self.device) + reward = torch.as_tensor( + samples["rews"].reshape(-1, 1), dtype=torch.float32, device=self.device + ) + done = torch.as_tensor( + samples["done"].reshape(-1, 1), dtype=torch.float32, device=self.device + ) + delta_z = (self.v_max - self.v_min) / (self.atom_size - 1) + + with torch.no_grad(): + next_action = self.dqn(next_state).argmax(1) + next_dist = self.dqn_target.dist(next_state)[ + range(self.batch_size), next_action + ] + target_support = ( + reward + (1 - done) * gamma * self.support + ).clamp(self.v_min, self.v_max) + projection = (target_support - self.v_min) / delta_z + lower = projection.floor().long() + upper = projection.ceil().long() + lower[(upper == lower) & (upper > 0)] -= 1 + upper[(upper == lower) & (lower < self.atom_size - 1)] += 1 + offset = ( + torch.arange(self.batch_size, device=self.device).unsqueeze(1) + * self.atom_size + ) + projected_dist = torch.zeros_like(next_dist) + projected_dist.view(-1).index_add_( + 0, + (lower + offset).view(-1), + (next_dist * (upper.float() - projection)).view(-1), + ) + projected_dist.view(-1).index_add_( + 0, + (upper + offset).view(-1), + (next_dist * (projection - lower.float())).view(-1), + ) + + distribution = self.dqn.dist(state) + log_probability = torch.log( + distribution[range(self.batch_size), action].clamp_min(1e-8) + ) + return -(projected_dist * log_probability).sum(1) + + def _target_hard_update(self): + self.dqn_target.load_state_dict(self.dqn.state_dict()) + + def _target_soft_update(self): + with torch.no_grad(): + for target, source in zip( + self.dqn_target.parameters(), self.dqn.parameters() + ): + target.copy_(self.tau * source + (1.0 - self.tau) * target) + + def save(self, path): + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + torch.save(self.dqn.state_dict(), path) + + def load(self, path): + self.dqn.load_state_dict( + torch.load(path, map_location=self.device, weights_only=True) + ) + self._target_hard_update() diff --git a/rl/rainbowDQN/network.py b/rl/rainbowDQN/network.py new file mode 100644 index 0000000..29fa77c --- /dev/null +++ b/rl/rainbowDQN/network.py @@ -0,0 +1,196 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +class NoisyLinear(nn.Module): + """Noisy linear module for NoisyNet. + + Attributes: + in_features (int): input size of linear module + out_features (int): output size of linear module + std_init (float): initial std value + weight_mu (nn.Parameter): mean value weight parameter + weight_sigma (nn.Parameter): std value weight parameter + bias_mu (nn.Parameter): mean value bias parameter + bias_sigma (nn.Parameter): std value bias parameter + + """ + + def __init__( + self, + in_features: int, + out_features: int, + std_init: float = 0.5, + ): + """Initialization.""" + super(NoisyLinear, self).__init__() + + self.in_features = in_features + self.out_features = out_features + self.std_init = std_init + + self.weight_mu = nn.Parameter(torch.Tensor(out_features, in_features)) + self.weight_sigma = nn.Parameter( + torch.Tensor(out_features, in_features) + ) + self.register_buffer( + "weight_epsilon", torch.Tensor(out_features, in_features) + ) + + self.bias_mu = nn.Parameter(torch.Tensor(out_features)) + self.bias_sigma = nn.Parameter(torch.Tensor(out_features)) + self.register_buffer("bias_epsilon", torch.Tensor(out_features)) + + self.reset_parameters() + self.reset_noise() + + def reset_parameters(self): + """Reset trainable network parameters (factorized gaussian noise).""" + mu_range = 1 / math.sqrt(self.in_features) + self.weight_mu.data.uniform_(-mu_range, mu_range) + self.weight_sigma.data.fill_( + self.std_init / math.sqrt(self.in_features) + ) + self.bias_mu.data.uniform_(-mu_range, mu_range) + self.bias_sigma.data.fill_( + self.std_init / math.sqrt(self.out_features) + ) + + def reset_noise(self): + """Make new noise.""" + epsilon_in = self.scale_noise(self.in_features) + epsilon_out = self.scale_noise(self.out_features) + + # outer product + self.weight_epsilon.copy_(epsilon_out.ger(epsilon_in)) + self.bias_epsilon.copy_(epsilon_out) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """Forward method implementation. + + We don't use separate statements on train / eval mode. + It doesn't show remarkable difference of performance. + """ + if self.training: + weight = self.weight_mu + self.weight_sigma * self.weight_epsilon + bias = self.bias_mu + self.bias_sigma * self.bias_epsilon + else: + weight = self.weight_mu + bias = self.bias_mu + return F.linear(x, weight, bias) + + @staticmethod + def scale_noise(size: int) -> torch.Tensor: + """Set scale to make noise (factorized gaussian noise).""" + x = torch.randn(size) + + return x.sign().mul(x.abs().sqrt()) + + +class ImageBackbone(nn.Module): + def __init__(self, out_dim): + super(ImageBackbone, self).__init__() + import torchvision.models as models + #self.resnet18 = models.resnet18(pretrained=True) + #self.resnet18.fc = nn.Linear(512, out_dim) # Modify the fully connected layer for your desired number of classes + + #self.backbone = models.mobilenet_v2(pretrained=True) + #in_features = self.backbone.classifier[-1].in_features # Get the number of input features to the last layer + #self.backbone.classifier[-1] = nn.Linear(in_features, out_dim) + + self.backbone = models.squeezenet1_0(pretrained=True) + self.backbone.classifier[1] = nn.Conv2d(512, out_dim, kernel_size=(1, 1), stride=(1, 1)) # Adjust to your 'out_dim' + + def forward(self, x): + x = self.backbone(x) + return x + + +class Network(nn.Module): + def __init__( + self, + in_dim: int, + out_dim: int, + atom_size: int, + support: torch.Tensor, + hidden_dim: int = 256, + use_state = True + ): + """Initialization.""" + super(Network, self).__init__() + + self.support = support + self.in_dim = in_dim + self.out_dim = out_dim + self.hidden_dim = hidden_dim + self.atom_size = atom_size + self.use_state = use_state + + # Visual observations are encoded into finite feature vectors before + # reaching Rainbow, so the same MLP handles state-only and multimodal + # observation stacks. ``use_state`` remains for checkpoint compatibility. + self.feature_layer = nn.Sequential( + nn.Linear(in_dim, hidden_dim), + nn.ReLU(), + nn.Linear(hidden_dim, hidden_dim), + nn.ReLU(), + nn.Linear(hidden_dim, hidden_dim), + ) + + # set advantage layer + self.advantage_hidden_layer = NoisyLinear(hidden_dim, hidden_dim) + self.advantage_layer = NoisyLinear(hidden_dim, out_dim * atom_size) + + # set value layer + self.value_hidden_layer = NoisyLinear(hidden_dim, hidden_dim) + self.value_layer = NoisyLinear(hidden_dim, atom_size) + + # norm stats as non-learnable constants + self.states_mean = torch.nn.Parameter(torch.zeros(in_dim), requires_grad=False) + self.states_std = torch.nn.Parameter(torch.ones(in_dim), requires_grad=False) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """Forward method implementation.""" + dist = self.dist(x) + q = torch.sum(dist * self.support, dim=2) + return q + + def update_norm_stats(self, norm_stats: dict): + with torch.no_grad(): + mean = torch.as_tensor( + norm_stats['states_mean'], dtype=self.states_mean.dtype, + device=self.states_mean.device, + ) + std = torch.as_tensor( + norm_stats['states_std'], dtype=self.states_std.dtype, + device=self.states_std.device, + ).clamp_min(1e-6) + self.states_mean.copy_(mean) + self.states_std.copy_(std) + + def dist(self, x: torch.Tensor) -> torch.Tensor: + """Get distribution for atoms.""" + x = (x - self.states_mean) / self.states_std.clamp_min(1e-6) + + feature = self.feature_layer(x) + + adv_hid = F.relu(self.advantage_hidden_layer(feature)) + val_hid = F.relu(self.value_hidden_layer(feature)) + + advantage = self.advantage_layer(adv_hid).view( + -1, self.out_dim, self.atom_size + ) + value = self.value_layer(val_hid).view(-1, 1, self.atom_size) + q_atoms = value + advantage - advantage.mean(dim=1, keepdim=True) + + dist = F.softmax(q_atoms, dim=-1).clamp_min(1e-6) + return dist / dist.sum(dim=-1, keepdim=True) + + def reset_noise(self): + """Reset all noisy layers.""" + self.advantage_hidden_layer.reset_noise() + self.advantage_layer.reset_noise() + self.value_hidden_layer.reset_noise() + self.value_layer.reset_noise() diff --git a/rl/rainbowDQN/replayBuffer.py b/rl/rainbowDQN/replayBuffer.py new file mode 100644 index 0000000..de38d0b --- /dev/null +++ b/rl/rainbowDQN/replayBuffer.py @@ -0,0 +1,234 @@ +import numpy as np +from typing import Deque, Dict, Tuple, List +from collections import deque +from .segment_tree import MinSegmentTree, SumSegmentTree +import random + +class ReplayBuffer: + """A simple numpy replay buffer.""" + + def __init__( + self, + obs_dim: int, + size: int, + batch_size: int = 32, + n_step: int = 1, + gamma: float = 0.99 + ): + self.obs_buf = np.zeros([size, obs_dim], dtype=np.float32) + self.next_obs_buf = np.zeros([size, obs_dim], dtype=np.float32) + self.acts_buf = np.zeros([size], dtype=np.float32) + self.rews_buf = np.zeros([size], dtype=np.float32) + self.done_buf = np.zeros(size, dtype=np.float32) + self.max_size, self.batch_size = size, batch_size + self.ptr, self.size, = 0, 0 + + # for N-step Learning + self.n_step_buffer = deque(maxlen=n_step) + self.n_step = n_step + self.gamma = gamma + + def store( + self, + obs: np.ndarray, + act: np.ndarray, + rew: float, + next_obs: np.ndarray, + done: bool, + ) -> Tuple[np.ndarray, np.ndarray, float, np.ndarray, bool]: + transition = (obs, act, rew, next_obs, done) + self.n_step_buffer.append(transition) + + # single step transition is not ready + if len(self.n_step_buffer) < self.n_step: + return () + + # make a n-step transition + rew, next_obs, done = self._get_n_step_info( + self.n_step_buffer, self.gamma + ) + obs, act = self.n_step_buffer[0][:2] + + self.obs_buf[self.ptr] = obs + self.next_obs_buf[self.ptr] = next_obs + self.acts_buf[self.ptr] = act + self.rews_buf[self.ptr] = rew + self.done_buf[self.ptr] = done + self.ptr = (self.ptr + 1) % self.max_size + self.size = min(self.size + 1, self.max_size) + + first_transition = self.n_step_buffer[0] + if done: + # Do not allow the retained n-step window to cross an episode reset. + # The final incomplete n-step tails are intentionally discarded so + # the one-step and n-step buffers retain matching indices. + self.n_step_buffer.clear() + return first_transition + + def sample_batch(self) -> Dict[str, np.ndarray]: + idxs = np.random.choice(self.size, size=self.batch_size, replace=False) + + return dict( + obs=self.obs_buf[idxs], + next_obs=self.next_obs_buf[idxs], + acts=self.acts_buf[idxs], + rews=self.rews_buf[idxs], + done=self.done_buf[idxs], + # for N-step Learning + indices=idxs, + ) + + def sample_batch_from_idxs( + self, idxs: np.ndarray + ) -> Dict[str, np.ndarray]: + # for N-step Learning + return dict( + obs=self.obs_buf[idxs], + next_obs=self.next_obs_buf[idxs], + acts=self.acts_buf[idxs], + rews=self.rews_buf[idxs], + done=self.done_buf[idxs], + ) + + def _get_n_step_info( + self, n_step_buffer: Deque, gamma: float + ) -> Tuple[np.int64, np.ndarray, bool]: + """Return n step rew, next_obs, and done.""" + # info of the last transition + rew, next_obs, done = n_step_buffer[-1][-3:] + + for transition in reversed(list(n_step_buffer)[:-1]): + r, n_o, d = transition[-3:] + + rew = r + gamma * rew * (1 - d) + next_obs, done = (n_o, d) if d else (next_obs, done) + + return rew, next_obs, done + + def __len__(self) -> int: + return self.size + + +class PrioritizedReplayBuffer(ReplayBuffer): + """Prioritized Replay buffer. + + Attributes: + max_priority (float): max priority + tree_ptr (int): next index of tree + alpha (float): alpha parameter for prioritized replay buffer + sum_tree (SumSegmentTree): sum tree for prior + min_tree (MinSegmentTree): min tree for min prior to get max weight + + """ + + def __init__( + self, + obs_dim: int, + size: int, + batch_size: int = 32, + alpha: float = 0.6, + n_step: int = 1, + gamma: float = 0.99, + ): + """Initialization.""" + assert alpha >= 0 + + super(PrioritizedReplayBuffer, self).__init__( + obs_dim, size, batch_size, n_step, gamma + ) + self.max_priority, self.tree_ptr = 1.0, 0 + self.alpha = alpha + + # capacity must be positive and a power of 2. + tree_capacity = 1 + while tree_capacity < self.max_size: + tree_capacity *= 2 + + self.sum_tree = SumSegmentTree(tree_capacity) + self.min_tree = MinSegmentTree(tree_capacity) + + def store( + self, + obs: np.ndarray, + act: int, + rew: float, + next_obs: np.ndarray, + done: bool, + ) -> Tuple[np.ndarray, np.ndarray, float, np.ndarray, bool]: + """Store experience and priority.""" + transition = super().store(obs, act, rew, next_obs, done) + + if transition: + self.sum_tree[self.tree_ptr] = self.max_priority ** self.alpha + self.min_tree[self.tree_ptr] = self.max_priority ** self.alpha + self.tree_ptr = (self.tree_ptr + 1) % self.max_size + + return transition + + def sample_batch(self, beta: float = 0.4) -> Dict[str, np.ndarray]: + """Sample a batch of experiences.""" + assert len(self) >= self.batch_size + assert beta > 0 + + indices = self._sample_proportional() + + obs = self.obs_buf[indices] + next_obs = self.next_obs_buf[indices] + acts = self.acts_buf[indices] + rews = self.rews_buf[indices] + done = self.done_buf[indices] + weights = np.array([self._calculate_weight(i, beta) for i in indices]) + + return dict( + obs=obs, + next_obs=next_obs, + acts=acts, + rews=rews, + done=done, + weights=weights, + indices=indices, + ) + + def update_priorities(self, indices: List[int], priorities: np.ndarray): + """Update priorities of sampled transitions.""" + assert len(indices) == len(priorities) + + for idx, priority in zip(indices, priorities): + assert priority > 0 + assert 0 <= idx < len(self) + + self.sum_tree[idx] = priority ** self.alpha + self.min_tree[idx] = priority ** self.alpha + + self.max_priority = max(self.max_priority, priority) + + def _sample_proportional(self) -> List[int]: + """Sample indices based on proportions.""" + indices = [] + # SegmentTree uses a half-open [start, end) range. Include the newest + # valid replay entry; the historical ``len(self) - 1`` bound silently + # excluded it from sampling. + p_total = self.sum_tree.sum(0, len(self)) + segment = p_total / self.batch_size + + for i in range(self.batch_size): + a = segment * i + b = segment * (i + 1) + upperbound = random.uniform(a, b) + idx = self.sum_tree.retrieve(upperbound) + indices.append(idx) + + return indices + + def _calculate_weight(self, idx: int, beta: float): + """Calculate the weight of the experience at idx.""" + # get max weight + p_min = self.min_tree.min() / self.sum_tree.sum() + max_weight = (p_min * len(self)) ** (-beta) + + # calculate weights + p_sample = self.sum_tree[idx] / self.sum_tree.sum() + weight = (p_sample * len(self)) ** (-beta) + weight = weight / max_weight + + return weight diff --git a/rl/rainbowDQN/segment_tree.py b/rl/rainbowDQN/segment_tree.py new file mode 100644 index 0000000..a19e49c --- /dev/null +++ b/rl/rainbowDQN/segment_tree.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +"""Segment tree for Prioritized Replay Buffer.""" + +import operator +from typing import Callable + + +class SegmentTree: + """ Create SegmentTree. + + Taken from OpenAI baselines github repository: + https://github.com/openai/baselines/blob/master/baselines/common/segment_tree.py + + Attributes: + capacity (int) + tree (list) + operation (function) + + """ + + def __init__(self, capacity: int, operation: Callable, init_value: float): + """Initialization. + + Args: + capacity (int) + operation (function) + init_value (float) + + """ + assert ( + capacity > 0 and capacity & (capacity - 1) == 0 + ), "capacity must be positive and a power of 2." + self.capacity = capacity + self.tree = [init_value for _ in range(2 * capacity)] + self.operation = operation + + def _operate_helper( + self, start: int, end: int, node: int, node_start: int, node_end: int + ) -> float: + """Returns result of operation in segment.""" + if start == node_start and end == node_end: + return self.tree[node] + mid = (node_start + node_end) // 2 + if end <= mid: + return self._operate_helper(start, end, 2 * node, node_start, mid) + else: + if mid + 1 <= start: + return self._operate_helper(start, end, 2 * node + 1, mid + 1, node_end) + else: + return self.operation( + self._operate_helper(start, mid, 2 * node, node_start, mid), + self._operate_helper(mid + 1, end, 2 * node + 1, mid + 1, node_end), + ) + + def operate(self, start: int = 0, end: int = 0) -> float: + """Returns result of applying `self.operation`.""" + if end <= 0: + end += self.capacity + end -= 1 + + return self._operate_helper(start, end, 1, 0, self.capacity - 1) + + def __setitem__(self, idx: int, val: float): + """Set value in tree.""" + idx += self.capacity + self.tree[idx] = val + + idx //= 2 + while idx >= 1: + self.tree[idx] = self.operation(self.tree[2 * idx], self.tree[2 * idx + 1]) + idx //= 2 + + def __getitem__(self, idx: int) -> float: + """Get real value in leaf node of tree.""" + assert 0 <= idx < self.capacity + + return self.tree[self.capacity + idx] + + +class SumSegmentTree(SegmentTree): + """ Create SumSegmentTree. + + Taken from OpenAI baselines github repository: + https://github.com/openai/baselines/blob/master/baselines/common/segment_tree.py + + """ + + def __init__(self, capacity: int): + """Initialization. + + Args: + capacity (int) + + """ + super(SumSegmentTree, self).__init__( + capacity=capacity, operation=operator.add, init_value=0.0 + ) + + def sum(self, start: int = 0, end: int = 0) -> float: + """Returns arr[start] + ... + arr[end].""" + return super(SumSegmentTree, self).operate(start, end) + + def retrieve(self, upperbound: float) -> int: + """Find the highest index `i` about upper bound in the tree""" + # TODO: Check assert case and fix bug + assert 0 <= upperbound <= self.sum() + 1e-5, "upperbound: {}".format(upperbound) + + idx = 1 + + while idx < self.capacity: # while non-leaf + left = 2 * idx + right = left + 1 + if self.tree[left] > upperbound: + idx = 2 * idx + else: + upperbound -= self.tree[left] + idx = right + return idx - self.capacity + + +class MinSegmentTree(SegmentTree): + """ Create SegmentTree. + + Taken from OpenAI baselines github repository: + https://github.com/openai/baselines/blob/master/baselines/common/segment_tree.py + + """ + + def __init__(self, capacity: int): + """Initialization. + + Args: + capacity (int) + + """ + super(MinSegmentTree, self).__init__( + capacity=capacity, operation=min, init_value=float("inf") + ) + + def min(self, start: int = 0, end: int = 0) -> float: + """Returns min(arr[start], ..., arr[end]).""" + return super(MinSegmentTree, self).operate(start, end) \ No newline at end of file diff --git a/scripted_policy.py b/scripted_policy.py new file mode 100644 index 0000000..57ab471 --- /dev/null +++ b/scripted_policy.py @@ -0,0 +1,233 @@ +import numpy as np +from pyquaternion import Quaternion + +from sim_tasks import normalize_task_name + + +class BasePolicy: + def __init__(self, inject_noise=False): + self.inject_noise = inject_noise + self.step_count = 0 + self.left_trajectory = None + self.right_trajectory = None + + def reset(self): + self.step_count = 0 + self.left_trajectory = None + self.right_trajectory = None + + def generate_trajectory(self, ts_first): + raise NotImplementedError + + @staticmethod + def interpolate(curr_waypoint, next_waypoint, t): + t_frac = (t - curr_waypoint["t"]) / (next_waypoint["t"] - curr_waypoint["t"] + 1e-8) + curr_xyz = curr_waypoint['xyz'] + curr_quat = curr_waypoint['quat'] + curr_grip = curr_waypoint['gripper'] + next_xyz = next_waypoint['xyz'] + next_quat = next_waypoint['quat'] + next_grip = next_waypoint['gripper'] + xyz = curr_xyz + (next_xyz - curr_xyz) * t_frac + quat = curr_quat + (next_quat - curr_quat) * t_frac + gripper = curr_grip + (next_grip - curr_grip) * t_frac + return xyz, quat, gripper + + def __call__(self, ts, step_inc=1): + if step_inc <= 0: + raise ValueError("step_inc must be positive") + + # generate trajectory at first timestep, then open-loop execution + if self.step_count == 0: + self.generate_trajectory(ts) + + curr_left_waypoint, next_left_waypoint = self._waypoint_pair( + self.left_trajectory, self.step_count + ) + curr_right_waypoint, next_right_waypoint = self._waypoint_pair( + self.right_trajectory, self.step_count + ) + + # interpolate between waypoints to obtain current pose and gripper command + left_xyz, left_quat, left_gripper = self.interpolate( + curr_left_waypoint, next_left_waypoint, self.step_count + ) + right_xyz, right_quat, right_gripper = self.interpolate( + curr_right_waypoint, next_right_waypoint, self.step_count + ) + + # Inject noise + if self.inject_noise: + scale = 0.01 + left_xyz = left_xyz + np.random.uniform(-scale, scale, left_xyz.shape) + right_xyz = right_xyz + np.random.uniform(-scale, scale, right_xyz.shape) + + action_left = np.concatenate([left_xyz, left_quat, [left_gripper]]) + action_right = np.concatenate([right_xyz, right_quat, [right_gripper]]) + + self.step_count += step_inc + return np.concatenate([action_left, action_right]) + + @staticmethod + def _waypoint_pair(trajectory, timestep): + """Find a safe interpolation bracket, including at the final waypoint.""" + + if not trajectory or len(trajectory) < 2: + raise ValueError("A scripted trajectory must contain at least two waypoints") + if timestep >= trajectory[-1]["t"]: + return trajectory[-1], trajectory[-1] + for current, following in zip(trajectory[:-1], trajectory[1:]): + if current["t"] <= timestep < following["t"]: + return current, following + return trajectory[0], trajectory[1] + + +class PickAndTransferPolicy(BasePolicy): + + def generate_trajectory(self, ts_first): + init_mocap_pose_right = ts_first.observation['mocap_pose_right'] + init_mocap_pose_left = ts_first.observation['mocap_pose_left'] + + box_info = np.array(ts_first.observation['env_state']) + box_xyz = box_info[:3] + box_quat = box_info[3:] + # print(f"Generate trajectory for {box_xyz=}") + + gripper_pick_quat = Quaternion(init_mocap_pose_right[3:]) + gripper_pick_quat = gripper_pick_quat * Quaternion(axis=[0.0, 1.0, 0.0], degrees=-60) + + meet_left_quat = Quaternion(axis=[1.0, 0.0, 0.0], degrees=90) + + meet_xyz = np.array([0, 0.5, 0.25]) + + self.left_trajectory = [ + {"t": 0, "xyz": init_mocap_pose_left[:3], "quat": init_mocap_pose_left[3:], "gripper": 0}, # sleep + {"t": 100, "xyz": meet_xyz + np.array([-0.1, 0, -0.02]), "quat": meet_left_quat.elements, "gripper": 1}, # approach meet position + {"t": 260, "xyz": meet_xyz + np.array([0.02, 0, -0.02]), "quat": meet_left_quat.elements, "gripper": 1}, # move to meet position + {"t": 310, "xyz": meet_xyz + np.array([0.02, 0, -0.02]), "quat": meet_left_quat.elements, "gripper": 0}, # close gripper + {"t": 360, "xyz": meet_xyz + np.array([-0.1, 0, -0.02]), "quat": np.array([1, 0, 0, 0]), "gripper": 0}, # move left + {"t": 400, "xyz": meet_xyz + np.array([-0.1, 0, -0.02]), "quat": np.array([1, 0, 0, 0]), "gripper": 0}, # stay + ] + + self.right_trajectory = [ + {"t": 0, "xyz": init_mocap_pose_right[:3], "quat": init_mocap_pose_right[3:], "gripper": 0}, # sleep + {"t": 90, "xyz": box_xyz + np.array([0, 0, 0.08]), "quat": gripper_pick_quat.elements, "gripper": 1}, # approach the cube + {"t": 130, "xyz": box_xyz + np.array([0., 0, -0.015]), "quat": gripper_pick_quat.elements, "gripper": 1}, # go down + {"t": 170, "xyz": box_xyz + np.array([0, 0, -0.015]), "quat": gripper_pick_quat.elements, "gripper": 0}, # close gripper + {"t": 200, "xyz": meet_xyz + np.array([0.05, 0, 0]), "quat": gripper_pick_quat.elements, "gripper": 0}, # approach meet position + {"t": 220, "xyz": meet_xyz, "quat": gripper_pick_quat.elements, "gripper": 0}, # move to meet position + {"t": 310, "xyz": meet_xyz, "quat": gripper_pick_quat.elements, "gripper": 1}, # open gripper + {"t": 360, "xyz": meet_xyz + np.array([0.1, 0, 0]), "quat": gripper_pick_quat.elements, "gripper": 1}, # move to right + {"t": 400, "xyz": meet_xyz + np.array([0.1, 0, 0]), "quat": gripper_pick_quat.elements, "gripper": 1}, # stay + ] + +class PickAndTransferTeaBagPolicy(BasePolicy): + + def generate_trajectory(self, ts_first): + init_mocap_pose_right = ts_first.observation['mocap_pose_right'] + init_mocap_pose_left = ts_first.observation['mocap_pose_left'] + + box_info = np.array(ts_first.observation['env_state']) + + box_xyz = box_info[:3] + box_quat = box_info[3:] + #print(f"Generate trajectory for {box_xyz=}") + + gripper_pick_quat_org = Quaternion(init_mocap_pose_right[3:]) + gripper_pick_quat = gripper_pick_quat_org * Quaternion(axis=[0.0, 1.0, 0.0], degrees=-90) + gripper_move_quat = gripper_pick_quat_org * Quaternion(axis=[0.0, 1.0, 0.0], degrees=-20) + + meet_left_quat = Quaternion(axis=[1.0, 0.0, 0.0], degrees=90) + + meet_xyz = np.array([-0.1, 0.6, 0.30]) + + + self.left_trajectory = [ + {"t": 0, "xyz": init_mocap_pose_left[:3], "quat": init_mocap_pose_left[3:], "gripper": 0}, # sleep + {"t": 500, "xyz": init_mocap_pose_left[:3], "quat": np.array([1, 0, 0, 0]), "gripper": 0}, # stay + ] + + ''' + # Old policy, oscillation is a problem + self.right_trajectory = [ + {"t": 0, "xyz": init_mocap_pose_right[:3], "quat": init_mocap_pose_right[3:], "gripper": 0}, # sleep + {"t": 50, "xyz": box_xyz + np.array([0, 0, 0.08]), "quat": gripper_pick_quat.elements, "gripper": 1}, # approach the cube + {"t": 70, "xyz": box_xyz + np.array([0.005, 0, -0.03]), "quat": gripper_pick_quat.elements, "gripper": 1}, # go down + {"t": 100, "xyz": box_xyz + np.array([0.005, 0, -0.03]), "quat": gripper_pick_quat.elements, "gripper": 0}, # close gripper + {"t": 170, "xyz": meet_xyz + np.array([0.05, 0, 0]), "quat": gripper_move_quat.elements, "gripper": 0}, # approach meet position + {"t": 200, "xyz": meet_xyz, "quat": gripper_move_quat.elements, "gripper": 0}, # move to meet position + {"t": 420, "xyz": meet_xyz, "quat": gripper_move_quat.elements, "gripper": 0}, # open gripper + {"t": 460, "xyz": meet_xyz, "quat": gripper_move_quat.elements, "gripper": 1}, # open gripper + {"t": 500, "xyz": meet_xyz + np.array([0.1, 0, 0]), "quat": gripper_pick_quat.elements, "gripper": 1}, + ] + ''' + + self.right_trajectory = [ + {"t": 0, "xyz": init_mocap_pose_right[:3], "quat": init_mocap_pose_right[3:], "gripper": 0}, # sleep + {"t": 50, "xyz": box_xyz + np.array([0, 0, 0.08]), "quat": gripper_pick_quat.elements, "gripper": 1}, # approach the cube + {"t": 70, "xyz": box_xyz + np.array([0.005, 0, -0.03]), "quat": gripper_pick_quat.elements, "gripper": 1}, # go down + {"t": 100, "xyz": box_xyz + np.array([0.005, 0, -0.03]), "quat": gripper_pick_quat.elements, "gripper": 0}, # close gripper + {"t": 150, "xyz": box_xyz + np.array([0.1, 0, 0.1]), "quat": gripper_pick_quat.elements, "gripper": 0}, # vertical align + {"t": 250, "xyz": box_xyz + np.array([0.1, 0, 0.3]), "quat": gripper_move_quat.elements, "gripper": 0}, # rise up + {"t": 400, "xyz": meet_xyz, "quat": gripper_move_quat.elements, "gripper": 0}, # move to meet position + {"t": 420, "xyz": meet_xyz, "quat": gripper_move_quat.elements, "gripper": 0}, # open gripper + {"t": 450, "xyz": meet_xyz, "quat": gripper_move_quat.elements, "gripper": 1}, # open gripper + {"t": 500, "xyz": init_mocap_pose_right[:3], "quat": gripper_move_quat.elements, "gripper": 1}, + ] + +class InsertionPolicy(BasePolicy): + + def generate_trajectory(self, ts_first): + init_mocap_pose_right = ts_first.observation['mocap_pose_right'] + init_mocap_pose_left = ts_first.observation['mocap_pose_left'] + + peg_info = np.array(ts_first.observation['env_state'])[:7] + peg_xyz = peg_info[:3] + peg_quat = peg_info[3:] + + socket_info = np.array(ts_first.observation['env_state'])[7:] + socket_xyz = socket_info[:3] + socket_quat = socket_info[3:] + + gripper_pick_quat_right = Quaternion(init_mocap_pose_right[3:]) + gripper_pick_quat_right = gripper_pick_quat_right * Quaternion(axis=[0.0, 1.0, 0.0], degrees=-60) + + gripper_pick_quat_left = Quaternion(init_mocap_pose_right[3:]) + gripper_pick_quat_left = gripper_pick_quat_left * Quaternion(axis=[0.0, 1.0, 0.0], degrees=60) + + meet_xyz = np.array([0, 0.5, 0.15]) + lift_right = 0.00715 + + self.left_trajectory = [ + {"t": 0, "xyz": init_mocap_pose_left[:3], "quat": init_mocap_pose_left[3:], "gripper": 0}, # sleep + {"t": 120, "xyz": socket_xyz + np.array([0, 0, 0.08]), "quat": gripper_pick_quat_left.elements, "gripper": 1}, # approach the cube + {"t": 170, "xyz": socket_xyz + np.array([0, 0, -0.03]), "quat": gripper_pick_quat_left.elements, "gripper": 1}, # go down + {"t": 220, "xyz": socket_xyz + np.array([0, 0, -0.03]), "quat": gripper_pick_quat_left.elements, "gripper": 0}, # close gripper + {"t": 285, "xyz": meet_xyz + np.array([-0.1, 0, 0]), "quat": gripper_pick_quat_left.elements, "gripper": 0}, # approach meet position + {"t": 340, "xyz": meet_xyz + np.array([-0.05, 0, 0]), "quat": gripper_pick_quat_left.elements,"gripper": 0}, # insertion + {"t": 400, "xyz": meet_xyz + np.array([-0.05, 0, 0]), "quat": gripper_pick_quat_left.elements, "gripper": 0}, # insertion + ] + + self.right_trajectory = [ + {"t": 0, "xyz": init_mocap_pose_right[:3], "quat": init_mocap_pose_right[3:], "gripper": 0}, # sleep + {"t": 120, "xyz": peg_xyz + np.array([0, 0, 0.08]), "quat": gripper_pick_quat_right.elements, "gripper": 1}, # approach the cube + {"t": 170, "xyz": peg_xyz + np.array([0, 0, -0.03]), "quat": gripper_pick_quat_right.elements, "gripper": 1}, # go down + {"t": 220, "xyz": peg_xyz + np.array([0, 0, -0.03]), "quat": gripper_pick_quat_right.elements, "gripper": 0}, # close gripper + {"t": 285, "xyz": meet_xyz + np.array([0.1, 0, lift_right]), "quat": gripper_pick_quat_right.elements, "gripper": 0}, # approach meet position + {"t": 340, "xyz": meet_xyz + np.array([0.05, 0, lift_right]), "quat": gripper_pick_quat_right.elements, "gripper": 0}, # insertion + {"t": 400, "xyz": meet_xyz + np.array([0.05, 0, lift_right]), "quat": gripper_pick_quat_right.elements, "gripper": 0}, # insertion + + ] + + +POLICY_CLASSES = { + "pick_and_place": PickAndTransferPolicy, + "insertion": InsertionPolicy, + "tea_bag": PickAndTransferTeaBagPolicy, +} + + +def make_scripted_policy(task_name, inject_noise=False): + """Construct the matching historical scripted policy for a sim task.""" + + return POLICY_CLASSES[normalize_task_name(task_name)](inject_noise=inject_noise) diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..2e7511c --- /dev/null +++ b/scripts/__init__.py @@ -0,0 +1 @@ +"""Command-line entry points for the SpeedTuning simulator release.""" diff --git a/scripts/check_chunked_policy.py b/scripts/check_chunked_policy.py new file mode 100644 index 0000000..d70a822 --- /dev/null +++ b/scripts/check_chunked_policy.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +"""Exercise ACT-style action chunks against every joint simulator.""" + +import json +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from chunked_policy import replay_recorded_chunks # noqa: E402 +from sim_tasks import TASK_SPECS # noqa: E402 + + +def main(): + results = [replay_recorded_chunks(task) for task in TASK_SPECS] + for result in results: + print(json.dumps(result, sort_keys=True)) + return 0 if all(result["success"] for result in results) else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/eval_speed_policy.py b/scripts/eval_speed_policy.py new file mode 100644 index 0000000..34fbc13 --- /dev/null +++ b/scripts/eval_speed_policy.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +"""Evaluate fixed, profiled, Rainbow, or external speed policies.""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + +import numpy as np + + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from experiment_config import defaults_from_argv # noqa: E402 +from policy_speed_env import make_speed_reward # noqa: E402 +from policy_loader import load_speed_policy # noqa: E402 +from scripts.policy_cli import ( # noqa: E402 + add_base_policy_arguments, + add_observation_arguments, + build_speed_env, + comma_floats, + comma_ints, + json_object, +) +from speed_policy import ( # noqa: E402 + FixedSpeedPolicy, + RainbowSpeedPolicy, + SpeedProfilePolicy, + rollout_speed_policy, + summarize_rollouts, +) + + +def parse_args(): + config_defaults, config_metadata = defaults_from_argv() + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--config", help="JSON manifest or named preset such as paper-sim.") + parser.add_argument("--task", choices=("pick_and_place", "insertion", "tea_bag"), default="tea_bag") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--device", default="cpu") + parser.add_argument("--episodes", type=int, default=10) + parser.add_argument( + "--seeds", + type=comma_ints, + help="Explicit episode seeds; when set, one rollout is run per seed.", + ) + parser.add_argument("--frame-skip", type=int, default=10) + parser.add_argument("--success-bonus", type=float, default=100.0) + parser.add_argument("--speed-weight", type=float, default=0.01) + parser.add_argument("--speed-power", type=float, default=2.0) + parser.add_argument("--speed-values", type=comma_floats, default=(1.0, 1.5, 2.0, 2.5, 3.0)) + parser.add_argument( + "--speed-policy", + choices=("fixed", "profile", "rainbow", "external"), + default="fixed", + ) + parser.add_argument("--speed", type=float, default=1.0) + parser.add_argument("--profile", type=comma_floats) + parser.add_argument("--speed-checkpoint", type=Path) + parser.add_argument("--speed-policy-loader", help="External speed factory as module:attribute.") + parser.add_argument("--speed-factory-kwargs", type=json_object, default={}) + parser.add_argument("--video", type=Path) + add_base_policy_arguments(parser) + add_observation_arguments(parser) + parser.set_defaults(**config_defaults) + return parser.parse_args(), config_metadata + + +def build_speed_policy(args): + if args.speed_policy == "fixed": + return FixedSpeedPolicy(args.speed) + if args.speed_policy == "profile": + if args.profile is None: + raise ValueError("--profile is required for a profile speed policy") + return SpeedProfilePolicy(args.profile) + if args.speed_policy == "rainbow": + if args.speed_checkpoint is None: + raise ValueError("--speed-checkpoint is required for a Rainbow speed policy") + return RainbowSpeedPolicy.load(args.speed_checkpoint, device=args.device) + if not args.speed_policy_loader: + raise ValueError("--speed-policy-loader is required for an external speed policy") + return load_speed_policy( + args.speed_policy_loader, + checkpoint=args.speed_checkpoint, + device=args.device, + factory_kwargs=args.speed_factory_kwargs, + ) + + +def main(): + args, config_metadata = parse_args() + if args.episodes <= 0: + print("error: --episodes must be positive", file=sys.stderr) + return 2 + try: + policy = build_speed_policy(args) + reward_fn = make_speed_reward( + success_bonus=args.success_bonus, + speed_weight=args.speed_weight, + speed_power=args.speed_power, + ) + args.restore_observation_encoder = isinstance(policy, RainbowSpeedPolicy) + seeds = args.seeds or tuple(range(args.seed, args.seed + args.episodes)) + rollouts = [] + for index, seed in enumerate(seeds): + env = build_speed_env( + args, + reward_fn=reward_fn, + video_path=args.video if index == 0 else None, + seed=seed, + ) + try: + rollout = rollout_speed_policy( + env, + policy, + frame_skip=( + policy.frame_skip + if isinstance(policy, RainbowSpeedPolicy) + else args.frame_skip + ), + ) + rollout["seed"] = seed + rollouts.append(rollout) + finally: + env.close() + result = { + "task": args.task, + "base_policy": args.base_policy, + "speed_policy": args.speed_policy, + "seeds": list(seeds), + "experiment_config": config_metadata, + **summarize_rollouts(rollouts), + "rollouts": rollouts, + } + print(json.dumps(result, sort_keys=True)) + return 0 + except (ImportError, RuntimeError, ValueError) as exc: + print(f"error: {exc}", file=sys.stderr) + return 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/policy_cli.py b/scripts/policy_cli.py new file mode 100644 index 0000000..f37243e --- /dev/null +++ b/scripts/policy_cli.py @@ -0,0 +1,179 @@ +"""Shared command-line helpers for base-policy and speed-policy tools.""" + +from __future__ import annotations + +import json + +from policy_loader import load_chunk_predictor, load_observation_encoder +from policy_speed_env import create_recorded_chunk_speed_env, create_speed_env +from speed_observation import StateObservationEncoder, VisualObservationEncoder + + +def comma_floats(value): + try: + values = tuple(float(item.strip()) for item in value.split(",")) + except ValueError as exc: + raise ValueError("Expected comma-separated numbers") from exc + if not values: + raise ValueError("Expected at least one number") + return values + + +def comma_strings(value): + values = tuple(item.strip() for item in value.split(",") if item.strip()) + if not values: + raise ValueError("Expected at least one comma-separated value") + return values + + +def comma_ints(value): + try: + values = tuple(int(item.strip()) for item in value.split(",")) + except ValueError as exc: + raise ValueError("Expected comma-separated integers") from exc + if not values: + raise ValueError("Expected at least one integer") + return values + + +def json_object(value): + parsed = json.loads(value) + if not isinstance(parsed, dict): + raise ValueError("Factory kwargs must be a JSON object") + return parsed + + +def add_base_policy_arguments(parser): + parser.add_argument( + "--base-policy", + choices=("scripted", "recorded-chunk", "external-chunk"), + default="scripted", + help="Robot policy wrapped by the speed controller.", + ) + parser.add_argument( + "--chunk-policy", + help="External chunk factory as module:attribute (required for external-chunk).", + ) + parser.add_argument("--upstream-checkpoint") + parser.add_argument("--factory-kwargs", type=json_object, default={}) + parser.add_argument("--chunk-size", type=int, default=25) + parser.add_argument( + "--no-policy-images", + action="store_true", + help="Do not render cameras for an external policy that only uses state.", + ) + parser.add_argument( + "--randomize-object-pose", + action="store_true", + help="Sample a new tea-bag pose on every reset (cube/insertion already vary).", + ) + + +def add_observation_arguments(parser): + parser.add_argument( + "--speed-observation", + choices=("state", "visual", "external"), + default="state", + help="Input representation used by the speed policy.", + ) + parser.add_argument("--frame-stack", type=int, default=1) + parser.add_argument( + "--camera-names", + type=comma_strings, + default=("top", "angle", "vis"), + ) + parser.add_argument( + "--image-encoder", + choices=("resnet18-pretrained", "resnet18-random"), + default="resnet18-pretrained", + ) + parser.add_argument("--image-size", type=int, default=224) + parser.add_argument("--observation-encoder-loader") + parser.add_argument("--observation-factory-kwargs", type=json_object, default={}) + parser.add_argument( + "--include-env-state", dest="include_env_state", action="store_true", default=True + ) + parser.add_argument("--no-env-state", dest="include_env_state", action="store_false") + parser.add_argument( + "--include-qpos", dest="include_qpos", action="store_true", default=True + ) + parser.add_argument("--no-qpos", dest="include_qpos", action="store_false") + parser.add_argument( + "--include-qvel", dest="include_qvel", action="store_true", default=True + ) + parser.add_argument("--no-qvel", dest="include_qvel", action="store_false") + + +def build_observation_encoder(args): + if args.speed_observation == "state": + return StateObservationEncoder( + include_qpos=args.include_qpos, + include_qvel=args.include_qvel, + include_env_state=args.include_env_state, + ) + if args.speed_observation == "visual": + return VisualObservationEncoder( + camera_names=args.camera_names, + pretrained=args.image_encoder == "resnet18-pretrained", + image_size=args.image_size, + device=args.device, + include_qpos=args.include_qpos, + include_qvel=args.include_qvel, + include_env_state=args.include_env_state, + initialize_pretrained=not getattr( + args, "restore_observation_encoder", False + ), + ) + if not args.observation_encoder_loader: + raise ValueError( + "--observation-encoder-loader is required for external observations" + ) + return load_observation_encoder( + args.observation_encoder_loader, + task_name=args.task, + checkpoint=args.upstream_checkpoint, + device=args.device, + factory_kwargs=args.observation_factory_kwargs, + ) + + +def build_speed_env(args, reward_fn=None, video_path=None, seed=None): + observation_encoder = build_observation_encoder(args) + common = { + "task_name": args.task, + "reward_fn": reward_fn, + "seed": args.seed if seed is None else seed, + "speed_values": args.speed_values, + "observation_encoder": observation_encoder, + "frame_stack": args.frame_stack, + "decision_frame_skip": args.frame_skip, + "randomize_object_pose": args.randomize_object_pose, + } + if video_path is not None: + common.update(save_video=True, video_path=video_path) + + if args.base_policy == "scripted": + return create_speed_env(**common) + if args.base_policy == "recorded-chunk": + return create_recorded_chunk_speed_env( + chunk_size=args.chunk_size, + render_images=getattr(observation_encoder, "requires_images", False), + **common, + ) + if not args.chunk_policy: + raise ValueError("--chunk-policy is required with --base-policy external-chunk") + predictor = load_chunk_predictor( + args.chunk_policy, + task_name=args.task, + checkpoint=args.upstream_checkpoint, + device=args.device, + factory_kwargs=args.factory_kwargs, + ) + return create_speed_env( + chunk_predictor=predictor, + render_images=( + not args.no_policy_images + or getattr(observation_encoder, "requires_images", False) + ), + **common, + ) diff --git a/scripts/rainbow_poc.py b/scripts/rainbow_poc.py new file mode 100644 index 0000000..5284bc8 --- /dev/null +++ b/scripts/rainbow_poc.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +"""Run a small Rainbow DQN optimization proof on the tea-bag speed task.""" + +from __future__ import annotations + +import argparse +import json +import random +import sys +from pathlib import Path + +import numpy as np + + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +try: + import torch +except ImportError as exc: + raise SystemExit("Rainbow POC requires: uv sync --extra rl") from exc + +from policy_speed_env import create_speed_env # noqa: E402 +from rl.rainbowDQN.dqnAgent import DQNAgent # noqa: E402 + + +def speed_reward(speed, done, success): + reward = speed**2 / 100.0 + if done and success: + reward += 100.0 + return reward + + +def run_poc(seed=0, min_transitions=64, updates=8): + """Collect real simulator transitions and perform Rainbow optimizer steps.""" + + np.random.seed(seed) + random.seed(seed) + torch.manual_seed(seed) + env = create_speed_env( + task_name="tea_bag", + reward_fn=speed_reward, + seed=seed, + ) + agent = DQNAgent( + env, + memory_size=2048, + batch_size=16, + target_update=4, + seed=seed, + lr=3e-4, + gamma=0.97, + frame_skip=5, + epsilon=1.0, + exploration_steps=1000, + min_epsilon=0.1, + atom_size=51, + v_min=0.0, + v_max=120.0, + n_step=3, + hidden_dim=64, + device="cpu", + log_dir=None, + ) + + episodes = 0 + successes = 0 + actions_seen = set() + rng = np.random.RandomState(seed) + decision_index = 0 + while len(agent.memory) < min_transitions: + state = env.reset() + done = False + info = {"success": False} + while not done: + # Exercise every action during the initial approach, then collect a + # predominantly safe 1.0x/1.5x rollout so terminal success is present. + if decision_index < env.action_space: + action = decision_index + else: + action = int(rng.choice(2, p=[0.8, 0.2])) + decision_index += 1 + actions_seen.add(action) + agent.transition = [state, action] + state, _, done, info = agent.step(action, frame_skip=agent.frame_skip) + episodes += 1 + successes += int(info["success"]) + + states = agent.memory.obs_buf[: len(agent.memory)] + norm_stats = { + "states_mean": states.mean(axis=0), + "states_std": states.std(axis=0), + } + agent.dqn.update_norm_stats(norm_stats) + agent.dqn_target.update_norm_stats(norm_stats) + + parameters_before = [parameter.detach().clone() for parameter in agent.dqn.parameters()] + losses = [] + for update in range(updates): + loss = agent.update_model() + losses.append(loss) + if (update + 1) % agent.target_update == 0: + agent._target_soft_update() + + parameter_delta = sum( + (before - after.detach()).abs().sum().item() + for before, after in zip(parameters_before, agent.dqn.parameters()) + ) + probe = torch.as_tensor(states[:4], dtype=torch.float32) + with torch.inference_mode(): + q_values = agent.dqn(probe) + distributions = agent.dqn.dist(probe) + + result = { + "task": "tea_bag", + "episodes": episodes, + "successful_episodes": successes, + "replay_transitions": len(agent.memory), + "actions_seen": sorted(actions_seen), + "updates": updates, + "loss_first": losses[0], + "loss_last": losses[-1], + "losses_finite": bool(np.isfinite(losses).all()), + "parameter_delta": parameter_delta, + "q_shape": list(q_values.shape), + "distributions_normalized": bool( + torch.allclose( + distributions.sum(dim=-1), + torch.ones_like(distributions.sum(dim=-1)), + atol=1e-5, + ) + ), + } + result["passed"] = bool( + result["losses_finite"] + and parameter_delta > 0 + and result["distributions_normalized"] + and len(agent.memory) >= min_transitions + ) + env.close() + return result + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--min-transitions", type=int, default=64) + parser.add_argument("--updates", type=int, default=8) + args = parser.parse_args() + result = run_poc(args.seed, args.min_transitions, args.updates) + print(json.dumps(result, sort_keys=True)) + return 0 if result["passed"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/run_sim.py b/scripts/run_sim.py new file mode 100644 index 0000000..3e2d395 --- /dev/null +++ b/scripts/run_sim.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +"""Run the recovered SpeedTuning scripted simulation tasks.""" + +from __future__ import annotations + +import argparse +import json +import math +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from ee_sim_env import make_ee_sim_env # noqa: E402 +from scripted_policy import make_scripted_policy # noqa: E402 +from sim_tasks import TASK_SPECS, normalize_task_name # noqa: E402 + + +def run_task(task_name, speed=1.0, seed=0, video_path=None): + """Run one open-loop scripted rollout and return a JSON-safe summary.""" + + task_name = normalize_task_name(task_name) + spec = TASK_SPECS[task_name] + render_images = video_path is not None + env = make_ee_sim_env(task_name, render_images=render_images, seed=seed) + timestep = env.reset() + policy = make_scripted_policy(task_name) + rewards = [] + frames = [] + + num_steps = math.ceil(spec.episode_len / speed) + for _ in range(num_steps): + timestep = env.step(policy(timestep, step_inc=speed)) + rewards.append(int(timestep.reward or 0)) + if render_images: + frames.append(timestep.observation["images"]["angle"]) + + max_reward = max(rewards, default=0) + result = { + "task": task_name, + "success": max_reward == env.task.max_reward, + "max_reward": max_reward, + "target_reward": env.task.max_reward, + "return": sum(rewards), + "steps": num_steps, + "speed": speed, + "seed": seed, + } + + if video_path is not None: + try: + import imageio.v2 as imageio + except ImportError as exc: + raise RuntimeError( + "Video export requires: uv sync --extra video" + ) from exc + video_path.parent.mkdir(parents=True, exist_ok=True) + imageio.mimsave(video_path, frames, fps=max(1, round(50 / speed))) + result["video"] = str(video_path) + return result + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Run recovered pick-and-place, insertion, and tea-bag simulations." + ) + parser.add_argument( + "--task", + action="append", + help="Task to run; repeat the flag for multiple tasks (default: all).", + ) + parser.add_argument("--speed", type=float, default=1.0, help="Waypoint time increment.") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument( + "--video-dir", + type=Path, + help="Optional directory for angle-camera MP4 rollouts.", + ) + return parser.parse_args() + + +def main(): + args = parse_args() + if args.speed <= 0: + raise SystemExit("--speed must be positive") + tasks = args.task or list(TASK_SPECS) + results = [] + for requested_task in tasks: + task_name = normalize_task_name(requested_task) + video_path = None + if args.video_dir is not None: + video_path = args.video_dir / f"{task_name}.mp4" + result = run_task( + task_name, + speed=args.speed, + seed=args.seed, + video_path=video_path, + ) + results.append(result) + print(json.dumps(result, sort_keys=True)) + return 0 if all(result["success"] for result in results) else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/sweep_speed_policy.py b/scripts/sweep_speed_policy.py new file mode 100644 index 0000000..42d9891 --- /dev/null +++ b/scripts/sweep_speed_policy.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +"""Run the paper-style fixed-speed sweep and optional adaptive-policy evaluation.""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from experiment_config import defaults_from_argv # noqa: E402 +from policy_loader import load_speed_policy # noqa: E402 +from policy_speed_env import make_speed_reward # noqa: E402 +from scripts.policy_cli import ( # noqa: E402 + add_base_policy_arguments, + add_observation_arguments, + build_speed_env, + comma_floats, + comma_ints, + json_object, +) +from speed_evaluation import ( # noqa: E402 + evaluate_fixed_speed_sweep, + evaluate_seeded_policy, + plot_speed_success_tradeoff, + speed_grid, +) +from speed_policy import RainbowSpeedPolicy, SpeedProfilePolicy # noqa: E402 + + +def parse_args(): + defaults, config_metadata = defaults_from_argv() + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--config", help="JSON manifest or named preset such as paper-sim.") + parser.add_argument("--task", choices=("pick_and_place", "insertion", "tea_bag"), default="tea_bag") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--seeds", type=comma_ints) + parser.add_argument("--device", default="cpu") + parser.add_argument("--frame-skip", type=int, default=10) + parser.add_argument("--success-bonus", type=float, default=100.0) + parser.add_argument("--speed-weight", type=float, default=0.01) + parser.add_argument("--speed-power", type=float, default=2.0) + parser.add_argument("--speed-values", type=comma_floats, default=(1.0, 1.5, 2.0, 2.5, 3.0)) + parser.add_argument("--speed-start", type=float, default=1.0) + parser.add_argument("--speed-stop", type=float, default=4.5) + parser.add_argument("--speed-step", type=float, default=0.1) + parser.add_argument("--episodes-per-speed", type=int, default=100) + parser.add_argument("--adaptive-episodes", type=int, default=0) + parser.add_argument( + "--adaptive-policy", + choices=("rainbow", "external", "profile"), + ) + parser.add_argument("--profile", type=comma_floats) + parser.add_argument("--speed-checkpoint", type=Path) + parser.add_argument("--speed-policy-loader") + parser.add_argument("--speed-factory-kwargs", type=json_object, default={}) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--plot", type=Path) + add_base_policy_arguments(parser) + add_observation_arguments(parser) + parser.set_defaults(**defaults) + return parser.parse_args(), config_metadata + + +def build_adaptive_policy(args): + if args.adaptive_policy is None: + return None + if args.adaptive_policy == "rainbow": + if args.speed_checkpoint is None: + raise ValueError("--speed-checkpoint is required for Rainbow evaluation") + return RainbowSpeedPolicy.load(args.speed_checkpoint, device=args.device) + if args.adaptive_policy == "profile": + if args.profile is None: + raise ValueError("--profile is required for profile evaluation") + return SpeedProfilePolicy(args.profile) + if not args.speed_policy_loader: + raise ValueError("--speed-policy-loader is required for external evaluation") + return load_speed_policy( + args.speed_policy_loader, + checkpoint=args.speed_checkpoint, + device=args.device, + factory_kwargs=args.speed_factory_kwargs, + ) + + +def main(): + args, config_metadata = parse_args() + try: + if args.episodes_per_speed <= 0 or args.adaptive_episodes < 0: + raise ValueError("Episode counts must be positive (or zero for adaptive)") + adaptive_policy = build_adaptive_policy(args) + reward_fn = make_speed_reward( + success_bonus=args.success_bonus, + speed_weight=args.speed_weight, + speed_power=args.speed_power, + ) + args.restore_observation_encoder = isinstance( + adaptive_policy, RainbowSpeedPolicy + ) + fixed_seeds = args.seeds or tuple( + range(args.seed, args.seed + args.episodes_per_speed) + ) + + def env_factory(seed): + return build_speed_env(args, reward_fn=reward_fn, seed=seed) + + report = { + "task": args.task, + "base_policy": args.base_policy, + "frame_skip": args.frame_skip, + "metric": "physical_acceleration=episode_len/physics_steps", + "experiment_config": config_metadata, + "fixed_speed_sweep": evaluate_fixed_speed_sweep( + env_factory, + speed_grid(args.speed_start, args.speed_stop, args.speed_step), + fixed_seeds, + frame_skip=args.frame_skip, + ), + } + if adaptive_policy is not None: + count = args.adaptive_episodes or 2000 + adaptive_seeds = tuple(range(args.seed, args.seed + count)) + report["adaptive_policy"] = evaluate_seeded_policy( + env_factory, + adaptive_policy, + adaptive_seeds, + frame_skip=( + adaptive_policy.frame_skip + if isinstance(adaptive_policy, RainbowSpeedPolicy) + else args.frame_skip + ), + ) + args.output.parent.mkdir(parents=True, exist_ok=True) + args.output.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n") + if args.plot is not None: + plot_speed_success_tradeoff(report, args.plot) + summary = { + "output": str(args.output), + "plot": None if args.plot is None else str(args.plot), + "fixed_speed_points": len(report["fixed_speed_sweep"]), + "adaptive_episodes": ( + 0 if "adaptive_policy" not in report else report["adaptive_policy"]["episodes"] + ), + } + print(json.dumps(summary, sort_keys=True)) + return 0 + except (ImportError, RuntimeError, ValueError) as exc: + print(f"error: {exc}", file=sys.stderr) + return 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/train_speed_policy.py b/scripts/train_speed_policy.py new file mode 100644 index 0000000..1365fb2 --- /dev/null +++ b/scripts/train_speed_policy.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 +"""Train a Rainbow speed policy around a scripted or external chunked policy.""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from experiment_config import defaults_from_argv # noqa: E402 +from policy_speed_env import make_speed_reward # noqa: E402 +from scripts.policy_cli import ( # noqa: E402 + add_base_policy_arguments, + add_observation_arguments, + build_speed_env, + comma_floats, +) +from speed_training import ( # noqa: E402 + RainbowTrainingConfig, + evaluate_rainbow_speed_policy, + train_rainbow_speed_policy, +) + + +def parse_args(): + config_defaults, config_metadata = defaults_from_argv() + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--config", + help="JSON experiment manifest or named preset such as paper-sim.", + ) + parser.add_argument("--task", choices=("pick_and_place", "insertion", "tea_bag"), default="tea_bag") + parser.add_argument("--output", type=Path, default=Path("outputs/speed_policy.pt")) + parser.add_argument( + "--report", + type=Path, + help="Optional JSON sidecar containing the summary and episode history.", + ) + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--device", default="cpu") + parser.add_argument("--speed-values", type=comma_floats, default=(1.0, 1.5, 2.0, 2.5, 3.0)) + parser.add_argument("--decisions", type=int, default=5_000) + parser.add_argument("--memory-size", type=int, default=100_000) + parser.add_argument("--batch-size", type=int, default=128) + parser.add_argument("--learning-starts", type=int, default=512) + parser.add_argument("--frame-skip", type=int, default=10) + parser.add_argument("--gradient-steps", type=int, default=4) + parser.add_argument("--hidden-dim", type=int, default=256) + parser.add_argument("--train-interval", type=int, default=1) + parser.add_argument( + "--update-schedule", + choices=("decision", "episode"), + default="decision", + help="Optimize after each decision or batch equivalent updates at episode end.", + ) + parser.add_argument( + "--checkpoint-interval", + type=int, + default=0, + help="Also save a numbered checkpoint every N decisions (0 disables it).", + ) + parser.add_argument("--target-update", type=int, default=50) + parser.add_argument("--norm-update-interval", type=int, default=100) + parser.add_argument("--learning-rate", type=float, default=1e-4) + parser.add_argument("--gamma", type=float, default=0.97) + parser.add_argument("--tau", type=float, default=0.5) + parser.add_argument("--epsilon", type=float, default=1.0) + parser.add_argument("--epsilon-decay", type=float, default=0.999) + parser.add_argument("--min-epsilon", type=float, default=0.1) + parser.add_argument("--exploration-steps", type=int, default=2000) + parser.add_argument("--per-alpha", type=float, default=0.2) + parser.add_argument("--per-beta", type=float, default=0.6) + parser.add_argument( + "--beta-schedule", + choices=("linear", "legacy"), + default="linear", + help="Importance-sampling schedule; legacy matches the retained trainer.", + ) + parser.add_argument("--atom-size", type=int, default=121) + parser.add_argument("--v-min", type=float, default=0.0) + parser.add_argument("--v-max", type=float, default=120.0) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--success-bonus", type=float, default=100.0) + parser.add_argument("--speed-weight", type=float, default=0.01) + parser.add_argument("--speed-power", type=float, default=2.0) + parser.add_argument("--eval-episodes", type=int, default=0) + parser.add_argument( + "--quiet", + action="store_true", + help="Suppress per-episode progress while retaining the final JSON summary.", + ) + add_base_policy_arguments(parser) + add_observation_arguments(parser) + parser.set_defaults(**config_defaults) + return parser.parse_args(), config_metadata + + +def main(): + args, config_metadata = parse_args() + reward_fn = make_speed_reward( + success_bonus=args.success_bonus, + speed_weight=args.speed_weight, + speed_power=args.speed_power, + ) + try: + env = build_speed_env(args, reward_fn=reward_fn) + config = RainbowTrainingConfig( + decisions=args.decisions, + memory_size=args.memory_size, + batch_size=args.batch_size, + learning_starts=args.learning_starts, + frame_skip=args.frame_skip, + gradient_steps=args.gradient_steps, + hidden_dim=args.hidden_dim, + train_interval=args.train_interval, + update_schedule=args.update_schedule, + checkpoint_interval=args.checkpoint_interval, + target_update=args.target_update, + norm_update_interval=args.norm_update_interval, + learning_rate=args.learning_rate, + gamma=args.gamma, + tau=args.tau, + epsilon=args.epsilon, + epsilon_decay=args.epsilon_decay, + min_epsilon=args.min_epsilon, + exploration_steps=args.exploration_steps, + alpha=args.per_alpha, + beta=args.per_beta, + beta_schedule=args.beta_schedule, + atom_size=args.atom_size, + v_min=args.v_min, + v_max=args.v_max, + n_step=args.n_step, + ) + result = train_rainbow_speed_policy( + env, + args.output, + config=config, + seed=args.seed, + device=args.device, + progress=not args.quiet, + metadata={ + "task": args.task, + "base_policy": args.base_policy, + "randomize_object_pose": args.randomize_object_pose, + "experiment_config": config_metadata, + }, + ) + summary = {key: value for key, value in result.items() if key != "episode_history"} + if args.eval_episodes: + summary["evaluation"] = evaluate_rainbow_speed_policy( + env, + args.output, + episodes=args.eval_episodes, + device=args.device, + ) + if args.report is not None: + args.report.parent.mkdir(parents=True, exist_ok=True) + args.report.write_text( + json.dumps( + { + "summary": summary, + "episode_history": result["episode_history"], + "experiment_config": config_metadata, + }, + indent=2, + sort_keys=True, + ) + + "\n" + ) + summary["report"] = str(args.report) + print(json.dumps(summary, sort_keys=True)) + return 0 if result["losses_finite"] else 1 + except (ImportError, RuntimeError, ValueError) as exc: + print(f"error: {exc}", file=sys.stderr) + return 2 + finally: + if "env" in locals(): + env.close() + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/sim_env.py b/sim_env.py new file mode 100644 index 0000000..a0f6d5e --- /dev/null +++ b/sim_env.py @@ -0,0 +1,221 @@ +"""MuJoCo environments controlled by bimanual robot joint positions.""" + +from __future__ import annotations + +import collections +import os + +import numpy as np +from dm_control import mujoco +from dm_control.rl import control +from dm_control.suite import base + +from constants import ( + DT, + PUPPET_GRIPPER_POSITION_NORMALIZE_FN, + PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN, + PUPPET_GRIPPER_VELOCITY_NORMALIZE_FN, + START_ARM_POSE, + XML_DIR, +) +from sim_tasks import ( + get_task_spec, + insertion_reward, + normalize_task_name, + sample_box_pose, + sample_insertion_pose, + tea_bag_reward, + transfer_cube_reward, +) + + +# Historical replay scripts set this after constructing the environment and before +# reset. New code may pass object_pose directly to make_sim_env. +BOX_POSE = [None] + + +def make_sim_env( + task_name: str, + render_images: bool = True, + seed: int | None = None, + object_pose=None, + randomize_object_pose: bool = False, +): + """Create a joint-control environment for any reconstructed sim task.""" + + task_name = normalize_task_name(task_name) + spec = get_task_spec(task_name) + physics = mujoco.Physics.from_xml_path(os.path.join(XML_DIR, spec.joint_xml)) + random_state = np.random.RandomState(seed) + task_classes = { + "pick_and_place": TransferCubeTask, + "insertion": InsertionTask, + "tea_bag": TransferTeaBagTask, + } + task = task_classes[task_name]( + random=random_state, + render_images=render_images, + object_pose=object_pose, + randomize_object_pose=randomize_object_pose, + ) + return control.Environment( + physics, + task, + time_limit=20, + control_timestep=DT, + n_sub_steps=None, + flat_observation=False, + ) + + +class BimanualViperXTask(base.Task): + def __init__( + self, + random=None, + render_images: bool = True, + object_pose=None, + randomize_object_pose: bool = False, + ): + super().__init__(random=random) + self.render_images = render_images + self.object_pose = None if object_pose is None else np.asarray(object_pose).copy() + self.randomize_object_pose = bool(randomize_object_pose) + + def before_step(self, action, physics): + action = np.asarray(action, dtype=np.float64) + if action.shape != (14,) or not np.all(np.isfinite(action)): + raise ValueError("Joint-control actions must be a finite array with shape (14,)") + left_gripper = PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN(action[6]) + right_gripper = PUPPET_GRIPPER_POSITION_UNNORMALIZE_FN(action[13]) + env_action = np.concatenate( + [ + action[:6], + [left_gripper, -left_gripper], + action[7:13], + [right_gripper, -right_gripper], + ] + ) + super().before_step(env_action, physics) + + @staticmethod + def get_qpos(physics): + qpos = physics.data.qpos.copy() + left, right = qpos[:8], qpos[8:16] + return np.concatenate( + [ + left[:6], + [PUPPET_GRIPPER_POSITION_NORMALIZE_FN(left[6])], + right[:6], + [PUPPET_GRIPPER_POSITION_NORMALIZE_FN(right[6])], + ] + ) + + @staticmethod + def get_qvel(physics): + qvel = physics.data.qvel.copy() + left, right = qvel[:8], qvel[8:16] + return np.concatenate( + [ + left[:6], + [PUPPET_GRIPPER_VELOCITY_NORMALIZE_FN(left[6])], + right[:6], + [PUPPET_GRIPPER_VELOCITY_NORMALIZE_FN(right[6])], + ] + ) + + @staticmethod + def get_env_state(physics): + return physics.data.qpos.copy()[16:] + + def get_observation(self, physics): + obs = collections.OrderedDict( + qpos=self.get_qpos(physics), + qvel=self.get_qvel(physics), + env_state=self.get_env_state(physics), + ) + if self.render_images: + obs["images"] = { + "top": physics.render(height=480, width=640, camera_id="top"), + "angle": physics.render(height=480, width=640, camera_id="angle"), + "vis": physics.render(height=480, width=640, camera_id="front_close"), + } + return obs + + def _requested_pose(self): + if self.object_pose is not None: + return self.object_pose + if BOX_POSE[0] is not None: + return np.asarray(BOX_POSE[0]) + return None + + def _initialize_robot(self, physics): + physics.named.data.qpos[:16] = START_ARM_POSE + np.copyto(physics.data.ctrl, START_ARM_POSE) + + +class TransferCubeTask(BimanualViperXTask): + max_reward = 4 + + def initialize_episode(self, physics): + with physics.reset_context(): + self._initialize_robot(physics) + pose = self._requested_pose() + physics.named.data.qpos["red_box_joint"] = ( + sample_box_pose(self.random) if pose is None else pose + ) + super().initialize_episode(physics) + + def get_reward(self, physics): + return transfer_cube_reward(physics) + + +class InsertionTask(BimanualViperXTask): + max_reward = 4 + + def initialize_episode(self, physics): + with physics.reset_context(): + self._initialize_robot(physics) + pose = self._requested_pose() + if pose is None: + peg_pose, socket_pose = sample_insertion_pose(self.random) + pose = np.concatenate([peg_pose, socket_pose]) + if np.asarray(pose).shape != (14,): + raise ValueError("Insertion object_pose must have shape (14,)") + physics.named.data.qpos["red_peg_joint"] = pose[:7] + physics.named.data.qpos["blue_socket_joint"] = pose[7:] + super().initialize_episode(physics) + + def get_reward(self, physics): + return insertion_reward(physics) + + +class TransferTeaBagTask(BimanualViperXTask): + max_reward = 3 + + def initialize_episode(self, physics): + with physics.reset_context(): + self._initialize_robot(physics) + pose = self._requested_pose() + if pose is None and self.randomize_object_pose: + physics.named.data.qpos["red_box_joint"] = sample_box_pose(self.random) + elif pose is None: + physics.named.data.qpos["red_box_joint"] = [ + 0.15, + 0.5, + 0.05, + 1, + 0, + 0, + 0, + ] + else: + pose = np.asarray(pose) + if pose.shape != physics.data.qpos[16:].shape: + raise ValueError( + f"Tea-bag object_pose must have shape {physics.data.qpos[16:].shape}" + ) + physics.data.qpos[16:] = pose + super().initialize_episode(physics) + + def get_reward(self, physics): + return tea_bag_reward(physics) diff --git a/sim_tasks.py b/sim_tasks.py new file mode 100644 index 0000000..4d3b2ff --- /dev/null +++ b/sim_tasks.py @@ -0,0 +1,181 @@ +"""Shared definitions for the reconstructed SpeedTuning simulation tasks.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Iterable + +import numpy as np + + +@dataclass(frozen=True) +class TaskSpec: + """Metadata shared by the end-effector and joint-control environments.""" + + name: str + legacy_name: str + episode_len: int + ee_xml: str + joint_xml: str + + +TASK_SPECS = { + "pick_and_place": TaskSpec( + name="pick_and_place", + legacy_name="sim_transfer_cube_scripted", + episode_len=400, + ee_xml="bimanual_viperx_ee_transfer_cube.xml", + joint_xml="bimanual_viperx_transfer_cube.xml", + ), + "insertion": TaskSpec( + name="insertion", + legacy_name="sim_insertion_scripted", + episode_len=400, + ee_xml="bimanual_viperx_ee_insertion.xml", + joint_xml="bimanual_viperx_insertion.xml", + ), + "tea_bag": TaskSpec( + name="tea_bag", + legacy_name="sim_transfer_tea_bag_scripted", + episode_len=500, + ee_xml="bimanual_viperx_ee_transfer_tea_bag.xml", + joint_xml="bimanual_viperx_transfer_tea_bag.xml", + ), +} + +_ALIASES = { + "pick_and_place": "pick_and_place", + "pick_place": "pick_and_place", + "transfer_cube": "pick_and_place", + "sim_transfer_cube": "pick_and_place", + "sim_transfer_cube_scripted": "pick_and_place", + "sim_transfer_cube_human": "pick_and_place", + "insertion": "insertion", + "sim_insertion": "insertion", + "sim_insertion_scripted": "insertion", + "sim_insertion_human": "insertion", + "tea_bag": "tea_bag", + "teabag": "tea_bag", + "transfer_tea_bag": "tea_bag", + "sim_transfer_tea_bag": "tea_bag", + "sim_transfer_tea_bag_scripted": "tea_bag", +} + + +def normalize_task_name(task_name: str) -> str: + """Return the public task name while accepting names used by the old code.""" + + normalized = task_name.strip().lower().replace("-", "_").replace(" ", "_") + try: + return _ALIASES[normalized] + except KeyError as exc: + supported = ", ".join(TASK_SPECS) + raise ValueError(f"Unknown task {task_name!r}. Supported tasks: {supported}") from exc + + +def get_task_spec(task_name: str) -> TaskSpec: + return TASK_SPECS[normalize_task_name(task_name)] + + +def sample_box_pose(random_state=None) -> np.ndarray: + """Sample the cube pose from the range used by the original ACT simulator.""" + + rng = np.random if random_state is None else random_state + position = rng.uniform([0.0, 0.4, 0.05], [0.2, 0.6, 0.05]) + return np.concatenate([position, [1.0, 0.0, 0.0, 0.0]]) + + +def sample_insertion_pose(random_state=None) -> tuple[np.ndarray, np.ndarray]: + """Sample peg and socket poses from the original simulator ranges.""" + + rng = np.random if random_state is None else random_state + peg_position = rng.uniform([0.1, 0.4, 0.05], [0.2, 0.6, 0.05]) + socket_position = rng.uniform([-0.2, 0.4, 0.05], [-0.1, 0.6, 0.05]) + identity_quaternion = [1.0, 0.0, 0.0, 0.0] + return ( + np.concatenate([peg_position, identity_quaternion]), + np.concatenate([socket_position, identity_quaternion]), + ) + + +def contact_pairs(physics) -> set[frozenset[str]]: + """Collect active contacts without depending on MuJoCo's geom ordering.""" + + pairs = set() + for contact in physics.data.contact[: physics.data.ncon]: + geom_1 = physics.model.id2name(contact.geom1, "geom") + geom_2 = physics.model.id2name(contact.geom2, "geom") + if geom_1 is not None and geom_2 is not None: + pairs.add(frozenset((geom_1, geom_2))) + return pairs + + +def _touching(pairs: set[frozenset[str]], first: str, second: str) -> bool: + return frozenset((first, second)) in pairs + + +def _gripper_touch( + pairs: set[frozenset[str]], object_geom: str, side: str +) -> bool: + return any( + _touching(pairs, object_geom, f"vx300s_{side}/10_{finger}_gripper_finger") + for finger in ("left", "right") + ) + + +def transfer_cube_reward(physics) -> int: + pairs = contact_pairs(physics) + left = _gripper_touch(pairs, "red_box", "left") + right = _gripper_touch(pairs, "red_box", "right") + table = _touching(pairs, "red_box", "table") + + if left and not table: + return 4 + if left: + return 3 + if right and not table: + return 2 + if right: + return 1 + return 0 + + +def insertion_reward(physics) -> int: + pairs = contact_pairs(physics) + socket_geoms: Iterable[str] = ("socket-1", "socket-2", "socket-3", "socket-4") + right = _gripper_touch(pairs, "red_peg", "right") + left = any( + _gripper_touch(pairs, socket, "left") + for socket in socket_geoms + ) + peg_on_table = _touching(pairs, "red_peg", "table") + socket_on_table = any(_touching(pairs, socket, "table") for socket in socket_geoms) + peg_in_socket = any(_touching(pairs, "red_peg", socket) for socket in socket_geoms) + pin_touched = _touching(pairs, "red_peg", "pin") + + if pin_touched: + return 4 + if peg_in_socket and not peg_on_table and not socket_on_table: + return 3 + if left and right and not peg_on_table and not socket_on_table: + return 2 + if left and right: + return 1 + return 0 + + +def tea_bag_reward(physics) -> int: + pairs = contact_pairs(physics) + right = _gripper_touch(pairs, "red_box", "right") + on_table = _touching(pairs, "tea_bag", "table") or _touching( + pairs, "red_box", "table" + ) + in_cup = _touching(pairs, "cup_base", "tea_bag") + + if in_cup: + return 3 + if right and not on_table: + return 2 + if right: + return 1 + return 0 diff --git a/speed_evaluation.py b/speed_evaluation.py new file mode 100644 index 0000000..4b4d84e --- /dev/null +++ b/speed_evaluation.py @@ -0,0 +1,93 @@ +"""Deterministic evaluation and plotting helpers for SpeedTuning experiments.""" + +from __future__ import annotations + +from pathlib import Path + +import numpy as np + +from speed_policy import FixedSpeedPolicy, rollout_speed_policy, summarize_rollouts + + +def speed_grid(start, stop, step): + start, stop, step = float(start), float(stop), float(step) + if step <= 0 or stop < start: + raise ValueError("Speed grid requires step > 0 and stop >= start") + count = int(np.floor((stop - start) / step + 1e-9)) + 1 + values = start + np.arange(count, dtype=np.float64) * step + if values[-1] < stop - 1e-9: + values = np.append(values, stop) + return tuple(float(np.round(value, 10)) for value in values) + + +def evaluate_seeded_policy(env_factory, policy, seeds, frame_skip=10): + rollouts = [] + for seed in seeds: + env = env_factory(int(seed)) + try: + result = rollout_speed_policy( + env, + policy, + frame_skip=frame_skip, + ) + result["seed"] = int(seed) + rollouts.append(result) + finally: + env.close() + return {**summarize_rollouts(rollouts), "seeds": list(seeds), "rollouts": rollouts} + + +def evaluate_fixed_speed_sweep(env_factory, speeds, seeds, frame_skip=10): + points = [] + for speed in speeds: + result = evaluate_seeded_policy( + env_factory, + FixedSpeedPolicy(speed), + seeds, + frame_skip=frame_skip, + ) + points.append({"fixed_speed": float(speed), **result}) + return points + + +def plot_speed_success_tradeoff(report, output_path): + """Write a compact success-versus-physical-acceleration plot.""" + + try: + import matplotlib.pyplot as plt + except ImportError as exc: + raise RuntimeError("Plotting requires: uv sync --extra evaluation") from exc + + baseline = report.get("fixed_speed_sweep", []) + if not baseline: + raise ValueError("Report has no fixed-speed sweep to plot") + figure, axis = plt.subplots(figsize=(4.4, 3.2)) + axis.plot( + [point["mean_acceleration"] for point in baseline], + [point["success_rate"] for point in baseline], + marker="o", + markersize=3, + linewidth=1.2, + label="Fixed speed", + ) + adaptive = report.get("adaptive_policy") + if adaptive is not None: + axis.scatter( + [adaptive["mean_acceleration"]], + [adaptive["success_rate"]], + marker="*", + s=90, + label="Speed policy", + zorder=3, + ) + axis.set_xlabel("Physical acceleration") + axis.set_ylabel("Success rate") + axis.set_ylim(-0.02, 1.02) + axis.grid(alpha=0.25) + axis.legend(frameon=False) + figure.tight_layout() + output_path = Path(output_path) + output_path.parent.mkdir(parents=True, exist_ok=True) + figure.savefig(output_path, dpi=200) + plt.close(figure) + return output_path diff --git a/speed_observation.py b/speed_observation.py new file mode 100644 index 0000000..3e3b72f --- /dev/null +++ b/speed_observation.py @@ -0,0 +1,284 @@ +"""Observation encoders for SpeedTuning speed policies. + +The speed learner consumes finite one-dimensional feature vectors. Encoders in +this module turn simulator observation dictionaries into those vectors while +keeping image preprocessing independent from the task policy. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Mapping, Sequence + +import numpy as np + + +def _finite_vector(value: Any, name: str) -> np.ndarray: + vector = np.asarray(value, dtype=np.float32).reshape(-1) + if vector.size == 0 or not np.all(np.isfinite(vector)): + raise ValueError(f"{name} must produce a non-empty finite feature vector") + return vector + + +@dataclass +class StateObservationEncoder: + """Encode proprioception and, optionally, privileged simulator state.""" + + include_qpos: bool = True + include_qvel: bool = True + include_env_state: bool = True + requires_images: bool = False + + def __post_init__(self): + if not (self.include_qpos or self.include_qvel or self.include_env_state): + raise ValueError("At least one state observation field must be enabled") + + def reset(self): + return None + + def __call__(self, observation: Mapping[str, Any]) -> np.ndarray: + fields = [] + for enabled, name in ( + (self.include_env_state, "env_state"), + (self.include_qpos, "qpos"), + (self.include_qvel, "qvel"), + ): + if enabled: + if name not in observation: + raise ValueError(f"Observation is missing required field {name!r}") + fields.append(_finite_vector(observation[name], name)) + return np.concatenate(fields).astype(np.float32, copy=False) + + def output_dim(self, env_state_dim: int) -> int: + return ( + (14 if self.include_qpos else 0) + + (14 if self.include_qvel else 0) + + (int(env_state_dim) if self.include_env_state else 0) + ) + + def spec(self) -> dict[str, Any]: + return { + "type": "state", + "include_qpos": self.include_qpos, + "include_qvel": self.include_qvel, + "include_env_state": self.include_env_state, + } + + +class ResNet18ImageEncoder: + """Frozen torchvision ResNet-18 image features for one or more cameras.""" + + feature_dim = 512 + + def __init__( + self, + pretrained=True, + image_size=224, + device=None, + initialize_pretrained=True, + ): + try: + import torch + from torchvision.models import ResNet18_Weights, resnet18 + except ImportError as exc: + raise RuntimeError( + "Visual speed observations require: uv sync --extra learned" + ) from exc + + self.torch = torch + self.pretrained = bool(pretrained) + self.image_size = int(image_size) + if self.image_size <= 0: + raise ValueError("image_size must be positive") + self.device = torch.device( + device or ("cuda" if torch.cuda.is_available() else "cpu") + ) + weights = ( + ResNet18_Weights.DEFAULT + if self.pretrained and initialize_pretrained + else None + ) + self.model = resnet18(weights=weights) + self.model.fc = torch.nn.Identity() + self.model.to(self.device).eval() + for parameter in self.model.parameters(): + parameter.requires_grad_(False) + self.mean = torch.tensor( + [0.485, 0.456, 0.406], dtype=torch.float32, device=self.device + ).view(1, 3, 1, 1) + self.std = torch.tensor( + [0.229, 0.224, 0.225], dtype=torch.float32, device=self.device + ).view(1, 3, 1, 1) + + def __call__(self, images: np.ndarray) -> np.ndarray: + torch = self.torch + values = np.asarray(images) + if values.ndim != 4 or values.shape[-1] != 3: + raise ValueError("Camera images must have shape [camera, height, width, 3]") + tensor = torch.as_tensor(values, dtype=torch.float32, device=self.device) + tensor = tensor.permute(0, 3, 1, 2) / 255.0 + tensor = torch.nn.functional.interpolate( + tensor, + size=(self.image_size, self.image_size), + mode="bilinear", + align_corners=False, + ) + tensor = (tensor - self.mean) / self.std + with torch.inference_mode(): + features = self.model(tensor) + return features.detach().cpu().numpy().astype(np.float32, copy=False) + + def spec(self) -> dict[str, Any]: + return { + "type": "resnet18", + "pretrained": self.pretrained, + "image_size": self.image_size, + "feature_dim": self.feature_dim, + } + + def state_dict(self): + return { + key: value.detach().cpu() + for key, value in self.model.state_dict().items() + } + + def load_state_dict(self, state_dict): + self.model.load_state_dict(state_dict) + + +class VisualObservationEncoder: + """Fuse independent image embeddings with proprioceptive features.""" + + requires_images = True + + def __init__( + self, + camera_names: Sequence[str] = ("top", "angle", "vis"), + image_encoder=None, + pretrained=True, + image_size=224, + device=None, + include_qpos=True, + include_qvel=True, + include_env_state=False, + initialize_pretrained=True, + ): + self.camera_names = tuple(camera_names) + if not self.camera_names: + raise ValueError("At least one camera is required for visual observations") + self.image_encoder = image_encoder or ResNet18ImageEncoder( + pretrained=pretrained, + image_size=image_size, + device=device, + initialize_pretrained=initialize_pretrained, + ) + self.state_encoder = StateObservationEncoder( + include_qpos=include_qpos, + include_qvel=include_qvel, + include_env_state=include_env_state, + ) + + def reset(self): + reset = getattr(self.image_encoder, "reset", None) + if reset is not None: + reset() + + def __call__(self, observation: Mapping[str, Any]) -> np.ndarray: + if "images" not in observation: + raise ValueError("Visual observations require the simulator images field") + missing = [name for name in self.camera_names if name not in observation["images"]] + if missing: + raise ValueError(f"Observation is missing cameras: {', '.join(missing)}") + images = np.stack( + [np.asarray(observation["images"][name]) for name in self.camera_names] + ) + encode = getattr(self.image_encoder, "encode", None) or self.image_encoder + image_features = _finite_vector(encode(images), "image encoder") + state_features = self.state_encoder(observation) + return np.concatenate([state_features, image_features]).astype( + np.float32, copy=False + ) + + def output_dim(self, env_state_dim: int) -> int: + feature_dim = getattr(self.image_encoder, "feature_dim", None) + if feature_dim is None: + raise AttributeError("External image encoder does not declare feature_dim") + return self.state_encoder.output_dim(env_state_dim) + len(self.camera_names) * int( + feature_dim + ) + + def spec(self) -> dict[str, Any]: + image_spec = getattr(self.image_encoder, "spec", None) + if image_spec is None: + image_spec = {"type": type(self.image_encoder).__name__} + else: + image_spec = image_spec() + return { + "type": "visual", + "camera_names": list(self.camera_names), + "state": self.state_encoder.spec(), + "image_encoder": image_spec, + } + + def state_dict(self): + state_dict = getattr(self.image_encoder, "state_dict", None) + return None if state_dict is None else state_dict() + + def load_state_dict(self, state_dict): + load = getattr(self.image_encoder, "load_state_dict", None) + if load is None: + if state_dict: + raise ValueError("The configured image encoder cannot load checkpoint state") + return + load(state_dict) + + +class ObservationEncoderAdapter: + """Validate a user-supplied observation encoder without constraining its model.""" + + def __init__(self, encoder): + if not callable(encoder): + raise TypeError("An observation encoder must be callable") + self.encoder = encoder + self.requires_images = bool(getattr(encoder, "requires_images", False)) + + def reset(self): + reset = getattr(self.encoder, "reset", None) + if reset is not None: + reset() + + def __call__(self, observation): + return _finite_vector(self.encoder(observation), "observation encoder") + + def output_dim(self, env_state_dim): + output_dim = getattr(self.encoder, "output_dim", None) + if output_dim is None: + raise AttributeError("External observation encoder does not declare output_dim") + return int(output_dim(env_state_dim) if callable(output_dim) else output_dim) + + def spec(self): + spec = getattr(self.encoder, "spec", None) + return ( + {"type": type(self.encoder).__name__} + if spec is None + else dict(spec() if callable(spec) else spec) + ) + + def state_dict(self): + state_dict = getattr(self.encoder, "state_dict", None) + return None if state_dict is None else state_dict() + + def load_state_dict(self, state_dict): + load = getattr(self.encoder, "load_state_dict", None) + if load is None: + if state_dict: + raise ValueError("External observation encoder cannot load checkpoint state") + return + load(state_dict) + + +def encoder_spec(encoder) -> dict[str, Any]: + spec = getattr(encoder, "spec", None) + if spec is None: + return {"type": type(encoder).__name__} + return dict(spec() if callable(spec) else spec) diff --git a/speed_policy.py b/speed_policy.py new file mode 100644 index 0000000..05caf9e --- /dev/null +++ b/speed_policy.py @@ -0,0 +1,322 @@ +"""Model-agnostic speed-policy adapters and rollout utilities.""" + +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Callable, Sequence + +import numpy as np + + +@dataclass(frozen=True) +class SpeedContext: + """Episode metadata passed to a speed policy at each decision.""" + + policy_time: float + physics_steps: int + episode_len: int + speed_values: tuple[float, ...] + + +class SpeedPolicyAdapter: + """Adapt a callable or ``select_speed`` object to the speed contract. + + A public speed policy receives ``(observation, context)`` and returns a + finite positive multiplier such as ``1.0`` or ``1.5``. + """ + + def __init__(self, policy: Any): + select = getattr(policy, "select_speed", None) + if select is None and callable(policy): + select = policy + if select is None: + raise TypeError("speed policy must be callable or define select_speed()") + self.policy = policy + self._select = select + + def reset(self): + reset = getattr(self.policy, "reset", None) + if reset is not None: + reset() + + def __call__(self, observation, context): + speed = float(self._select(observation, context)) + if not np.isfinite(speed) or speed <= 0: + raise ValueError("A speed policy must return a finite positive multiplier") + return speed + + +class FixedSpeedPolicy: + """Always choose one physical speed multiplier.""" + + def __init__(self, speed=1.0): + self.speed = float(speed) + if not np.isfinite(self.speed) or self.speed <= 0: + raise ValueError("speed must be finite and positive") + + def select_speed(self, observation, context): + del observation, context + return self.speed + + +class SpeedProfilePolicy: + """Select piecewise-constant speeds over normalized nominal policy time.""" + + def __init__(self, speeds: Sequence[float]): + values = np.asarray(speeds, dtype=np.float64) + if values.ndim != 1 or len(values) == 0: + raise ValueError("speeds must be a non-empty one-dimensional sequence") + if not np.all(np.isfinite(values)) or np.any(values <= 0): + raise ValueError("Every profile speed must be finite and positive") + self.speeds = tuple(float(value) for value in values) + + def select_speed(self, observation, context): + del observation + fraction = min(max(context.policy_time / context.episode_len, 0.0), 1.0) + index = min(int(fraction * len(self.speeds)), len(self.speeds) - 1) + return self.speeds[index] + + +class CallableSpeedPolicy: + """Give a descriptive wrapper to a user-provided speed function.""" + + def __init__(self, function: Callable[[np.ndarray, SpeedContext], float]): + self.function = function + + def select_speed(self, observation, context): + return self.function(observation, context) + + +class RainbowSpeedPolicy: + """Inference-only speed policy loaded from a public training checkpoint.""" + + def __init__( + self, + network, + speed_values, + device="cpu", + frame_skip=10, + observation_spec=None, + environment_spec=None, + observation_encoder_state_dict=None, + checkpoint_metadata=None, + ): + import torch + + self.torch = torch + self.device = torch.device(device) + self.network = network.to(self.device).eval() + self.speed_values = tuple(float(value) for value in speed_values) + self.observation_dim = int(network.in_dim) + self.frame_skip = int(frame_skip) + self.observation_spec = observation_spec + self.environment_spec = environment_spec + self.observation_encoder_state_dict = observation_encoder_state_dict + self.checkpoint_metadata = dict(checkpoint_metadata or {}) + + @classmethod + def load(cls, checkpoint_path, device="cpu"): + try: + import torch + except ImportError as exc: + raise RuntimeError("Rainbow evaluation requires: uv sync --extra rl") from exc + from rl.rainbowDQN.network import Network + + checkpoint_path = Path(checkpoint_path) + # Public speed checkpoints contain tensors and primitive metadata only, + # so use PyTorch's restricted unpickler for downloaded artifacts. + payload = torch.load( + checkpoint_path, map_location=device, weights_only=True + ) + required = { + "model_state_dict", + "observation_dim", + "speed_values", + "atom_size", + "v_min", + "v_max", + "hidden_dim", + } + missing = sorted(required.difference(payload)) + if missing: + raise ValueError(f"Speed checkpoint is missing keys: {', '.join(missing)}") + support = torch.linspace( + float(payload["v_min"]), + float(payload["v_max"]), + int(payload["atom_size"]), + ).to(device) + network = Network( + int(payload["observation_dim"]), + len(payload["speed_values"]), + int(payload["atom_size"]), + support, + hidden_dim=int(payload["hidden_dim"]), + ) + network.load_state_dict(payload["model_state_dict"]) + training_config = payload.get("training_config", {}) + return cls( + network, + payload["speed_values"], + device=device, + frame_skip=payload.get( + "decision_frame_skip", training_config.get("frame_skip", 10) + ), + observation_spec=payload.get("observation_spec"), + environment_spec=payload.get("environment_spec"), + observation_encoder_state_dict=payload.get( + "observation_encoder_state_dict" + ), + checkpoint_metadata=payload.get("metadata"), + ) + + def select_action(self, observation): + tensor = self.torch.as_tensor( + observation, dtype=self.torch.float32, device=self.device + ).unsqueeze(0) + with self.torch.inference_mode(): + action = int(self.network(tensor).argmax(dim=1).item()) + return action + + def select_speed(self, observation, context): + del context + return self.speed_values[self.select_action(observation)] + + def configure_environment(self, env): + """Restore and validate observation preprocessing for evaluation.""" + + env.load_observation_encoder_state_dict( + self.observation_encoder_state_dict + ) + observation = env.reset() + if self.observation_dim != observation.size: + raise ValueError( + "Checkpoint observation size does not match the environment: " + f"{self.observation_dim} != {observation.size}" + ) + if tuple(self.speed_values) != tuple(env.speed_values): + raise ValueError( + "Checkpoint speed_values do not match the environment: " + f"{self.speed_values} != {env.speed_values}" + ) + if self.observation_spec is not None: + actual_spec = env.observation_spec() + if self.observation_spec != actual_spec: + raise ValueError( + "Checkpoint observation preprocessing does not match the environment: " + f"{self.observation_spec!r} != {actual_spec!r}" + ) + if self.environment_spec is not None: + actual_environment = env.environment_spec() + if self.environment_spec != actual_environment: + raise ValueError( + "Checkpoint environment does not match evaluation: " + f"{self.environment_spec!r} != {actual_environment!r}" + ) + return observation + + +def rollout_speed_policy(env, speed_policy, capture_speeds=False, frame_skip=None): + """Pair any conforming speed policy with a configured speed environment.""" + + raw_policy = speed_policy + prepared_observation = None + if isinstance(raw_policy, RainbowSpeedPolicy): + prepared_observation = raw_policy.configure_environment(env) + policy = ( + speed_policy + if isinstance(speed_policy, SpeedPolicyAdapter) + else SpeedPolicyAdapter(speed_policy) + ) + policy.reset() + observation = ( + env.reset() if prepared_observation is None else prepared_observation + ) + decision_frame_skip = int( + frame_skip + if frame_skip is not None + else getattr(raw_policy, "frame_skip", env.decision_frame_skip) + ) + if decision_frame_skip <= 0: + raise ValueError("frame_skip must be positive") + done = False + total_reward = 0.0 + info = {"success": False} + speeds = [] + decisions = 0 + while not done: + context = SpeedContext( + policy_time=env.policy_time, + physics_steps=env.physics_steps, + episode_len=env.episode_len, + speed_values=env.speed_values, + ) + speed = policy(observation, context) + observation, reward, done, info = env.step_decision( + speed, + frame_skip=decision_frame_skip, + quantized=False, + ) + total_reward += reward + decisions += 1 + if capture_speeds: + speeds.append(speed) + + acceleration = float(env.episode_len / max(info["physics_steps"], 1)) + result = { + "success": bool(info["success"]), + "return": float(total_reward), + "physics_steps": int(info["physics_steps"]), + "policy_time": float(info["policy_time"]), + "mean_speed": float(np.mean(env.speed_list)), + "max_speed": float(np.max(env.speed_list)), + "acceleration": acceleration, + "successful_acceleration": acceleration if info["success"] else None, + "decisions": decisions, + "decision_frame_skip": decision_frame_skip, + "duration_seconds": float(info["physics_steps"] / 50.0), + "nominal_duration_seconds": float(env.episode_len / 50.0), + } + if capture_speeds: + result["speeds"] = speeds + return result + + +def summarize_rollouts(rollouts): + """Aggregate paper-facing success and physical-acceleration metrics.""" + + rollouts = list(rollouts) + if not rollouts: + raise ValueError("At least one rollout is required") + successes = np.asarray([item["success"] for item in rollouts], dtype=np.float64) + accelerations = np.asarray( + [item["acceleration"] for item in rollouts], dtype=np.float64 + ) + successful = accelerations[successes.astype(bool)] + physics_steps = np.asarray( + [item["physics_steps"] for item in rollouts], dtype=np.float64 + ) + mean_speeds = np.asarray( + [item["mean_speed"] for item in rollouts], dtype=np.float64 + ) + return { + "episodes": len(rollouts), + "successes": int(successes.sum()), + "success_rate": float(successes.mean()), + "success_standard_error": float( + np.sqrt(successes.mean() * (1.0 - successes.mean()) / len(successes)) + ), + "mean_acceleration": float(accelerations.mean()), + "median_acceleration": float(np.median(accelerations)), + "acceleration_standard_deviation": float(accelerations.std()), + "acceleration_25th_percentile": float(np.percentile(accelerations, 25)), + "acceleration_75th_percentile": float(np.percentile(accelerations, 75)), + "mean_successful_acceleration": ( + None if successful.size == 0 else float(successful.mean()) + ), + "successful_acceleration_standard_deviation": ( + None if successful.size == 0 else float(successful.std()) + ), + "mean_physics_steps": float(physics_steps.mean()), + "mean_commanded_speed": float(mean_speeds.mean()), + } diff --git a/speed_training.py b/speed_training.py new file mode 100644 index 0000000..1c02dd5 --- /dev/null +++ b/speed_training.py @@ -0,0 +1,298 @@ +"""Training and evaluation loops for the included Rainbow speed policy.""" + +from __future__ import annotations + +import random +from collections import deque +from dataclasses import asdict, dataclass +from pathlib import Path + +import numpy as np + +from speed_policy import RainbowSpeedPolicy, rollout_speed_policy, summarize_rollouts + + +@dataclass(frozen=True) +class RainbowTrainingConfig: + """Practical defaults for speed-policy experiments, not paper reproduction.""" + + decisions: int = 5_000 + memory_size: int = 100_000 + batch_size: int = 128 + learning_starts: int = 512 + frame_skip: int = 10 + gradient_steps: int = 4 + train_interval: int = 1 + target_update: int = 50 + norm_update_interval: int = 100 + learning_rate: float = 1e-4 + gamma: float = 0.97 + tau: float = 0.5 + epsilon: float = 1.0 + epsilon_decay: float = 0.999 + min_epsilon: float = 0.1 + exploration_steps: int = 2_000 + alpha: float = 0.2 + beta: float = 0.6 + beta_schedule: str = "linear" + atom_size: int = 121 + v_min: float = 0.0 + v_max: float = 120.0 + n_step: int = 3 + hidden_dim: int = 256 + update_schedule: str = "decision" + checkpoint_interval: int = 0 + + def validate(self): + positive_ints = ( + "decisions", + "memory_size", + "batch_size", + "learning_starts", + "frame_skip", + "gradient_steps", + "train_interval", + "target_update", + "norm_update_interval", + "atom_size", + "n_step", + "hidden_dim", + ) + for name in positive_ints: + if int(getattr(self, name)) <= 0: + raise ValueError(f"{name} must be positive") + if self.memory_size < self.batch_size: + raise ValueError("memory_size must be at least batch_size") + if self.learning_starts < self.batch_size: + raise ValueError("learning_starts must be at least batch_size") + if self.atom_size < 2 or self.v_max <= self.v_min: + raise ValueError("Categorical support requires atom_size >= 2 and v_max > v_min") + if self.update_schedule not in {"decision", "episode"}: + raise ValueError("update_schedule must be 'decision' or 'episode'") + if self.beta_schedule not in {"linear", "legacy"}: + raise ValueError("beta_schedule must be 'linear' or 'legacy'") + if self.checkpoint_interval < 0: + raise ValueError("checkpoint_interval cannot be negative") + + +def _normalization_stats(states): + values = np.asarray(states, dtype=np.float32) + return { + "states_mean": values.mean(axis=0), + "states_std": np.maximum(values.std(axis=0), 1e-6), + } + + +def _checkpoint_payload(agent, env, config, seed, metadata, completed_decisions): + return { + "format_version": 2, + "algorithm": "rainbow_dqn", + "model_state_dict": agent.dqn.state_dict(), + "observation_dim": int(env.obs_space), + "speed_values": list(env.speed_values), + "atom_size": config.atom_size, + "v_min": config.v_min, + "v_max": config.v_max, + "hidden_dim": config.hidden_dim, + "seed": int(seed), + "training_config": asdict(config), + "completed_decisions": int(completed_decisions), + "decision_frame_skip": config.frame_skip, + "reward_aggregation": "undiscounted_sum_per_decision", + "observation_spec": env.observation_spec(), + "environment_spec": env.environment_spec(), + "observation_encoder_state_dict": env.observation_encoder_state_dict(), + "metric_spec": { + "acceleration": "episode_len / physics_steps", + "control_frequency_hz": 50, + }, + "metadata": dict(metadata or {}), + } + + +def _numbered_checkpoint_path(checkpoint_path, decision): + checkpoint_path = Path(checkpoint_path) + return checkpoint_path.with_name( + f"{checkpoint_path.stem}.decision-{decision}{checkpoint_path.suffix}" + ) + + +def train_rainbow_speed_policy( + env, + checkpoint_path, + config=None, + seed=0, + device=None, + metadata=None, + progress=True, +): + """Train Rainbow against any ``SpeedPolicyEnv`` and save one checkpoint.""" + + try: + import torch + except ImportError as exc: + raise RuntimeError("Rainbow training requires: uv sync --extra rl") from exc + from rl.rainbowDQN.dqnAgent import DQNAgent + + config = config or RainbowTrainingConfig() + config.validate() + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + + state = env.reset() + agent = DQNAgent( + env, + memory_size=config.memory_size, + batch_size=config.batch_size, + target_update=config.target_update, + seed=seed, + lr=config.learning_rate, + gamma=config.gamma, + tau=config.tau, + frame_skip=config.frame_skip, + epsilon=config.epsilon, + epsilon_decay=config.epsilon_decay, + min_epsilon=config.min_epsilon, + exploration_steps=config.exploration_steps, + alpha=config.alpha, + beta=config.beta, + atom_size=config.atom_size, + v_min=config.v_min, + v_max=config.v_max, + n_step=config.n_step, + hidden_dim=config.hidden_dim, + device=device, + log_dir=None, + ) + + state_history = deque(maxlen=min(config.memory_size, 100_000)) + state_history.append(state.copy()) + episode_return = 0.0 + episode_decisions = 0 + episode_index = 0 + update_count = 0 + losses = [] + episodes = [] + numbered_checkpoints = [] + + def update_network(number_of_updates): + nonlocal update_count + for _ in range(number_of_updates): + losses.append(float(agent.update_model())) + update_count += 1 + if update_count % config.target_update == 0: + agent._target_soft_update() + + for decision in range(1, config.decisions + 1): + action = agent.select_action(state) + next_state, reward, done, info = agent.step(action, config.frame_skip) + state_history.append(next_state.copy()) + episode_return += float(reward) + episode_decisions += 1 + + progress_fraction = min(decision / config.decisions, 1.0) + if config.beta_schedule == "legacy": + # Retained trainer behavior: repeatedly close the remaining gap. + agent.beta += progress_fraction * (1.0 - agent.beta) + else: + agent.beta = config.beta + progress_fraction * (1.0 - config.beta) + agent.decay_epsilon(decision) + + ready = len(agent.memory) >= max(config.batch_size, config.learning_starts) + if ( + config.update_schedule == "decision" + and ready + and decision % config.train_interval == 0 + ): + if decision % config.norm_update_interval == 0 or update_count == 0: + stats = _normalization_stats(state_history) + agent.dqn.update_norm_stats(stats) + agent.dqn_target.update_norm_stats(stats) + update_network(config.gradient_steps) + + state = next_state + if done: + episode_index += 1 + record = { + "episode": episode_index, + "decision": decision, + "return": episode_return, + "decisions": episode_decisions, + "physics_steps": int(info["physics_steps"]), + "mean_speed": float(np.mean(env.speed_list)), + "acceleration": float( + env.episode_len / max(int(info["physics_steps"]), 1) + ), + "success": bool(info["success"]), + } + episodes.append(record) + if progress: + print( + "episode={episode} decision={decision} success={success} " + "return={return:.3f} mean_speed={mean_speed:.3f}".format(**record) + ) + if config.update_schedule == "episode" and ready: + stats = _normalization_stats(state_history) + agent.dqn.update_norm_stats(stats) + agent.dqn_target.update_norm_stats(stats) + # The retained SpeedTuning trainer optimized once per decision, + # batching those updates at the end of each episode. + update_network(episode_decisions * config.gradient_steps) + state = env.reset() + state_history.append(state.copy()) + episode_return = 0.0 + episode_decisions = 0 + + if ( + config.checkpoint_interval + and decision % config.checkpoint_interval == 0 + ): + numbered_path = _numbered_checkpoint_path(checkpoint_path, decision) + numbered_path.parent.mkdir(parents=True, exist_ok=True) + torch.save( + _checkpoint_payload( + agent, env, config, seed, metadata, completed_decisions=decision + ), + numbered_path, + ) + numbered_checkpoints.append(str(numbered_path)) + + if len(state_history) >= 2: + stats = _normalization_stats(state_history) + agent.dqn.update_norm_stats(stats) + + checkpoint_path = Path(checkpoint_path) + checkpoint_path.parent.mkdir(parents=True, exist_ok=True) + payload = _checkpoint_payload( + agent, + env, + config, + seed, + metadata, + completed_decisions=config.decisions, + ) + torch.save(payload, checkpoint_path) + + finite_losses = bool(np.isfinite(losses).all()) if losses else True + return { + "checkpoint": str(checkpoint_path), + "decisions": config.decisions, + "episodes": len(episodes), + "successes": sum(int(item["success"]) for item in episodes), + "updates": update_count, + "losses_finite": finite_losses, + "loss_last": losses[-1] if losses else None, + "numbered_checkpoints": numbered_checkpoints, + "episode_history": episodes, + } + + +def evaluate_rainbow_speed_policy(env, checkpoint_path, episodes=10, device="cpu"): + """Evaluate a saved speed policy against the supplied base-policy wrapper.""" + + if episodes <= 0: + raise ValueError("episodes must be positive") + policy = RainbowSpeedPolicy.load(checkpoint_path, device=device) + results = [rollout_speed_policy(env, policy) for _ in range(episodes)] + return {**summarize_rollouts(results), "rollouts": results} diff --git a/tests/test_chunked_policies.py b/tests/test_chunked_policies.py new file mode 100644 index 0000000..b9b29ef --- /dev/null +++ b/tests/test_chunked_policies.py @@ -0,0 +1,98 @@ +import numpy as np +import pytest + +from chunked_policy import ( + ChunkPredictorAdapter, + ChunkedPolicyRunner, + TorchChunkPredictor, + as_action_chunk, + interpolate_action_chunk, + replay_recorded_chunks, +) +from sim_env import make_sim_env +from sim_tasks import TASK_SPECS + + +def test_action_chunk_interpolation_changes_execution_length(): + actions = np.arange(10 * 14, dtype=float).reshape(10, 14) + accelerated = interpolate_action_chunk(actions, speed=2.0) + slowed = interpolate_action_chunk(actions, speed=0.5) + assert accelerated.shape == (5, 14) + assert slowed.shape == (20, 14) + np.testing.assert_array_equal(accelerated, actions[::2]) + + +def test_upstream_chunk_adapter_accepts_common_batch_and_dict_output(): + actions = np.arange(4 * 14, dtype=float).reshape(1, 4, 14) + adapter = ChunkPredictorAdapter(lambda observation: {"actions": actions}) + np.testing.assert_array_equal(adapter({}), actions[0]) + np.testing.assert_array_equal(as_action_chunk(actions[0, 0]), actions[0, :1]) + + +def test_chunk_runner_accepts_online_speed_changes(): + actions = np.repeat(np.arange(10, dtype=float)[:, None], 14, axis=1) + runner = ChunkedPolicyRunner(lambda observation: actions) + samples = [ + runner.action({}, speed=speed)[0] + for speed in (1.0, 2.0, 0.5, 1.5) + ] + np.testing.assert_allclose(samples, [0.0, 1.0, 3.0, 3.5]) + + +@pytest.mark.parametrize("task_name", TASK_SPECS) +def test_recorded_action_chunks_complete_joint_task(task_name): + result = replay_recorded_chunks(task_name, chunk_size=25, seed=0) + assert result["success"] + + +@pytest.mark.learned +def test_actual_act_model_accepts_every_simulator_observation(): + torch = pytest.importorskip("torch") + pytest.importorskip("torchvision") + from policy import ACTPolicy + + config = { + "lr": 1e-4, + "num_queries": 4, + "kl_weight": 1, + "hidden_dim": 32, + "dim_feedforward": 64, + "lr_backbone": 0.0, + "backbone": "resnet18", + "enc_layers": 1, + "dec_layers": 1, + "nheads": 4, + "camera_names": ["top"], + "pretrained_backbone": False, + "device": "cpu", + } + policy = ACTPolicy(config).eval() + for task_name in TASK_SPECS: + env = make_sim_env(task_name, render_images=True, seed=0) + timestep = env.reset() + initial_qpos = timestep.observation["qpos"].copy() + predictor = TorchChunkPredictor( + policy, + ["top"], + qpos_mean=np.zeros(14), + qpos_std=np.ones(14), + action_mean=initial_qpos, + action_std=np.full(14, 1e-3), + device="cpu", + ) + chunk = predictor(timestep.observation) + assert chunk.shape == (4, 14) + assert np.isfinite(chunk).all() + timestep = env.step(chunk[0]) + assert torch.isfinite(torch.as_tensor(timestep.observation["qpos"])).all() + + +@pytest.mark.rl +def test_rainbow_dqn_optimization_poc(): + pytest.importorskip("torch") + from scripts.rainbow_poc import run_poc + + result = run_poc(seed=0, min_transitions=64, updates=8) + assert result["passed"] + assert result["successful_episodes"] >= 1 + assert result["actions_seen"] == [0, 1, 2, 3, 4] diff --git a/tests/test_paper_parity.py b/tests/test_paper_parity.py new file mode 100644 index 0000000..83ebf23 --- /dev/null +++ b/tests/test_paper_parity.py @@ -0,0 +1,241 @@ +import json +from pathlib import Path + +import numpy as np +import pytest + +from chunked_policy import ChunkedPolicyRunner +from experiment_config import load_experiment_config +from policy_speed_env import create_speed_env, make_speed_reward +from speed_evaluation import speed_grid +from speed_observation import StateObservationEncoder, VisualObservationEncoder +from speed_policy import FixedSpeedPolicy, rollout_speed_policy, summarize_rollouts + + +class CountingChunkPredictor: + def __init__(self): + self.calls = 0 + + def __call__(self, observation): + self.calls += 1 + return np.repeat(np.asarray(observation["qpos"])[None], 100, axis=0) + + +def test_chunk_runner_replans_at_each_decision_boundary(): + predictor = CountingChunkPredictor() + runner = ChunkedPolicyRunner(predictor) + observation = {"qpos": np.zeros(14)} + runner.begin_decision(observation, speed=2.0) + runner.action(observation, speed=2.0) + runner.action(observation, speed=2.0) + assert predictor.calls == 1 + runner.begin_decision(observation, speed=1.5) + assert predictor.calls == 2 + + +def test_decision_step_uses_one_fresh_chunk_and_holds_speed(): + predictor = CountingChunkPredictor() + env = create_speed_env( + "tea_bag", + chunk_predictor=predictor, + render_images=False, + seed=0, + ) + env.reset() + _, _, done, info = env.step_decision(1.5, frame_skip=4, quantized=False) + assert not done + assert predictor.calls == 1 + assert info["decision_physics_steps"] == 4 + assert env.speed_list == [1.5] * 4 + env.step_decision(1.0, frame_skip=2, quantized=False) + assert predictor.calls == 2 + + +def test_stacked_unprivileged_proprioceptive_observations(): + env = create_speed_env( + "pick_and_place", + observation_encoder=StateObservationEncoder(include_env_state=False), + frame_stack=5, + seed=0, + ) + observation = env.reset() + assert observation.shape == (5 * 28,) + frames = observation.reshape(5, 28) + np.testing.assert_allclose(frames, np.repeat(frames[:1], 5, axis=0)) + next_observation, _, _, _ = env.step_decision( + 1.0, frame_skip=1, quantized=False + ) + assert next_observation.shape == observation.shape + np.testing.assert_allclose(next_observation[: 4 * 28], observation[28:]) + + +class DummyImageEncoder: + feature_dim = 2 + + def __call__(self, images): + means = images.mean(axis=(1, 2, 3)) + return np.stack([means, means + 1.0], axis=1) + + def spec(self): + return {"type": "dummy", "feature_dim": self.feature_dim} + + +def test_visual_encoder_fuses_camera_features_without_env_state(): + encoder = VisualObservationEncoder( + camera_names=("top", "angle"), + image_encoder=DummyImageEncoder(), + include_env_state=False, + ) + observation = { + "qpos": np.zeros(14), + "qvel": np.ones(14), + "env_state": np.full(7, 9.0), + "images": { + "top": np.zeros((4, 5, 3), dtype=np.uint8), + "angle": np.full((4, 5, 3), 10, dtype=np.uint8), + }, + } + features = encoder(observation) + assert features.shape == (32,) + assert not np.any(features == 9.0) + assert encoder.spec()["image_encoder"]["type"] == "dummy" + + +def test_paper_manifest_and_ablation_inheritance(): + paper, _ = load_experiment_config("paper-sim") + assert paper["speed_values"] == [1.5, 2.0, 3.0, 4.5] + assert paper["frame_stack"] == 5 + assert paper["include_env_state"] is False + assert paper["speed_weight"] == 0.01 + assert paper["update_schedule"] == "episode" + no_image_path = Path(__file__).parents[1] / "configs/ablations/no_image.json" + no_image, _ = load_experiment_config(no_image_path) + assert no_image["speed_observation"] == "state" + assert no_image["hidden_dim"] == 1024 + + scripted, _ = load_experiment_config("scripted-tea-bag") + assert scripted["base_policy"] == "scripted" + assert scripted["speed_values"] == [1.0, 1.5, 2.0, 2.5, 3.0] + assert scripted["decisions"] == 100_000 + assert scripted["learning_starts"] == 128 + assert scripted["beta_schedule"] == "legacy" + randomized, _ = load_experiment_config("scripted-tea-bag-randomized") + assert randomized["randomize_object_pose"] is True + assert randomized["update_schedule"] == "episode" + + pick, _ = load_experiment_config("scripted-pick-and-place") + insertion, _ = load_experiment_config("scripted-insertion") + assert pick["speed_values"][-1] == 4.5 + assert insertion["speed_values"] == [1.0, 1.5, 2.0, 2.5, 3.0] + assert pick["decisions"] == insertion["decisions"] == 100_000 + + +def test_paper_metrics_use_physical_length_not_commanded_speed(): + env = create_speed_env("tea_bag", seed=0, decision_frame_skip=10) + rollout = rollout_speed_policy(env, FixedSpeedPolicy(1.5)) + assert rollout["acceleration"] == pytest.approx( + env.episode_len / rollout["physics_steps"] + ) + summary = summarize_rollouts([rollout]) + assert summary["mean_acceleration"] == rollout["acceleration"] + assert "mean_commanded_speed" in summary + + +def test_speed_grid_is_stable_at_decimal_intervals(): + assert speed_grid(1.0, 1.3, 0.1) == (1.0, 1.1, 1.2, 1.3) + + +def test_zero_degree_speed_reward_ablation_is_supported(): + reward = make_speed_reward(speed_weight=0.0, speed_power=0.0) + assert reward(4.5, done=False, success=False) == 0.0 + + +def test_reference_results_cover_all_tasks_without_checkpoint_paths(): + path = Path(__file__).parents[1] / "benchmarks/scripted_results.json" + benchmark = json.loads(path.read_text()) + assert set(benchmark["results"]) == {"pick_and_place", "insertion", "tea_bag"} + serialized = json.dumps(benchmark) + assert not any(suffix in serialized for suffix in (".pt\"", ".pth\"", ".ckpt\"")) + for result in benchmark["results"].values(): + assert 0.0 <= result["learned_speed"]["success_rate"] <= 1.0 + assert result["learned_speed"]["mean_physical_acceleration"] > 1.0 + + +@pytest.mark.learned +def test_resnet_visual_speed_observation_and_state_round_trip(): + pytest.importorskip("torch") + pytest.importorskip("torchvision") + first = VisualObservationEncoder( + camera_names=("top",), + pretrained=False, + image_size=64, + device="cpu", + include_env_state=False, + ) + env = create_speed_env( + "tea_bag", + observation_encoder=first, + frame_stack=2, + render_images=True, + seed=0, + ) + observation = env.reset() + assert observation.shape == (2 * (28 + 512),) + saved_state = first.state_dict() + second = VisualObservationEncoder( + camera_names=("top",), + pretrained=False, + image_size=64, + device="cpu", + include_env_state=False, + ) + second.load_state_dict(saved_state) + assert first.spec() == second.spec() + env.close() + + +@pytest.mark.learned +def test_retained_act_checkpoint_loader_runs_on_simulator(tmp_path: Path): + torch = pytest.importorskip("torch") + pytest.importorskip("torchvision") + from act_integration import build_act_chunk_predictor + from policy import ACTPolicy + from sim_env import make_sim_env + + config = { + "lr": 1e-4, + "num_queries": 4, + "kl_weight": 1, + "hidden_dim": 32, + "dim_feedforward": 64, + "lr_backbone": 0.0, + "backbone": "resnet18", + "enc_layers": 1, + "dec_layers": 1, + "nheads": 4, + "camera_names": ["top"], + "pretrained_backbone": False, + "device": "cpu", + } + policy = ACTPolicy(config).eval() + checkpoint = tmp_path / "act.pt" + torch.save( + { + "model_state_dict": policy.state_dict(), + "policy_config": config, + "stats": { + "qpos_mean": np.zeros(14), + "qpos_std": np.ones(14), + "action_mean": np.zeros(14), + "action_std": np.ones(14), + }, + }, + checkpoint, + ) + predictor = build_act_chunk_predictor( + "tea_bag", checkpoint=checkpoint, device="cpu" + ) + env = make_sim_env("tea_bag", render_images=True, seed=0) + chunk = predictor(env.reset().observation) + assert chunk.shape == (4, 14) + assert np.isfinite(chunk).all() diff --git a/tests/test_sim_envs.py b/tests/test_sim_envs.py new file mode 100644 index 0000000..497d822 --- /dev/null +++ b/tests/test_sim_envs.py @@ -0,0 +1,107 @@ +import numpy as np +import pytest + +from ee_sim_env import make_ee_sim_env +from policy_speed_env import create_speed_env +from scripts.run_sim import run_task +from scripted_policy import make_scripted_policy +from sim_env import BOX_POSE, make_sim_env +from sim_tasks import TASK_SPECS, normalize_task_name + + +@pytest.mark.parametrize( + ("alias", "expected"), + [ + ("pick-and-place", "pick_and_place"), + ("sim_transfer_cube_scripted", "pick_and_place"), + ("sim_insertion", "insertion"), + ("teabag", "tea_bag"), + ("sim_transfer_tea_bag_scripted", "tea_bag"), + ], +) +def test_task_aliases(alias, expected): + assert normalize_task_name(alias) == expected + + +@pytest.mark.parametrize("task_name", TASK_SPECS) +def test_end_effector_env_resets_and_steps(task_name): + env = make_ee_sim_env(task_name, render_images=False, seed=7) + timestep = env.reset() + assert timestep.observation["qpos"].shape == (14,) + assert "images" not in timestep.observation + action = make_scripted_policy(task_name)(timestep) + timestep = env.step(action) + assert np.isfinite(timestep.observation["qpos"]).all() + + +@pytest.mark.parametrize("task_name", TASK_SPECS) +def test_joint_env_resets_without_external_object_pose(task_name): + BOX_POSE[0] = None + env = make_sim_env(task_name, render_images=False, seed=7) + timestep = env.reset() + timestep = env.step(timestep.observation["qpos"]) + assert timestep.observation["qpos"].shape == (14,) + assert np.isfinite(timestep.observation["env_state"]).all() + + +def test_tea_bag_pose_randomization_is_opt_in_and_seeded(): + fixed = make_ee_sim_env("tea_bag", render_images=False, seed=7) + fixed_pose = fixed.reset().observation["env_state"][:7].copy() + np.testing.assert_allclose( + fixed.reset().observation["env_state"][:7], fixed_pose + ) + + randomized = make_ee_sim_env( + "tea_bag", + render_images=False, + seed=7, + randomize_object_pose=True, + ) + first_pose = randomized.reset().observation["env_state"][:7].copy() + second_pose = randomized.reset().observation["env_state"][:7].copy() + assert not np.allclose(first_pose[:2], second_pose[:2]) + assert np.all(first_pose[:2] >= [0.0, 0.4]) + assert np.all(first_pose[:2] <= [0.2, 0.6]) + + +@pytest.mark.parametrize("task_name", TASK_SPECS) +def test_original_scripted_policy_completes_task(task_name): + spec = TASK_SPECS[task_name] + env = make_ee_sim_env(task_name, render_images=False, seed=0) + timestep = env.reset() + policy = make_scripted_policy(task_name) + rewards = [] + for _ in range(spec.episode_len): + timestep = env.step(policy(timestep)) + rewards.append(timestep.reward) + assert max(rewards) == env.task.max_reward + + +@pytest.mark.parametrize("task_name", TASK_SPECS) +def test_speed_wrapper_completes_task_at_original_speed(task_name): + env = create_speed_env(task_name=task_name, seed=0) + observation = env.reset() + assert observation.shape == (env.obs_space,) + done = False + info = {} + while not done: + observation, _, done, info = env.step(1.0, quantized=False) + assert info["success"] + + +@pytest.mark.parametrize("task_name", TASK_SPECS) +def test_scripted_policy_completes_task_at_1_5x(task_name): + result = run_task(task_name, speed=1.5, seed=0) + assert result["success"] + assert result["steps"] < TASK_SPECS[task_name].episode_len + + +@pytest.mark.parametrize("task_name", TASK_SPECS) +def test_quantized_speed_wrapper_completes_task_at_1_5x(task_name): + env = create_speed_env(task_name=task_name, seed=0) + env.reset() + done = False + info = {} + while not done: + _, _, done, info = env.step(1, quantized=True) + assert info["success"] diff --git a/tests/test_speed_infrastructure.py b/tests/test_speed_infrastructure.py new file mode 100644 index 0000000..d06298f --- /dev/null +++ b/tests/test_speed_infrastructure.py @@ -0,0 +1,158 @@ +from pathlib import Path + +import numpy as np +import pytest +from dm_control.rl import control + +from policy_speed_env import create_recorded_chunk_speed_env, create_speed_env +from speed_policy import ( + FixedSpeedPolicy, + SpeedContext, + SpeedPolicyAdapter, + SpeedProfilePolicy, + rollout_speed_policy, +) + + +def test_speed_policy_adapter_validates_external_output(): + context = SpeedContext(0.0, 0, 100, (1.0, 1.5)) + policy = SpeedPolicyAdapter(lambda observation, metadata: 1.5) + assert policy(np.zeros(3), context) == 1.5 + + invalid = SpeedPolicyAdapter(lambda observation, metadata: 0.0) + with pytest.raises(ValueError, match="positive"): + invalid(np.zeros(3), context) + + +def test_profile_policy_segments_nominal_time(): + policy = SpeedProfilePolicy([1.0, 2.0, 3.0]) + assert policy.select_speed(None, SpeedContext(0, 0, 90, (1.0,))) == 1.0 + assert policy.select_speed(None, SpeedContext(40, 0, 90, (1.0,))) == 2.0 + assert policy.select_speed(None, SpeedContext(89, 0, 90, (1.0,))) == 3.0 + + +def test_fixed_speed_policy_pairs_with_scripted_environment(): + env = create_speed_env("tea_bag", seed=0) + result = rollout_speed_policy(env, FixedSpeedPolicy(1.5)) + assert result["success"] + assert result["physics_steps"] < env.episode_len + + +def test_physics_instability_becomes_failed_terminal_transition(monkeypatch): + env = create_speed_env("tea_bag", seed=0) + env.reset() + + def unstable_step(action): + del action + raise control.PhysicsError("invalid simulated state") + + monkeypatch.setattr(env.env, "step", unstable_step) + observation, reward, done, info = env.step(3.0, quantized=False) + + assert done + assert not info["success"] + assert "invalid simulated state" in info["physics_error"] + assert observation.shape == (env.obs_space,) + assert np.isfinite(reward) + + +def test_recorded_chunk_policy_pairs_with_speed_environment(): + env = create_recorded_chunk_speed_env("tea_bag", chunk_size=25, seed=0) + result = rollout_speed_policy(env, FixedSpeedPolicy(1.0)) + assert result["success"] + assert result["mean_speed"] == 1.0 + + +@pytest.mark.rl +def test_prioritized_replay_samples_newest_transition(): + pytest.importorskip("torch") + from rl.rainbowDQN.replayBuffer import PrioritizedReplayBuffer + + replay = PrioritizedReplayBuffer( + obs_dim=1, + size=8, + batch_size=4, + alpha=1.0, + ) + for value in range(4): + replay.store( + np.array([value], dtype=np.float32), + value, + 0.0, + np.array([value + 1], dtype=np.float32), + False, + ) + replay.update_priorities( + np.arange(4), + np.array([1e-6, 1e-6, 1e-6, 100.0]), + ) + + assert 3 in replay.sample_batch(beta=0.4)["indices"] + + +@pytest.mark.rl +def test_public_rainbow_training_checkpoint_round_trip(tmp_path: Path): + pytest.importorskip("torch") + from speed_policy import RainbowSpeedPolicy + from speed_training import ( + RainbowTrainingConfig, + evaluate_rainbow_speed_policy, + train_rainbow_speed_policy, + ) + + env = create_speed_env("tea_bag", speed_values=(1.0,), seed=0) + config = RainbowTrainingConfig( + decisions=12, + memory_size=64, + batch_size=4, + learning_starts=4, + frame_skip=50, + gradient_steps=1, + train_interval=1, + target_update=2, + norm_update_interval=2, + exploration_steps=20, + atom_size=11, + n_step=3, + hidden_dim=32, + update_schedule="episode", + checkpoint_interval=6, + ) + checkpoint = tmp_path / "speed.pt" + result = train_rainbow_speed_policy( + env, + checkpoint, + config=config, + seed=0, + device="cpu", + progress=False, + ) + assert checkpoint.exists() + assert len(result["numbered_checkpoints"]) == 2 + assert all(Path(path).exists() for path in result["numbered_checkpoints"]) + assert result["updates"] > 0 + assert result["losses_finite"] + + observation = env.reset() + policy = RainbowSpeedPolicy.load(checkpoint) + assert policy.frame_skip == 50 + assert policy.observation_spec == env.observation_spec() + assert policy.environment_spec == env.environment_spec() + assert policy.select_speed( + observation, + SpeedContext(0, 0, env.episode_len, env.speed_values), + ) in env.speed_values + evaluation = evaluate_rainbow_speed_policy( + env, checkpoint, episodes=1, device="cpu" + ) + assert evaluation["episodes"] == 1 + assert "mean_acceleration" in evaluation + + randomized_env = create_speed_env( + "tea_bag", + speed_values=(1.0,), + randomize_object_pose=True, + seed=0, + ) + with pytest.raises(ValueError, match="Checkpoint environment"): + rollout_speed_policy(randomized_env, policy) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..bd18e50 --- /dev/null +++ b/uv.lock @@ -0,0 +1,911 @@ +version = 1 +revision = 3 +requires-python = "==3.10.*" + +[[package]] +name = "absl-py" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/4f/d79676ab82f2e42fc3611618139f13a9c4c31d0cff4b486982047679a802/absl_py-2.5.0.tar.gz", hash = "sha256:0c996f25c0490700fadabe6351630f6111534fa0ae252cc6d2014ea3b141135f", size = 118119, upload-time = "2026-07-03T10:57:48.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/0a/a10b45aab35b175aded078a462dc8d0c698f5b13946e7cb0869097b78bb6/absl_py-2.5.0-py3-none-any.whl", hash = "sha256:0f17b89f2a4eaaedc4f28c622998aa690564b3012a396a4ffad0821007fe03ba", size = 137410, upload-time = "2026-07-03T10:57:46.735Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2a/23f34ec9d04624958e137efdc394888716353190e75f25dd22c7a2c7a8aa/charset_normalizer-3.4.9.tar.gz", hash = "sha256:673611bbd43f0810bec0b0f028ddeaaa501190339cac411f347ac76917c3ae7b", size = 152439, upload-time = "2026-07-07T14:34:58.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd6280cf040f233bd7d3407b743b4b4c74f70e8e1c4199cb112a62c941c0772a", size = 322240, upload-time = "2026-07-07T14:32:36.236Z" }, + { url = "https://files.pythonhosted.org/packages/de/d1/b4319dc3229d8272fba305e206fc0a148e2de8d4087917ce62ae6382f359/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa99adc8f081b475a12843953db36831eaf83ec33eb46a90629ca6a5de45a616", size = 216475, upload-time = "2026-07-07T14:32:38.142Z" }, + { url = "https://files.pythonhosted.org/packages/80/33/6c99c1b3e6b8bf730e1bc809b9a2608f224145069114c479a2e9e1494346/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c1225416b463483160e4af85d5fc3a9690ccb53fd4b1865a6437825f5ede3209", size = 238670, upload-time = "2026-07-07T14:32:39.658Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f4/ffbb83546e1f198ecc70ecd372b65cf2b50f9068b380abd67640f17a8e18/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:16d10d789dd9bcca1173c95af82c58433122564b7bc39385124be735a35cbe99", size = 233476, upload-time = "2026-07-07T14:32:41.155Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5f/b98b8da398637b551e427e7be922bdec19177dc54d6811dcdaa503f23aac/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bb41182d93ea91f60b4bc8fbf4c820c69ef8a12ab2d917f3f1834f1acad07e8", size = 223817, upload-time = "2026-07-07T14:32:42.592Z" }, + { url = "https://files.pythonhosted.org/packages/36/31/a276bb2e66243072a3fd06fdcab9cbb61a305b02143d70d2bda21d888fa8/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:bcf74c1df76758a395bf0af608c04c82257523f55c9868b334f06270d0f2112b", size = 207974, upload-time = "2026-07-07T14:32:44.258Z" }, + { url = "https://files.pythonhosted.org/packages/5e/be/7ee4453d7e88dfbc4104ccd34900b9f2c7c17dac22881865fe0e82424a25/charset_normalizer-3.4.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b5314963fce9b0b12743891de876e724997864ee22aa496f903f426c7e2fa5b2", size = 221655, upload-time = "2026-07-07T14:32:45.64Z" }, + { url = "https://files.pythonhosted.org/packages/1d/85/181c652953eb5276d198f375b1dd641047392050098100a3a02d6534f657/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e9701d0049d92c16703a42771b98d560b95248949f23f8cf7b4eddd201814fb9", size = 219229, upload-time = "2026-07-07T14:32:47.376Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e7/aaf6da33fc9f4691cda8f7efbc9f69179d3d39ec8a4799baf273ee1d8db0/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:65a7ff3f705e57d392f7261b6d0550fe137c3019477431f1c355e0db0a7d3e15", size = 209704, upload-time = "2026-07-07T14:32:48.855Z" }, + { url = "https://files.pythonhosted.org/packages/63/01/f2fb3bd3a73be48b173ee0c6aa8d2497af97d5663a8c4c4b491de4c62f7a/charset_normalizer-3.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79580094b00d1789d1f93ea55bc43cb2f611910c72235b7657f3482ddcc1b22d", size = 226243, upload-time = "2026-07-07T14:32:50.239Z" }, + { url = "https://files.pythonhosted.org/packages/c4/02/c57a22739fe05246b0b5783b3bfb6afaac4eebb46f3ececdfb2f048f780e/charset_normalizer-3.4.9-cp310-cp310-win32.whl", hash = "sha256:432786d3561e69aeeae6c7e8648964ce0ad05736120135601f87ac26b9c83381", size = 150935, upload-time = "2026-07-07T14:32:51.676Z" }, + { url = "https://files.pythonhosted.org/packages/37/8d/ca39a7559a4797505530d084fd3a49a2c959efbbbff146302fb7be4e3b35/charset_normalizer-3.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:8c041122946b7ba21bb32c45b1aa57b1be35527690aeb3c5c234521085632eee", size = 162314, upload-time = "2026-07-07T14:32:53.193Z" }, + { url = "https://files.pythonhosted.org/packages/01/da/a44bd7a13d426e69e4894557106cd58669097bfad4a8681123b618fbfc5d/charset_normalizer-3.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:375b83ed0aecfce76c16d198fbc21f3b11b337d68662bea0a995046682a11419", size = 153075, upload-time = "2026-07-07T14:32:54.554Z" }, + { url = "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl", hash = "sha256:68e5f26a1ad57ded6d1cfb85331d1c1a195314756471d97758c48498bb4dcdf5", size = 64538, upload-time = "2026-07-07T14:34:56.993Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "dm-control" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "dm-env" }, + { name = "dm-tree" }, + { name = "glfw" }, + { name = "labmaze" }, + { name = "lxml" }, + { name = "mujoco" }, + { name = "numpy" }, + { name = "protobuf" }, + { name = "pyopengl" }, + { name = "pyparsing" }, + { name = "requests" }, + { name = "scipy" }, + { name = "setuptools" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/bb/48499d7a063652250b5af00b3193e99b43fb24586d45b2e3dcaa61bcfb21/dm_control-1.0.9.tar.gz", hash = "sha256:452f175bd04fdd0692c01cfa25dc09ff7ce61a81674f92cb1c4ac0f5cb6e1fb0", size = 38980591, upload-time = "2022-12-09T13:20:05.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/34/e9d3224a0c4496e62cd6b6eb53fe863644ebfff19bad1c8e4fb0d26270b5/dm_control-1.0.9-py3-none-any.whl", hash = "sha256:531e0bb310c62fd9e4058a295fae4f3f22a58de3e7c0e394fe08bbd8db2ba331", size = 39281788, upload-time = "2022-12-09T13:19:52.584Z" }, +] + +[[package]] +name = "dm-env" +version = "1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "dm-tree" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/c9/93e8d6239d5806508a2ee4b370e67c6069943ca149f59f533923737a99b7/dm-env-1.6.tar.gz", hash = "sha256:a436eb1c654c39e0c986a516cee218bea7140b510fceff63f97eb4fcff3d93de", size = 20187, upload-time = "2022-12-21T00:25:29.306Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/7e/36d548040e61337bf9182637a589c44da407a47a923ee88aec7f0e89867c/dm_env-1.6-py3-none-any.whl", hash = "sha256:0eabb6759dd453b625e041032f7ae0c1e87d4eb61b6a96b9ca586483837abf29", size = 26339, upload-time = "2022-12-21T00:25:37.128Z" }, +] + +[[package]] +name = "dm-tree" +version = "0.1.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "attrs" }, + { name = "numpy" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/66/a3ec619d22b6baffa5ab853e8dc6ec9d0c837127948af59bb15b988d7312/dm_tree-0.1.10.tar.gz", hash = "sha256:22f37b599e01cc3402a17f79c257a802aebd8d326de05b54657650845956208a", size = 35748, upload-time = "2026-03-31T17:35:39.03Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/76/781bc1a8ce0f4be153755e36be547d7d36964fb6d265b9b29503ed3e0a0f/dm_tree-0.1.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8b606661abcb5336e60ce4cd6f3bec794ec794f91d8de001c1ea451dd7a7411", size = 311543, upload-time = "2026-03-31T17:35:04.766Z" }, + { url = "https://files.pythonhosted.org/packages/7c/b9/2f6278c07728c60411d363aab1b5de53b75bb3bdf27032e871c240f3b4de/dm_tree-0.1.10-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fcf11edc379723b8a17b76b6f63643e9280d55f23c37994805bf27282074192", size = 181202, upload-time = "2026-03-31T17:35:06.266Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d6/2b88e4eb5e3e5ecf9d61afe55e463ce7c9e4d1dc6630b9f7038a62e548d1/dm_tree-0.1.10-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7644b24bb5c7810b601f4b28cf6e4b516da96713ebfd9e45585240318c6b9384", size = 183874, upload-time = "2026-03-31T17:35:07.746Z" }, + { url = "https://files.pythonhosted.org/packages/49/9f/6fea8ba8cb69136af0511868bc41dfb88d0b8c3a85497dbbf16271cd84a7/dm_tree-0.1.10-cp310-cp310-win_amd64.whl", hash = "sha256:d7f42b2148a1a3758230fbf93c06b9475e5d4bd62a4d19eacafa8210b03421ac", size = 110740, upload-time = "2026-03-31T17:35:09.045Z" }, +] + +[[package]] +name = "einops" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/77/850bef8d72ffb9219f0b1aac23fbc1bf7d038ee6ea666f331fa273031aa2/einops-0.8.2.tar.gz", hash = "sha256:609da665570e5e265e27283aab09e7f279ade90c4f01bcfca111f3d3e13f2827", size = 56261, upload-time = "2026-01-26T04:13:17.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/09/f8d8f8f31e4483c10a906437b4ce31bdf3d6d417b73fe33f1a8b59e34228/einops-0.8.2-py3-none-any.whl", hash = "sha256:54058201ac7087911181bfec4af6091bb59380360f069276601256a76af08193", size = 65638, upload-time = "2026-01-26T04:13:18.546Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "filelock" +version = "3.32.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/57/3ba6e6cb097f85b855b00163d169f35365f44277df044dcf96d55b8f62a3/filelock-3.32.2.tar.gz", hash = "sha256:c33351e1f49cae33414acbc6d56784e6ecee82514ec90795da1161fc4836b5b8", size = 217172, upload-time = "2026-07-29T22:46:04.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/e8/72f8cef9fdfeffe06213fe8508039396ee48daa0e3259457ed766173bfd6/filelock-3.32.2-py3-none-any.whl", hash = "sha256:87dd94cf281e586d135fa51132b8e3d9a598b316e90377a288663c9321036c82", size = 98830, upload-time = "2026-07-29T22:46:03.52Z" }, +] + +[[package]] +name = "fonttools" +version = "4.63.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/c9/4141c90a90db20f807c7e10bfd689fe53eb8f7f4caff58ee4d4dfe46919f/fonttools-4.63.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e3297a6a4059b4acc3a1e9a8b04741f240a80044eef08ebd32e8b5bcdddce75b", size = 2884632, upload-time = "2026-05-14T12:02:38.56Z" }, + { url = "https://files.pythonhosted.org/packages/b8/46/ad12b5c10eae602d7ef814b02afa08aacbf89da917fed5b071282b7eadc2/fonttools-4.63.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1cd75a03ad8cb5bc40c90bfde68c0c47de423aa19e5c0f362b43520645eea94", size = 2429441, upload-time = "2026-05-14T12:02:41.162Z" }, + { url = "https://files.pythonhosted.org/packages/90/8f/bdca24a84c81d56fffed052229cdcff368f6e05882e526f4558891481f65/fonttools-4.63.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0425b277a59cff3d80ca42162a8de360f318438a2ac83570842a678d826d579", size = 4946346, upload-time = "2026-05-14T12:02:43.41Z" }, + { url = "https://files.pythonhosted.org/packages/04/59/a639c0e136441ee91a65b56fdf89e5d075927e7a09c559d1b0f5276577db/fonttools-4.63.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d7e5c9973aa04c95650c96e5f5ad865fbf42d62079163ecfab1e01cbc2504c22", size = 4903184, upload-time = "2026-05-14T12:02:45.742Z" }, + { url = "https://files.pythonhosted.org/packages/e6/53/91b7e0cb45b536f3da1b29ba8cbab89f27e8b986809e0b1982303a3f4eca/fonttools-4.63.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cb014d58140a38135f16064c74c652ed57aa0b75cbf8bb59cac821f7edb5334e", size = 4922967, upload-time = "2026-05-14T12:02:48.386Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b7/87439bf44e6b97c5538cd29d0b7e366a5b8ce2cc132a4134fb67fa3f2fa2/fonttools-4.63.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:032038247a96c1690f9f31e377c389383c902531b085aa4e4dabd6f57f870e69", size = 5042799, upload-time = "2026-05-14T12:02:50.424Z" }, + { url = "https://files.pythonhosted.org/packages/ad/7c/8b96c3263b89ef99cded544c0f0636686f85dbd3c211c4dceef0231fca23/fonttools-4.63.0-cp310-cp310-win32.whl", hash = "sha256:a8b33a82979e0a6a34ff435cc81317be1f95ec1ebb7a3a2d1c8a6a54f02ae44e", size = 1519704, upload-time = "2026-05-14T12:02:52.523Z" }, + { url = "https://files.pythonhosted.org/packages/e5/4d/2c2f0069970b6907de8fb5b05c5c0193cc22f717df151d1c7aef1c738f58/fonttools-4.63.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c18358a155d75034911c5ee397a5b44cd19dd325dbb8b35fb60bf421d6a72ac", size = 1568666, upload-time = "2026-05-14T12:02:54.917Z" }, + { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, +] + +[[package]] +name = "fsspec" +version = "2026.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/78/f34251dadb8f3921264a1d9b8946f5e542014ee2614b285261b4e40e6775/fsspec-2026.7.0.tar.gz", hash = "sha256:c803c40f4cf860b49dea58ee3e1c33cb9c790520e233537e1340049f89b82a88", size = 317040, upload-time = "2026-07-28T16:34:51.052Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl", hash = "sha256:b57ddbafedfaef7018c1ecab32aa200a9d7ca26b77965f64e48b70061249d279", size = 206583, upload-time = "2026-07-28T16:34:49.538Z" }, +] + +[[package]] +name = "glfw" +version = "2.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/62/096058bcb4b4fb28f7ecd28fb048f07969d90b243c417af5f6d09d45a0c2/glfw-2.10.2.tar.gz", hash = "sha256:5d2cf97c66bc42a6b583be0e307eae5a3945438322e2ed0c5e4f14dc251d693d", size = 36307, upload-time = "2026-07-21T14:42:36.732Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/80/5e575ec14f54dc0a644e7215985b9ee7c5044fcc3594d6b83dfdeb04ccd4/glfw-2.10.2-py2.py3-none-macosx_10_6_intel.whl", hash = "sha256:a04d25bb535a3a29e173ea1abd658e161681b5d3816e00bc51c122f74cd7fa3a", size = 110295, upload-time = "2026-07-21T14:42:25.625Z" }, + { url = "https://files.pythonhosted.org/packages/e5/2e/22216db429690aa51fa87d2e2b5e6b610c5a37b9df7768da2927f52f8704/glfw-2.10.2-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:c000b8a5e5fb4374b2c18d12347255ccb92001b9bcf80ef74c56072acbb98fe3", size = 107146, upload-time = "2026-07-21T14:42:26.854Z" }, + { url = "https://files.pythonhosted.org/packages/75/a4/9ccee9d5c3b9c5d6bafce3e8d53ab8318eff30124e3c19b95580bebaa6d4/glfw-2.10.2-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:0ffe2b48b51f37b05e8f027f57c0b8cd213affaf22fc83401bd9621692d4c6c8", size = 235005, upload-time = "2026-07-21T14:42:27.955Z" }, + { url = "https://files.pythonhosted.org/packages/77/44/37aeed50c581c76e1c5bb83b696a06f98f8ecc979ed8564dde3eef908e8b/glfw-2.10.2-py2.py3-none-manylinux2014_x86_64.whl", hash = "sha256:82daf1f87b2a48815637dc6f6720d4a55a57ba1d3683322dc20dc28065754f97", size = 246951, upload-time = "2026-07-21T14:42:29.107Z" }, + { url = "https://files.pythonhosted.org/packages/52/fc/29b4f1a8c8e33d8934781330a0845458b01da7f389d9fe6a3350e752b7f3/glfw-2.10.2-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:7604425ec95665cc6a25c3ed7d07e9660d394a34472ceffaec0843c844e7b649", size = 236018, upload-time = "2026-07-21T14:42:30.623Z" }, + { url = "https://files.pythonhosted.org/packages/69/84/1b98671314ea5f40397586b6cd14db913de3196333be558fdc177e61708f/glfw-2.10.2-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:b860de3ca0686182483f98f3ddd12e660acf25b3e0d521450ec9a3f999f72a65", size = 248490, upload-time = "2026-07-21T14:42:32.377Z" }, + { url = "https://files.pythonhosted.org/packages/12/d9/bd2e6c8dbadcf69fcd2289705e75881258b46221c196903a52e9f6e97322/glfw-2.10.2-py2.py3-none-win32.whl", hash = "sha256:a94aefe8c48886fd83cd6e11e936846166a4b5b94abf1f4bf599d984774b0b1b", size = 557654, upload-time = "2026-07-21T14:42:33.903Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6c/4ca5f3ab85a8d7f612ce857208726e9b834e54e559751e3d4f98cc2f7509/glfw-2.10.2-py2.py3-none-win_amd64.whl", hash = "sha256:15fd0666cd8f1b0ecb535c3abb712b8ddda053bf8d16de2353b1c6ced0e65402", size = 564433, upload-time = "2026-07-21T14:42:35.465Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "imageio" +version = "2.37.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/62/aa770a9307508d2a2a2c62d536a49347bffe9e55322db27838d3c93d0b07/imageio-2.37.4.tar.gz", hash = "sha256:e45cbc5e83502047fb138f7f585f7f105a136a57eea5f4b3cfc6ce1b52720bd3", size = 390173, upload-time = "2026-07-20T05:26:11.369Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/2d/ca050652104bab2cf55e569db2a178b1b61cb041fef28307f2db383f6d9f/imageio-2.37.4-py3-none-any.whl", hash = "sha256:1ab2e22c8debf700f24c3ac43e8f95f3b3a8110c83b93411e97b4b0b2cd1c7e6", size = 318000, upload-time = "2026-07-20T05:26:09.874Z" }, +] + +[[package]] +name = "imageio-ffmpeg" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/bd/c3343c721f2a1b0c9fc71c1aebf1966a3b7f08c2eea8ed5437a2865611d6/imageio_ffmpeg-0.6.0.tar.gz", hash = "sha256:e2556bed8e005564a9f925bb7afa4002d82770d6b08825078b7697ab88ba1755", size = 25210, upload-time = "2025-01-16T21:34:32.747Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/58/87ef68ac83f4c7690961bce288fd8e382bc5f1513860fc7f90a9c1c1c6bf/imageio_ffmpeg-0.6.0-py3-none-macosx_10_9_intel.macosx_10_9_x86_64.whl", hash = "sha256:9d2baaf867088508d4a3458e61eeb30e945c4ad8016025545f66c4b5aaef0a61", size = 24932969, upload-time = "2025-01-16T21:34:20.464Z" }, + { url = "https://files.pythonhosted.org/packages/40/5c/f3d8a657d362cc93b81aab8feda487317da5b5d31c0e1fdfd5e986e55d17/imageio_ffmpeg-0.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b1ae3173414b5fc5f538a726c4e48ea97edc0d2cdc11f103afee655c463fa742", size = 21113891, upload-time = "2025-01-16T21:34:00.277Z" }, + { url = "https://files.pythonhosted.org/packages/33/e7/1925bfbc563c39c1d2e82501d8372734a5c725e53ac3b31b4c2d081e895b/imageio_ffmpeg-0.6.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1d47bebd83d2c5fc770720d211855f208af8a596c82d17730aa51e815cdee6dc", size = 25632706, upload-time = "2025-01-16T21:33:53.475Z" }, + { url = "https://files.pythonhosted.org/packages/a0/2d/43c8522a2038e9d0e7dbdf3a61195ecc31ca576fb1527a528c877e87d973/imageio_ffmpeg-0.6.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c7e46fcec401dd990405049d2e2f475e2b397779df2519b544b8aab515195282", size = 29498237, upload-time = "2025-01-16T21:34:13.726Z" }, + { url = "https://files.pythonhosted.org/packages/a0/13/59da54728351883c3c1d9fca1710ab8eee82c7beba585df8f25ca925f08f/imageio_ffmpeg-0.6.0-py3-none-win32.whl", hash = "sha256:196faa79366b4a82f95c0f4053191d2013f4714a715780f0ad2a68ff37483cc2", size = 19652251, upload-time = "2025-01-16T21:34:06.812Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c6/fa760e12a2483469e2bf5058c5faff664acf66cadb4df2ad6205b016a73d/imageio_ffmpeg-0.6.0-py3-none-win_amd64.whl", hash = "sha256:02fa47c83703c37df6bfe4896aab339013f62bf02c5ebf2dce6da56af04ffc0a", size = 31246824, upload-time = "2025-01-16T21:34:28.6Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/f8/06549565caa026e540b7e7bab5c5a90eb7ca986015f4c48dace243cd24d9/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32cc0a5365239a6ea0c6ed461e8838d053b57e397443c0ca894dcc8e388d4374", size = 122802, upload-time = "2026-03-09T13:12:37.515Z" }, + { url = "https://files.pythonhosted.org/packages/84/eb/8476a0818850c563ff343ea7c9c05dcdcbd689a38e01aa31657df01f91fa/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc0b66c1eec9021353a4b4483afb12dfd50e3669ffbb9152d6842eb34c7e29fd", size = 66216, upload-time = "2026-03-09T13:12:38.812Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/f9c8a6b4c21aed4198566e45923512986d6cef530e7263b3a5f823546561/kiwisolver-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86e0287879f75621ae85197b0877ed2f8b7aa57b511c7331dce2eb6f4de7d476", size = 63917, upload-time = "2026-03-09T13:12:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/f1/0e/ba4ae25d03722f64de8b2c13e80d82ab537a06b30fc7065183c6439357e3/kiwisolver-1.5.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62f59da443c4f4849f73a51a193b1d9d258dcad0c41bc4d1b8fb2bcc04bfeb22", size = 1628776, upload-time = "2026-03-09T13:12:41.976Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e4/3f43a011bc8a0860d1c96f84d32fa87439d3feedf66e672fef03bf5e8bac/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9190426b7aa26c5229501fa297b8d0653cfd3f5a36f7990c264e157cbf886b3b", size = 1228164, upload-time = "2026-03-09T13:12:44.002Z" }, + { url = "https://files.pythonhosted.org/packages/4b/34/3a901559a1e0c218404f9a61a93be82d45cb8f44453ba43088644980f033/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8277104ded0a51e699c8c3aff63ce2c56d4ed5519a5f73e0fd7057f959a2b9e", size = 1246656, upload-time = "2026-03-09T13:12:45.557Z" }, + { url = "https://files.pythonhosted.org/packages/87/9e/f78c466ea20527822b95ad38f141f2de1dcd7f23fb8716b002b0d91bbe59/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8f9baf6f0a6e7571c45c8863010b45e837c3ee1c2c77fcd6ef423be91b21fedb", size = 1295562, upload-time = "2026-03-09T13:12:47.562Z" }, + { url = "https://files.pythonhosted.org/packages/0a/66/fd0e4a612e3a286c24e6d6f3a5428d11258ed1909bc530ba3b59807fd980/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cff8e5383db4989311f99e814feeb90c4723eb4edca425b9d5d9c3fefcdd9537", size = 2178473, upload-time = "2026-03-09T13:12:50.254Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8e/6cac929e0049539e5ee25c1ee937556f379ba5204840d03008363ced662d/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ebae99ed6764f2b5771c522477b311be313e8841d2e0376db2b10922daebbba4", size = 2274035, upload-time = "2026-03-09T13:12:51.785Z" }, + { url = "https://files.pythonhosted.org/packages/ca/d3/9d0c18f1b52ea8074b792452cf17f1f5a56bd0302a85191f405cfbf9da16/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d5cd5189fc2b6a538b75ae45433140c4823463918f7b1617c31e68b085c0022c", size = 2443217, upload-time = "2026-03-09T13:12:53.329Z" }, + { url = "https://files.pythonhosted.org/packages/45/2a/6e19368803a038b2a90857bf4ee9e3c7b667216d045866bf22d3439fd75e/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f42c23db5d1521218a3276bb08666dcb662896a0be7347cba864eca45ff64ede", size = 2249196, upload-time = "2026-03-09T13:12:55.057Z" }, + { url = "https://files.pythonhosted.org/packages/75/2b/3f641dfcbe72e222175d626bacf2f72c3b34312afec949dd1c50afa400f5/kiwisolver-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:94eff26096eb5395136634622515b234ecb6c9979824c1f5004c6e3c3c85ccd2", size = 73389, upload-time = "2026-03-09T13:12:56.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/88/299b137b9e0025d8982e03d2d52c123b0a2b159e84b0ef1501ef446339cf/kiwisolver-1.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:dd952e03bfbb096cfe2dd35cd9e00f269969b67536cb4370994afc20ff2d0875", size = 64782, upload-time = "2026-03-09T13:12:57.609Z" }, + { url = "https://files.pythonhosted.org/packages/17/6f/6fd4f690a40c2582fa34b97d2678f718acf3706b91d270c65ecb455d0a06/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:295d9ffe712caa9f8a3081de8d32fc60191b4b51c76f02f951fd8407253528f4", size = 59606, upload-time = "2026-03-09T13:15:40.81Z" }, + { url = "https://files.pythonhosted.org/packages/82/a0/2355d5e3b338f13ce63f361abb181e3b6ea5fffdb73f739b3e80efa76159/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:51e8c4084897de9f05898c2c2a39af6318044ae969d46ff7a34ed3f96274adca", size = 57537, upload-time = "2026-03-09T13:15:42.071Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b9/1d50e610ecadebe205b71d6728fd224ce0e0ca6aba7b9cbe1da049203ac5/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b83af57bdddef03c01a9138034c6ff03181a3028d9a1003b301eb1a55e161a3f", size = 79888, upload-time = "2026-03-09T13:15:43.317Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ee/b85ffcd75afed0357d74f0e6fc02a4507da441165de1ca4760b9f496390d/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf4679a3d71012a7c2bf360e5cd878fbd5e4fcac0896b56393dec239d81529ed", size = 77584, upload-time = "2026-03-09T13:15:44.605Z" }, + { url = "https://files.pythonhosted.org/packages/6b/dd/644d0dde6010a8583b4cd66dd41c5f83f5325464d15c4f490b3340ab73b4/kiwisolver-1.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:41024ed50e44ab1a60d3fe0a9d15a4ccc9f5f2b1d814ff283c8d01134d5b81bc", size = 73390, upload-time = "2026-03-09T13:15:45.832Z" }, +] + +[[package]] +name = "labmaze" +version = "1.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "numpy" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/93/0a/139c4ae896b9413bd4ca69c62b08ee98dcfc78a9cbfdb7cadd0dce2ad31d/labmaze-1.0.6.tar.gz", hash = "sha256:2e8de7094042a77d6972f1965cf5c9e8f971f1b34d225752f343190a825ebe73", size = 4670455, upload-time = "2022-12-05T18:42:43.566Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/0c/6a3941f48644c0b9305c7a22bd51974be1fed8e9233b16c893d728805143/labmaze-1.0.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b2ddef976dfd8d992b19cfa6c633f2eba7576d759c2082da534e3f727479a84a", size = 4815423, upload-time = "2022-12-05T18:41:47.351Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fe/b038c6a15732eb064767dc92ca39a38b2f5df183576384f0cfb6a4840f69/labmaze-1.0.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:157efaa93228c8ccce5cae337902dd652093e0fba9d3a0f6506e4bee272bb66f", size = 4806825, upload-time = "2022-12-05T18:41:49.922Z" }, + { url = "https://files.pythonhosted.org/packages/59/ec/2762281d4f26845b20bb7529742a6914fcb07c8e7c522175b879df0127cf/labmaze-1.0.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3ce98b9541c5fe6a306e411e7d018121dd646f2c9978d763fad86f9f30c5f57", size = 4871532, upload-time = "2022-12-05T18:41:52.784Z" }, + { url = "https://files.pythonhosted.org/packages/4d/93/abac7877e1d7de984a2f0f5be561ff0dc795ae7e22595cf2f7c7032cd27e/labmaze-1.0.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e6433bd49bc541791de8191040526fddfebb77151620eb04203453f43ee486a", size = 4875892, upload-time = "2022-12-05T18:41:55.603Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/5262db11b3c1db8e4fbc3feed9baed4f95db6047b8d9dcaf4f9fb8da9ba3/labmaze-1.0.6-cp310-cp310-win_amd64.whl", hash = "sha256:6a507fc35961f1b1479708e2716f65e0d0611cefb55f31a77be29ce2339b6fef", size = 4812953, upload-time = "2022-12-05T18:41:58.098Z" }, +] + +[[package]] +name = "lxml" +version = "6.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40", size = 4197430, upload-time = "2026-05-18T19:19:06.424Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:09dd5b7075dc2f7709654a46543ba1ea3c2e217b2ed8fbd413a8a945a0f40f60", size = 8541124, upload-time = "2026-05-18T19:17:11.589Z" }, + { url = "https://files.pythonhosted.org/packages/78/20/f7095ed9fc2c025f9cfe71cc6ec9f1feb05624edc1812423b5f1aecf3d4b/lxml-6.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f6ac4ef4d82dff54670227a69c67782ae0b811b5cf6b17954f1e8f7502fc0d1d", size = 4602783, upload-time = "2026-05-18T19:17:20.888Z" }, + { url = "https://files.pythonhosted.org/packages/4a/a4/65c63ca98bd129f6cff7b8c2fa48953ab058cc6005b541354e7dd54d8000/lxml-6.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:556e94a63c9b04716f8e4de2abb65775061f846e89331b6c5be79183a24f98ea", size = 5002687, upload-time = "2026-05-18T19:17:01.738Z" }, + { url = "https://files.pythonhosted.org/packages/96/1d/ab7a5c4b5a394d98a94e2d0fc67bab8297597426770dd4978370fbdaf531/lxml-6.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6bf403fbb3b3e348a561a5f4f0b9961835657981c802a1df03653eef8a9074", size = 5155099, upload-time = "2026-05-18T19:17:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b1/07603bfeeb891a2596d5c2a68f7d2f70f7d11c841ebe391412c69c2857b0/lxml-6.1.1-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1dde6131244bba38a17c745836ba190bc753fd73c9291666287fd0a3fa3dcf30", size = 5057225, upload-time = "2026-05-18T19:17:08.117Z" }, + { url = "https://files.pythonhosted.org/packages/7a/16/cb391ee4b90186fa16d9ebcbe3ea96c71b8da3b0686386c8dcbcc3c67d44/lxml-6.1.1-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98fc784c2c1440667aeedf8465bdfe10208acf0ead656a2c68627299f546b315", size = 5287643, upload-time = "2026-05-18T19:17:11.507Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d6/b619717f918fd76747448fdbaee0e769edbc70e659b5b5d0112b7020b7a3/lxml-6.1.1-cp310-cp310-manylinux_2_28_i686.whl", hash = "sha256:add8cf6ddf9a65116119a28ece0f7886e30af27ba724a7594305f1d1b58a92a1", size = 5412445, upload-time = "2026-05-18T19:17:22.182Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/12bc5390ac0a3edeb579d9535e5049a5dda663438728e179d52fb319c33a/lxml-6.1.1-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:cf9d57306d848218f3601fee7601fab1a327c942d56e2e97610583cb4dd74206", size = 4770864, upload-time = "2026-05-18T19:17:26.851Z" }, + { url = "https://files.pythonhosted.org/packages/0b/59/6500c09da3137f54f020e908d81cfc5ee3e8888e908fd380207afad7c2e6/lxml-6.1.1-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88136950da4d13c318bde414ce10219931937851327f44328f2df4d2c4614067", size = 5359594, upload-time = "2026-05-18T19:17:32.527Z" }, + { url = "https://files.pythonhosted.org/packages/f2/9b/f64b4cc6b7ebcf75d95af3cde934d254b5f2f10d4163928d838d86b6eb48/lxml-6.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cecdd5dfdc87b1fd87dbf81d4b037a544f47f4c744200a67013771682d67686a", size = 5107713, upload-time = "2026-05-18T19:17:04.402Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/c7388ad5d3a72315d2832dc1458cbf4f2af7f2b990b606ff4876efd04511/lxml-6.1.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd312b9692e831d2ffcad61eab31d91d4b4655a962e61de8fb410472cbcd37aa", size = 4803973, upload-time = "2026-05-18T19:17:06.545Z" }, + { url = "https://files.pythonhosted.org/packages/3f/22/76197f0bbf165f0b9e75be59be4997e5259cde973f12f098c1b54c7f5d60/lxml-6.1.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5b7328b46d49fc9477d91ae8f6d55340347d827b7734ba3ea33faae0efef1383", size = 5349925, upload-time = "2026-05-18T19:17:09.743Z" }, + { url = "https://files.pythonhosted.org/packages/24/52/d2a0cfeccb9bcdc47c7ee05cdae5d69b48c9acf20997790a6338bb0d0b3b/lxml-6.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37a58976370f36d9329d118ad0b953c5aeb9119ac9c6a4e258942a225d0573a1", size = 5309825, upload-time = "2026-05-18T19:17:13.831Z" }, + { url = "https://files.pythonhosted.org/packages/19/4a/b30944266776c2f49749ef2445aa7e78898194134b80ad776386f61b56ae/lxml-6.1.1-cp310-cp310-win32.whl", hash = "sha256:cea3f4c1af79af13cdb2da0c028111d8f8522d4f22a000c82385535f24e5cf3a", size = 3598402, upload-time = "2026-05-18T19:17:08.21Z" }, + { url = "https://files.pythonhosted.org/packages/9e/97/33691c66a4d7ec1a5a98e7c909a5b83ee45c7f7ba4cf92b1c4cf26e98079/lxml-6.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:3abf332af33a74288675d936fe861fd4344da0dd6622193fbc4f2bfbb35536b5", size = 4021295, upload-time = "2026-05-18T19:17:28.638Z" }, + { url = "https://files.pythonhosted.org/packages/d0/5f/26a4dd0e12b9456ff7b12a21af5b491eb6629680d1edd73f4140fd386bcf/lxml-6.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:8dadbe5b217ff35b6a8d16610dd710219b59b76d13f0e3f0d9f36786206e4485", size = 3667717, upload-time = "2026-05-19T19:22:44.474Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/6f/340b04986e67aac6f66c5145ce68bf72c64bed30f92c8913499a6e6b8f99/matplotlib-3.10.9-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77210dce9cb8153dffc967efaae990543392563d5a376d4dd8539bebcb0ed217", size = 8296625, upload-time = "2026-04-24T00:11:43.376Z" }, + { url = "https://files.pythonhosted.org/packages/bb/2f/127081eb83162053ebb9678ceac64220b93a663e0167432566e9c7c82aab/matplotlib-3.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e7698ac9868428e84d2c967424803b2472ff7167d9d6590d4204ed775343c3b", size = 8188790, upload-time = "2026-04-24T00:11:46.556Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b7/d8bcec2626c35f96972bff656299fef4578113ea6193c8fdad324710410c/matplotlib-3.10.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aa972116abb4c9d201bf245620b433726cb6856f3bef6a78f776a00f5c92d37", size = 8769389, upload-time = "2026-04-24T00:11:48.959Z" }, + { url = "https://files.pythonhosted.org/packages/12/49/b78e214a527ea732033b7f4d37f7afb504d74ba9d134bd47938230dfb8b1/matplotlib-3.10.9-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae2f11957b27ce53497dd4d7b235c4d4f1faf383dfb39d0c5beb833bff883294", size = 9589657, upload-time = "2026-04-24T00:11:51.915Z" }, + { url = "https://files.pythonhosted.org/packages/5f/15/5246f7b43beae19c74dfee651d58d6cc8112e06f77adb4e88cc04f2e3a23/matplotlib-3.10.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b049278ddce116aaa1c1377ebf58adea909132dfce0281cf7e3a1ea9fc2e2c65", size = 9651983, upload-time = "2026-04-24T00:11:54.766Z" }, + { url = "https://files.pythonhosted.org/packages/75/77/5acecfe672ba0fa1b8c0454f69ce155d1e6fc5852fa7206bf9afaf767121/matplotlib-3.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:82834c3c292d24d3a8aae77cd2d20019de69d692a34a970e4fdb8d33e2ea3dda", size = 8199701, upload-time = "2026-04-24T00:11:58.389Z" }, + { url = "https://files.pythonhosted.org/packages/2c/2b/0e92ad0ac446633f928a1563db4aa8add407e1924faf0ded5b95b35afb27/matplotlib-3.10.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1872fb212a05b729e649754a72d5da61d03e0554d76e80303b6f83d1d2c0552b", size = 8293058, upload-time = "2026-04-24T00:13:56.339Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/74682fd369f5299ceda438fea2a0662e6383b85c9383fb9cdfcf04713e07/matplotlib-3.10.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:985f2238880e2e69093f588f5fe2e46771747febf0649f3cf7f7b7480875317f", size = 8186627, upload-time = "2026-04-24T00:13:58.623Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e8/368aab88f3c4cd8992800f31abfe0670c3e47540ba20a97e9fdbcde594b3/matplotlib-3.10.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6640f75af2c6148293caa0a2b39dd806a492dd66c8a8b04035813e33d0fd2585", size = 8764117, upload-time = "2026-04-24T00:14:01.684Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "mujoco" +version = "2.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "glfw" }, + { name = "numpy" }, + { name = "pyopengl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/03/7ce6078745085febd22fc4586a63016a71125031b97883d456ce1d64e5ed/mujoco-2.3.3.zip", hash = "sha256:8bd074d3c5d9d25416cf2a5b82b337a7431a6e20edbd0da7fbc05ee5255c1aaa", size = 633278, upload-time = "2023-03-20T18:23:59.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/2c/f59255b4fbd159a374c4077721bc5baac11afcc15b8a28f8c7658ac89df5/mujoco-2.3.3-2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7b95a0b7ae8bb9e36d04ba475a950025791c43087845235bb92bd2dd1787589a", size = 4308671, upload-time = "2023-03-20T18:09:30.955Z" }, + { url = "https://files.pythonhosted.org/packages/31/20/afc0ef5d5b9d96f3853458329f39518e638f41c0439c94ae2b97a9ab9f3a/mujoco-2.3.3-2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8b9f8e9e6d47fe60f96dc54be780a66a38d5ec2ff94d091ad54c6f87468b4b6a", size = 4177357, upload-time = "2023-03-20T18:09:34.016Z" }, + { url = "https://files.pythonhosted.org/packages/6d/da/27b0ef31aa23f64c21e7129ddf378c2548be45d87433f89e2bea4cafc811/mujoco-2.3.3-2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9cbd3b60ac30f0b6661de050ca3e1de906b9c28ed9d084bdd708c141953247d", size = 3995762, upload-time = "2023-03-20T18:09:36.335Z" }, + { url = "https://files.pythonhosted.org/packages/6d/27/90cc9b4f88c5b797417e1fbeacb7590cd85f7e464a8ab79f60c885708e39/mujoco-2.3.3-2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7fd195bca86102788d86dbc2773c59c1f0ee3933b35eb0f6a86f0f2aeb5065", size = 4270849, upload-time = "2023-03-20T18:09:38.593Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b3/e9119ebbbe9ea830e6c8ab7eafc0de7c82b38d6b71d2b2e38ba20e43a1b7/mujoco-2.3.3-2-cp310-cp310-win_amd64.whl", hash = "sha256:f3595e992770eff3f842cb80f7eb2b7b1b3e78995b6ecc247f98036da17ef74f", size = 3190540, upload-time = "2023-03-20T18:09:41.101Z" }, +] + +[[package]] +name = "networkx" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, +] + +[[package]] +name = "numpy" +version = "1.26.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411, upload-time = "2024-02-05T23:48:29.038Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016, upload-time = "2024-02-05T23:48:54.098Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889, upload-time = "2024-02-05T23:49:25.361Z" }, + { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746, upload-time = "2024-02-05T23:49:51.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620, upload-time = "2024-02-05T23:50:22.515Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659, upload-time = "2024-02-05T23:50:35.834Z" }, + { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905, upload-time = "2024-02-05T23:51:03.701Z" }, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.4.5.8" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b", size = 363438805, upload-time = "2024-04-03T20:57:06.025Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.4.127" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/42/f4f60238e8194a3106d06a058d494b18e006c10bb2b915655bd9f6ea4cb1/nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb", size = 13813957, upload-time = "2024-04-03T20:55:01.564Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.4.127" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/14/91ae57cd4db3f9ef7aa99f4019cfa8d54cb4caa7e00975df6467e9725a9f/nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338", size = 24640306, upload-time = "2024-04-03T20:56:01.463Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.4.127" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/27/1795d86fe88ef397885f2e580ac37628ed058a92ed2c39dc8eac3adf0619/nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5", size = 883737, upload-time = "2024-04-03T20:54:51.355Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.1.0.70" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741, upload-time = "2024-04-22T15:24:15.253Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.2.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/94/3266821f65b92b3138631e9c8e7fe1fb513804ac934485a8d05776e1dd43/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9", size = 211459117, upload-time = "2024-04-03T20:57:40.402Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.5.147" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/6d/44ad094874c6f1b9c654f8ed939590bdc408349f137f9b98a3a23ccec411/nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b", size = 56305206, upload-time = "2024-04-03T20:58:08.722Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.6.1.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/e1/5b9089a4b2a4790dfdea8b3a006052cfecff58139d5a4e34cb1a51df8d6f/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260", size = 127936057, upload-time = "2024-04-03T20:58:28.735Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.3.1.170" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/f7/97a9ea26ed4bbbfc2d470994b8b4f338ef663be97b8f677519ac195e113d/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1", size = 207454763, upload-time = "2024-04-03T20:58:59.995Z" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.21.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/99/12cd266d6233f47d00daf3a72739872bdc10267d0383508b0b9c84a18bb6/nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0", size = 188654414, upload-time = "2024-04-03T15:32:57.427Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.4.127" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/ff/847841bacfbefc97a00036e0fce5a0f086b640756dc38caea5e1bb002655/nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57", size = 21066810, upload-time = "2024-04-03T20:59:46.957Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.4.127" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/20/199b8713428322a2f22b722c62b8cc278cc53dffa9705d744484b5035ee9/nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a", size = 99144, upload-time = "2024-04-03T20:56:12.406Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pillow" +version = "12.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/c2/669d88644cddb1485bd9534e63e8cf476c8e51cb3c3a1297677023505c0e/pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a", size = 5392418, upload-time = "2026-07-01T11:53:27.808Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7", size = 4785287, upload-time = "2026-07-01T11:53:29.761Z" }, + { url = "https://files.pythonhosted.org/packages/07/50/b5d688cc9c52d4482f3d5bcab6ce20bc2a74a85d2343841c907444a3be2c/pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f", size = 6253754, upload-time = "2026-07-01T11:53:32.298Z" }, + { url = "https://files.pythonhosted.org/packages/4e/89/36f4cd76cf4baf05c50ababb976249153f18c959171c7f6ba09a6f217260/pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec", size = 6925605, upload-time = "2026-07-01T11:53:34.487Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c0/4de58cf6633b9e3a6061ef4be6fb91fc3c90b812ece886f531e3c523d777/pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468", size = 6327788, upload-time = "2026-07-01T11:53:36.433Z" }, + { url = "https://files.pythonhosted.org/packages/87/3c/14d53682a19550dbbaf3b598f807d5457646c510805a44c7d7891cd1cd1a/pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed", size = 7036288, upload-time = "2026-07-01T11:53:38.712Z" }, + { url = "https://files.pythonhosted.org/packages/38/1d/36279e3c77efe034e4cc2b0393ee74ffdb5a62391dacbf9b916154f5f0b8/pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1", size = 6472396, upload-time = "2026-07-01T11:53:40.781Z" }, + { url = "https://files.pythonhosted.org/packages/48/7c/8fa0039574c476d7c6fa57dd7c32a130436877c6ec1e5ce1cc8ec44878c1/pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb", size = 7226887, upload-time = "2026-07-01T11:53:42.764Z" }, + { url = "https://files.pythonhosted.org/packages/fa/17/e324be141d173c1c919428066c3259f21c1b8982e564e01a4a81e96dbdcf/pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f", size = 2568039, upload-time = "2026-07-01T11:53:45.372Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "protobuf" +version = "7.35.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/01/9ef0afd7999eb9badb3a768b4aedd78c86d4c65cfaf1958ab276199e76b4/protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a", size = 458717, upload-time = "2026-06-11T21:55:40.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6", size = 433226, upload-time = "2026-06-11T21:55:31.719Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/dfb89eb0e652a1ff073c39a59fb5e3a83cfe9b57a2c83fa6d78270101767/protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799", size = 328847, upload-time = "2026-06-11T21:55:34.035Z" }, + { url = "https://files.pythonhosted.org/packages/0f/58/dc12f2cd484951524af6e3382c785869b9b3fb5e52ee95ae23add53ee8f9/protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4", size = 344030, upload-time = "2026-06-11T21:55:34.941Z" }, + { url = "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4", size = 327130, upload-time = "2026-06-11T21:55:35.921Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bc/6d6c7ba8709c85f8f2c390b2b118d6fb08a783676a572271851bf45a7d22/protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30", size = 428945, upload-time = "2026-06-11T21:55:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/0a/19/8d0cb6f20a1ef7b18f1c8986ad5783f22f84cce39c6ce9a6e645ea55192e/protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87", size = 439996, upload-time = "2026-06-11T21:55:38.123Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9", size = 171659, upload-time = "2026-06-11T21:55:39.155Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyopengl" +version = "3.1.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/16/912b7225d56284859cd9a672827f18be43f8012f8b7b932bc4bd959a298e/pyopengl-3.1.10.tar.gz", hash = "sha256:c4a02d6866b54eb119c8e9b3fb04fa835a95ab802dd96607ab4cdb0012df8335", size = 1915580, upload-time = "2025-08-18T02:33:01.76Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/e4/1ba6f44e491c4eece978685230dde56b14d51a0365bc1b774ddaa94d14cd/pyopengl-3.1.10-py3-none-any.whl", hash = "sha256:794a943daced39300879e4e47bd94525280685f42dbb5a998d336cfff151d74f", size = 3194996, upload-time = "2025-08-18T02:32:59.902Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pyquaternion" +version = "0.9.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/3d092aa20efaedacb89c3221a92c6491be5b28f618a2c36b52b53e7446c2/pyquaternion-0.9.9.tar.gz", hash = "sha256:b1f61af219cb2fe966b5fb79a192124f2e63a3f7a777ac3cadf2957b1a81bea8", size = 15530, upload-time = "2020-10-05T01:31:30.327Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/b3/d8482e8cacc8ea15a356efea13d22ce1c5914a9ee36622ba250523240bf2/pyquaternion-0.9.9-py3-none-any.whl", hash = "sha256:e65f6e3f7b1fdf1a9e23f82434334a1ae84f14223eee835190cd2e841f8172ec", size = 14361, upload-time = "2020-10-05T01:31:37.575Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "scipy" +version = "1.15.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, + { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, + { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, + { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, + { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, +] + +[[package]] +name = "setuptools" +version = "84.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "speedtuning-sim" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "dm-control" }, + { name = "mujoco" }, + { name = "numpy" }, + { name = "pyquaternion" }, +] + +[package.optional-dependencies] +evaluation = [ + { name = "matplotlib" }, +] +learned = [ + { name = "einops" }, + { name = "packaging" }, + { name = "torch" }, + { name = "torchvision" }, +] +rl = [ + { name = "torch" }, +] +test = [ + { name = "pytest" }, +] +video = [ + { name = "imageio" }, + { name = "imageio-ffmpeg" }, +] + +[package.metadata] +requires-dist = [ + { name = "dm-control", specifier = "==1.0.9" }, + { name = "einops", marker = "extra == 'learned'", specifier = ">=0.6,<0.9" }, + { name = "imageio", marker = "extra == 'video'", specifier = ">=2.31,<3" }, + { name = "imageio-ffmpeg", marker = "extra == 'video'", specifier = ">=0.4.9,<0.7" }, + { name = "matplotlib", marker = "extra == 'evaluation'", specifier = ">=3.7,<4" }, + { name = "mujoco", specifier = "==2.3.3" }, + { name = "numpy", specifier = ">=1.23,<2" }, + { name = "packaging", marker = "extra == 'learned'", specifier = ">=23,<26" }, + { name = "pyquaternion", specifier = "==0.9.9" }, + { name = "pytest", marker = "extra == 'test'", specifier = ">=8,<9" }, + { name = "torch", marker = "extra == 'learned'", specifier = "==2.5.1" }, + { name = "torch", marker = "extra == 'rl'", specifier = "==2.5.1" }, + { name = "torchvision", marker = "extra == 'learned'", specifier = "==0.20.1" }, +] +provides-extras = ["learned", "rl", "test", "video", "evaluation"] + +[[package]] +name = "sympy" +version = "1.13.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/99/5a5b6f19ff9f083671ddf7b9632028436167cd3d33e11015754e41b249a4/sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f", size = 7533040, upload-time = "2024-07-19T09:26:51.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8", size = 6189177, upload-time = "2024-07-19T09:26:48.863Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "torch" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/ef/834af4a885b31a0b32fff2d80e1e40f771e1566ea8ded55347502440786a/torch-2.5.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:71328e1bbe39d213b8721678f9dcac30dfc452a46d586f1d514a6aa0a99d4744", size = 906446312, upload-time = "2024-10-29T17:33:38.045Z" }, + { url = "https://files.pythonhosted.org/packages/69/f0/46e74e0d145f43fa506cb336eaefb2d240547e4ce1f496e442711093ab25/torch-2.5.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:34bfa1a852e5714cbfa17f27c49d8ce35e1b7af5608c4bc6e81392c352dbc601", size = 91919522, upload-time = "2024-10-29T17:39:08.74Z" }, + { url = "https://files.pythonhosted.org/packages/a5/13/1eb674c8efbd04d71e4a157ceba991904f633e009a584dd65dccbafbb648/torch-2.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:32a037bd98a241df6c93e4c789b683335da76a2ac142c0973675b715102dc5fa", size = 203088048, upload-time = "2024-10-29T17:34:10.913Z" }, + { url = "https://files.pythonhosted.org/packages/a9/9d/e0860474ee0ff8f6ef2c50ec8f71a250f38d78a9b9df9fd241ad3397a65b/torch-2.5.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:23d062bf70776a3d04dbe74db950db2a5245e1ba4f27208a87f0d743b0d06e86", size = 63877046, upload-time = "2024-10-29T17:34:19.174Z" }, +] + +[[package]] +name = "torchvision" +version = "0.20.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, + { name = "torch" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/59/aea68d755da1451e1a0d894528a7edc9b58eb30d33e274bf21bef28dad1a/torchvision-0.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4878fefb96ef293d06c27210918adc83c399d9faaf34cda5a63e129f772328f1", size = 1787552, upload-time = "2024-10-29T17:40:34.071Z" }, + { url = "https://files.pythonhosted.org/packages/a2/f6/7ff89a9f8703f623f5664afd66c8600e3f09fe188e1e0b7e6f9a8617f865/torchvision-0.20.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:8ffbdf8bf5b30eade22d459f5a313329eeadb20dc75efa142987b53c007098c3", size = 7238975, upload-time = "2024-10-29T17:41:03.374Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ce/4c31e9b96cc4f9fec746b258d2aa35f8d1247f4f58d63f9c505ea5eb254d/torchvision-0.20.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:75f8a4d51a593c4bab6c9bf7d75bdd88691b00a53b07656678bc55a3a753dd73", size = 14265343, upload-time = "2024-10-29T17:40:57.799Z" }, + { url = "https://files.pythonhosted.org/packages/17/11/b5ce67715bbbec8798fb48c4a20ac28828aec1710ac01091a3eddcb8e075/torchvision-0.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:22c2fa44e20eb404b85e42b22b453863a14b0927d25e550fd4f84eea97fa5b39", size = 1562413, upload-time = "2024-10-29T17:40:39.991Z" }, +] + +[[package]] +name = "tqdm" +version = "4.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/3b/6c24bec5be5e743ffd99576daa5cc077722fc7d5bbc00bd133fa0c698dc6/tqdm-4.70.0.tar.gz", hash = "sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220", size = 795438, upload-time = "2026-07-27T11:33:15.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl", hash = "sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953", size = 80184, upload-time = "2026-07-27T11:33:13.167Z" }, +] + +[[package]] +name = "triton" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/29/69aa56dc0b2eb2602b553881e34243475ea2afd9699be042316842788ff5/triton-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b0dd10a925263abbe9fa37dcde67a5e9b2383fc269fdf59f5657cac38c5d1d8", size = 209460013, upload-time = "2024-10-14T16:05:32.106Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "wrapt" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/b0/c1f5a970721f06b85c0cd5142e0ff8fe067708abd779b0c4f4be7d61d09f/wrapt-2.3.0.tar.gz", hash = "sha256:681a2d0eefd721998f90642762b8e75c2159ec531b20ad5e437245ea7b06a107", size = 131509, upload-time = "2026-07-28T06:06:14.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/31/5822ce37ca8820c2ed35a498c67c8b37960b9cee2ba437fd32849d0a234c/wrapt-2.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0bb2797048db0956348cb3058c33bc4184614f13231389cfbccc16a5d32780a7", size = 81191, upload-time = "2026-07-28T06:04:04.858Z" }, + { url = "https://files.pythonhosted.org/packages/7a/5a/3c6117938be98754578ab83f5a40d7d0ea2cd2c487dc5cd6027ee7228229/wrapt-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce9f398f868d2b3b27aa2ea4de79645ef9077aeeac8dfc2814b0d542c6a2b87f", size = 82255, upload-time = "2026-07-28T06:04:07.151Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0f/94ae724c5087eb6054c0d63febd7094947dcf302fe058e2e0488102a872b/wrapt-2.3.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ad71df7a04dd3497e9302e81f4a7c91bd401ea0e15a9df9029527900f94bee43", size = 155228, upload-time = "2026-07-28T06:04:08.272Z" }, + { url = "https://files.pythonhosted.org/packages/6c/21/1f780bba935dcf697c0c59de9be3a559bbb8e31a53ca3f25422023738432/wrapt-2.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc82c2ccc8e234c844f5303d9f2984b346dcdd53e94823ce8420d2c75b4b9023", size = 157073, upload-time = "2026-07-28T06:04:09.459Z" }, + { url = "https://files.pythonhosted.org/packages/73/31/6c7799d7b6431fcd7e1b83245fb45258a2d2c3a2187fbaecb83572a72d7a/wrapt-2.3.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6e19531ae33c508cea7d84a7edfda01fa86e51b8d1a93a77712c55e6e469152", size = 151594, upload-time = "2026-07-28T06:04:10.784Z" }, + { url = "https://files.pythonhosted.org/packages/ce/17/42d670dbfafd49076c6eb2b7d67633d7e1c968e39bfb11a135acb6fac67b/wrapt-2.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:df4ce31150bcd5d9f36f816aac3010ab4f4bf8672ac1d3b0ac7d539ec61c7c02", size = 156069, upload-time = "2026-07-28T06:04:12.316Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d6/c66b4ba4eda49257c84d5c2df26118280f09ca7905aee20d0064db778d13/wrapt-2.3.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e2e692bc0d63f881cf7006730a56bd4e0c2fab5dc318466942805d692b166276", size = 150930, upload-time = "2026-07-28T06:04:13.482Z" }, + { url = "https://files.pythonhosted.org/packages/c0/f2/1a3b949c0322fb27396eafd1044328c1cb0400e0b32105d75a3cd03096e7/wrapt-2.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c8388ba7faf5dbf9ee106bb70d66f257629b1bd98091123e19e8a4553a319199", size = 154525, upload-time = "2026-07-28T06:04:14.698Z" }, + { url = "https://files.pythonhosted.org/packages/12/65/147563a3dfa6e830c857b93b530ebd8c0cd9d540e5914aec8f9b12880c02/wrapt-2.3.0-cp310-cp310-win32.whl", hash = "sha256:e045ff75d7d94900fc32896ed93c45ce2d2cac28c9dead582ff9a5a49d446e35", size = 77879, upload-time = "2026-07-28T06:04:16.102Z" }, + { url = "https://files.pythonhosted.org/packages/c4/eb/921405b4dc55d4f8be4c700ef120539fdd75d5fdb50d83bd257171ee18e0/wrapt-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4fc96b159af0a3e0faa72475a69d66292bea72a5bed1e1aca1bffbddc3cb2b0", size = 80733, upload-time = "2026-07-28T06:04:17.43Z" }, + { url = "https://files.pythonhosted.org/packages/b6/13/75947450c5bb57795fa86384721cd52c5c4deb0879022f309501a8a85d44/wrapt-2.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:1236fa25173ca964c97422470482e9011b9e3c7ed0d75798b40b3da3b0e0e760", size = 80199, upload-time = "2026-07-28T06:04:18.761Z" }, + { url = "https://files.pythonhosted.org/packages/00/39/3daf9f47be208606586de4568ba6713db53ebc8fd7a575aea1fe57983b69/wrapt-2.3.0-py3-none-any.whl", hash = "sha256:d8c7ed08477429752b8c44991f40ad7838b18332a160698740a6bfbc10d998a2", size = 61866, upload-time = "2026-07-28T06:06:12.9Z" }, +]

}L6Ydu9${6}Rh@8#~P<1>+2@-5L9a-Ss7- z`s1^$4H`ckFN0jub3+(*Qw55CFWzkbGGAFP^3@z8#3KHh3j<5Zu=<%yyQF zI{&B5h?dF5M?CudL0y454kSYtMI~+lgcG2DvOjwkqTNTYLQR3mN=jAOAQ>bw;mi$q^gHL<6l8ARsaS+|3VXGWd@n}Vn$0u;zM^kZ& z6ymPiKVD@5ISK`s9%SUe4|!+-3sIsPH!<}hAld>f*m$+|NSd+tuSp}LDvL*SE-o%4 zxFPa+0FR-t%JelL1t!_?`VJ6>0x~MhD!T@_n>iE0DgYDM(Y%VWhag;n^(1@~!b6yR0WsRF(*p&@EfpU5{UtgZju8S7;fyTy$pG%hMX+- z3oRs+JnESEr3D8p3E_0!IOCDMey86+LI(ELg|B%~7yc-=P1DePHc7#eX%qie-y8Qg zR&majKFF&rk@a6HJKKFy-P zFsM4E$#ULk&1=mRa%|-&3@>o{x>Y<7@)+Z&PCV<$A`CWfMbE@L6kvdTO6&Ril8&ikZcbjvrPHy}zA%9>509o~ zXi8vVzW#%;$PS?rCkh_-09>pz{5FnvojHJ9g?~FJmjqvIuD>CSwk0p1#ypx+s@j%1 zB(qmk7SYn9k*wZqquHLazi4L%Y}3f;l{vH#F^Ibq2XKGA;n&gO>dLN6^7_j=$~ zT9bz3ZDFK^$?%M1pD}pU>DzThmrSWcb zhpiXJ5lcXMfA!RdZ7u;g-2zV^-yJymtGNO~B92WN{b=wE33Kb;nxXKt^Mmod!8#+ z+!=#EN*-S9kXstwkf`P6;lpK2?iL);=iC1#JzgXUN8czU?s=r}mNQZ41)&h{8b*Hl zF~@)I*$9HLgxIG?SZ&BI#FatfY?j!nq0pp}7M!xp6xO+%o|D6UUG65U2=(mWtvI7| z_``{FPQ7zwXM9%O?xGlO*V|gm+RMjUF6!6UCJxT2%e4V-E9sPdGp@rr*6e_aeo ztPHSY&bfS{h~wu-H#IFQqb(Y@A9e-O4&h-y^OvQn;u$+>)E0jwT)(qeHvA#gAmKk6_3=$7F#w=rBf zZmA<){&YG8v((u&%3O88IoB0bRnW9fml%<7yj< zH+o7nxK)uHWc_w&oZJfCYJyRu|6K~sZ_i1sJ%h8n3&iwLqtwEdvF(9?p|IXeKlW*h zor^f@VBIP8{c!gBQa`+kMX2ySHGnd<=&OLtl?c`q)~QHa9H$H z{Acy}7l@({I-;yU3K}-eBX%T3M`Fi^-Ey5HIk*h+-%87m%+thJW?XD)arLP8O$mw+yYPnIjxe>qEap4LLPVeno3!cpm`Tv*b=R`Vk z`cg@tO`sX_j_6(DTtIw%P)#_yW2fcvm_P-eypkM+P-Wx4=lI|m_Rtx zxx$rcVT9Ob!v;QtA{$Tju}Y4({EE+q{Kb_t-C`x?v!;{S=GEBZa@YXD`2W7jd2sdY zfN}NYZi&SaQ>3hdFgKb1?wOXAbpIvOL;b~dRhMl3#ktmYk6xd^^0crEyH6Tf_SBNb zFZ)fSc9@9~|1j{sn@JzbP#Js7;BPa+IqqRaaS)iX_X>Hjvy z`S0uQ8P2}<{O&wp4?cH7umq(6)TC+KY5F+s?_Xs?8un;K-fT;LmgL*=3%Gw?{zDSL zC5MQi*H;)9B)jc#}JA1mcueaTMDX=wfT|y-;lClxRz-w^aqB1JnikBY#Z7oz+PP5!KutrP^d*2j`zjaAnMz`apEF%Q&PaL#DV9Dh zH?rFi`z>|w$u=(ViP6!)XS=$&>(BgK04>W6z_yaryR8y*sHl=UANgsDeHph`*UNqq z3^`Xh6DG34Cuj#%VEcw7KF%o)!24Zt07XV_WUEgZ)@2u9!-r3vRfB3LNX`MAz zZLO)~`hk8WIx4Eg*s*#74+H76_j`EQ3d8vwvjwE~SJRxK6g{u$-c%_%Hi2Z|uq5{< zDXPd+ID*p){p7DSMD3&$g`&d$z&R!~_Xi`eK3&>^Dt_P#!fnzo&){2w32e{kv7Y=4WB zW@OQ14rV<&s9(-WNjV!5Sq|x59s8!NP~FLV>?!FFxb0V`>L9q1Ts32%pB;rWdrxAv z?N(eCD#6&&HtKFZyT5J=a~PO$6!CXaR`YwP$ovYuxb4kZrJ<}V}r129?-H9TUapnt(%;l*+2 zd+ia)hk@z!_|lWfldt#>|O^6>LcON-=B=gcAZm5v9V6~I9R z*mNKU4JyrF@N)1b%TAPE-y%i;LY|frcIHhv_NWtzPgy=OP1tf!m&#AqAZ$nRX(MGA zpE`eR8!(z0q`qK|cu&l~w1s#?**;yTGgz*(%dmO;)LAy-3WsOH8`3dZEd0(#hr7gQ z>*ZzlhqSwRi`z$XiIy(L<;gob1w*afS&NJHC*9YWBN)P*?`{9Ml|KI-kiZ7ijj;k* z^!$c~8NkTrF5=6LoMY}&)Du_9L-kn?n<~q_Z)r0MNMkJjtW-W%caVE`Z3*21WB>j8 zw}Q-Hy@(+rk@37Q|^v}SnCRPy3@31B#BY{|*wQe3z@WC1rHxCbV4F7WJ zg2te}t~UKw9hta4Vt@zR=Ysp$vu82NSda3#<`Rz|MtBWEyywSTgIYrb9Ai-`wK8jM zfpDIrd?Cv=ZID-5yX}q```LmmmlW0;-)0ib!w*r5mY`2m%)Tpo1%Yn4A`tPB_f=47 zyZizJQ2#FPp{M-hKvd6iM;qp?`ycqvJ}yJ)sXCea!XLr?f*#Ge)Y8hTF9)`@gSfPH zPRhBXS(A|V4ar`|q&zk*@q2~%I2USAciZ4|p||sDceCKfkEzMYyuc0jW=c6h%)lIg z^z-Np!gMm(+uQRw-RAQ+T%a*_VW6Zq@pPN1FawgqGLVa5aWZYd83GrrkCEx@6@Qy7 z&=D(H!qT0b04+I((Qke(!$o4@5Dvk$vp7_h%J!Y8 z@kh_m4Q2rIChG|>HAK&EO#gz>*AIypLftt6c4}{L@kObK-~csSXe{kz3UO3xMhrPl zsDDXsi^D=uQNA`y6IF^j>+&DMAcN@{?A$M(hJ}E3DDjw$W-%F<#*jK1WYZx-t+QCB}5TOu~L^JKplDI%u&--mM)XYQ*@{m7O6 zZ$m?QJ9>XEVzC$w;+|Z>-u6AQ|GO#)8vPS#Kh@$YX{*}ck(h8J6|h8-5U zHF^lvA`<$Z7VIUbGRzTEkn^qrq<|MN7Ll(0!;}{%t2GJ+08YXd=6rG6m7HJ?66=-zRJEoGK2WyzRbYNn3165!=w~Ce_5$Rd#T>t; z_49dPyiTQ`#Gb*TWqR+G#aMl<1qolf)@vQd)b6UsU=c)cwPDQx3I*x_i5h; zTZVnFL!$&f@6Njs;l(X{tUsr8z|*R?tOZ~Ve62oceyYlb`E3=sh=NO;Us=BkXDB-J z#!qg-><T~^h4oMbb4m0SHoD;Jb% zX8Rn{-*1&6!|Z~x6wPUsSNp)E84?(PjPN2tXi6UU0PF`r6{)geZn)rq@?vvt(v)g* zdrJ$=6n07}qkb>!xaIDA{(jbt)?dekIU~Qy-f*2-srw(EV%hryRn&dSaNri{x+S3%N7aQ zserQn_P()azk0vNN`zs{0P~phpo4fZZ00Ur+r_<(vp1+e#YxUc@0%k8qalQ%-5i5G zKkhCKIR6psbz_D#KY?O0%`T;EQV31H9i48507zZpqnlWdr19f}YbE=iwQ*VO26p@G zqqR1#3Q)zGUCkl_3wx$#IyCW|?&A~D%;S~UnD>@VjIqgp4~@XED4^q09kMW=e{Fcw z9zlIVO?lIPnLkfKJunjfUXBx;+LA6FM|HiP9)J6_u3WO;4`%Mgu_?9g&i5VrXdi z?%g}UB%rT9SEva(KX@%A)cLBo*3%{H#kagy#b-7u?gbU#NV-SLQ5QBsDe65;6E-%` zY5keP@0Qiz41$0IrGezazh6rNfW;a8@=^*DKkvT%6lur|L??LT1@ z1z>T&Z*m9B_+xz4ZhLe`iSIGw6yL`2TdtPpk@$S=xsBCREiB4&Z127+%dci0<7JD?9t%!k}>=u}|w^_|&}Fxw-yFuN2){3n#D7;~DPkO2f-^$_yi+99lnkgKY2{ z_MBGC8Wjd%98??gb@suAj@td*srULN_W*D=OZBQZgK)Xo+1X8xjZcXX8yg!3TI0q~ zo79w2X~Dz1}}NcT~P{qs_9!mE;A)#ps+Blxo zZ=)%^sT8w!R>oD*gSv^KkCG4ocyC&ZdS3GW`MbML5x%hlV}5f*C2B6ah7yqPX~Lp| z%*BF>UO4v0iqhd*Y_G`6RN2&TVg$s87dLrR_wvBYL?9+B+diwlU`?7o=t~hZ>%#bX zrzplaHtq)u-a1|ClKHJ((Qi{g=QIb#Ik%G zEuYd>R=fCByO0WX$Gwq&X4|@s>BO38y~4jd{Ykadu23p!Dkx$(n>^p`{6}w?&sy$p zwR@M|yY=FqIOm7iUFeYTS}-@cg=CvAGb}Qd{x+QYVbATz1@g9|1ATsfo&fPVBViER zL&|2{t|4QckZRUgCyneh+#Pa&nCP?f>b2OBsPS$7Nd$eUrIb^!h4xJ&FAhpc45bmB z6Z8AQApmDD^81(&zpsvKZvf($v&0BxdHHgr?sS_+BF;>ed=d0-^KI4^JYk=K5j+_( zZbMOEiX8l&6{Ys0Rv2slRdnyk{4$cPl*ava6`}sk1;Fx2I<0hE0J{47P(5WZppo%< z8vI}Yd_Z<{HIaWG#}bQf@%}9?Dgv4Z1YjvTTy95&Q9EoewO+YBN{F-NpuoFtE1o`< zJ6EVLget$}^_F}VRkr78m)1#O89gLs8B6y$hWX`){KTXbwX zqyeNmjAcoMXsCm{-5-SnM!8Js&U@xJB@p`%81=HC zd=z>$sz3uqouHUZ$+Pc@S? zpCkD_Jv_!Az`#)XzUbDjMqa^JIN#6@hB?fB3pw`jp18VUm@BH~!nbB8zZb8IV$G64;BnFgk`_<1PI(O3N7e(rA$! zA3wc~U&6-@VpphE?_gwT5*I1-O(`KA{{3qTdWP%e02~3GVq0tNb7+oif3x z(7LDO-kP8_w>00YgZJjea=-&O>#T(HtF3TD=`T6P&Q}}%kEXMXs)Fmfwv?2VAf3|P zUD6?qbV(!K9nuZbjnduS4bmXp-QA7f_I|$CzcLt%bJpH_#hllghkt~84-27(y4;Lz z@R~2gS;vl=@#6y24z_qWU^ZE`UrmxCgX)`4w~8deEX8)IO$lMJn!bj2=eZS{jcxth zaDPl@Set;M)uH&YMR(K1-kFYjcPr<8ul}W**GmpL`B`U1sQ5zFUfH4fUDyZG*>bCg zKhn{#o0vZB`Rp|9w-3F~hduK>XD5q+H){~i z@b6_(M@ZMm>*HL9J0IbQQ7>~2H0QI+sz#eTFx|5AX<-}Nbi8nQL!{CNad4(Lgflen zm)4BoGJXAod&WB&#olTmpy_HBLNLx4n6;7xA!8yX@VcaO?;NetQUm7PAqvN@D`${i zPlTRQD@KbK`#CW{e*N1@2#3rB<*y2uD=vngvqaglIIgEoame?te}nx)M-c{kDE zyjNu$ZEF9<3;s%M^?o?_DeIq3Wb9PNL}NWIzi3tMH|k_nXb4el>EZADIi>u3Jw7w!(Ja&=72R_#FjOEl`;Q?3}&83Gj*IumW zL{J`Jk*Db|AfaP1XsD<<4vS?g+7F5Nu*<)l5v~x336$mjkS zN#0d9Yq%A61uHEb+8PhKva;=cm!I@E(j(qo9Bw{7nhp(<2sqFs)+j0aEVp?Wd@Aio zN^I9tuIbvt+i}!QPjE7{E>HfOH{h_A$*%?F3mRw=_{EV?FaomDURbZsk_G4`9~@>M zJO!6pIEO90^*i72-Iy=t0rU1|o-b4t<;S1ml78}shp&oCe(-dlt*Vm|=OF8RdvS1bTPhFOcb93Rc?)s+Z{)_Xex08%j#XW#v0cv^e?b zqeWkpv|Dqtvgq(LQ&ay*7ok`EugeY(3xlGH*1p^hjSHHRThk$#Qv%O z4)I!K!WQV|L88O}Pwln|4RtnGMg_#Z=1cXk9yhp2Mrb};cZ^nMjh;uU!P&{=@XdFJ zR!i+bNs#|CCjcg1oQ5fgtgIKhl6S^PNS|G^j`hyg{+|0neG9YKP@OHfxe;7$!_(z) zv{7Mm-`E`$ko6Z|*}m)WDTMYe^sCdGJG`zgC@{EI0XwUtPe~%_5en#@wETQWBJ2 zyE45LU}{l@Fv$EA@B%E7;^Ja##yb886hAS1UeE;lbwqsVd_2E#<6a<>!eTK?S8O}G zGdMOTCo3Dcc}YUYAhmJ2g5K8mweRk5hL$}u-gM})y+z)#w?hFH0Mz zq7BkbvyUKfh?eVCuMRBomkG;R894HA8=`=w@^qmlc&5^{USLb5H84xKU{?j984MojOp6PzF zQvdcogLBf<+uZz+rou(=%$&h|jJ~i)V~|p`>}J%vLo8O5czpnFsGk}sc*7p+f>ZAE z=c6v=`|`0d@4V_uVh{G-jo++kYb9k~=~WF)nZdDo6WQhVypVN*At(>d94H?Ig;XMIbrABVW=6 z9n!b$y7>?MV;8LSE02;ChtE#c*+=Fgb$e58lZ%(v;T<+7{G#Tm+-oIjjADwySqk7J z{P!^_U5W;OZCz^f+?M=(&+B}ueRjpKrt9tD-R=s+=hZAf&+XUd$9LQ}Z~1<2eASM5 zs}*o4Hp-zg*QaiAdVeBtqc9ddHV-7;e;F7hD%Ud(4`bv^$7dIlLUH-LZJ3Y<-0#NBXJ?eC3W7!xX6iG>VX;6=?8LV!Ixz z#Qet2>}ZKCn%r{TNeXZ+~j8Nl4Aiw>0(g@e_~WZSh2`w}@H#e6QAO8-AB>)XN9BImG>}W^ejP~bQ( zWrispmuh{B+3{%{0zK|U`Rhc>Ho+6MDGz04FyeQ#Ua5Ego`M=ijMTbsQ{a9^y;{3} z`RMf$pWE!hsG=%tE(|rk$2hvpbJf4R%*dY^93Gx!auQa(dgN7*Z?X`A27@`w{p}mk z%*;x&;lK;Odwf8T?eqodU)!_Q8detXHlM#dKhJJ6c(Z=|WT55UZr9l468gVhfPO`K zb?eZPF<)K#LJ9o9(=Gw8`=aGIp<^J^2%7u7gWW|E64FZPES|l+rjF%lBE4x|e*5pK z*KzJI-cMp08XXHAKA(xteV*=q#-uj$qu!UczlI$jb4yV5SuNk&(+;%?`J2siZ<3iV zH`=}CGSKu^kpjHSq1R-#*tch0tWZ(aGR;6H1WPy98|#L&c)pkjvSDfW`m6YZYTA{C zYn^e*3iDN-r{7Z_T;7I0#6jyQi?ndK3VKW_adoo0MQuuE<-Xe_3kFG`pPfC16+_vjKS~%(Hk(m9mkR>`?o9>~#EbH~KFhBB~ z(=a-FX{chhUfV2Ayt%``SZ;Qp^z?Wpc{f=cdp1aL53)_1GwbvHtV@p?nS2FetQFuQtny6!lD16*uzVa!ZS zNYHVd6pJ8E{U|ir^5VYuCURO*$b^DZCqaB}1R zy4~eWj4l#5rORIUx2mnC-2ru;Z#epoMvOU5x&%nbcjVhVh~NS%bNLSnaAQCC>J%?6LYK9>!5rfcCMQ=E6yehiu$YT{mRbGy>{=(jrrLp%}Nz-^#&2@ZGaO$ zr>@m&{qu8g<)P2PN{f&Rdf45npC5Nhit&bR>LA!qAXFpZPMp;|oy@*8svX z>Ca1J%8yT1<;OlJQv*50FLBLv{&}S0o|6-Ar1Y>kpY@YF#^d(-irdqYf|(=?e8hP& zK)Q}QQCs09aLn3`lzrC~n3BSESld$q>E&*In6c8lGcj=iIEoT1EG*@1x0>n~p}URc zM+WX-LU@~hC+>%e&3HymOnRmyUd0i&pYK3KkmnS|xKDVF%z(JJhnC!QI z+j5P-WwS@%x>AJac?dp~4jZ`y`J9-hHq7$h7+6$fi3@qWztTaY-v`rp-bO?Jr-*PX zsDVv?3Xx1=?0?fCxXpRcqtq*;4|2i=Fvg*nFGh`9QM?>BtIxm$(xTVlZAD+>`EY4; zG6$OD{&dTjVq#+dP-SDhXMC=G5nOLOeg6VY@LZ`zTt)`J)nYA>ik>Xi9Rd6mtiT!= zQtALK(LZHttrxf<4b)Nn%wT?V^%)Hvp0b!{a(mGV7V6z=4_(uic}YlO@_uV&2*QlK zpYsWlUl1^;zKX9o4+R8IAgBtBLX^4rk$=NwY14ES`;9|hPAco!Is1s&VOK`avoi!5 z$T|O!bmsMIoKF@LXw}@^P6q3fd0nhQO}2S}0(fG;&J|BUG7$$bgMim`gdyz>hJ--I z!MSV;b;S264+uN4(Bgn-fKpJ9sNfNp!s!L{_(n%Zy#TBy2$^6pM*=0Z2X6Bhh@L;y zVC1dDa@qQ`L-%f1P{(w{DMCQmx$)rffMq`wbNM!5FK&*m?QK&;7ot5Gh2k!Z5Zu4$ zNm}b;rElRwUpckmj>Q*plmT?bpItQIgMI-_rC=mHXYhTnS|`_#?%B#L0wuFnxW=oflB`CTu+2C-@+@<2gLy0)G>Rp|X#Tey z1i~*sg>R*SaRM4GQpo7b&P!H+iMRcaEeA{FiAtN!=XNRYeTn}2HzH#z>eJN_Z3UoG zeo#M_0CD)Qm*{|9(wF&Z+y_7iLj)oS`5$8>2p|48{Lc^sT5Et86O5-+t#jCut6AU! zWU%>HfN?bB<6!>oKS~mBJF8*35&2_5y&7~<=k@Uqu=G43BE!`Cfj&9(suE~-ERjq8 z>4mF;z_@fn+iInG#-QqJi#m{=d$m98rU99X;T?Fk>VPA#)O@y7W1gz_9JGmbd%L~? z3aWDZ<00)VPUoulM>NlBE?=#B%PxsGQa*#^Nf;Oy>nih?^iKw;yj8(DyyFN6rUGe#zIp?Lmu8t2@(Uf`!#{rjGcNb6+l-2u z6-a>({^YrqmX`-bBax$MFvLHDVQ199QF)8Chv%1JXduY{KE9X6<3t0!2O7bZnj-;W z$iY3p1vv}Ao8T5B6)$@Np#q4Y0rL>Ew*VVx$O%$ux2o8G4P(?3&K1WgfNr~@f?evi z25vG+F6RI;Ca*~`ETNww^Enw|Ke~V#0%eDB^);#E*%-__lKnpzr~s2iGKZC>0FgFO zDra&ff@`R14C*5>ml#(wP_Y9aIJO<8=MdK+s4t@hU$Ke!Nkd3`6! zd+qWrM7V7r41jdMKnZ@djP} z%-+_y^Wrcylj0Y@6-9*?6_yU5^oQd|*{AIAhax~EX#nHJ#?ya>J$(s76DuqFt&>aM z(?(MLb;MsiKIi^Ko%Mm;<7S3%ga6>C29VvnS=$@m{t*L_-})-l@wPJF>UJHfWbfH(m)8aL!-`;mdRQ!!Yor^Lwb}n0g zEmf?2<|mh2iU|?BigWG+BhNobm}ddRD~C3*eG~lVdSSW(mC*)Mwg}|t+n=5gg2wy>;gw!+8#YGGNw;~(sVVrN`*w|Qq??i4lI#BNoXkpRNeWK#!-Jm5YvTepUDcYB;2_tcOOg4;=r*b;*L=g*%g2T@G; z0vVtU40lx&$9G}H^r*d{BaYNMT^bavSLF7K8vjmc2EyyEGmWshmC z`rDL6*H;^7`(GBCW>4;Cu@AegnV^D{Dbf%(fDzk+&xXm}=7s1EIQy<~4Lup-yWWKb zYp^Qg59!Ef-FBlYxep%Q+drQfy}+r_PYZtlP+U4{YB%t@5V@{Hj5I8rz^A=Lu#N$` ztGwU~8@^3pyQ&(Ze2X!6n<^B~KlkME<6pyI2@^tMaO z3hWx{R-0h#&-&VFQSVofLp%fftsrv^0AYTVndpO5LjA(^jca?`4=XS*@P3_1h`=bs zCe%)BLHl+iE+M{jvEfzm>2a&L0CQ2do|{^+qz1KUe(ih`QRdHzskXu3(V$VF0I#3f zhhmJGETL%*?04NdWH|Du5)kb|_mB54-j8pc*ql$7LkIrdzmS`J%sw04fnXBW2=KT8 z^%W&0pIfij{ZZP_yAdmGfd=DIr$tjnQ?LlyUD@2tv?DV4{M9nUl zYaWO+Vx4Fr*v!Oyt+C1+_&ypK)M;Kwo;YnT8HTvk%>40CpLG&!K*HDQSQorG@OT55UNF@euxS$E><9x&|His4lx1evSfO} zA-3hs;0!-#8u<o*ef9iGvh~1}238FyOwM0sv z1>>ZQ!3WT^$W%8qXc^61we3Lyd7Q!Kx(97CcwWmIR-287F)ax;JF>GOyI^7PzsV244y4cL%@{x~{L&;&52114k|jKG%2uHekL1BvIKIqlNet z(vwZ1=KSRw_T6cGV|DWh=n7N~l#tKh2yL4xT@&740S3B3Q{d>JBJIu|-t$y^q90_dmH z;dZu}(S>5P3Zt;9zZ$mY0|J*Rg>Co#+j;pBZB4U8(Bw0rj3X zX+bV$>tD~CaFl$VYkrFglGswF>@EE-O-DxmJwG|H-6*nAV%-DZJ`I$5jNeba8u6V;F(0ffQ)YLBxW1^th$b()>%42!Fk>l(_cLW}8IBP&mz z-v_S1ci;N~we!T*#RwQk#3xI6C-6OhaYWfC;!j@g@SF3#71)}>U(~~ic?7bjL3HbZp>dQ2wt-ZhJ=M=b zJ_lwFb&fjWv+*8Dtp|S(SwRaKQW){Xy1U8|t=Ed@hB?@|fiO|=;jmve4&LV>n><6W zxb72YS{L3u-AT2NxQ2n`9wZXR5@B^`A;>X!?<4P38A^T5I?RoW=K1j}VqIbCC2s((n^<*g!K4% zBl4nFB1rY4_g+94Wd1qs;BPbzRh$KL)b#Z9tk)KfL^ z!4*^n@8!-`DTlu=^(wv(HIK<%4Nt{gZmhoMoco-ggMT#no3(--i$xc8`C7&J!3*^Y z)=iD6gDB0FEkkUWsBLLl!3o-CqSj0{Wp<*`P{urTa+li+I ztt@(r1;s?diJ3*|x^k8aKFwCj);&C}Gm@~hSZlb=i660NRG-uol=y}4wjveKPO|5CJ$`QVq z4yrGeQoW2FG&-GKT5hYztzCf9bHLA&sYAlILViN=aid?K?9j+#pSBmtAf?TJ&P+Ug ziOT-;z1+fF)-Bfv1;fQ4-^eNX35k^;;e58+cVf2A+>4z8eQAPJKVz{6+RhdHsi>kK zV;DFV@x7VNvnQKcTv)TiV{JJ8f)aIhPzah{Q7xS~Br0@rPEBQa_#Xhl2PDlvSVgYu z$L#}rkzntF6Bz!NsFoQ(+bN7_tkCm6!4watjMZhACVO1VbzI9im=N;POb4YtqUbRl z?mc+*J4pEj$*0)WS)JeeU$-S49?{+&8%xLyajOw1_VLp1SGc?mDC_n0@vXHj`%P=i zExe874}*LKCe2(UHP<}~3VX>>%%va9I7w?|_z8m*C6ht&x?+x>%8J%m$;e5U{gbfcEqESIV zEs$cEld(kPt$B>U{!hJw*wIalQT=k8j>4vVqh zaq&5pD74fmz~|Jhf^4mw6)c=z%6C^gT9deFBom6W*j`st)IAi1wG3! z3#m)aKkT&IH>)dRbfx%mc+ec1nBjbJceMH}QCq9dk^*Y}{E=oMyF5Z2UmpB$(80(~ z=<7dy;IlUmdWvYOhcJvPpW_!w2bL+pi_Q;5I*2hCffO@GUXM)Kw3k~@u+G84=1EjX zsG*`V6zERLlp)A)j0t5x*U|QL+H#+1Vr)zg5G#`n;7IBB1SziYZc#??eTXgy7i7nan6$`V^bz( z?e5B|oXT?1Idt0NN2*MHMnnSeNAEtIeMfG%#r~DMXblFl3YA^{zHL) z+zrTG!iQG#mTSO_muBgfCW%QNKfiNBO6?H%_r&C0HJ(XAxAbU*`WV% z>GmJO%%e51k^JYvBmxKMJ1K!n05K0FRO#&BnOOlfoeVy7 zme=l;mT~(gbv57i%>VtY=s>V|7B9q)FT_05N%?szdP=db?!@n#&N_YB#Bi(|YRVzq z{=bV3{Am0$JPmrA4J~QpmbpRlCiHyBKF=o zj;fQtnp@z_TFzsK^&b*oIG=Gie$tDRiaGxxef$aCs0yj*05|XcHjko(aEX%oV5PK< z-@LkeH+i<*T}Rm3SHz3wTlK(L5?pf7XE&pe&d7`4UXjPDE^h;$X+*>k}eSYN0KfTbC`}3?VcUHIEJcxX1Znx_jo6-Rj0VCj7H`^(MWn;f>UBQJ52)q3N``lHCTc=L% z`?YArL|G=RFZXL!Zh~YesyGvNX^Dl|`Qvn9@kJYxFftcMkC|G)*7%)lH|`f%l(%4s zPYgm3xox95aCFNikkiDA{5wGz*h-fJcr4(Qjh4n^1k*ijC0*p{jQudBd`g3=MeoZ9S)-%&1Wjf=LxC=75L+9RbJb&Hbq)9Ezk& zP^N^aaM(`_eC~RLKZB2KcJ9|Ql*n57)xD0>=_@`-p5ef zW|d{kZGDAN4e#5nUN~l2B3UKrinNAECFx`T?FQ!DfS$AAjLs_KWSPf~fZJ5+AG&g35#Utf!x*vd+jg`YA(Q){#C^^oX_g zi_Y*pGJgbzIb`e|^}`ktcwK5(`*wynQfP7}8B#QTVxb7AX<16Q)VW@6#C!0os`9@I$NrWt&8N1%#8mgZDkG^fp+%#eG3XYE5oRoCT&Bp(^-k7@r01p; z;7&wKW19Wgz~w0w8yk17B9NHH+lPc>QO zRskC-48=H}2r`$W|JGLtIcokFxkkS|xtiVB*_D^AXFqVK^jKk*AZ@ZzNC!?4URk3j z%o|dlL>66+@{Dt)p2HVesV`>7df78S?e5_$D#vZ^>}-0iEIm>+KHxXZk@GhtdwH&C z%BUR;ia(yfbu1_yjf0Pp01s?<%)QSDU?+B@iC@wZEp>%4g#g8 zkdRBsC>VF0IyU(!j_%ms9jp}O<{ANtsya_8uEfznf#|;H95&rQI&X065({?{F zq|%{uoxcxgGJUq^Ug>uxjVT^NXzi+eiClJ1Fr_sEp?efM{wb#tkad7r)I@U7#W)-H zDnNgjX=a~$uy$((+!IkAEX^7?yzBY{Nb|~JBNMIc!z0GujN?tS37WX*kyt+Ii>l>( zi*cvccr(yzC(OY~phr(K%ucWIg>u^4V#%CCEt+>pDULj~|MdbWCL*J@ z;KTnGJ_a_>{KbowMK9??hJ_N6_s8Nrv*oE~VO5&?!^DaGZYZ|&q75Dz>c;5?pbxWb z=S`}R33%`io5A$j#HBHvK}zXZE*O*v$~vPKr$;n`?@9#>A}}k4stp=X5tK3F3|Inl zXat!I_fXlt@2eT$z$y{%UlE?K^M_?!laKD(eJxcAQ0r~7dY+g34Q$Y;qNckc37&;x zct`;esDdchL=E-dp9$hTeX}veuXP5BN^66f^OhT z#jB{j{kwN7bkVo?je}QIeYlCvn5CIp>A{ou!`>8 zaO=pm^rR%F`bHZ1Dp0*Yhw|7a2Z@#L)k@Aqf|A5UX;ik6wo6a!g@&jd>+H$fUs-^JukvrcVeKK}3(Obg9h zO0Fr1bXmnmze>G!N52{{wU(oA8paShJOH8U&6kG2p&I5DEL|JE|1ic;=ONb4d>wB@N}J))ER z;(Z@t>>5VfMm}>}`bEMS_t<^53r_U9_!kC`oq#7S8MbkrF6kPfyFlMiGat0hP*@RY^+JJ}00ME4pIhTrIfKSrC|L={ZLJGZEW|-h?i^*1haP)~=!Do1fP*EY{hFA#GFh zWdv(4riNUe^TAKg{nrKFg`^W{iH%c+{-r&A9Q73kqkMn+b)**E+Qb+joOz1P!Hq?p zXN+`%l%>$SA2{Zsrq6TTFtE4M;Un*+0W!-oU@+G-Pc@3zXW*F%7l2c^s-k(kAK0*E z16$bK44UTb#|3XM|~X@q=| z50j|eg?|>G@zjMUc7wgn|8`S31l9Fp{OszX)%WWUqT-PRKEyy_u|6@6yOTdNlH%@~ z*49y@CbBeK#PBDB=&Q!miEB2NJqM2Smd-jA%1zFDntU15IAA^ekqcQ^tk*=NhNwAp5j}jqA#4le(Rkd8RZfNTw9q259 zn*P5f7$NoXp7UE3Yg*zvw#agYt6DAm>9Y;%y(Wuu(31T`3|wlMx(n^fIs1fov~lxN zD+3=`di#e+-I;prc_XO~_}H#;(u~tMwQ9>;*u~xxwp&WNNyY0KN(^kYF*0-Ehm&t` zYF@;Wu`gH|+OV}5Lkoom;))&$py-%IeRuf!@Ppq{KA~+$l5rxk7}U312i7jdE9Uh} zbXf}6!&+9D0@mpZrRqi+F@^^>d|!XTdlg>_!11l{x6^NF&bo3!^t4B7-FvPbBL~kN z8CO$WRPE>P7Qwh@hl`YoXT2p_`b`!hu0lxs!|*H&31#A&eWPvuuMGfr)zs1P0#5Az z5wN(*sNC2wC~$m|Mg2D(`SZTLAk4#e-h~o?Fc$=su*Ii-CPUWbo+QkmvLz}2p zut>zmNVt?vG{!L0O}6nVGRq1^2+W0Q+lDAdN8?2d9~%QM@EG6M4O8zMosBhuw3T@>m}m&v)cDb01Z!s##W6cD^g^~_Y)zyeS*~e$+><5Eh6-9{yLEt_R*r5!Z{%c1_S4cXIz8HsC9^T zl{%IhQ<}LyG70VdxtkYqFsW|B57;lRsZfj%zsLn(#W*ey?rG!~qFrd#?GP8>l-Y1v zD|$W-A*@FLGALkIf|Tg}Xo9DRVjw0-hOH5_1umU+3;Rr86ypsELK8lc;wbhnhB9<% z!MJV3>o=sa-`T3F!`{#ui9SshUoDV1rB&tBJKp46s?^QjTUGJvTR9cXZHe98qguD_ zrVrI7cV+Ict~Fu`i0nMiL+^U8 z8%f6FnxW5WZo&qQCN+q$D;G{;_uqew!2i|L*q}MWrE9rlS)Yu-jURP+7aHNsz8a&8 zL9yNR&^*K=n4JR|BA(;=ACS!M&xGip1XPx7&!E8K^5h0>8TXj9KsL_JVQ5Yc$8V*w zj53e9at(EIQq8aL6b3wL99XiwerRHEGk=&@hdTXT=h`him+Gv9RZ;ht=x>?3^SLVb zUcI;}t0&TXBb6k~sm*SgS4TeTZKY_cn=n*=_ZxT1sKU584=q6ri#)=iBI5$*;gJjI z)*n-Z6%EDtxM#Lp1hIXkMX}gtI>&SY%?p;&pFjI%qCkrfM#Bo!a7~$%h<(VrdiPU1 z$%(+6Z*uf!G&<2)GBK&yS5btB>g%o_gGPSNVk5sQD<%HEdacM6Wc_*Y4({&Ce(9^L zyE(u)U@#?O6&28nHYyci5k?BLtZ@pI!2}xzfd;0|VovqTm%`#jP^J7AD3q|W@vRNH zVQ3P8xKYp+{PovcNv~=mv&RjeW+Eek#*By4^4v8FJX2 z$vtT*P`}w|8;yikFyJvvIkP7(GoWXgaGIhqqYG+yw8%1lHbM%>8LpRM%sYd1x@iG7(0 zyj4~|XoOn#FUqoE)O|b0i9b!5(=OhJy95plRV}nWAA|jN;e9l3Gr*tu=7*@>n*}3| znz85^^OLy>J>Wb5AYbRR)lqQAz-{JcDGo|_3OzG#nq4H!;B%5k*AoEVY@#b^hU_3K z3hCk}6QPtq_SwN;@_p=2ckW*8U`6L;{iun9xp`Pje)+f1L)!>)n*0XcQwBE^t&d!2 zFd>oRKhO8l#2_36;M{8x@VpzAM@Bdgd*CC>uZk~awrHoE_?t{UwZ|+P-z^7jcPb~`$}1ZM-$8)c*#Y4KZ7@?db!ZXH2Ly;{zJ>khJ8yV zP54ZDOzPV#Jx$Hi%7qMMwF}?N+6YURu$Drz4(8hyGKA-=I1*tb?QuMd*&Ru)?%{2r z!ZhKH9|mzX4%Gz6uyZe(mgnx7i0hRaWgN5y(8=R7ExqsA&oHufTZ9>!2aSe+G;(mz zu4M&~l>U2><#2I9DYiNsV&jV$Dh@>ww=xvP?<-l8NN?8*og*IXHWiBh=^XCIbzv_R z($?4Hh!}hp?2D5LwzleO1mTGTM@>4+LQToXupye3l|y?TLy=_mo%NMflp}F+8As~b zVBSIBIV7o7NBjqh@oV)#XMX0vpXL_|P!tii&}1bHRTN&&X&(j*BZo38{Gtyt3l9fq zSZNxNSJ}*lCro(T4TdB*#NuRGYO4p0;*$^^^mL+=s<(Jc2V)^GtXQa3(~t(t>NM$u z9GI{>Aqw(xZ%_9AI2N^L{|U(qA-uR?gXZU^^(_#_j%uy)7l(D{4QQ4UO7D}b*{g#~ za4izFB;lo03&lC_r$)6y35AvI{dJpB=z=x|B^Om(|EEeXzIRGY0~+^7EU3P?QY4iw zopQH3=(F6{E)*|cqs)Kj&>u&dd#i+Bs#d|ccarhS*bi9hZm{L!M@N?sC?x+(ErgYr z^pg2VzJ?4$z-c2@Ki?WcJH>&fwJSd%c4j4i-`8)gzqDl-9441!tZPJ~?J)7C`J2W) z4e5Ey3sDZSIq_upZw0b`v1c8VR7Cy`P@L8=QK~t;kUEnSeRC}e^M)D?H$-b|1eeVk zGqrRml{v(C8ehYEtia>DNKpR&^#UX;*~B6=U8+k(ZzS2i&Tn3%zUlv49e{4~e&!gm zi)p-3jZ9->WyVqjw3YF8yH_zae!IpnC4iFE8_%~DG zItXQ-%kHYgJh?Wu-1%WZ?NVtrRga7NiGn`%!}Re$YqVYA>d^=O{ro_Lqt>^~c0n)C|A;5c!8Lm@L^p$(mOV_1mH z8dFx%zPUlYLOMA3)=JC=2p^YKtyV<`=43IUj8_n=_oerc7j*715{%;R(UC9Z6z*FV znx(y&7~u$#2Bn-i$Ze8jN#ykT%QwkM$m1O5@5ZgCBe#6tz#K8}N*3cU`ML^ptj;g# z;RhE+R8U^iR}haQuH!-8$FmpQtWGhShw(kN`S4^Tf1Xy=Rqw{=z=&iKV`Xcy6YNSf z%3NT;;~jR5gm@j<&t@35o$}WYal<~SUN8dgIIzkP4&sZ-m%Q9O6B85bh5E>+2bpm3 z3ti?@K1Uz2VjSulTx12-U8!nC9^cYmB15}C+kREPjcWP8?@=84?{A(jbG24-Y{Vc{4?7R0AQ`KuLBM6&i*aXt6 zoW;Tp1X|1$K~ZsuA&z|Thtb7)GccUfFkUgPrkXkxDmgbBW+{U2e@_SJYg!S=j0E$_ zpG#*mZ==9uWZz~_zLR$}*lS!VFFwSr7~gZ`>YdP|8&pZsbdHcOCm2w_g4h##b^B9j zcX1as;%xY$#FwB;XG~?Xe|V1^nzhx-bKf9RvaUNJ7SrBe#d&W2kIfBU$$ zJ)XOE1R*SUG=E?lo%@&}1++OaDxboaW5l;AIzajy7SI!$J#SfG8u9Gs2TAwqKvULf z^pxKtM@Tjv;>Sa?D?&gNO1DYfP&Hv>=OT(0y@_I;o}^Ps-ybN^rWVoNrsX1~iM~u; z?*A1xWCqfN$Zw9elMhSn^V*CB@~I*%i)(q?$8Mt-jS+bBJKx004!Gi(bvyHscl2N_ zs1se*g)sk0(7{vUoPL`@VXR<2KqEODYK|mXN*nR)88I1IZG4>U^VH1I+N%9$N|b<0 zS9A5m(XCatWC1c|C>1l`LNzz4N*el?B^?pr1wliFZ(8~xU*Z~!)O}TmA?XQXdD_U&wiXV zEZd%mntL@5Db~UjZs#cfcxlNw06MiuR4c!4N-Bv-b6pHeJn=Yh3C#h zgZURK4=D?LQ-;;ij6IZI-f~XNSoD_(JWeA?M=9w=V$SIV=A(g|C4tVPTe@af-^o24 zj<>Gi;_E#U@BZqsELk0>mgp!(=vRNJM^+~BX@7__NACFM#}Gj}WaP`0eb0*D=i49+Aj%h5nVOhb zzsSpL#32gTjS>YOIHXftbWnqp?PqR&;peN#8~FsQJ)U(nqJru0Zef*permtE?aYE zbmqK)Fn;!%x8(2))bRM;(gk+x%pIDdFuTv)+Cr`o*A>qS(=rYq0 zijgLJO3p)$fb?D+Xoz zX6EM5pE3bGF<+@HIa0KmPg@VUMQW<+>oEzdSM)6odMNp)47a-aR#Qt?w+JTVbfp<6 z7^Ox@)nxgf)aTskb?bG*k?blCXiyL&?JYG#N-bK~+^&eYbl)-_G+{Wb_l1jhIIl|a z&!h>wyrd-8oew?edjzB%YO)mv^(cl|(b?1qx#AHl8Vh`Foh;%{9Lr?t4Qyhp5;Yeo z>G1L>8HTi~2W3mZI_W+c)a2PsGKWrth98@I;`RR~8mDI7$-m zPFWV81S(MMFk42$2sV4>J{vR`pdl!Rb{3{#2_~5*J(}U?txX~9g%=15SK@A3IEDDf1#(PZ2_yX zsouL_5VJf3(eQe~-u0Ax!P%Lj!j~_#VDU3p<`ap{>{kaHQkI*WTdR4(UcSw%iL?}A zvxz);ilxAN*RZM=)DZ+qbTc>WF&*&4YwrNqFSRkZ& z?D-15eivE4+sWxzQu}!nmvu>1>2jlQwY2ip_4OK!!=aIOvPl(p${;+-%&w&Y#|XCU z$*XyDL@d&AG8^k1qwUvIZMqD>^R6a$a_iFuk{lWQLV1ka8ELnJ+Lz8<`7#!Z%Ruh&M{mI_*br#l{ONc_WJ8YHpBbOC= z3v!oka(wK1?WWc3anm4=@(B}`>*I%Lb3~I4A}>aWaQDU!S!PiXRzLm$=(Y+Zq~-Q@ zzOTQ&VQ!Vl$;%IfCgkKO%4|`?eu8LzaYEbq#Igef`@aBn&EM3M#59iuA2|8_zL63g zJ^NyAorlt*S~9Y-)~|PU(F-DDoO};9yUxZOOLpTQ9{VTap1~Hchf*$%a+T+VgD!5eHVJ?)SLwlsO-YEAi3Wt*MSp=5a}XZlWbgZmEi zf6o@4DCd0$nw`!>wfd+gOQ@p~=3J)p355e>XyNL|blKJn;n`>TzHLgETo9(w#q=37 zl_kFV5)(Ukk*LU=&=Dw-h<$poNJCY)>FFq}L;U{S9J)KCAJa6?9NX%JuDE5ll!!(GR#DmMal1{<@`Ad18BlMSgf8+> zqz8^o*>UVj_HR2)!}0Mr9mB)J1J#$9zU31q8H1~Ixi*#Y)fqPC)J)bg?1zS^xVTLh zEsn}bj=wONbOl<`7WtUT+C@b2lp|$7Ll+uab=VnEYt)Ag>XT0dTU5(p;b<(D{YoO| zp)sWMR5#<}yu44oQ#Ef{V@F@E7)fBkj~%&w(blYUr6^~uGtat9m~tNQ+}EpvQh>kY z=a7zAJvv=1zUX{?28w&@^_qERQ6bnD0h3gA9t3Mgt*tAVO}ZS%6+I~$m#dDoI*7BW z_t2UUfs`@^k-itb;tq4y>BOFM1eP2;E7I8>yd;7+;eB!}qr0vqu|B7}R(zQJ7L^G5Ro3l(A%`d=)s~^LpION< z+I~yqW7n(CV(da&NppOoqxuZ8&$jyY5fb_a$d6a{W9-C5kqBm^Ng^<`1N2c)YNRC0 zd9Y|GviPTDwL{QHQXT-yz~d{41R-6V<$+%%>T!A`B}0r9=@V(KTW0MkQ!!$>Pyl(7 z4|#&IqI*jdG5L!R@lmC1?Lp(s#z$(*%5}+}pT6QZD0girm@k87o^Db6OC?ewjL7HN zGP6}4Gvs0E$hkT^VnuzMvlJkdmju6#?CodaQc+M=S zisyf{Cpvs@S6XZ}M*{+gN|+Z38(NU>C2T@n?2F3aM$(1fS>%uPV%G zyeQSpu?{Jon8fu-S89EbNIIQJHe!*W(XSwCvEReH5(b+D03E|jtMOYj4z)$f`bl{( z8?^NXq4K?|{FUf5zLzcIJD8WnQhz*N!(!*BofpCkHC2&&=t(jq{UEOOK$o4zDCb{` z)js286~&%qg`QvqT#}FEC!;rR^eBGjv_z!f8^&qTk#{T-N!T5Lq1sLTjx03^?R5aboG%o$YRCL_|C7;ZL94 zkYgc~ZHhZ=)`=333o5qO=CtH>XOm2du|1t{Zj>5Qiqn1u#Ql-9`%GGg7sKlzPMly; zi73%wk7$=TWB#t3M~?a96mUre}dJ5--c9E`5Z-~-Mf zE5ssjdY-1}twj0jW-KEiKQyD@L?MPMe9#D#+#egJD9uy$HTE_A{ElJr(!bY2`r+Pt z+56NsVA2}k`0_}w`~Pnipe|EpheLqLD4^p%10K9u+s$srRxEJb|13CR1wDOZU7bt{3lVZg31+S{1tYt(W*pBfSLRR_AX3}e*%A62 zmyw~Xq$H$oj}jUY5dqLXcT@=2tduM)en0%)A~dmJdk?vt%$MW91&Pi~PuBp=&7L5b zUE-hB4Cl2#0E4T1d3hOlE1HTCY+?Qs$pgS~J8s-r3S9Zq`3BWEiq4M!GnniPJcF=FVrXoQJFAq@*nh=0p~;1T^wKVD*$w8lRX*ZV}SA4bl>H)qN1-K{h03{^}OI}Oe8iUDkg>HF`LX*x>hBT=)>CDS0SErr?uLbf5a_3 zNV_3Tisv}j$D%=|u6ui`WV>oqF+=$*r=#$l+uG{f13G8f6uOxh;iCat^_P|)sb>?;xx6`z8H zQyt~c=k$1YR+us-;+^)U3HC&%8{c%=d9q5_Nv4n#M+Y1mo^P>-NR991mK?nfQJYz+ z4;_{+EnXO%wI}yENJ{k8A1QB6XV#n}DN7@GE`H#M>L|qwkUZ|RU+|k&fc8?ve0*Ov z21W70BYd3mHcr>RdXFVN1wj}g3xta)DWt8v45+RSfZ(%mU)R+rEl?1}FvF6b4*E{(1=PCVfsa4|7jm1; z|H&;==#%hEz`yryD?s?ZKbk!Nezyr6I{6&dxOfs_K6*|{5__8gO({kGTTF#Hfc5qU zbS-0WnS0MXrg8-T0R^!4!gW@6@)mrspU+M>)upc+(Cynoh%_V#PB!oZiSgbN{YnuK5P({$JsD1D zP$IPR+lp=Vd$fB|-;;=ed%Wk&0nmiK=cW6@F#uB@nr7?MaXFfrPN&~v0)=b{BHoYd zD6NslgPhGy_fNcHsoD%K=?msE6cY111-}yU7k+kOsH86JDcx$Zh8=0BpBa)6sYeUC zi$$knv5k`aqaJ~-2Ce%0X2v6({Nr!BtGA%;k*WBzJAyxaMmOt zO5hqisw$C387f^zs}eJB#@${US&(i(6o$73Kl3c4WEXftT!Kb8!Kg{-?h|H z$S{79PqluL&$Q0+s>)2aHiP#)`GIf%g)^}jB(Sb~@$IbZ&3g)F!-xIyZ+YNj^+`6g zgd3h4zk!?qtO7kFBg*3NhX1n{a0OeF?2$ z2YLKXS(}DzitHfd^0fyz^tTpFg0QTVcH0E`$pL1@}S|PDkIM0#z9XM

K_&zoKU6m*yZ$}3Y8Lh&v8lCW~wR$z`oDz7(F-zlrMa#e30Xn=3zLB@q zRN$5Szd-OF;CG^o^@d-47Kj>cs1~my{D!kYn3Z6|zQ!D_E1|6oZ6d)~D1Pb7(H?%c z+f`Gz2okErh;aB7Zh`2wRZ3`&q^;tthTm#4${BunU9eGOt5l0~N%$Rgf#|kXN@$Oy zt>Q|CU)wXD7=Alnun}9OT3kQEFX0PBx2;k_dn9cYeGz^y0V6Sd%b;K*wu&AAwCDkZ z?>-cWZd;{<_DI?)`iAHqdS~HV22E_#REr+jcW;#v+9PSJ=(l4m(Z3E~4QSRX)uOlj z-S40h+9PSJxbwnu#~o7meSWi6sTTJ;-+iSgdelu7gx^0yb+9PSJIDg=GqMV7s??ekWVyje(&vy9LXMyOpRZ3`& zc&lh5<6MhYan=sMsV&$bQBy6>gWVF{wn_=@k+fA@mv9HU!gYJ)u~n+YHKW_!?Y31) zXpf|=;u?<8PH&*wQ4(9FT3lbd9f{qxN(t?ev{m$XFf-6|>h_6>tx_%eBHcc<-L^^z z?UA%q^bIj*(97(0_KB@hE&6TU&T!qfN(t=|%W7qLu!bKrq5AMN&l+m;_>Vh3{OI!z z%W2}}Q`i2y19SWJlZSU&)%Lf_8r8}?Bi4Apvxd6X1yf$_uJ#qER9hURQ%Lg2SZ)B*A{a(AUUOjk1^|I-nHPp5Gz3_U6<$3b*1&h5= zAli@g+?mxmLp*D!Yn^uJTOF2t%FC};-!2e&c9rVs*Lv1a*BWxfSN3~O{5tQ)`PFKx ztgjjy+m$~u&9jEO*6FA9oNXDvyj*{`r~OxnE!L>kUoc{=2Rv)2YmMBj-)zeU<>je6 z^(zo>TTZ=JyYgR$tf8*;`31|)wp>D9ZaHz;0&&lgot145oKSsqh-VFTt=4f%&$g^R zUhezKQU&5k%Vc)IUK6TYP4TRuuJxzQde7!PFJA{TvRT%*>dMb}*3dW_EO(95=mpD4 zXMU=SaP-!sg2Jp-<@Ucsdi5Ctf8?k%k$%9 z^jk_?e8LM(96ZFchPu|h@AjE(nTWg$dnxg6%a-=)L>na`Yp84Cu35gKNT)=eEv;&K zmyk8owdS3;%xufSiU zpYk$BWlGp+uW+=hgfjz1yJfg?8c#u%t#8@V?$~`oHG9CbhPq_;NBYfHLTj?GcvwD2 zjKph0*3ej&wlF1DvuvA#Z1%Y+WDSj@gtN~>(z@cl6RLee z)=-yJ_UJ!biPT2tSMysjO5R!ESwmx8mSxP#xTci2>yVaNu(4Fg8X8+=8QGjbt1NSx zmti~0>^f%gIxHibOVC~=QXBTXWoXrlA!}%?%krzma!S~B%;I%erZ?B}`yuvH!tP+5 zcTi_FrBlLYxH@Mzm2hsysI-iHZaa*zJinTcUCZw05{z~ww5BXO*K*6^I?fJRL!H3b zwfuTs4x_JYCbIkk15QTh9=e(;Dt~hvtEqkHU;d!*@yw2y` zG9kJIGlLRZQ_QdC&$-s6y^s=nTYj}A_McFl5VD5Gab@`+-5%yd%iHMXFcaA28dc{SrR%HGDS^z^ zT%#<*rrW?;WSKX;j5R7H=mB7j(p6vSlz<07Z%HL=A-pBpgBO)$&*j&#+!W6m>MeQw zv`;&f(3-OB*8DoQe8#heI)S>_D)=ZVk!R1YTJ~%^Yv~%*yn~O={;-2RJ#O?zMptc= zSZ>+s)Q~mQZG5}Z2OUaiO_m=nWY4ZPCVAFSCr}sf2d*h47C-R?Hj&&TVw4xSdWhB^VijpGV*N}Ol;2Q8~^^|+8VG_)#P(7|T~9$-qeTdu~t zcb!oEdB_^-1iVQ;QR9qGi3K(@ST@?~kACb~L!H>M_iG)Tqu`gOgn7tyddMo_{0I-3 zGZ8%JEc>C&qIcOkxai-WHPmg4-RG4KCA22{N}A1ZXw}shdDhTy9ab0TE3_~r%nP4I zFI**DKj4LPU4eI=WxHGU>;bk$^$S@;-Nvcamphcun(TLXU(cU~R=vEyvxYi>y0{wP zno=UOe;}R2lR3Qw)prM-|6H=Ezy$L6d1Le|i(RW0}QF~iZn4)co5iO7ZRb0YTun6K#RgGg;O z%x}jiS!al64fSz_y7Zb-!sbNxMKLFGKY)2q?WKgR2EOycYQQ}X)(oXn!d3&{d0{o+ zehDi8cST{9(RiCfTS{9=O5{x*E5^teBE9r<)LM1xJw5BZE z@7~R-);G0B-`l`#;5uMK$8Jjez`pVO!HK_V?`gmDQi&26F=$~}uYU6UR&L{#BYw~* zYQY|~QlcgQz4O=``ZZLdBN3w=Ho|Dni5dyktItGAEIZV{osbP z%y2qiVIITZ!z`K;H4>-`gwA#;@#p+Yp3m4Xq*bDXjxk#Y&+K2_cj}~>=l*<0Ctw5C zb*4^+Q8^K4}>yz8@ zUC!G0-X}JST4+18QUcoH|7ytN9_vzX34TzQjUvH%)muu5uk){-&b8}Mi4rC=jh)y_lFb|-y_R?3h-)tU$N|Z?VxaMW} zmBY&@YQYA4hLkuaf9Gz#{We@BD3eHc-Z@btp;{6f zXy$ISRH6iJ2Opj`NWccHvsKVaiAzIY)o#0SNL?jLun&V5UL;@x^|E)Nl@j{BSCuG% zs1f=q>?W@N#W9T)TeqCK&lUUCRZC-JDe)V7GjsieZyx=y?O0TzgpQaj``(-*8|zGZ zb!Lyj=hjtA<5wwRdmMiTvByzKkwA|G?=>efBPt{iNkti2D6_TU+(>LVp;{jxn8OYuS}A_NPhhV+Nm_#9rA8IPFV`o9%wsILh|FV!z~xDiUa6 zu(4>FFz>!+zXs%dg_t+zT}10SAERtvBo#s>piwVqt;zRlem`v9bsN;;jLLXB##M;7 z?`E^;H&cGoK5OQXq*Y3AencET%l>RLwOx4a=STdYTGWC)Xr;uq`MkT<4gIPrL74<+ zz7TKEi5dyjLK#{qF+YFTd1d=Gph{3Cq2n#fwy~M|<4fLYU%TI;Btp*_6{i3xA@goB zc8dh;g|pOg`4?#Jwy!$Ud%?L1y&9D1ap3GF%W|Sd0(DUfWoQ+ME>EVa5|l~MGYDrz z;>kFnS|~#+C2}t#GcTj65|l~kIL@*Ur}S@J_TZ$Mqqf=632M=+!3kDMylcJ>o~XCh z-ny!iB7vI1^Ksk3FU^{G&7tjc>{rD7i)%lD`Hj-^&R`1op33-v-P zC5~Jp?1~oH_g+Ti9Sd28 z7{LDXd$r?!aDR?I;m#Yq%h*7;=ZFEIRa3V*yjs-ay-5ihCBD1EC{YRH45(LoJ! z$5l}aHgIoJ!bZE>z-U(q$|UqY+1ze%p93~HzYWhhV={Qw7?Z(M%Xmzltlb z*mGXgf(>Y;gv76^Dq(C11S1w{fT4*7(Qo?)&+>Z=i zhDuN-p?B8348MaUR10O?|CF$q+HGK_Rtd@^bSz}qK#QbKpLKlurgJ~2F#hT1=kgX3 zBdoy#m}QYvjH^qRT~uK#6e}`guh2?~W%7vdspe&sgi)IGd;xwfqj67oHLlr%vu5v`FZEviFwkI<`A|QhPt!P0$ARGQ1|7 z>99w_KFWM*zjE`blan7k$4Lp>dHMaoUQH!R;6w=iZrBgzgzxT(TDT5qrG)Ju-3E4$ zD$$cBoFOIqTE7kwtXEH(x+OB~gjJ#hZHN7N-YVZa7qwsyS}9>WdcO|r=vBh&0Kq;C zJC>aA7(h`AHlURf`5p9KkxJOp#gU(7lb$@Zj`?cq&ZDh$TUsyv!S?6NZh`W)$G7I? ziT?Mk`YvsM&xsld)j~OFDS`TJDrw+<=B^uZ3{2W`h1rMvEaU>Po$u^JpZ%eYV|;V@ zd-mV(FZ`xK3Dvr6Fnr$uoxj*_`2wL@mED8Z8#}EqyF}F3D%HB_ZoIuUptILv-4NEW z&?>Dr4!LG>u)o4Stju{!WvPR$8B?6G! zP>B*}{uXaN4d`6v1njoMzd-EspYWx9+}qh#g);8o&}YI|{xNzIqNZBsuG8Z6Vk|W$ zRHDTBcZF;PaU|Aw9V;%6_h|=o_8tFP$AJq&`KUMMckD6+C)fizzpTI6;jJQ3Q>}&T zjB%}B-TOv!BGbB*_{p3=|KdozBX0j{ydSDH@tE+X?8~ostD`BAsYHq8UI_Fjliu%u zi7p$e_0J2&`gPnm^SzFyM5YoY&buwpD_?@MRJEa6R~#C?@?PotQAblEQ;8B=Z4>CR zZ!ZisV8%z{-Tw?(h9EiiU1Uce(0RaF3p)emhJ?&O z<=$1TZ4V4BLGPA`XhS7R%pCrGzozmiQLW2Q3oXGYDG||zN|cy>ba-mxXpe+G+sn6w zmK^x$GP6t1d5!l&wXVG;wCdB}E?p*~4XsOw)nQeOt8*>Cj+$z{KQ7RC&PznJp%NuJHw>$2*~?I^DGvlKco`)k z+E9rScbwO1Bd|MfNwxZ{ihWe@mP$mlp%NvAJh-XTWv@@QjvBL>Yr*R)5z&T9lu)0@ zlw~BU*7z+)yA61+B_i5Ti4y8Xxs6EZ`g+<5Te%IaoTat4#!;eLhi@7PjNKAJ8<|R! z*!{+^o|m6N)jDT#uz_c=DUqo}iOxLdOKC2tsn(f)2{tg7G$&M|M4#Kjb(H4Bnrf|h zT(E&Tu|%-1YAR9Utet|5(%fECtv`N0*udOgBBBkID6vyL_;BSlO0_;ZDYT?wYgCDd zHdLa-2JeQMsJzyy)`ou%Ex}q_BBBkID4{c-Da#Y3TK7*4ErHKaB4{I1i4ryKsZWRUyYrsvND1}AmU=e$JJ?N>JhB>}LDjmjPuQzr$5J9< zt5l-IJMRS=dmnFAw4quz?Gm(h89BeBL_`}ZQDUR>e&F*;qk=c^q0Z}2t*@2|TBCZs z+)*L``C6+IB`(@!Ew{1x=`VGdve;0qcmBJkYn`(3yp9q9$Ze=ZiH>n0=5TY%iybi0 zbsehp-hYRVls;kd!|f88(NnVeGd=x#s7V_!<6O9RqMmeg4S8PJ=0Ml0Qr@xM2U`TLw3i{ z|MyG>Omy|GYAtbU(7I-~r#ngnpwPQgmlFCsrZ!Y-&SK$7{c_P$$rJ2Ew4rq=QF_j6 zY}H3+hX@3Ear3uA8TX^VpSQ?8Cs9+ag`bBQ3GR7QB2$SHo418%OL^?7*7sHpUIxZ) zQzBD|5|gF}Z>jtYs@94t2X6__U{fMfi4u<=9K62rT%uaNJ`P%#OPUgyN|exekl*uo zKU8b{^x(Z>PAn0Ig^{QdB{YJR*vNGJ9JgLrOR#3>x{?qz)f(|lATV~D5}8Vr*nC3B z8d`n^RqKmC1T8#+O^Hk;O6XINUWaP+zc)M|m`h4T>|K>8q0f!IGtuKZKT+KE+e51w z9n^?mD6f>qsgV=ulLfc8Sr#SFc#E%?U$MgqvzZ_1uBE=0N4ZH{F?iSdb-#I}<$*kZ zEeL2ax6|KGD-xe?H>v*2V$<5!S^Jo3h?s}Elz3-d%yuhv9)2jI=l34)(yZ6dx?|MS z_U3?UG5gdv_kC}6N?e}xt&bYN^2`TMJHDzCC7xX#v)xLaZ`}zS`@GRQYp3^)8FhO5 ziB**-fnN!Mc;w+creE7-ms{Jv{q{u9c#A7XOPHMt<&-cRt+b&MCDwfpQTFLl_;^&GZ@G0-OC5>TDkm`-?!rqsur`Q;clkH z7u!v$4Bz9DmUZn8sziy>xT-Ad`A;8Ls>Q5t7-K1M@T-5TOdd6@WzF7)RaK&dj_E8L zZ)fyxv|ZWuah~y(W0%?MrtGnNA$q>;rY}_9d;ZTY?HBHwJReHv&eGm?vERx}y5-Mp zPwx^k-oggzWfs11BbO`eQtOBJuAX<}1ub(X?^4yel+Yb=mR)D>OpM!jYTHA3##`7x zz04-K>kIt~yX_A*9a!DyowHj;JpA*j)}@5*^zGi;@4OZtaZcM)dB$7VK)uY0_|mq0 zXQ#xP!-iFFe)+VPWA1CIszeEmSa|;P>VJ-#(#DLpuz`A+-SOaymnlR)-d%Ca>cF3! z)Uw-!YgM%_B{cGqWyoK<g z@RI-hzU>@4KUXbg4IO#y;)VU-$3H))`mgnW+cIL{-4(4%3Ehi^T&Dfoe%r>3x3~_} z%j~B&AKk04ububxSXpAG|$o*=c(QTGh*E8P2hAqCc*{Z3vMTL0DaF*7k zgvM$@UtRsPAEB>e{#w+_e!H&kXN9=Wb;lf6-F>COE!AJGTi3dj(3n%W=O-*V823Ep zuSLBaCFjrhs1U#U@L;>=zx`gz?N^^!*SeI@bE+&m(8lg>8{ccY!`|6eEso<|PJh2} z=5^X>2UedxYKfL!U)1YbmlAs37M{V|&R7!9pl7_r{Xo5ZYR^6A?ZVmJrO)nJUF)S! zM;^QK|LR(o5_)bJ=91I@^4ScVOFZK(Y@lAwK5IVtX5kES%4s`R-}%i;BmeT_{tc~5 z2|fP|bK<85y)?t-M9+8&8>pAF=(vfm70yy$pS4AGn-lIG`PzDGH?%G#)YlIAYY$xa zz8TDT3md4HtHHRfUn%(QkKMXqb@{Vz7};~<(G9Ij3EeYT&SG1mc6|K$8E@nnZ{3E~ z%T?{r^It0LKYCuYYIV(}&l|Z-zik>?mlC@7$+AOjt!=yYyczG??^0EZtMkW|7YqBS z({JioU4NN_M(%Xxgof6ogzn+8>^Acm2Hiht#((UWVX8$h zkKC`Jbt$2H(Jb5C-u}Gl#FiO{*zeU;i+<3BZx{EqLss}}<;y2}j{M|?!x~zb61oG( zGV{VK$6VBFhWT(Ye=X{zKlhK1io1y`&Yw^jIOVEMZeRM?hSsHo?qu8xZ=Lkb6?Y*o zfNIe%?LGOK!mj9|7w5HpcJk9B9zE%VhSsHo?#O&sluiA|lXqelsao{HVWT;r5+yWZ z5q1+hJowxQT!(6LXMw&-i4iZ(n|1ONSKjrwU584PNMkbC6^-8LnoV#&REzs4+?xV% z{)GD0pY@)B`=JsgG=k*gs=mRiy+>kPsTQ-*V(g}bjjQ^gy*8bJaitO^G!o{|M}2JP zW+U-@s1~!);u%Z{dp_#N%{XKRo)48Mp)o*z&Kv(5d&EdQ=c>hQw3tg$!k+U+^|%XX z;5k=`5*o|QvUdAb(_?$TqR2ATO{t6G#=QmUkm&a)nYbU_&zCNeo15T!&YyDU!oEv z^lcdTuNt*^tG8(WTGY#IwD7f3!u+eoKD(^n2LDPWO6Zxl`-zP;x7wfuexhnI8!dds zlrTTBF=Dq-ZSWISqJ*B^yT99b{_mq(;P0xI((?{ZUu8jkS1*N|exd zRkLiKtx>-_n!zPSZ)IMt&6fLLEjSRAgt;Fdeu5QkHV68hG3 zmaX^d-|8baoz}9UMF&+&_FcRaoB{YsTRK94FZ`Rni82xl%S6q;>p2^x2mRE_y#&`AiqUZB2$SH^tGdnT7KpJ zZFSa*FQv0wBCKJduT-K0_YASGq7Bu;7ueZXB_i5Ti4xo);XawNHHp`uTKI}RY~T)- z2ta<%RiXsq79WO!N?TW-PDF^A>RaSAa6>Eh&EKB1S4$l zA5t5tg*+CpfjlN9BHB=i5{v=D4@zyQ7IJ~W2C}P^h-gD4N-*LHe=fD5TF4jz8_4ET zBBBkID8a}r{L<8hY9SK|Y#_TziHJ5-qJ&1EQyZ!!xondtw-dBc)4G(PZR`_L8>&Tn z$c|7Vq79WO!9K)(C$*tk>^EdxC=tOL8nNLbYw4o9uxOO4Vl-f`&u2;yFQX--al_`i zcAFC_QG$EX(leN;7P1<_2A;v@gi4g)p1L%bWU7TMO0a>sq&cAyB^Vnh&54<6AY`_<7PN+l)jV&j0d!|~F<#u*+LM2Mjc6o20TC|6~ zL5bk{k*P!p_F;LCqgw1Y>~Ts&w4o9uI2PhwjYLhgc>l3iYf5A)QG#PS?m43k)#5nD zp0g>DsYD4rn{n?PZKxKXN9>)O5}8Vr;2aZU0MUkOab7_Tped25Lrz5n z8`?x0Hrl-fJH67l~yZ3r@sVsg~_OoH%FM_r7DRl+YeYTV=ac zuNVDeyGbvj-%71AEIc2oWqU&>zI&^b&>l%!WpM_t7h}od0ba%!Yu+l=vfaHC-~A3M zp*@ne$|6NxFP=M#=y(~=WAj$2mc?hBnERbayAs+XX{#*O=k;QavY4EgF?Tg@m1HT8pZB*);6yQiWO6{usuUYLWi#v#1iFXJUsxEV%`ruE8HIQMM6VrCJ=XEB~?^qT5y}p*@neiu1?l zWBP2tnW*>Xeg2PDsTQB@W#3t{Omy2SCA3GpRWVsHqm$jBb0k+g2%|J(9MHYdA(by@75=NoCA3GVbotp=(lw{ z!*$y#CA3GpRUrH~)pk}i=HZ7A>3sd>uYAQp87q#RQ~BSozZbqQ)Jb3#r55Hyl(Alw z2taN_B}&+No6|#H`KDk)wJ_Jh2G)-f5pAeM2|G7*+7xY;fI3^HT3D}O!{l3(2ta-v zDp7*A-#fQpqo!K4hx=b5q79WO!9HC7`-`R5QBy7U8^%?Mh&EKB1jj<(>x(v2i}xQR zu|z~0DpA7D4ZWv79g1}q>UrnTz#Lp6q79WO zVdsWUU$U@hL$$D;yAAUIN<_4w5+&^1(CN9`!mEKg`%1Ooali&vgAxJA`${EB*tub# z|6H`8T3GdA1FL9>h&EKBgq<5Yece+<8>$5_12(WamxyRXB}&-2q0_hYfX@hZ_LXYE z4}uM>=OqG=_mxVNuyaGFZx~#(p<3`oU;}r%qvjQ;n*rDssJ;J3jBp24OBVwSNk zB`jX*e=pA^ss%q0HZYeoB@la!btz$SU;le~PE;*;vakVvw<&=ba;!@Ui(mWS%X7PG z!JBj&Hn%q=5DSlWDPeJV|9g3jQZ0C|uz@wIDS?=NtV;B&*ILzre+?U0Ynu`{ zn}~HOVdo%PEl%Va>-k_#hw1>SxiQxKCQ;8Dn!_pq7rdsSb>~Ts&w4o9uI2N$KGG+hgt253Z zy?;}~4%?Xt#!7;t^H8|N&8>+=|jObuB+p^XD#Kw4qv@=MfigPN+l) zu3fuM#3_*Wm1=RlLcF~>p%Nvy2G4p7XH#lJwYcsgLf@QFi4ycB{;_k>hHBA&z{y5) zLM2MjCz}4{r-kcKE&4$?F=B-sQBS_2XhXH=m*Q-y zIiV6I=xawCHSRxDi~coiln5IrVgI2LCAepZeHCq}7WWD0s}d1ys6+|wed0Z*jZC$; z-@!dE5z&T9l;9pNj@@WOwYYD?*ewy!hDwy+UNk;~(S~Yq|A}X?L_`}ZQG$EwIG02l zs>OXY=8_T-ZKy;E#s=b?7;UH);{lixOGLDx5+xYph;w_ip<0Y+=P6V}=i5pAeM3C7N%&k${>7UN~`8A?R7p%Nt+ z1B|{;w4qvz`@#1q5wKCU|H&|yWZ52_h$mp~V)>eUrrP7xy?W$a7` zejg{}dvyNx{yd5k39KKGV2^BHK=ty~W)E{d{+{g5(W;ti-P{tidJgY~ppBZ=r3B`D z*hu0GZbP;9KPhMp8{d125)o~vL<#LTQ?~Z!y<1Z)`|7E;#ySNlrWa``cfMzQ9`dTAu`Mis24kT%tR<7QefW~_3|(O znn!C53-?1u^;&Ce=32N8eG1%0jf85A@73zWkGA{22(3#A%*SY95-;(wt6C2&3R+jJ z-pgai-4dDBrG)lEave3*I_j3tKR4f%_L~#-KcTO*E+tC68~X|#0NRTgz`jE2Wy}m% zwej~Ps^(X&S~I>0S{S=ciA*I*=-icFxoTN10B;GNs1m^|uc<@{9X*MSOrPi9t{>)L z%(Xfnr-W+R_hr3Rm`j=yDp3Ny9eTGsC#u#ZCj>3biA{-2B}(X>O|GM+T08zb+;hzB zC4#-1sYD4K3vMG4h#KGu5rM$&9%ZbSFHQ-6-}sz7YEa|Y<-803oc)F}dwtAE*&Fys z#AzSuMbruFE6Rv+t#x$x`@Ze@X|@`H_cCT2?050^BxdP0RO^gi1}!{; zC4x3;Dp3OaUDznkC91Vaub_pwq(np;Dp5k`d{efr&3m_|S~o2UHZUia2tc@Uk0GPI zSU;4|RRVhW7YOz)JV^EeJXZGMZ`&nm;5PK$@_EF4*0B%_@H$kBtMfONZiv__txE~| z63Jf8@40Hxf0*{GPkmpD9*IP>p>-)ipD6CtBEdNkJ1jm$^~*o?y&7zk2z*=J#}Bml z3@*Cl{~+R1i@KEHj8VFdnrd;Dz?C;8;_QREl+Y*G?;x){&OWG@vmNeWQzClEm<^QB z(UaK7xEf$@$RPuo(e6&{>(Clc=?apOI*~STF$kY z&p8KUp5I{r-htht^KUojZ`Q zO7NPJa~!v!THiZ4T;B8cQ1$M2wOO}R9zQAcdq!{7brmdLa& zCD`l9IgZ; z!8=$}i4t5t%6kKP7U&at9PkEiS+J_N@JH(wJpk5)wTL#JnEZvu+i`tK^uv2swRlZ< zCfM3Y@H+fNk##A-K1`w?ZbP-+JwEjApAY)dPa05DB%%$iO9`BEfJmYr;X0(=WA+Ii z*~&*P@)MJUh&Hq?CD`jp^uuka)}t>5Pp@^AuM!W?s`r1vXVAKoDEW!Tq<#rzQTip* z_x#LH8gLy+9L`&%TJ(edeP1_3v_bz0bt$1pR{5;{Ut zg1c?36WncMHJ}fdL^=J+Rf~QbR-6(MTcr{uv=7r(aTdih!C4zm6zAj8^HEbRt_*k{ zn-Vc(2q|PxtdNa(E3H5@Z1*Y@O8ALA-hEz5o9J>Bb@tV~23T9*=d zD-=&{a;on(RBOXyf{mjt%KQz}?g_0+3B273!Wz?cs_!;b>(ajj8_;S_s6+|cPEPgx z8B{IWTjA+%{Ec6npUl?v`7nTIbvsR%EoQM4(}QKUAUw-g8L$iq}z7ttUW{h);LO3i+d_~$R#4$P>B-iub8s`3$u@oYR-0uA<{=J z@4Qrt-Ya%qCBm$@jhaf7ps!utL8=!0YwRFPM6{t2CAeoO?Q3hQ#oYvU!X<(>{EbG; z45&*9?qskx%(9+CHg3G~@$kmU=RG;=p=~!Gv++NF+xdq>vn{w@VJ3R}`{D2Q6)z)t z81bwT`(5zlEY;!~h50HaezVW8#*>SUXsos2Q18m%E#7agSckJZ4YVmo*NKA=SZd|*u(ig)Uo1An`T_sBF zHoxN6(bfhVV~zOg^WlwmPClouT6`Wc5>w)pWd=3=X;*&ro!8e@qQpVV1{;G`$0%8D z*+Gq`jF@o8^>x+aQ;U(95=WlAYGdzSBN~fcb5C6*O8n`6t$rP6tpgi>HDVtlcE9?b zx@vJYz<5oGoyV@&*!%6_jq`>*Qdfx*zw8@q4EqCY{Md-`MhyM&BX!l{eh1Nyl=yte z(v7zFhBq#FenDL&N?iB-&HOqB-U}O-t-W;PT_g5;c0paWxZgpHBqc^p>(%(O=ZMCP zNek;LQKI*MH+372KLHz4F6-5Jz=%zcSXfsr?ssthkrFGc^F@8G-NCg^?b%R?5?^02 z+HHKc22OZi_~94z2aVXq2-V_#2j?FtapnH=>zgkc-Wa^?vJI6evFiL$ZsRXo!Nxz0 z7-PiBMyM8dML7RRi9`Q2x4zle!y9XkT%n;7B~}_9Y}6;hM(YD}>%TE#!X_&;RExVU zoK&Yok2y2zui2IF(6U-XB}$xs%SgYDou|RZn1^Q8A2Q+wBUFp=UA*s+5@%1IUSH5- zMB`_@1~*iq#NOKl8|U2!8?PQey}qj5^B?sX+)ypXjdA*#5@*eyS|9ko;f*b~AJR~X z5??R3iC;(G$6(_hFHfz%_~G!zhQA!rP%TE!af+N0-%Q!Re$ku58`m7YenTZne0QT@bz~zNbI%^$P>B-Tyta|s=r;g1-u!yUS$7$+zzEgi*$qzIQvxo=J9g!tu05im z5+&{!xS`lkLbZ5S2pcIeqxbk$wCW{ml}ePDcHB_ut9f7V*xE4SKSrn)&kE63De?C~ zZLPDdcYkQTs}d#t_3IzGjd0Ju`hHvM1395u+*9G6r^E)Gt5tfwHoP&%Mu|$4cQt;=ERh^?WpOMHEb5G_Z-|%i4uqW zGS~=ndyf;QR~Fh#y{*l=s>MAZ=Ju4RKQyxfU-URz4OF7U+jG|T>j-PqWFww4;tV5H zi}78oQ7Q4Of6cAzXsg!4~eZj7}yB`({4eq{?= zod?^ZGhb++B}-UlqKt3-+4yt<~_2tM4Fm-ni^WyILS7S>gZ zk$?DbDe?4>rK@k6*Y|7l6IG(bt^fOh+X%ks1#2%|on=J-=N8mei>F!eMN{I^u`5=$ zH}7>>^LJIE#NmB|jo?%N!U%ZC*BhZ)x(7^&!%kkc3NQQ{^TJi4#MF-l`*no9!SN@p zT0O*wMc3X_S1sLhro?H>4643ucd*Z0*Vk2|#9vnrHo_ify=4bgXBaWr_8+RHyW*6X zcH`RB&uv%q3)@GjM2UfS4)W^=d$s+I=xsZ%rEMRjTDrSWiT5{MuiD#ocgNd)P$f$2 zab&O&_MDT9Si^`#$4#!QmPRR3;)=6}R$sC!f7^DcDp8_y(HedoVei~-1fGw+MyQs? zPEumaeTG&4YrE~mZGWy3C02Sh*a$Izi;Q^2h|O((u38#_Oo?TNY+QZDq6X(!oIxc@ zY;t?Bf%t=EA6jeU>dQv#VQ~i4(nxAbtn%9MD&~^g77U!F5+yGEOR!-ciP>1rh)0aL z_^pAnR7+#MDY3i}j~cQ4n*&=_q6BUCS^Zm!SFdWseMVgQ*1%TPqCLdIQ^F!F)u-&r z2TpymRV7NW567K=@0VB2(5+~Xne9i9QTYL1cs6+{lg}XO{ z4U5TC^O#IUwRrz=(vT7sld0x0nTkr3;FxaT6K|wkZ^XmaSKGWerlMLL$B3k+#9Q`6 zEp1QKkw;Iis6+`qo453Vjc1Km+=xSunOspVK97jKro>R28G6{v@S{`Csi;H=&M_DK z32#mAV#JC@d~?z{71iRrg4kJuVJpr)w&HxU z(IXX=D8aSs%093$!H6A<->^O3$iFl%P+vd>fGZI-R7L<#zK zj~oFTD;QBR;!j4X7X3M#ZKs6AWGZ<~rm7Mp=%b#x32fYIzUcPmi~ePk6{@O5zZ7pk zq{KxJ&a5B;`9#ZVRh1|~Uwfz7c#HK?Bk)8$W`t_dzs7qRDKYNk>6I_d)8A;Z!Bv$g z!9Byve}|0$wl{dmh`oCZuBsOI2{>I!iGHt6tvqjgocY@isj5T??tNb06E=p~uIM8p zPBTKaxZlAkSxStzz1khN^E&V7^{XmTf_u0R2f{|n8T(frHDVhhREzsIoc5)}XP=L) z%(a=}w6R00Dp7)a(O<3t8$BK$Te;ncDL)xnRW0s6aR!+Zzq)@lAMG!`y-`&qN^nno z#DDQy2&+jrqwYZPQ8?7nPX)%E7Y)3!lvW=@MQG&67*-yj9T5GhmUS-5D zj8HAc1MsG7N<3+?j4LfN@#)#at13}~F^*RsgN-Qz#<%{{h=+_&EygwQ26jrAKa=G# znW{>ZV5}zCkeEzWwHTj)jg;uI#Q0fvhL}uMB}y>n6#D9l0pn*~ZNxmg4%K3u34N6k z4_S96p08msvcKhoYB64hd!7~zNd^)@5+G(xo)hs9iy5}&;?wZ711p9gIAQHc_aEr&UA ztVNyY8F8r*s>OIR=ERg(=A`NM7i<>2*5+N6D8U$cnA`iDFunf15#w#%RV~KFF}J70 zXAjQwJJ_(*KqX2r)*sfW?Tx_s;7dlR7UTO^qf%lUJDb?eR<%AOSE#B)37%PmwRRUf zo7milgKZsDEuK?gtxbtZljhf3ZFN4tR%ewc!Lyg(Gc0SwSR>9fLbZ6_0-qrzzOb{R zd+o~Sm|vn2C3uDue4m@`tOz^$;ivYjsus_U;QOS+2s^=g#k{5I=3l8q37&-oAMR)) z<{7bu5vs-WFZggN@uHpGy<}eB-p?=c(NISc`$B5sUpQu_q$Ad4L5);R+ z*ns!?SMy#~q6E(-gHQcKBla|6(2pOfs20y7;ZvuC#bo?s)M7Ffl_mTc15e( zK1wA@@XR~x)okb0Siy)FPCloiT0G~*UM(eFwiEXiZFje??FUt&1kdino^zSa)@v+d z#LJT>S5%AV_1JT!1l}CLYVh?7V=5|9g6|-Nz4LS<9y8*nwy#w!zITAVb4nbSzX9>4 z?ax)B1mC3yF@V#Jz>a=|5vs-aClCWjiBH$sxG~?N2FqBSK_yD?osbaASk~VCKosW> z7H3c`z6XL>MoN6&&OR`gOt5%~N|gBB@4~wuAtv*UX=C2q{QZHgs-`q<7Fc* zv$&5+l%VYpTk3BF&TF@Sf8Z?DqCLFzk`f2~;+O_JrmL>r&)+Y}vPvi7ZM-)q@B1#^ zXs&c_xCpVO4Q`y=*yWieN6r4?^yG~cju=D)Q)1&eN5V$-@}P6;Dp3Mu*a-2&LuVY~ zM0JZ>k~dN~@)6lgiL0JCu(9l8qucK|X_gbLO9?!i_v?NB!FsvE;RGWkUbug=#)2cxnX%?O8#Gj+1lC|&M>t~{d(Nibs;^szHi}xX2d$J? zWO>~2e7yIBTwkx77QIJ;Z2 z*NWb%ht}CXc_W1$Ahc3q{8v4l*k_js{(cGTQUX3I{vOUCiv;=#_0p4tR!S`M+bgep)7M+25+x9MfsN3++2Ygd4<9zX?c$veOZtlYHrUX9%d$V*cBbFK z7p+xAE!=-xM@sCv`mRp&>UC_=yWD^JmD@WkXjOQhp-8Y^?uwy>au>1YwEk{m)q{`s zcUUMPc?bzNY zHdLYn;t#M9-eEcOt&3)1v~RTiiOE|pj8Z@=C7>PtujcQtur4JKN8#U1w?N=JP%on` zEO!wbzj=Eru;c7Hv@Rt+?2Rwpu&=KE??tUAzV>|)Z)EK2^%FKGK?#gFkXgw@pQok##ok(Ja}5=lAHc9`c!+) zRZE|hl$hRoy4(1hJs-uV2(7|Xls-}GEc=9C$Ior{VU!bEjH+V3N{OSse5Uf~(Mz?j zZF8bZltA1U*AeF3pMLw6+ZbhYVo?jNf>uhb^i|I)`sys3+f~ANG6=-4VI!;`IZ-3Q zdKu-0R!Z0!-n+$2ccE9r);e)YT=rol@jIw_;tW%PzlN;a4rHH!7s@P_cDrFAfS~J=KHt} z_&zG(c?*am+VSnBN@wt|%=fAOcG|)j@O@N^r$F$pQo?+=>e-L}tpz@uN|eAk6>J1Q z(R?^>6@0j&7On$YDeC_u-_HqJR|2Pi z_4M>-1aXZ*s6Mo-VrIer&K2JpJGOXs_xYE~$=s%RGJ6 z;+ZFQ6Sah}-Gtk~ZbBtWpbXn#$8yk&L#n@DV#ArOwkzU!Ep|dYAI9G4FDu|nG2E*i z@QY)rtwX;z`byi~sYD5!V1o#6SsXQeQuU%f56Jt}C}arxVz77TbW8Je>tQWP=Drlv|f@vrEb(MXB6avPtv@8)lEur4Losu2As60ia5Y!$Rp zV*C8c7oNRhMYY%qh}@(EdiTexdG9)bR-s-cct1jHX{~wT4z9QUHp!bD&_WBLl@b=q z@ZPmphQF5q8`L7f5qfnWy!&C1iR!t}4;%HLLFXoKa&ROfl9m!O5=#VZfKWQiESBM; z#9|rAn;d+)5D`p?9qswJ{ngR!EvL+K0@s0hmEg<}VwRs>JIQU_x55L-n;d+)pp_C= zUKnPdt)|TP_cCCETDT6BIV&Bx5#Ig4oOsVC{}}bdev6VfIXH77LYorvZBDdtl&$>a z2PFbFKq#GM7R&JKu$j8bSrl5FwGnAf30V!Cz;zS}t{)*5E-Ow|>*eYLt(3qzi0iO* zu&NRzxITVyF5a2II+({YoWRwhUapCV{HMevotsr3{nMXj-2VOsRh1~gbv~R;96x1K z@2idNB(A6hd(cXW^Og;M$sR9^^7k^(SJWaweSp_cCxD)WUV3Og}iB-Q`4$gleG-tpf4YGrl*t zd*}W9y$sl(776ldUA2A`D*>>3Ea-t@JvswVl_2SIum( zomcX<2zOys^(gOoDsS@E$-;)JUin%Fs%Q_ow#vaaB9`cz^c;_ncZJxTjui9^T8q-uccOFGDQD z32Jd4jkg|BVy{nbZ~bAPbKA!EKC!A2B^VnB?`0qcfM?KR0Lj}Tj0Zp~C7^BpXa8#c z?gy@eT4*84jD7?gP!0bV2-VUuYqGa@KD`|gmTU*R4y}vv64c9BP3SAcWY*i|i#ChN zByWo_ii5sN3A-QlCExEc3im@LN-!D~?m1#hxDMQpq89H>O4uj?kztgmgz+oX%cxoy zyB5o+kDuGVr9LRd@zVPpw}Eo?6vn^c3?|O1!w}nfgbM zFV+5(&50^ef)U{`@2&|(?Yq86?L zS}7r?WL2JXL5nA5@Lp3wPU4)vNGuXOyMtHj9*QG>f8l_^TVFxLv;mJD_ zJU_?&GbQp9_YAvKl_-HSY{#9jUk7%=s-^EXq=fCZ8{BQHL=;`r}4>4d$l9(qgw1Y#FkRRqET)G(I}M^3A8rYuoj_F zRs64Iyq%q8ll?j@Gp(0Hmh_F{-=T+p;ae}3|G_25|6qA$y^Ne#mU}%VY9v&PHuCK9 zDM1_d->$lp(AJug{|l|MOdDPoGI&@<3@;Q`0lMzLVF}_mE{ccdNGzPx0jbO#+tWEwJcMY z6W{#~Dxp1+w#u@;dA)e8UcH_zMW zWz1b#Q$o}%3t!Z-Yq`jaQH)xozxynz zg!V{cBV*fPgbc(b8?jZY#b+D&giA!Xtx`gJ#9I|@aIQtGIBO$^bjb#Znrd+#?3U=ZRZ3`& zq^;t*ggeL;uG=e*tx_$n8Qu17x2;k_dn9cY*Kmw>dIQ~#lGrNM;`-X{NbI&%N@$Oy zt)jn!nSq{Dw@*}Tm1@x!>GrAZwpB`KkEE@lZ-_aAUS_wmPi&QH(QoT^hU>OfN@$OG zt3bdLM?T@%$fS$!R$_ic87q!`k<`n{H)WkrEzF4^uwIpjXhS7R*!NSNj^E#{u~n*t zxfV9^JiI9pZD?Ie*mq!^FhzTUp-vmBh4l(HOpb5L#xel>3w@;$C1^YOrmXLCREzd- z|4T%)p%Nw7hsif(-G*wh-}3ypR{682?G zCz7vhx((IBN{0K9=i5$+XhZ8#!oHd5MDmqQx1m~CIbkEu8=ex;hSsHosymL~NJ%csXg2w?HSPe=`T6Z{&UfWYGKuf4XmOiBHB=i z681%6r<06q-dCyxF9SBPI+uuOLnTVsmzAAP@F~(RHB6Cd~zB&HBDLWxoW}pfem;|B_i5Ti4vBtsEG~Lf_Fw6O$lT; zighVrd6)d}<-Sracu4H4rUWuI#k!QR+;0B&@;z5Acx14Fd)|~l#;I7B5|($#|6U%u zss*1BHZXRZ63Dw0>r%pUKKb8~g)_b9ss+CdHt-BKC6Gla)}@5yR`9=<=MvR|p9mY6 zOPUgyN|dnd5l)xqMAd>P3mfovn-a)35$jUIa$We}%X7PG!JBj&Hn%q=kT)aNrG#bk z@V}SWDAj`Z3L99Xni9zW5$jUIzVYpUFR!(#1^*g0u+}yuGL@%nqd|cRo z&(M^>ch6&8O4v8o{qNC}spVc@O|{@t!v=hxrUbs<9_v!VGCug?C#=7dU=pzYG$pr%^1 zhrL0GFvIS**Hoee`>?dfsi_wG4SSpt5pAeM366y%FMzMLs>S=C=c)F7D-&9m5**Vp zFF-+2xiZOD?_scJfG*IcN=9w>r#SiSIjsSZKxL4 zE5zHI6Dm=HYjDhp7;UH)*Ih*Dn-eNgg1$t|7!qx$7X1gDY&0iSq6B@SB%`O_bJe0B zgcFnIgi4g4ZdCzgn4LnTTu#t~=gXhXFa*TCFfBBBkID8X1wTydfe)na@GYgCDd zHdLYnV@`49j5bt@aVD&_B_i5Ti4u&RMGqj_P%XyG;4_qnXhS7RFa{VsnP@|`825wk zlM-*_zu>vGzFVt$eJJaDAn-E7>0(aQNT?Rd&{E$n%dWHE_f-(v9)Uqrm zY9v$(W!&?Wcq;!L%eMAA7L}k(LOr!C%ZVBZ)j}C#Hzf|VUp3->e0qJqs!IMp%H9O- zuj$(VKQfdcM1vqvNr_pCBqYf9Boef@s3E0onwp1PQ>r|shC{XH;Tq~1DwODt-lAGE z@O;0`qX=nA%wrK_P!vfJ;s5#Ub=LR!tn7ZWe{a2X9reF`H&+Rdols9L%SxhfLbZ6zu{{!-l)wMzkKcc& zgvU;(rH9?D-lJbi z-yC@QjMH{aCsd2aoTDOvSuNS%tfmqkJE5Lhng^2& zCsd2aoNFV2**V$Z?5q+VJE5Lhn$MFBCsd2a^cf-nFC*EYm!T3KJE0z6@=KBpCsd2a z^nD@$Zzysi>ILlWMHwgaY0c)Q+j)QUuT&*>r8RicDH3$|ybO3((|^{0edktm;C zddPK^DB;gER~^E$n}~EBXxE>1YDMCGdk2e!kAF~Ci4y*9+8(AVK^tt>-&$%#VmBL0 zimmXSJC!KmV~p*3suHxpc761rRwTyRm{`0xYj8s)O88jGoeEi2C1``~`Y1}RNR(qc zJ>-T;l<+a%cA-@X+F-jr8&E3}N7)=zeEPTVHdLa7&t0}}tx6;tXxC>oYDMA$xIL<#q`%|?}=4NBa<_G6CiMwFg@#_Q0wl<=6r z`l=+-l~=X=nj(STt>Mfv-Vc>{{K0lT_OW|j5``1qu17`GibNTCF;;7+LF#04L9IsU3@i__44cM4i5^031YS9L@B2i{0GLE|{@jL?w&vDq;UJ_}f zu4*M47=t5$*&tm9=MR;5zJ%?1uEyr5l1MX7Rf{&L6$#90$p+^^m3ZEVgy)=Wt}Tf) zb5^xzgIbZm?3`?HK39q7uSj_A%zTEDNFG2{i#Dhg3CZ=?8S^P(g?Cu_cFNzkWGgtzP2 zT53fC-fOZ!e^(_+Xl^-q$Rr9UXoKx));SV<$L$|~pD_;c#SHk;y)hT9B*){%>@j6j zhy5MeMJExoW_M~;2m{h@KvXg=5c76FE!u#cbXKZ0yHji2n9gGufHwab(Rm$eV_GHM+=aqD zA^f}TFY&L7IpOh=?i`84?d7vO_twERl_K6i(0vt?SN_NSs%W?Q@YYQHc`V6G9udc2^R(A4bpyt?SN_NGu&- zbJRA-`=~?-?g^m{TZ1f#!U@`-b=^4%FM%FM%FMjpe4l_@U$lzeA-o_dri0}gf{FQEQ$1fRJCY>T9Lq8+rVAS_|~dK_nL4|2yNI{QWEJs zuWHc-wIZ?MKW*LMXpC1X(Y+?z6G9s{CYD6ugtx0ZMle^u3@4QfRKUSD}X2G>;LzriEH-~7>r z`JyF}{KTpjZBQ!`<+olkdao++-x8AGZx?9;uj+d7A zBJpUsZg42RFs>3Me2lT*m{bYcV7or9P%9GG+n88Py?1a!B}({MX}^`J612f~eSD-= zBxIy+s6+`L^X)f3Rf0CyuFnS4iiFHK4V5V2bC>;gsY=iW+x1zET9J^Mv!N0td=9qX zU{wj)V7or=QY#YT0W?&ig!>ZqTe2!a8*JD82Wmy)X4^AS9Dw|;N|bP)$bJ)7C1``~ zx*tTXNQg()P>B-m+u3jXsswGYUH9jx6$$Yy8!A!4eN_7$WR;)|w(EW=wIab$+WspV zDpA6HZT+n!DI;iu68FOWn6rTqIIFa$2tIW~+fu?~2J5Smpii9$x8czQwIYGuP5E~C z)D4v=;jxe1^OB%Xoe1wMkBX=j2|Ojq2A?aHDB&@jJ-a25p2Vsa?NKWdc-oT<_|y%R zcsxkLV^MntOM*UiBD`IXQmGXQytO&*IeqGeN|f-J+QyQSpii9$+F-jLZBr`}k^^X{ zLbzLQ%PbA^FO!MJN zfO{~6+x2WMwITuUHQAuQs}dzNx19Fk zkSLs>4YsSlaEt`saRAAV&gVMsqUwC|+kf&v`J3t{p|gRG+Ni^whyxBSe|g^|bi6`! z=%jTcW(FNAc}8jONY|oTs9Bwe?!%TtxQ#;FQbNc4XhXG7dpp_KW_)%2NR0JWp=~Ll zy%24v7HWtm8)qJ9b7JQ_C^pjf09>L(*S)JFHELET8>c)~oj+isDDQcpTBxL*i0yk| z)w0Z4+8iZkRj5P>y-%j^Hgs%91?psD+mov^j-Hijp)PhJ`1I-ZMH?znLa#3oMR``4 zdSriD+cIf<64e_FM4?*WS;6vR?5i$`OeIR_+ZAo7R_y@Gi}4P&5Wvz~Tc|{dmbbQf z<@)^m_DRcy@=evZIh<9dT60%0g3oT(gi4f9A2rx0RBO_imObS=*d>vvLDwZ_ zLguDX1wLH|tIN9|Y1*F0Mu zzjTqJ+*qc1ljDmiJqaFSAOFlbEuvv@Ip{ zEinDkM*0E``-E#A{^Sq6=!>-1#P4i8E7kILZ~4QrRsxvaK|d=#B}(`i@`(vHnm)C! z@bXM}>>kdT?H3u*w4oz_k0tZlPzNjQ!~=R|oCcx>`D~@;bCFCH%dy zRWh}qTK-1;@3Eh!-6^!uBnYLaUE5N^-+x;rQyZ$~?|i?LmZn`cw9zD*Hnc4zd>pe? zGPR*vK6Z^-_lvY!h&Gx;(}uRCgg!k`PXFx6eNN@7uFss)4qB3Sr_hG2*8(W~4yu;V z)DQi2IRv59yY2z7EhXIhu=QHCp<3>7+;Z8cX%%WuaPr{~616Nn|Qf!Xy0_zobwt&mho~>5|A)qJ(FVT0Jt=^1KE;vKFG* zyDCva$73kVQ=(d){i2`PLNsltL)50;bsFG>09?4uXr2@ZA%Ha-I@bX zEw{%UKnnpw_718<3GYLWsNt*%)$)F0oY^IjsYD6Cv#lewO8kjo?Cc{(OH@>-mX9Tj zqq-zg)dluD+fu?uzGie+lzmmGmXCIf2V00{@2W%zAHkbZYSV^l`KZmfwuNZgP>B*c zR^k`AgNHU=`FL34tV^G0-|nsrX0y5*>(BY!Ww~F0coW3X1N+of%kMu&hDh9Y;gH5-3x+j5 zeSS<`B}$-zeY(C4zekVk4iGPb=ng`){E4C87KtZz+`RG4uZA`DJGrf{5+w%QZ8kPL zjW!ApD}h*dN?TpE{E6W_7>WP+{l<+IKO5HA`OJ&zDpBI5^#`Tvm@$Jkeg@+6Plq-7 zo^?@Owfu?Ud>)CJs}5}3i7U_VxwWnmB~ZaW*%-J!YcTcbJ+Sc_h&}#%YhAVcxuRbZ zi6hTiukq6!!y6yncwb#5N}#fRvT?ztv~l*C>opDs(R12;b=C6cmHt&E&KtW{-k5XL;<`$dSlVx+WaF{)?MrN5_*SEo#? zuZMfSRkuM6)$&-DtKpHjV8P|}0sk7-7`NBphDww`ZTfT_t365^e|-7!`U@WpYkX_( z!41{&h@PwZkvRRFN%bq<9M-t~04V5T?+VsiB4?d=i_ir0pzY@gg?+j_EmS=RhwjGJ0qksLkxPzO& zyLCe)N}z&$vhm<5-0w4YPXGE65U0Mgbwjm0qr)}&NZc@RM*G8yhc!01c4$K-N}x7< zva!Khw9##Y8SNb)wgRDAp7-HigGl_o=lJ%&WWyUzUO23w5+zWY_8rv#@edHH<@rnYRV4o3z!{@vqjxt!@2W%z)TU21?4Ez|jTxinl!R(|Mu+!2 z5?glkuXTS7J&UJAB}$-zeX?QC?#d7MuicK`?Es-#o&(~u8;Jup99KIRPx~{Yhcr~8 z#K%838}<%fb=%n58z4UZ_K=2Zc@Bv0U?eU%XHxB5ytRAdJy(em%huQ~U5AY&pIkJl zHWkF$AXLk9KpaaV@z8?HYmZ~}ITz!VN|ZR{d)p@)HYWb!<;!b*F~Thcp<13P;+PnT z{oAJ124WOlyT_o0N|gAY+s%fJ?Y&N)R(l^K^>~cCs^u9dj_r{cICoajs>oBC-2}kJlz*R_ld%P$f#Nx4>-JT>GOrkJmnc&=ci-44 z*)SjOh--V~pMc0tSX@^vUs0kD7m2xpSIIwy*S8z|M3pG9_iCe(4f93o8?TZ#K->sF zQMG)Pl)h*r4jsEzPVe<5c&{o^;^Kdq4fClt0dWwBf!ofjtCp{l(x;BZ@n@}2VtE7x^A~E&%8|R-QD%ulqluDF%{lD^b9Tuw%0nrzc*Yk*@RLj>=8LLI& zfoXI)5scJggk>vlt7*OWP|yKEL*zK(EMc(2O`g)TDnIg66?M;EazBq=UW5X zRieb?y zaR%<-Yq*085A0J@i4y)S+`AKPASaWTIhmSj`Tb|ME)vMe=q!hO4WC(uS;5H%1NgHSE^=eY6{3FKsIWlknni4yLkp1mDyjDj!vL-?W-w(Fa# zmiwjL2M~$Z9-dYE2m0#v5&d(ODB-^L_h)lY>VY8UfmjGawcNkv&VfiQDW=u_1yBFd z6$a%hQNm+}m;WDatb^F#B@l;n8PJ(US4|+G0uX$2IneK!egJ;52B52 z5EXp{;#VM4%i|rc(MRGb#Al%)N_Z@~_qw#v?Xj`7yFi??>yTWvJpSYkh)C@JK>zf#zwpl1xk{Aq znEHgbm%zqN5B9G;k9&R(2-Wg9n!9%*(SaPm?-0?Cxpru-5+yu0F#9Rm*l2?pqiz7P zCkWN@d;oXvL}CDP8P_8-@yUh5a+N6IIgVE!rH%8}89(YS5OYDOmghCND=ZT5XR$;srZ<@p)fh{SZ{mhQ2fOs*0oJm+M6^_z9Zx8DfjMO=q!d7g=V6^TcX zBb$oe{Wf}6B}#bi%2!v{R9+qQCB$m8#d3`ZPpE($PRHB6EmTgQNi>&jD zAg%$STAoklm>7w}&YD(#4x{KE7|z0e9gk<+WWCKk%Rah z=0Vl+bqdb4kvQt81@%#wosY)stP&-B?ZteC-XO+;I3I*+`Faa|hDdydwW9lR<#XYe zs6+{0Lo(mz4_GUD2gIqhi_A~F2h9*tMvElq>Bq!J~3EzEql?_*+KsFtrs(x;9Dax#rFCsR|2628W2vB4CqrB23Jvh?Qr zYO3Yys*DXHu>fnrZ{QC8714xBl<>7;i*Z)NnlK}lAAnFTUms?S6N&y5|3GN)=Y_RP4F*TJa;d>A)cAf^}Q4rroT&r5X?|`v$Bz|7*fOr$}xk{Aqy%d%M zI2QyX`r#l{%lA((2M~!x8x3tNK-OSYarunOoWtUoiX8 z(<_afjc+HYmOnAf2u5P)+!JXddwJj`b(JW=W7@EM;!mefPDH-*?O{iXKl#jTM&bs1 z|El++JIws^neB=2wv^zz$-i6f^}K0Er7K@^jX7aQioe0sio_k4AC`#T7c5BoOS~;5 zic`(TgKu#U%i;K9)@fJeBNyTe8>;0a5i`w^*kix}>B=`T|Gk=tb z2M_AmP%R%(nK6&VE%?UPmtRetaU;Ghq7o%I=F^7d^!NXCpLFH>bX%iQ)#A=7YDMCc zXLm`&*H8RrLnS_!kT_xHhRH_v8QlBv%pKzz?V~On@!c0UOoX@VGaOeiBJunKJ2l=q z;iBmqzPn{ZB}#A(=5^Q_%h-!{OlP%h)R0D1i}t7$iKVNi+D^qk@f~`V_}or{z65R9 zT2YnocHQHkRwUkgpnp26g&Ti2?Jx1Rl<0K_zYS39`1=9e2XIQCfsLI$ykO=N5APOs zq`2qAm9a={e|n$BZm0Jd`PM%BHdLYneLLE)wY!yitd-8{kxlmsJ5t;Oq*f%>{vv&s zv$)_#6VmGSk`(PHEMk4*bZye%c@&-3rLUc2j8 z3+pfU={sw?KOGWwq_{`U71v0t-+O+&?b%yr)$W`W_I@zlVY^(dM#c zaLz72OS>#wYlm;~n*+6u!=9=Vb1#`$-*=A{cR1vKj}3cRl!#}w@A^NkP5kk%XMKim zQ+Y(s)qBq%@T?wujNeN!ds%kso#)q9==0Ug=Z*t==;F@_P9=T*@t^XIRrL$6r z63o2NhV|~vJ*U+detX!ATlPCX^p(eLw4wcmy=r%#&o9IlTjH#$TDqdN_^OpU&5$$e7pwt zmmI%oxBAM1uN!gPdq&U(+x6(4J6$3%^v%24$KHSOjGy;BqoEQdn17%R+rx6>+gGOg zgWK+PM%eY@Sqf@Jf<0^h6=@HPx1|L0DE@coRtR1P+x2XVA9oUuzj;^scH61A4sA<` zKA-c8H{Mt0FT8Tp7O#9dV{2T8YI)X(eH97ZkJ`)ob|1<6p%Nwd7SM*>bKDPpC9UB7 zsA~DWi3FaK^j$SRS1PH#U9`bxEX%e(ZffnS|NG+(XX8CrEqzz`K6Vn>*QO;KzsCDf zeT#Tje2d~6wQ2A9={o)kqmO4fspVN!j#rUb<@2X&UmUyg%p7B)N|a#UmuF?;?!n6z zCL8x)Oss10tf&=<@n6{Y;SR&tt`g5DlVJXuHf;VViNXnQ*R$NziUj7UoR1^tD3vI& zWG}N}^C0G^yxS-DZO=JMwLDwTc`y=~Yx6Oe44lciRwYVsJ%QI@^ZBWL2J)bRF~=RO0ItB)Bd@8|IgkMDjAKTC_o}NWk|=Ht74P#MfI$T)68_$%gq? z@O|>1OkF&kzK?48DiHmvNWh27FZ}y0Bk04aL;gb$a_iauObi`PM|NUZwl zKB;%>@GO1Ji(0!3dpl+ddSHJJ>;qu&x%@+XdiGu zx{hmlFHJi+ye(f{On&<>&4zjUH{e@(-7m;T_J*ggTE6DVXrc%NqKRaK(S%Br;4y7m z#B%KP$@zb;_^nx^5Ec1)Eh8acA7<=y#C!Zkj>l?8?|Di-YRH;9T#x8ZB}#Awn}qGM zIBD8Z`IWsMp49_Uk=jsN&oIjd&pk1}d*|DBcm~m(YS9MUfJ=} ztk|v+em^X?w9$)p2RGkh_pp#wlUXP0vpq%N%Z!t2yFU9+D-xUs@jhgj2XmDu;q&8Xmwb-C;yhU9G7`b7WxGBnGV>pa zt2%bd|9#=!iEbuXOx*qq(MP7e3A zxS|w^PtNI+pZ%THN7i=VH&=-g?mya^7yU$>Q~^IR?BsBtky?@XWm!jY!H*`SeHpwC z*Wz{X*!^HzyDN#p3Dx2;wIcCCSr76_)Jjo_`_v@dpSN|+%~pM$n z`|w<;jKqPzm|2_m%N2K+cg?YB&jhc7Z7Jc=%l6;reuiHT`fREx*dip2Yu_en8laom)& z_k;J`wVd#ny8nyZm%-Ti?%!X_Tt*^X%j0P7dWb}~MR$#Q`D>TV*r(?ixk{Aq+<@)N zU=D!qAaVd(%uhVhimZ+dF~WE zxDIX0^CfK8b2Zji%*jld_}L8PWWsI{&*HGJB7yr+U+MjBBY8hmqJ(Fo?4C2X#OvVw zsA~DWi3FY!5*eQol~mtgUb#KH$Ys>WPfNLs@Sf}Y=y^CJrXkly8_4yAeHnaHc~*P} zTi)7q9eit5%d@8(uOhJ<>PP+c`ITqhi!o6pN_a-t#@#hmdnegA8e?Kri)TfxNbF{{ zu(K6WKT0K@Lnh&wZJR$zqHx07^~^T4B7r%o!M@@gr4l7P4{!4z^X(fSelK$wVV8wx z=s6EYg6js4G*T`jSBVn7(qQv>eT{)Ut71Op+Nu_>iCU3>2av9V9)L=C?1Zn2m|s#7 z$!Dl)k)T#2;QJ&S^nFy~Yb+#ueaHMO_&$xRF8*{neIM2GH68j_k>Gk%najvkqJ*zg znV-n@DBeNjGV-bxuY+2VkX5qW*SVB zAGIPOD~f3c1Z}t$uY%VuNy>(+ETpsjnDKXj@9~ zn6^o086uW+9gJ91%hzie6-5G3QNyDml_=qB!i>UF&4=qQAyienkmkyrEypL*mzcIHI31p*^4Q8WM zQYCn{W}~cRmfcZj7H7XPM;!hodXm|p{l;uN^xbrfdeZ6dm%YcQ-D{sYp;|nqRwPi_ zI^983wyvp!$4;OwcCvBM%N%`5g0-*{p;|nqRwPiNJJ~=@@0v<@>;x)zCma9s55|Kf z!J6KQP%R!)D-x(Qo@{)4R(nk)Jaz(g%9D-FKBT`}5``10#batk;>oi9;2szgRl;K@ zP)R-6_;}sLuu&3)6RO2yYDMChvX0^+)KOFkkDWk8_+;bwgFb-|Egn-V5^Jn) z^&tD99;8Zm>;x*?CmWB?{RlQnqHsdBcucKG^eTOZSKu?KgvU;-@#445#>9WYMoAP- zs8%|LRwSmsXZ1PjsL!bq9y{^J3wKF2>is{2jglywP%R!)D-xTOeqw+4i7Mf-6E}Y` zCfS(S>jT&*iNXoh;xV-%@%d7#mpTvru1a|9#I@Vil8rYudmlDRqHsdBcucKGEVJ5Y z*2Wx#6bbXJv@ISxas9)aNnhbQ0-;(wW?w}Dy<6jTuy<9$V<-B}8k}s{ zJ+Bg~#batk0#8Y@!KXweJa*!+hX*Aa_Uu*()#5R=B7vtp+2GTz5*|D8pTdNWtJF(}_)=M^QEU6Nz#batk0;5l|!O=%0Ja*!P4f`b;YPBu6@tAxi+Y`JmoWW#)hDxq3D zrdA~2Wh5K)GE~B2C$_$Bm1M(wpDLkRJf>D8;4LK^^p;e@V<(P1W94MSe7Gv1T0Ev! zB;fTW8}#~A!eb|Pc%oObVZLaUP%R!)D-vbxvx45MN_gzVHCLMrysL;Ns)TCsm|Br| zy<8bRqrqsRvn?Jw;kKvu;{M%|D4b9&9#bn4<&|gXtGY`3I!JgQey)>11HyOnhmx591_l_=q3%x;ge zdR<8rPS6J1_0fk~kr-!VV)o*!!3~ut;bUdLYrX~>B~ds*8*JA{QEEk^9H}#m?G2SE z;bVTky;p<{8QT*<8*JBS18PO$D4V0QPyhDahDwz1xoglzv{4d;6UheJ^;wNtkvOAV zS9=5d$W)?)&%yhgwi0ZVMBxN&uw9>>sTGM~<+|EZR6kXT67Ea%ewQ{%qHuyX*sgmS z)QUvu$5XjHZQnj(ST>r^t|j3ywT&euk>2yF7Hv=~5*U4w4URr4@%WsC=LT#{EQvH;Rkdh? zT9Lpgnrv{~Rf*>rNO+FJ#`cn6E+Y}%u4g}}6$#7+$p&Wwl_=r48k?g^BF!IFE!v}2 zBrvNb8=Tct;&~quo^!Ifwj|O#Sk z;AJEm^h;FYc{mcD12o^KB$(?!lt68#WaG9$RU4|M9$*X6 zw4o9uP{AqL7>%#2LRp?&)lv_zg=pGPi4v&u)rAe!QV+08g0%sgZ7G2|UtRQ-YN-d< zC6TE_3Dhx4Hd^j^rdsL&c1@^63Dhx4Hd>zDOtsVl?3z%C5~yR8Y_z%lnPF@D`$JLnTW1v(Q?#N45O^ zGpFAr!K%8c-`SQD{!BNk_V`&9s^!ly*Cx6oGLlwP{1Oe7@ouWS0c1%cs6#TT1vG%$k~LKK--kPPKgALNsltL}V zN_dW=Ikq=#sFvq7IJUPCO&cmv!gDpvIjU(xwLCw=IjV(d+E9rSo^xu>wM`qU<#{H~ zwJk)`hDwz1+*#9SXxdOM&zI3>Xd#+5RHB6E0Gqx~(}rq!-jBXd3(>Tp5+zVyF^w^; zKAdX#$~b+v7NTiGB}$-9WU|rfi>j8d@Y5GKQra2th6 zlyKWEu|c6)ZjU+S7NTiGB}#Z7w!}Ei>!|K}Xd#+5RN_6&EVn-kEwNgmT7LhTdyho9 zFFf1hzKNq4f8ZO}9qf0FMHn;i?{?39C%F@z^VY~B61SH*{kgXeuBk)`#tgJ!&u&Q+ zPS6IeYh)3L&C0cj7qH()B}y=6pbdKmOQLXsHfUWVi%9HNuCW}C-=C{Q3C0YxVPi>2 z6i(0vt!rcvi8sr&qOW29l}eOg%s?A9CYD6u1Z~i|Mi!AcuUzw*i+yA&QGzi8ZP?ge z61X2m&<3q*WD$v_18nVX8|;Tui4u$%Xv5~Hk|>;@4O-X8A`*L-YmnDrU!O{pV9Y=p zHrJL!;RJ2ax<(d}_-DD6dL{NJszeFK476cBLrD})&<3q*WD$uapWB-72<)>|i4u$% zXv2J;k|>;@4O-X8A`%_={UF}!?0W1MRf!Ue8EC_NxRNNGpbc8r$RZMJooZ|JH(}qa zN|a#CKpW5+xWjblOPzLeK`SYh)1#oK@N#&9hR8 z5{wx-`>IN~4UH@!f!?k0I@r4^QGzi8ZP-1p65dxDSwsR)NwUGGL?ucvW}ppwcB=$! z(7Hwzk-*cQZ18DUi4u$%Xv5yYDnT2xu8~C~@Yd$+E55ZVQGzi8ZP-{+C1``zHL{4r zhX1tv)JJ2yQi&3b8EC`C#414>w62jwB-SnWQ_sh^s}dy`Gth>O?Nx#{Xk88B}y=6pbeX&sswG&x<(d}z^s;Ra8^@^5{wyW!{*v5K^wHLkwqjhJ0}~QomHX) zV+PtVpP@?72CZvk5eax1$p*a)l_){4k2cKrsS>n7>+Ty;D-!UQk_~!GDp7(yDs7k# zS0!kJ?YbvRtw_M@EAPkPno5+QuT2}~i&hERV7u;-Q!5hiUXu-auPRZ3F#~PjT}Av+ zC1``~YGe_KatC%cuYF>>N|bQh7JvAjZ6|1h*8Qxg6^Zi7GkC~#l_=qTXz_>iRU&AE z?RxK0D-z`$%y7@^DpA6p1&crAo+pAf*seb%)QZH}A}~l<;TT*1SrhaDq12 zu0QS6io`F={nTyv2AxWj@ORVJ?nO=AEXq718V~njqmPFwM zZLnP*eW(?Q>upTTrrtZap%Nv0thBY%k|>;@4Yuo}D77L{j?@{(_J&H7@G;-kgk@|` z1Z}WgpAD!LiE_rtFh@01qJ+;~wze&ER3d1D?fR@ntw@wJXNI}9p%Nv04z@LVnQIe4 z8*JBSXKF>F^Z@8nH&mj8`x3U-KzxQo&<5LeFN0cS7mK}gytSV8$eIna4Q4)m{ zw83`WTcTDZN{=jq57$tM67JjCJ{j@h53B0up_7&fAl_=pcwT&euK`%TJ zw83^g+NM?{BnQw?i4vY0urX0`0EwUtw(D5~YDGeF84Z;v;W-W)+a;Hg2-;w~p8cR! zBrqGKzT#}45+yuWV{=qVr1_(&MSIkW1ZK5lgR`1SJnuuob51tbmPDEdt6H={tw>;Y zPBu6@tHkqHBs_O!K0`^Q`Mjz{8`O#fyo_XnUWQ6|?1bk4&G#vZmlL z7PG4EGanDjk3>CT)w<}fMzCgaBz}mBw@<7vJnx6P$SP3+Unxm8>}w=tjof@F>LRNa z>hYwrV(sNflr?hmPf@K|B}(AiJIRLCd_nag)-2AugHSEh6-qXaKn>|gpu$o9&98># z`=L&?N|eBNf07NWg`bfzJYhg#?e^Bvu#m|Q2JEPvVN|eCYh>{Ka zO7qV^eE#XMyf5l)s}|}!B^#{i9f_H!8-6FQJiq5wR*7l0r3Ajil>TmCwC;f#xvzoP z19ihy3-zj!4b~=)#F40Y`_mr7^N&!?TqR22ds4}U)mT6K%=PlaLG+wSjQ29N-50&3l3-!a24c3Z}L|G#@zYO*0 zRiXsG)|G5n&HIy3Blnem4$EIdJ$ltb9kgVFHSZ%adTNjS{qDo_IY%w7t3(NWbu8Ji z@3&99u1Ee5h~tl6TvsjBb4xbJ8>)pmfyu_U zC&RxA#NCg~sy&CkI&nmQ)|F|tr3Aj+m;P?`4So&+wc_(jK&Te#9VQz;d7uaD$_Vko zNz-Z{b{n3*-F*~P%YG-Og6Uf(UY}ngg6~F za<6!ESbqD-Td*EWQ=$aEvYP(R+ALXi^+l6vZ-RK@q%9h%g*uwa#*K&*A~AQfakV8F z89vO1u!2joEhX^f$nB1F;AzxG?)!Oh>@ znl)dV5+(3$%k+1v|1oz?|Jo7|r@pgwL$y%XG}+i@d{5SV5#k2a$bES6uzZ7ShqC5N zQ=$aEzM1~c3MHuZiyFBdAhrUbTBy&OY@B&uPu71C;`cqrkNQhCJb&`SVXWZNlqi93 zji$d_&6hWp?K^5Zh&Mo}7V69<8wVWPlQmz2U|fJ2x%r}vhqLBOQ=$aEtlIoL^|QhW z)k3}8rj1B+TXB5*-8ie4a8@c&0^fd3Hmt8+T()m}1H?Z-s21w}Hv1|P{|_~CXQOvF zLGP+W34G}`*|2;5#W!ZO&nXGjLjB@ogZDfVTXyuXcYkeIJ{M1kN|eC2c#{o#c2|D5 zfBkm!ZU+d}LLKI0gU@ax4%l#9{aifl&x{_zx=YQrl)%@5)8FkKyy~{G^*2C#{OutP z)j~b#WP|TuBrZXX+;{QT?v3|cB}(Ai$jOF{C7)b0sXi6N+8|U5b+MBTjwO+J2o-N1 z$LMn|#w(R5f$vBs8#X5X;^oWheKEo<1)*A~@11OLOpL_-ZPV%lF^aC;V-PFRG}}@F z-@{ISx3Rq!YUI9;k$ODFUDZOJ@??W!dn5+VomGDjckn381}aekU;j=vY>wLEky-VZ zL0knwwNP(8+29-%iQQ2ncOquBUYG|}q6EHAo^04$`=dFJ*GGdm4)dUDp>BM#!MQdP z*G^hc-x;&>K+Mi6Q379MPd3bFxElmLfOSBq)+0;J27QJ|3_^|Ehj8Uv!pl&J68K(x zvSGf@qo|R~xpr3&s&&%sw(EhuPb3bS+M_WW_q^xPi|Z;;0$;RGHq3`R0#$WC0g;`s zxUO2qEH)eT;UX~?HF7_O*S8z|M3pFk@AoGg=8M)*BewzKM)--Ug%5wF`$1nc5{IJV zExp&9;JvCu2~-$JHq58q1jIog25vjAu38f(+HM;9)R8D_tyj=^? z-4TcfRiXsyX(SsKbKVSMAc*5mZL6!+MkkvM#+;G(4JzKE#(Mq^qEwYAfvP0QhQ-b^ zLGb-p4TNg#v(7H|o+EaS#5h#EeH-!l*ASnpL zs7jM;z$1Zw^(AW8G6yjF{Q>Q&bbL*C&St`so&X_68=ov7nE-W@i!2= zqrS6h`E$$~(vet*H)<8UQ758KwMvxmchhQN_uOgo#+o3WYHO>hmcNgzg&m0vFfx1{ zBf~({+g6DZKE~MBrZ)$%Hi&0XZ(Fr|TwzV`Nc6KR;Q4S=0au99z60B$>BaZM#kxG!Pfp>G56GKc{nRLlK`TQ2*Q^>NZ$U_?87pAT>c z|L+&wSs$kGWCb~ew^JsS1tF09{TGN*2hUL8FBDY3+m(GksYynZ&tf$ zN|bQlj$i!Gvc4c{AT9=>TJFzHJ7~$6NFXOu-wB>2ax$!TlWedpCEQ1~`Ua!mi~bPA zgzfs~s^xy^wW}{-eVo*i5wATwtNssM`Ryb6vp!B!qJ;a}R;S@W5U78iF9e}l?q82P zaWU)Tq?U|WQcSD=3!eU^D-2?_o2Enwj~Q4=0;`vZ4PF9qNVh?`YI&Tn+V>Z;@=a>V zh}B=cy#5?woCSLgW?h-4LAV}@hcFjil~U75+ytqwQ3&S z9vfS~3&c6Q4#`!^Aq)~sFAlqlgbwbe1X>B0W>=W);P z0ijwRM^D{<5o_0^mW=2?4&Zl)=*L_;l$B_j5+yu0z)CAww$TPN+HU}{CkWN@e888r zMPni{0J)6ok(v19!eOjLlWedpB|OJrb!E<5XMFozAm)NlEzfI=*?tjg*QA!3m1sOC z!`d}Xi4vZxX(d$4^E0#&iRs8K-D5c!R-$RzP{MOg)>pq-XZ)xeLA;3TP%Y0hv9BWW z2y$do(YxP9@2W%z&z;#F+yFVUTS`K;JYU9p9*JEa=wG8x{SclKl_=pkKzkDJe6W9Q zE{F#}sFvsb`0PgF8=sA>-HxaI*0Doaqbl_k+fu@Fnf4C8{^;1+JP^m={ZK8>U-BJ{ z#J7-posYNn1ia@eQNnYwHZpwwyh*hgAPxedTAqjHSQ3dPuUuYRjL~NfMjw?Z;kjiS z;l?8C{33{JK&Y1IlQ||v;;^%()tEnml@FB*w! z#;%p`1@E;t{9TnO;cJuTQ|}4l5D>S5P%U4Nq)#0QPX`Ga!BdLbZH-m@!Ty`eUWK zAEKi55l5*+319QJSZxxBo*-619Hm;m&dpdY67OThy(gl(DToJEqJ*#ATg=H-{gpu+ zbxK=JwS2vvF=r&WbAYqKGQ_niQNs5iSnNCv#G@d-jks2|eBS|M=Sch9HCPpS29+q`dqOOi(Hna|o(6Fm@(ilw z`#_k>h{QLr_QA1a0`es)Q3BO<()?&SnKeMrZ~yhe0i#swh{J8~2el&cbr63CaU1eJ zDpA61TW)D>5OY9WyKq3eYPmh;mLh?wJ^3|##*Zwk_P`I^Htmz~ek*J6q`zApPAfuJ zwYbZMTD-Gt$q1<@oc6G|#P2_~P{An?-&)H273&Fq{2I=7SD=W zk?}cMOoVM%ZBMGHL zJ>iCG`KZmTd?ZkjEkE?}Cq~?eeSIoXg7XT`(AEu5^)2<)KHb)6RJGVw)QZF>&o=7` zH&o*D6$#X+OE$XC;5Xt~Pxz@@XU;$^xvnamHS>W4exIqlPr9TC_*4NGx5|>Iwf7d+1f-{sRg6E3{$jQ6*70;qAItL#;?i zJ>j&6#oJN>wGWexzaPN;45#!Nn2#JgbL0~b?-q8wxOc|Yw@7S%dY}A*|H@~+wa>l{ zl_){~k+yApQ0fVXT`%rsQY#W`f02F@mtF9q326_Dx1|LAVE*0KIZL8&f_=qy-CL$s zBu@G~{kAXLc>g2Q9u{v)3C0ZkyR8Y2`)XnBsk?UGVfdd83A*uO&Bp$wGX6>~N zhR!MX^^Tj8 z_Q|+J3DmVs#K&uJpA72>KREsGGf=-a?5yz&0(Xc+V(6Q9jXExCA8}gGGa4#Uf;kS_ zwtX_F!<&Bfi#ohvXN_kItJlci6+? zIa0oZEpKhQ4!*Uj<(XTKSCLrd^QY_E?y~*J9AlzNlwfX|*J0!C!OIpV8~0#LtZMO| zQ!5hVzp&qC9EP!7C7!b;!5lel*!)ovg%jScXVR$^3CvMx?>Xlvl_;@fFSB9uAnOUQ zw#nzyQBOGRNbwZ`&V!L)J>gX^9Y1p6#@}tILicM6F1` z14!3F4?rcp7D9q+FSKEPNl7H1p{hk2)QSXrpJao+k4k(^hs1@uawpHW9p+!b_i6MR zz2OM@KC0y_P4urK0UxgM{ij}>@%0nG*-(iRTnnQO^An|>aHFcl>!4O7R{eAzUPn=f zXX)!|)be#adasc<6u(N@<@qN@tbnilt3(N|H1e!$x5!`5{86%jdcuvW7SD=Wk!T-q zKv!Yfc{0mL2^{W!!aY2GRJZJ+g!^`k5G&$kz>OPQ2Xw71kDB-p(!%`(^ zgVz15s1*sVq^w%r3(O8hg1vjh;(eLRsHsE=@AcM-&{Zv-A+;i*Ri{1RflSXcjZ$PL-2_G3+D~(sR zcvjSkgjO?GiNB8|d{naf=l5YueD2(LXI|ZVY1l2|BWJ3yUXEi%3>ad+?c4G34_XMG z6$zzd<#!)NspX?Kv)Pf5*&tVm5rS8N@pBnl_IUH4I_6$$!R>?`nrofiCPLfZSm>u@bz2anwkw)Md(p;|nqRwTAq^_}E}FTCTBu=m3~a;|Mg z;ssQ-dhNmOM?Q%!8>vJIj{t1-_5PLTCmT=RIVtS@@W_H%kvRAlGf8BRUUO{P$-ygk zEnWwYJ>J>=``pRF7-z55mdrqm6ZU?1W`b+YkwDgQNrUWTMd8iqVv;r z%sRd;?EUZz3$-F~@gR%t9>&+KRHB4OeYUD!5``1ITDI$v99MzzWe0z9SIT9K$8~61 zo^xQko)xjaV)kQRpTQ%M{Rn$MJYT}TiUjUQt?zzY&E)-1i4vaov3t%e4zC~HgM7~;fsuh%o<;_hDB+n@(x@|9eu?c~j8`gA!t=W} ziekK~oxK0#kxyW}QZ3KDa!icGZm70-+^8#Nu81$OsYD6SQ`>CtwbkCKU3ctnb~p&* zu4;J>nP(CS+Tc^-Hh2eJi^ps?5}2bB!8uALJa)qK@HP)J-@e~EpE8$`2-orqJ?Ftl zaNS_f$5JjMSBVn7(qQv>eT{+Xtmb2`t!mL8wITrzAQAKcRKjB?d|kx+k}9EEJf>D8 z;QJ&S^nFy~Yb+#ueaHMO_&)h_=WH~BzK?48nhyP|NN_!>%w^;%QNq`$%unQc6z@6K zqw=a2uY+2V;JO+KtgGcJ@ii|JzTRegCb+J4bFU9aU|lT{-mb5)(cg^(av8}6av6D5 zi!|Gf#2#3K&Z7IQH+O~)VF-{^zAjVNGU%O?56p2MQAC;fE)8ixW?>i?DzIMyq8%l>& zTR*;g+Qyd>?i;Q6|i6TY@>5hT~Px8HR5Ok^g)z6@VKXOtQVS#hta zL$4mHBKmaYi!WTOR@LH_Q!5h4 z8YE)T%!z52g}3E<7)Wqu1pkgcMJ}UCc)PlPA`<2I`Z8ueRHB5RmE~mo3x7_~2Ce&9 zQ7aP2;-ubX7DpvYc#qgGk>(wl<=Y-RA>aJw58AzVTlYz9J?7T7Vda(IH8`(51!B>I zi|RfPwywS@@rN(37`6V<6Y?n+b_?rK?$y{DloD@0eMNnT<0j-g-TqwNV;SbyJwmdK zxf1_%a!36;#~{Ah@UHY5Mc%2_ys;8{{;hlCv>#5$SGeW%`#g)&nzK@3&XHMTIIeu) z%^!@?oJ`EBC^3JXy#6wX@eePmX=I{tLY67<@+()=#^TDq{k!LCI@ju)7>NZZbkz35 zmEW`RU1=vEue^1ZQ5!G)U|H>$gD2!K{i<&m8T1W~HvTxeTmEzO)%2%sgWucPmOn9k zxBYpucM!dsvv*g%`SqRjX;(TD=-u3VSIlk$O*fdgmTXC%Iw4G%`&Un5y1w^sY z6=_E!iPqUtiLbvkxAx|t6Y{r@`CU!tbDekNS#`VM?qp-NTN*X>WYpt`#B0~wP^wY zvTVYn5u?^SVnV*^;oU=Yr-ZhIr{v28qu5tZzLkYIO0OvrUrid(P8+MhhDtOlj&Uun zqusAVBX=dVCCn7~cRJ4Msb$?mB&-o@Byb(=ejS=;PpqI=DuCLn5IiwXSVy@BSIraVmQEzNc<$*S7qu%r{hGt@GZi{~7b(+ec2S>sk37pee`0JsTd!j?ydN)N9$b3N@9O?eaJ}E3D_fUW;<)qgPS4e}TN-tLCt7zT zDDeTtl9`wXH#=c|-Nz4llS;?y=(*mx={m01W`G*wEaGKYis`2y2r{lRS9h=%kb7FpPFy2wxzug ziJ!u6UjgIQp+7h?j&QQy+%rWsu3${8`IzXrm$Yw1h-hOR{B}Mimtefow)C1Jfibb> zW1`0c90%22BrqG)d^YeHhjWI~k-%(_`)uIx5@!I9ifoqAd+w1J<64cpl#Vv|4kA(1 z;QwXi-ff4zI~#{Pv%)TqSq+SY|DAgLX9VllQo`DBte4AU)^KYf3MW*{ZLlI+3(>Tp z5+(F(c}DzaXT?gfJQG&;V`W+%vkITKWa>_+7VG7bU`@RiqG>}VN@$NH8%=^WS=lb@ zGqMIOk6A}iTZ(6;TC7Z)2vkLEA(}Q+qJ;KHJgbGf?2y`Jg-uplr43fX)Ry8|sTOO% zl3-oS7Gk+)rG)lKJS)~2WxK3j%DSe0++w5fJE&T$wn~DPNn42Jo|O{XBk`Hv8ClC8F^A-0zyN?d(s?ZjbhCwb48))$)6= z;>Y~uL+8_D7M6EbN@$M+qVRWOpVL;_+25`~AFbGGqj^@U<C3_xd+yrCR=O_kMS!R${qlrG)lKI;+C3!^c{lm5$R%%RMV4v`6Auxo^lZ!@bPqjy}z^ zQZ4t}mOH{N_pFrA9^qN}8_VOBFqY3K$8$gKjW>$NH$n-$?4d<{)jMdCWEeU|;=_k+t7MQh8njIdawt>fHZ zb%%|TC^`w%nw+#EvAxxB%TC6Qc$L_(5f&k}bzHntPuM7lqLWaq$w?~`hnH*g&!BFG zO6=GOi`&{dUR>}s*eHpjlTfY6Nh=cEYrwnR?+N?8bCy|Kre%ahmTetpp0E;Zltj@< zsMh496^T8{dR`mh7b7aMVbnsOO~;B`hn_*750OyD-z{ystmiS%HIiFTS{2A zrLAMXDXYPT?7u1rYuB_UC#?$ch5b$#JI~7B30qrASPrPIWBZ*}rwt>DPQuzXt;tC% z64#dXybeO$C6y>)*{`;a1Lo02Nfe!gwQE|FlU5{7+`xYO`WAj!tP&+`C9bWb-?#d} zMoAQ%gtcp0lap2??mRBlmd*Z#s#Ypd!ZL+z9kl~#qa=z>!rC>h$w?~`e8=sd|1Q zre%b!tGUlm5(R!GR1&I%euHNb33wT)ujpl{#Ey-yH8%HsN+S6sty<=zL;~JYvO#Z2 zC3b9ttu(q1R}#s;YSl7dD-!Vfk_~!&DzRfDYz5PO(UM4hVyl+FvhfuaNC1V_+oUYjZQ+fCU;OP64#V{ zb!YSUgKeT^g!kcxAAJfNB~f$|sx`TTT9MePyyxSwms2I)(Pz4V5208PQu#t z`%kS%$g^Aiwy&+DQ)_ZM_Gfyx9X^5$d3H-ewI+8^D-ylS-`$;9{_c+Vqf^TWe`~*5 z`vcf0iK3HGt;rqKio}R=EE#*->gDh5+C<9;AAL^Q_&wMtiK3HGt;rqKio`d|F|j-9 zhO5NKD-u3d{_3X-VWT99PQu#t@sV1Q7*zfy?vdti;@UbowI-)yAMBXlfbZbJyz6zYZHRN0o$XP41vpBxJ5Ff3MaiT1NQnyl>CfU_<8G zl2EP59n^}%5v9-YLG#yVZK7p_dl{FV^D1nVMA1p8*5nRqMM8X^^4Di=qGg2pL}L$o z1vbR@DGAk@+(E5KoHfvVxM!Qc3~LiDBi!qof8)!rQ4&Qbp<0tWs1=E2$Cxkr_!*~{ zzYJ>=EhF4VJv*n3k|;U})tcNvtw?0{ufSkk?p13OEhF3uHyf>lYU#1Hlx1fhlVXG7 z30#M^s+F*IJ({3aB+$DxoLTB!l_=q{kKOZD!uraiB5FkfPf4-?pE~`b zieqA@mfcN{;q2LMB~;6vu}D0zG{v07)6HKy*|Y2MAlvmQ)!xBY!rJvHm0FRINVxp9 zlf8pVc(iR}Nh@LRphw%(iUdZVoc9Ahb@|&R8%vb%+<=XVt%Qvwo;9FWBru958yrPd zqJ(EZY;12OY)tg*2el%B*&x~AY@iY)Jd0yI-~23S{^qAG&16b= z&dKK5R>I~e&qh%z5>Hr;tk}E!Jr1AUPA!{7J*#FuLo1)AnSMFQSZvO#Z2B}#ZM(|ovA!h9dka#AZ2@cNPsdVMNU!n3vJ zi?$Nx!+ExrT9GJo$OXMul_+7mNW`a3XVpoVFKSxm`$pnlKisdKqxH~R_$!;OXIswu zJ>*_^%)Iz}V{V+kMf&@y1NirnC^`w%nlYPNk@({_15*y5-*Z3DRbt0Rd~y3G$;NBP z(MCxWorG%5m`$xneDaI4lZ}PDo|LP^j*a;JO&cZ~SA9+!B~f$|sx@OawIcD`)21gI zL%%vUSBV`P(evI7l8tGzxbL7OicUhcX3VBmB;Nh$+sVd)bq>u{V#h{g*??r@lRt1D zNJ$i(glf&0ZCXlv@0e8@yyx5hX+PX^mGIbzHK(kTY&c1Y)Yc&Bvfn0Y-&Z~;~vA44gCLHC3bAY&|SZtZ1ldK zI~7Wz=pLbYbhrdA|g-Swno zW9zfeuBpV1jd_4#0s(8vrI{=+0JqDmI)b zRLf&ETZ5_)%RMV4v`6Au>3W2&Y_z-|&9hQ1U2kb2mU~u8XpdCRDt#f+a{9W4&|;%` zR;s1zA1%ak&q@jHk$6^`WA_}Ht!G#6NAs*y%X4J^`O~h1u7$+2^6V+cD9?-9j)bnx zO0_gw|DW}h651o_tnhzqg!9Zcy?f15x7cX*m1;TtpO2zSXph9R@^fdj<-K6hRu_Gh zsg}2Eu~UU;Ub$YO5`Kmj71?=NU-^AzgzZm^#mf~N-dCAw`8}}cw?ZuUtd!6mv2*e} z=r|;#-n1Rc~+|B&#UDxD#UWnN(t?ecve1sFw5m5k>#u^HkxOpTK;ZZ2C70V z|E$s%zb$K|Jrd8#$6B71kJ^?Itl03gYL4xlSx3v_>C+Q!sKiH3(%K`D@Og=M(C5K_ zd*y{{`JA!b-i4u7Peuvtk$6@?Ak`5T6*qXpOs3KSb6_TlD*5e;{Gf9XV;e!9{*iFoUlEm{efvHPKCqC}TxRs4UAojr>tMHGb#vrWasz(5v+H8gidObj(M zQ6oR_17yKO#I^r`xgcr_f{~bMgF0&mCcBsl{soiWKw;6ud(U~R>gle2(Sc!#>GRaR zU3Kf$tzvkG^TBr-Mz?uI)oTxbDzBdX{Ih2UqIy;Mgal_c#PJgTo^CS|-OlsiHYyX? z6I8KXWBU46mx{uBKir6)j_{0Ex0f~B9`$9-xhdrwK^5nzly5(LA#F@IK7QnqD$mEV z<_sPZr4zHPli+NY^2I~`Y^s;v`sacw&-1co^c@nV6SF)av5k`FulfJ{{Q1Y73#vT- z%bF|okSLv)SIe6D>X0a%nB@rxX1n;m;Sc<|QIG%n z(T`MlbuDY=!9${SVwNW)xHe1q{xQGDcjduPR5?p5Yi8|3qI6=GCnT6-N_p~~_cc~G zzkL0QDrfCw&E4RTD4m$)2?^%>_@u@AH)Z3g7r(xu%6WcSb2m67N+)J{LV~+Q{O!m3 zhHU(N>-Q_FoP(D&cgsVfbYhk#B$&bDvqk>)r`Fw%|5r^FbK)UUIx))=63nhjqPKe{ z-RH!bIrI0BX%yT+@3@0gDMFGCu3@;jeU)uLTJ zRU)*f>UFf?6%}5IaFyY{tDSB=-b1QW&9Ef~8>bc3Jc)Tyd#u~}B<4n{%!$?8_8wDx zd#YljMP#NPh(oVP#99%Zdr64(Rp+F?c|@O7r`=iYtOhKvUa_x;e5rgM=sj%-sv_D& zw-rZlF=jHQ}}5Dr2xQRj;V>dUVY&5Qkooi2ZRpgN@)QI`X~a z3^tlqRC#rIzZ!^UgHK3sL_*xYbh>N)+V@svwBL7mj@PIhWU_z4NOeOf9dPIqZz%Cj0( z%m#;qPIr7l!fl`WbV`+tJabYtW}h9QQ!4u+;kHk&I&I5Fo}H;0^W%=tX`6kKaNDQw z_{*AWZ_7sB0Z=t&?H!?81NKG2ZQmy7_Cq%EE`zFZ$Jr6O{a{}t-1e=AZgFHI?_{VN t_rx8cTO9U9!foH~=x#|i@-~X9no&=;QIQjOMCn9*;(hmYmnFjOe*t`u``7>g literal 0 HcmV?d00001 diff --git a/assets/vx300s_8_gripper_prop.stl b/assets/vx300s_8_gripper_prop.stl new file mode 100644 index 0000000000000000000000000000000000000000..36099b4221155b491a2ad61fb799c7fd7d443b77 GIT binary patch literal 31684 zcmb`Qci0_OwZ<1wZ!i!DV3Zb`G(n<3EHXsrDp4{(+D58{t&! z2|4?nkC;JEX(Wl4T>Yg+&3)2ocwwg1lk zqh}1WGkxGgNv$2Mntts`raErYcVnXTAyeMor{#SNd3C@38Bbj@-k&1 zt@zHEaMPN04Q^QU{kR>jYzM1mEm_xy-yM8VOsE%}T|SFUyt^~*w{2%`Fkn^c5L#b7 z7fG&n;=sb@@;+Y{8P(o*+#1$CUpB&(K1Q@o9Pp}S*>C&by>_gXXFm7){zLEkaG(GC zuk>B2N5l^;=QGM@dac)I*_l4*w=+SwvgNG0edLb@{BdtTbY6c%s2liT3loFaf6;v0 zdH2O(t%57aS8eqFPPUfswRCKa;Oji~nzzRIS{-opsQ8+f?GRQyKj^-OCuU9BE+)!$ z1U&;2{QRrferP#g+eO=<|JZtdE8}|s^734`n{*$)IagVx#Irg_fzH#_*#v< z_v!eFa^<;V)jqE-Fyhj2PsW70>2j`!7$lDxeb=x2pZK9xY`GwLMy*M{;-QCPAFiww ztDZROB_oo>3t~du#I<7L`%_;x`j-0!^iTXyE4J)C|2?%P`Dv{=u@6_)idAQv_rA6# z4twOLm{2!yt(f39D(X}c+_z7;=AGTWk8LJQ4Ep(iaI8B1+|}*bPTD8*CWLz*Cb*X{ zAFgaUs}8#DIP)>;nZy6h=bVY&y$|2jub#cI&$s-R`~TXg|VzWVS= z2tF1QI}eN>@cwT7_RIPwez=0){K9*E-g5q^JNw@J`unuUO!CE}ZtlBwt4#*%?{65S z_ksRgc?G$5zF>n(2E1z4=Lhd@LsT{iqePAD$?Fryl?M{dSkEckp&?eg{Kdwu4pQ8Mkxh&(*D4Y#tMe z!3Q6U2^|gEwb7BK9>vQ`f>qD`Zie}|>+JR05#b?ymx^Nx6Z$qVA3Czsws~bqujnM&V-&7OqtUCnoUHokwrpXpz|^H2R# zf3B<*tL9z(VxL!KUtieQn_vqQy`K+Oy|eT+^Kr%g?f8lE6|-}|$6|t?O%>Y@#DXtg zq-2u!zxi1Ie4B04_U!o)gn9cVr_ z9dTvN2dnt}L`3OB_?_|g(7}4VBp)^Yy7+E)<=JJ`^Vwq3o?s~+6x zk@%@C+u>NX^^mQNn6=~LnCST6nlN$BT6-A1+k+3)YLy&)iCO-<_CWvgdoHu`jqlD| z$rHt@=}WFK;$MsBu7u$Giix4W`mxam|L8X>sTI@QKJh}zNO>o63z>Lf#d${0 z|F8RN=Zeqb{4K9C)gI$+?|nTSs}9^B*Wmc!vwIUkFUrJ_O>q5BTQaLwE4JKm!=+ZM zrE`DL+lOP-`7d5%#HO=v>`er`IeQW3B)fpVIozj|iE zWb<+JHQTjV758v8LMj3lCQwdu-=m6LcKS5)vGCpR%x6{H2iFLx2w0dvIn8}PFLK5s z=0mnPVE7nT#czh*1T0LToaT5tPo6o&w?m|VXoFSp`@A;+3lk`(xgS61tnvD@%*UN` zPH(U(9&z+0U||B~H20$#k6(+-iI4`+y|O$VImwe6ok|XR-v5c7-ej>^#Rt7758t{WK}#a z=}o}G1j=dd$3Y^?zVj*banblsHdz&qoO%`^Mu|6EKH!B z+FV3r{eKOZk8H$AO;*LTm)-;{OrV_Rew9Mxl({p_NAq73o2=qF)v5>_iwTrdTNM#` z^v)g4$Al4+o2=qd*s2H|iwTs|Vs>}%pbK<7D00*IX-!teqrTn*EKH!B=6;kZve9ZA z&Q}-i7mKDfSrv~uevi1+xZFwIfzBZ-Fs(7?qBcvi=VFKke$2{tR z)uxz_jfb7pWK}%#su5BVurPsgn){ia$if3|GaoPi^OPp5;<;gskcxnX36#?ut5IM4 z@N?!P-|^TctK#*U8X*+{3lk`(xnDIBIpOCY%>4D3{n)`xR>kW~H9{%^7A8qZw9pFXuE^74PZP2&o8Im_RwT z9e$CE#!WIG%hyU8tm0j{u7p$sj>QDZY3}1dM2>vpTi%CU^`Wmd*usR)gxexEckb&D zt|AgU7E~5L(H9bXJadlucxvs@4Yn}BF*+i>2v(t-=74yH10s;GZ#;_b{zlJC+4#%j#Q`- zQW3B)fpVJrXb6#Qp75)3;!gY4XIrd_<0oo_R0J$cpq%E2thxM;XPA#~PrS6nsyG&> zMo2}#!UW1`?qh#MUOVGN??Zk%>fRP2g!HYZaYP&~#IZ)b309$;=00vsv zV#|zGail_xkcxnX36yo-uF()8gPz*Sd>p>b=!{iy{6vkAihzX)l+zq>8O?L>t{vRJ zZ^o)PlA}gQMZm%Y%KGlo$Ptm#&mLm!*#5wSGgig1CN)AT0v0AvPA#5A;~qDA!NxvU z?{G}UsyG6sMo2}#!UW1`j>wv8m)q{Mn>FX;j8z=H)0L2lz_FM>In90SkM<=`o^S2= z+u}1bR>jdmH9{%^7A8THDah)B)RRp3jIZ87mK7FH|D;f6WnHgJ{K-@`c(WW8=;VJ@Ar5v3S692do z5eNVCz{wd~n80p-TEwsvgsTX|x^hfFNL(}9ul9=!-v5}4ElgmyKP@5$3c^(cB4{`! zAS9;jV$Yx~I_KbwElglHQ&({;vZf$hMIdg0_dG*l*huS3syP2u&*NYT{ zs|bw{Q186w84^F3VSS?9an|UJEleOjKv%*v4n(9NTty&SfTIXP;;!|qZ#3JtUEWa21i5 zcaC8SiC5P?)xSUFqvK|^c*MdZ86K~Q6ojjY#Kt&0k_ibNAve7b9aFb-9Nk}x&j(OO z6tj+Z_3sluLe~29B3Om8jf0iYF}3&Mbc8&gRXX;y`7X*&Q1j;rJ)?P%% z)Yc9iA@9yA9s8OOAKkPn0>@$kWg7?U(REC1K6HdUhE+QDH6K-MRBr+nCQ!CySM90+TLr2IBR_T3ZK73Trst6p536yP2tv>K` zng5gTYTj4n=f?C-ZxSO|#dl>yC}xC@plkbk*U#egI$PP#wh*(eyEWw(BOQWOdNqxx zVz#>w!pCAluZPi?6@*{1XjMLBo&RVrJ~Dtuj$=Kkvno>QBL4uL4v zH21ODh}ll_D$2VY0gw;JD#VDV6iH5mhy3+$+;Sdq;5(Ky?|jG7Ay~!Zhu#ERn7}tQ zseMDEhp*06@vRK%%k7AWvR1-ZO7C#HYJQ%{?K2-G;aG)!7qiBmL~xfd5%#o-vXufEs%=s2ZF~}i0e!#UbGx1D&Ptqj#Y>@)seTxZ1ZRk9?Dv=g$W*` zh6G!f;QQE!POVslsB)c6c4E)FJcGi=VuGLluvXkB@}0qFJ**Y0@O_N#>F8H<5usRo z1)1QxC-6~xC4_5>*!(p2Uj{`!TVi0n`E>RW(S-B(QX?nPOJZx3|l-T9`0dg@Ng z`B+SFpKmSi5Qs2M?Rzd>#}C)ry}WEWVmVWb|3~bx&QkQd0DcP0M@cwVA#z!FvpTWP z81tm64jPr`o_*EtpwJ;ztV z?+IS5;~pcd6{~pdttSz@qnHR+)#&UBTXj1oFcI#nu@8Qpb*yD~eieIOuE`MLScS;-H1`ql++(QTerP#cnBd+O z@}lLARfxdXw^}Doe^os-6a1DaDpmA8{AS@jT7DCSwPF?Txb`H9ueR`3V}h?u=z~?f z;~Ei);q0=7iRhYl2!6kE-NRjdFE4$tiX(F)qT_=tOoY)1?1NPtvl|f|A8cVFjK)=Y zhu|1Nj^*PcL0;a8tm4SLi0JrW6-UiQge!fpieuv3S!R_E^voI=*YE^ud!ZBWm#o{BG4_BTmj^*N* ztBB}YD<;DDEAvu3wS13qWH+CYpjN^vj=GMBPOaF&L>Ph1wc-|XY-Jb&=^d2kid)E$ zV0>jGaa|GN-PlZ+ElluzY(6>!w~%AO`HUFhN*}D^$nJ>f_+SeY{M-aS9G^vw z_~iD51gkiHGa@>*Vha=etk_z3(<8bT-rx}c%C;`v$M5-W1gjDs6Hp_pC1_5@YnJhf zC%y}T)Yr;i6IP)N6@PCcGUeD4tsR?8ySKshMH#i?uj@L5)CpGc=tJb$Espd)Wa*q& z8?1`I48%C78vzRwJVwz7y6ImsANTGwtjVhQdqs?cx)HE25srOk|9VgJ@$%rUnyljQ zc2`C4Y#U$U^PE~_*5f;xkDa&NwaLegzZ1q>y&C}w6Fl=4nY8I9=41HS{hF+bzhuVj zz8e7x6XA^hw1L&l$E(L5(qt7@rgVQ;*T_~yVC{_wUe^-Y=bnSS4|m)b)@kxw24&=N z;#H$=1gjETjS7jSFC1Y$ZkhR7gDoh72v?(Gf>p>T6B0kX0MFnR`8^G`pbUanKSg4K zRmgG^5*yB(XzjRf!9@+WpbUc7NJV0TRmh$c5)V9VyM1ol(YrR-f-;D3?KLJ?g=|eB zG50gr?OXo2E61<}We~igr*TUW!K%bo2SZ}rzhJj-_nH5g#}<@9@QR*DLAZ)wm3|?u zxkW-^`1Sa@=B-q`! zRmj{D679RbY0vp9pSZcj7L-Bou9HYXxQbvEvVeue-lN8wkEw6}sl^tQLGb#6NI|%Y zU{zv!ULkS!#)q1Z7p@zeu?1xiyka3z5UwIvmDuV>Nc`Z6{mjQB_m9Zff-(qRvCt?B z5UwIvmDqYoNGyG9wE6hqHalf(K^X+kclE6d!c_#T5?e0`iAx7>X+E;=@0GCyWe_~y z6)6Z;5v)QEvXI#Fn6=Euvewv)EhvNF`L4zef^ZeVDr8s)i9dYmV+}tpdG_qd#rp$q z1AdqAzM)7jf>kId#jfSRis{~m``L;!o2=qp#IA%?1dhc7%E`n6J;zjR?k_o55JRRrb(P$i}ciO;3y zn2)Ld9MfV86Pq8tr`{K7{_^oa9pU8+^a(3l?SF+ zJI2rWj|N+qxN7gA=3~ZTC#a8ta20{$LY3rR6%uFs_AK+U?6apf*uuo3c?;(G>oIir zMDN(( zT$V3su!V`am#?K7{Vx6XM12&5s|XwyD$OUPs*qUY8;6>Yb+#YeWD66AE}URK4n69- z>Z2fBMc}wlCAn9H#EnnyXFhH}Wki!LOx(ELEc3D8?wRVNAY4V@xKJgzSB1nILw7YF zvzPDKWD65#p1aI^ymi~f>Z2fBMc}wlCAn9H#Jk&XX+91)X|E<*nE2FHA0F`6~^ZZo*IGno3Tx{FrjZ}^P#zr)JH+MiokK9viEsAB=qo3|I?pq z@`?xdkKyWvm*T&Y;G7&>rWFhvSy(9)hVf(^Ok` zQmm|B(bWj9JNLo79#ps}YQ-wL&=2?)>KFEHU3<5(ehJ^!6}_ha zd;M}UY=`6X!_P`|u3UL`S;cpLPr~Pc>?_YZ6S}8of3F#7QLBy*R`H$RlMuErp?gK< zL%+MLwOrS!2YjtGvq@W5pslPKNLF&L_`LJGgs+nnKir9|;x|K2BDm&E@HsRWuDl+s z;x|J?D2BV8EllupQ#7L>_&LzM!ajfA^sCP{KQ~6W(g&+_=g$cJhBGDb7MaAf4G9W5^u-V90_gRwX(A2 zRf~PNvR16py{XKfQO!&c6H*fVr0UL(`Ous`G12kCD&0LXLh~HPMCl`FITN~*VzlPo z3HuV^zE<}sOr^OWV;`<;2di{H$_UN%5ff6LUA`Vn=-!Lbn#H45E4JuWkATI|D> zwPKa-u^6FQHDW@#)rtwe7gVhBlF)rF8*OXGgSPH-**&J23EH}Qruh{tLqhHOV3qF5 z*Z=(`f1B~9DWi(nP^b|RWr&HM0q z)tanAKbY9~p)29@suhIgRckX5_M)0s&3tHnN>=T$2R%d6IAf}b?Yt7bklOIm|f zc)AjM2D=hIuUbJ^UbQw8{A^lYHS?ia(i*J7GpIS@^{MSj_`GTbf!=@#eu70bubTPL zENKl^;R)7NReiR*5iOnGemY*5c!0RAYIsgZXENkczOpYHcQXOyutm|8q_MKVI47 z6$H$qYHI+V5X?X9Usow+@rlocQ_MfGV&QfEXFddT0L!7@#@rzB8DWaq1lCa?FA44$ zxF^EMAPHyNRx8Xua4hzL89IaXo5llWXXD`^KGiwQm>){e5}{@(@Y^Iv-UIWpG} zb87n+V=w}6<@I0{uXsg7#|K-Oz+BXFz|?%OidXI;qV!R$GvHWE@Y=1z&vtQhn@y?t;W#l2lbROia(&gcP{;Qlx~S6E>|AB7bJ%XQ!TIrq8l z`}}?7*D0|ckoc@+y$Ru-fe9Wh2etCK?#+ikF1NNPA#7oSN6zNMm3Jbm_zv$$2tUuf zHxcy=9UrXX9g~RAs^N{p7AE*92;0Fb-ua1$(nqn@hqo6K{4|@7l5qS)@l(X-Fsv1; zFe}!mr_KsXw|5jDiwS-ru-_FPQ}Y-;YPl<)4_5KaA|lFm1XqxW@Lj99aWh4HZrqH=gWLy)*Sr_O zDwHh)uC`pW>3Sbdv*~86itno$Ar%1&6DV5-T=k*Zbj^om)6G~F-}yB{DgqWJP__)X z>O-^Xnh(vUo3Sc>9&3bD1T0LTY#DIXhi20?ADT@!V^#d#tr0%|Zb87p1j_oAxxU*i zn{LZr56z~Vv5I?~u7uCOTM#%F6DZr)5$Z#;>6#DCrkk-U?%`^LR0J$cpo}$Z%cg5S zG@EY5Dt;cj5>gR37859223&22X45qvnoT!j6+hcu38@GiiwRzt6wz$Dx)Li+v*~86 ziu)4FnX9!b2%mqqAYfqv<#K&jv+0iUJ~TIO#;Ults}Vk%Zb87p1j?2HS8Ju&bQ|7> z=Eluf75Bk4!e`Sh2w0dv*)rg&56z})J~TIO#wvbOcO`r_-Gacem_S+g*lZ11v+0@- z&5fI}iu>BGgwLj15I7bSD3^P}noZYyXl~q$Rq+V0M)+*H1px~aC|d?xJy)7dx9P8k z=Eluf6^~?VgwLj15U?eHx&;9X6TJUv*>uf^=Eluf z#WU=#gj9rO(`_?>GWJz1o38oL+_)L5;u(F7@Y!?=0v0AvwhXv>t~8sj`Ow_B8LQ$o zhZ^Ct=@tYmOrUHTaMg!q(={KO8@I(OUUTS5_-wibfnza&vSq+kADT_qd}wam7OQy8 zp)29D=@tZz#RSTlB!R`EQcE8(;076gvP1j=PZ$_+ar3)Ij5cu0#a VOkg%qW)~|6R}onK;5kP~{2$;m(f0rV literal 0 HcmV?d00001 diff --git a/assets/vx300s_9_gripper_bar.stl b/assets/vx300s_9_gripper_bar.stl new file mode 100644 index 0000000000000000000000000000000000000000..eba3caa21990c28559553fe0003ae379514e7215 GIT binary patch literal 379484 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:WfBSN(sYU3!tO?rYNF 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