-
Notifications
You must be signed in to change notification settings - Fork 2
Merge Ricsi's second branch with first branch. #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Merge completed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR merges Task 6 and Task 4 solutions, integrating Hungarian assignment algorithm support and Hydra multi-run configuration capabilities into the formation environment codebase.
Key Changes:
- Added scipy dependency and implemented Hungarian assignment algorithm testing
- Configured Hydra multi-run sweeps for comparing greedy vs Hungarian assignment methods across multiple seeds
- Updated Docker configuration to improve build reliability with Python 3.11 and optimized layer ordering
Reviewed changes
Copilot reviewed 5 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test_env.py | Added two new test methods: one for SDF circle distance calculations and another comparing greedy vs Hungarian assignment behavior |
| requirements.txt | Added scipy dependency required for Hungarian algorithm implementation |
| pytest.ini | Configured pytest to exclude large output directories (wandb, outputs, multirun) to prevent OSErrors on Windows |
| docker/Dockerfile | Downgraded to Python 3.11, reorganized COPY commands to optimize Docker layer caching by copying requirements.txt before the full source |
| configs/experiment/sweep.yaml | Added Hydra multi-run configuration to sweep over seeds (0,1,2) and assignment methods (greedy, hungarian) |
| .gitignore | Added multirun/ directory to ignore list for Hydra sweep outputs |
| .dockerignore | Created file to exclude large folders (wandb, outputs, multirun) from Docker build context |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ], | ||
| dim=0, | ||
| ).to(self.device) | ||
| env_hungarian._FormationEnv__update_assignments() |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessing a private method using name mangling (_FormationEnv__update_assignments) bypasses encapsulation and makes the test tightly coupled to the implementation. Consider making this method protected (single underscore) or providing a public API for testing purposes, which would make tests more maintainable if the class is renamed or refactored.
| result_td = env.step(action_td) | ||
| self.assertIsNotNone(result_td) | ||
|
|
||
| def test_sdf_circle_known_points(self): |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test method name 'test_sdf_circle_known_points' uses the abbreviation 'sdf' which may not be immediately clear. Consider using a more descriptive name like 'test_signed_distance_function_circle_known_points' or 'test_circle_signed_distance_calculation' to improve test readability.
| def test_sdf_circle_known_points(self): | |
| def test_signed_distance_function_circle_known_points(self): |
| @@ -1,5 +1,8 @@ | |||
| FROM python:3.12-slim | |||
|
|
|||
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Dockerfile now includes blank lines at the beginning which are unnecessary. Consider removing the empty line at line 1 to keep the Dockerfile clean and concise.
| FROM python:3.12-slim | ||
|
|
||
| FROM python:3.11-slim | ||
|
|
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider removing the blank line after FROM statement to keep the Dockerfile more concise and follow conventional Docker formatting practices.
| def test_assignment_hungarian_is_one_to_one(self): | ||
| """Hungarian assignment should make one-to-one assignments. Greedy will prefer closer targets.""" | ||
|
|
||
| # Greedy assignment | ||
| cfg_greedy = OmegaConf.merge(self.cfg, {"env": {"num_agents": 2, "assignment_method": "greedy"}}) | ||
| env_greedy = FormationEnv(cfg=cfg_greedy, device=self.device) | ||
| # Both agents close to the same target point | ||
| target0 = env_greedy.shape_boundary_points[0].detach().cpu() | ||
| env_greedy.agent_positions = torch.stack( | ||
| [ | ||
| target0 + torch.tensor([0.01, 0.0]), | ||
| target0 + torch.tensor([0.02, 0.0]), | ||
| ], | ||
| dim=0, | ||
| ).to(self.device) | ||
| env_greedy._FormationEnv__update_assignments() | ||
| unique_greedy = torch.unique(env_greedy.assigned_target_positions.cpu(), dim=0).shape[0] | ||
|
|
||
| # Hungarian assignment | ||
| cfg_hungarian = OmegaConf.merge(self.cfg, {"env": {"num_agents": 2, "assignment_method": "hungarian"}}) | ||
| env_hungarian = FormationEnv(cfg=cfg_hungarian, device=self.device) | ||
| # Both agents close to the same target point | ||
| target0_h = env_hungarian.shape_boundary_points[0].detach().cpu() | ||
| env_hungarian.agent_positions = torch.stack( | ||
| [ | ||
| target0_h + torch.tensor([0.01, 0.0]), | ||
| target0_h + torch.tensor([0.02, 0.0]), | ||
| ], | ||
| dim=0, | ||
| ).to(self.device) | ||
| env_hungarian._FormationEnv__update_assignments() | ||
| unique_hungarian = torch.unique(env_hungarian.assigned_target_positions.cpu(), dim=0).shape[0] | ||
|
|
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test contains significant code duplication between the greedy and Hungarian assignment test sections. Consider extracting a helper method that accepts the assignment method as a parameter and returns the unique count, which would reduce duplication and improve maintainability.
| def test_assignment_hungarian_is_one_to_one(self): | |
| """Hungarian assignment should make one-to-one assignments. Greedy will prefer closer targets.""" | |
| # Greedy assignment | |
| cfg_greedy = OmegaConf.merge(self.cfg, {"env": {"num_agents": 2, "assignment_method": "greedy"}}) | |
| env_greedy = FormationEnv(cfg=cfg_greedy, device=self.device) | |
| # Both agents close to the same target point | |
| target0 = env_greedy.shape_boundary_points[0].detach().cpu() | |
| env_greedy.agent_positions = torch.stack( | |
| [ | |
| target0 + torch.tensor([0.01, 0.0]), | |
| target0 + torch.tensor([0.02, 0.0]), | |
| ], | |
| dim=0, | |
| ).to(self.device) | |
| env_greedy._FormationEnv__update_assignments() | |
| unique_greedy = torch.unique(env_greedy.assigned_target_positions.cpu(), dim=0).shape[0] | |
| # Hungarian assignment | |
| cfg_hungarian = OmegaConf.merge(self.cfg, {"env": {"num_agents": 2, "assignment_method": "hungarian"}}) | |
| env_hungarian = FormationEnv(cfg=cfg_hungarian, device=self.device) | |
| # Both agents close to the same target point | |
| target0_h = env_hungarian.shape_boundary_points[0].detach().cpu() | |
| env_hungarian.agent_positions = torch.stack( | |
| [ | |
| target0_h + torch.tensor([0.01, 0.0]), | |
| target0_h + torch.tensor([0.02, 0.0]), | |
| ], | |
| dim=0, | |
| ).to(self.device) | |
| env_hungarian._FormationEnv__update_assignments() | |
| unique_hungarian = torch.unique(env_hungarian.assigned_target_positions.cpu(), dim=0).shape[0] | |
| def _get_unique_assigned_targets(self, assignment_method: str) -> int: | |
| """Helper to compute the number of unique assigned target positions for a given method.""" | |
| cfg = OmegaConf.merge( | |
| self.cfg, | |
| {"env": {"num_agents": 2, "assignment_method": assignment_method}}, | |
| ) | |
| env = FormationEnv(cfg=cfg, device=self.device) | |
| # Both agents close to the same target point | |
| target0 = env.shape_boundary_points[0].detach().cpu() | |
| env.agent_positions = torch.stack( | |
| [ | |
| target0 + torch.tensor([0.01, 0.0]), | |
| target0 + torch.tensor([0.02, 0.0]), | |
| ], | |
| dim=0, | |
| ).to(self.device) | |
| env._FormationEnv__update_assignments() | |
| return torch.unique(env.assigned_target_positions.cpu(), dim=0).shape[0] | |
| def test_assignment_hungarian_is_one_to_one(self): | |
| """Hungarian assignment should make one-to-one assignments. Greedy will prefer closer targets.""" | |
| unique_greedy = self._get_unique_assigned_targets("greedy") | |
| unique_hungarian = self._get_unique_assigned_targets("hungarian") |
| ], | ||
| dim=0, | ||
| ).to(self.device) | ||
| env_greedy._FormationEnv__update_assignments() |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessing a private method using name mangling (_FormationEnv__update_assignments) bypasses encapsulation and makes the test tightly coupled to the implementation. Consider making this method protected (single underscore) or providing a public API for testing purposes, which would make tests more maintainable if the class is renamed or refactored.
|
|
||
| WORKDIR /app | ||
| COPY requirements.txt /app/requirements.txt | ||
| RUN pip install -r /app/requirements.txt |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RUN pip install -r /app/requirements.txt step installs third-party dependencies from PyPI without any version pinning or integrity guarantees, so each build may pull a different mutable release, including potentially compromised or typosquatted packages. Since these packages execute code at install/import time inside the build/runtime environment, an attacker controlling a dependency version could gain code execution or exfiltrate secrets. Pin all dependencies in requirements.txt to fixed versions (and ideally verify hashes) so this Docker build step only installs vetted artifacts.
Merge Task 6 solution with Task 4 solution.