8000 Updated Addition of FTOL (q_solver tolerance) Hyperparameter to Config #88 by Joshjppark · Pull Request #89 · talmolab/stac-mjx · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Updated Addition of FTOL (q_solver tolerance) Hyperparameter to Config #88 #89

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

Merged
merged 15 commits into from
Apr 14, 2025

Conversation

Joshjppark
Copy link
Contributor
@Joshjppark Joshjppark commented Mar 8, 2025

Second pr, first one closed because of failed linting checks and faulty files paths used in tester file. Linting and pytest updated.

Addresses issue #27 by implementing FTOL (tolerance) hyperparameter to pass into q_solver attribute in new StacCore object in stac_core.py. FTOL hyperparameter found in model config file.

Newly defined StacCore object has three attributes: opt, q_solver, m_solver. These were previously global variables defined during the python file import but now are added to the StacCore to pass in hyperparameter arguments (namely FTOL). The StacCore object has two functions, q_opt and m_opt, which are wrappers for the previously defined q_opt and m_opt functions. These functions use the q_solver and m_solver instance attributes, so wrapper functions were made to use the partial decorator for jit compilations to bypass 'dynamic' input types.

Stac.py was updated to add the StacCore object as a Stac instance attribute, and ComputeStac was updated to pass in the StacCore object as an argument into optimization functions to access the q_opt and m_opt functions.

Test file ran to ensure right object types of StacCore instance attributes, correct tolerance hyperparameters were being passed in, and JIT was compiling correctly with the partial decorator

Summary by CodeRabbit

  • New Features
    • Introduced a new StacCore class for improved organization and modularity in optimization processes.
    • Added a new parameter to key optimization functions for enhanced flexibility.
  • Refactor
    • Updated method signatures to accommodate the new StacCore instance, enhancing the optimization workflow.
    • Modified existing methods to utilize the new stac_core_obj for optimization processes.
  • Tests
    • Introduced tests for the StacCore class and the compilation process to ensure functionality and correctness.

@Joshjppark Joshjppark added the enhancement New feature or request label Mar 8, 2025
@Joshjppark Joshjppark requested a review from talmo March 8, 2025 00:14
@Joshjppark Joshjppark self-assigned this Mar 8, 2025
Copy link
Contributor
coderabbitai bot commented Mar 8, 2025

Walkthrough

The changes update the optimization workflow by introducing a new parameter, stac_core_obj, across several functions. In compute_stac.py, direct calls to global methods are replaced with calls on this new object. In stac.py, a new instance variable is created and passed to the optimization functions. The stac_core.py file is refactored by encapsulating optimization methods within a new StacCore class and utilizing JIT partial functions. A new test file, tests/test_stac_core.py, validates the instantiation and behavior of the new structure.

Changes

File(s) Change Summary
stac_mjx/compute_stac.py
stac_mjx/stac.py
Updated function and method signatures to include the stac_core_obj parameter; replaced direct global calls with instance method calls on stac_core_obj.
stac_mjx/stac_core.py Refactored optimization functions into the new StacCore class; introduced private partial JIT-wrapped methods and removed global solver variables.
tests/test_stac_core.py Added new tests to verify the correct instantiation of StacCore and to check that optimization compilation behaves as expected.

Sequence Diagram(s)

sequenceDiagram
    participant S as Stac Class
    participant CS as Compute STAC Module
    participant SC as StacCore Instance

    S->>S: Instantiate stac_core_obj
    S->>CS: Call optimization functions (root, offset, pose) with stac_core_obj
    CS->>SC: Invoke q_opt / m_opt methods on stac_core_obj
    SC-->>CS: Return optimization results
    CS-->>S: Return final outputs
Loading

Possibly related PRs

  • Remove globals #43: The changes in the main PR, which involve modifying function signatures to include a stac_core_obj parameter for optimization functions, are directly related to the retrieved PR, as it also introduces a new STAC class that manages similar optimization functions and requires the stac_core_obj for its operations.
  • Merge initial mouse work.  #57: The changes in the main PR, which involve modifying the optimization functions to utilize a new stac_core_obj parameter, are related to the retrieved PR as it also involves the compute_stac.root_optimization() function, indicating a direct connection in the optimization logic.
  • Save output data as h5 #84: The changes in the main PR are related to modifications in the stac_mjx/stac.py file, where the new stac_core_obj parameter is passed to optimization functions, aligning with updates in the fit_offsets method that also utilizes stac_core_obj.

Suggested reviewers

  • charles-zhng
  • talmo

Poem

I'm a rabbit with a hop so spry,
New code changes make my whiskers fly.
StacCore leads the optimization parade,
With stac_core_obj, the bugs start to fade.
Hoppings of joy in every line displayed!
🐰 Happy coding in this burrow of upgrades!

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (8)
stac_mjx/stac_core.py (6)

147-151: Add parameter and return details to the docstring.
While the docstring briefly describes the squared-error operation, consider including param/return entries to maintain consistency with other functions:
• Clarify the expected shape/type of x.
• Clarify the scalar or array returned.


153-187: Use a structured logging approach instead of raw prints.
The try-except block currently prints errors to stdout, making them harder to filter or search. Leveraging loggers (e.g., Python’s logging library) would provide more control and align better with production-level best practices.

 try:
     return mjx_data, q_solver.run(
         ...
     )
 except ValueError as ex:
-    print("Warning: optimization failed.", flush=True)
-    print(ex, flush=True)
+    import logging
+    logger = logging.getLogger(__name__)
+    logger.warning("Optimization failed: %s", ex)

234-239: Address docstring style issues (line 234).
The docstring triggers several style warnings (D205, D212, D415). Make sure the first line is a one-sentence summary ending with punctuation, with a blank line before detail sentences.

🧰 Tools
🪛 GitHub Actions: CI

[warning] 234-234: D205: 1 blank line required between summary line and description (found 0)


[warning] 234-234: D212: Multi-line docstring summary should start at the first line


[warning] 234-234: D415: First line should end with a period, question mark, or exclamation point (not 'o')


243-249: Document the init method.
A direct docstring on the __init__ method will address the D107 warning and help clarify the meaning of the tol parameter.

🧰 Tools
🪛 GitHub Actions: CI

[warning] 243-243: D107: Missing docstring in init


263-279: Fix docstring format for q_opt.
The docstring summary line should end with a period, and a blank line should separate the summary from the detailed description.

🧰 Tools
🪛 GitHub Actions: CI

[warning] 263-263: D205: 1 blank line required between summary line and description (found 0)


[warning] 263-263: D212: Multi-line docstring summary should start at the first line


[warning] 263-263: D415: First line should end with a period, question mark, or exclamation point (not ')')


[warning] 263-263: D402: First line should not be the function's 'signature'


293-310: Refine docstring format for m_opt.
Similar style warnings (D205, D212, D415, D402) apply. Ensure the summary line is on the first line and ends with punctuation, and avoid putting the function signature in the summary line.

🧰 Tools
🪛 GitHub Actions: CI

[warning] 293-293: D205: 1 blank line required between summary line and description (found 0)


[warning] 293-293: D212: Multi-line docstring summary should start at the first line


[warning] 293-293: D415: First line should end with a period, question mark, or exclamation point (not ')')


[warning] 293-293: D402: First line should not be the function's 'signature'

tests/test_stac_core.py (1)

26-26: Avoid referencing internal/private fields.
optax._src.base.GradientTransformationExtraArgs is a private API that may change without notice. Consider asserting a public type or verifying behavior in a more stable way.

stac_mjx/compute_stac.py (1)

13-280: Consider updating function docstrings to reflect the new StacCore parameter

While the code changes are correct, the docstrings for all three functions (root_optimization, offset_optimization, and pose_optimization) have not been updated to include documentation for the new stac_core_obj parameter. This would improve code maintainability and help future developers understand the purpose of this parameter.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a7f543 and 4c79d04.

📒 Files selected for processing (4)
  • stac_mjx/compute_stac.py (8 hunks)
  • stac_mjx/stac.py (11 hunks)
  • stac_mjx/stac_core.py (3 hunks)
  • tests/test_stac_core.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
tests/test_stac_core.py

1-1: pytest imported but unused

Remove unused import: pytest

(F401)


3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)

🪛 GitHub Actions: CI
tests/test_stac_core.py

[error] 43-43: FileNotFoundError: [Errno 2] Unable to synchronously open file (unable to open file: name = '/home/runner/work/stac-mjx/tests/data/test_rodent_mocap_1000_frames.nwb', errno = 2, error message = 'No such file or directory')


[warning] 16-16: DeprecationWarning: jax.lib.xla_bridge.get_backend is deprecated; use jax.extend.backend.get_backend.

stac_mjx/stac_core.py

[warning] 234-234: D205: 1 blank line required between summary line and description (found 0)


[warning] 234-234: D212: Multi-line docstring summary should start at the first line


[warning] 234-234: D415: First line should end with a period, question mark, or exclamation point (not 'o')


[warning] 243-243: D107: Missing docstring in init


[warning] 263-263: D205: 1 blank line required between summary line and description (found 0)


[warning] 263-263: D212: Multi-line docstring summary should start at the first line


[warning] 263-263: D415: First line should end with a period, question mark, or exclamation point (not ')')


[warning] 263-263: D402: First line should not be the function's 'signature'


[warning] 293-293: D205: 1 blank line required between summary line and description (found 0)


[warning] 293-293: D212: Multi-line docstring summary should start at the first line


[warning] 293-293: D415: First line should end with a period, question mark, or exclamation point (not ')')


[warning] 293-293: D402: First line should not be the function's 'signature'

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Tests (ubuntu-latest, Python 3.11)
  • GitHub Check: Lint
🔇 Additional comments (17)
stac_mjx/stac_core.py (2)

7-7: No concerns for the new import.
This import is standard practice for enabling partial application.


189-201: Consider symmetry in error handling.
Unlike _q_opt, _m_opt does not handle solver errors. If failures are possible here, adding a similar try-except block or a graceful fallback might keep the code consistent and robust.

stac_mjx/stac.py (5)

15-15: Imports look good.
No concerns about the new stac_core import. This improves modularity.


72-72: Initialize attribute consistently.
Defining self.stac_core_obj = None clarifies the attribute’s presence. Good approach for lazy initialization later on.


234-235: Great use of tolerances from config.
Passing self.cfg.model.FTOL ensures the solver respects user-configured tolerance. Good design for future maintainability.


244-296: Coordination with compute_stac calls is cohesive.
Your approach to pass the stac_core_obj into each optimization function ensures consistent usage of the new solver-based architecture.


344-346: Lazy instantiation logic.
Creating the StacCore object if it does not exist ensures the class's usage remains flexible and memory-safe.

tests/test_stac_core.py (2)

16-37: Redundant config usage.
The function signature includes config, mouse_config, yet you overwrite config from disk within the function. This might be confusing if the fixture config is needed. Validate whether you intend to reuse the fixture config or the reloaded config.

🧰 Tools
🪛 GitHub Actions: CI

[warning] 16-16: DeprecationWarning: jax.lib.xla_bridge.get_backend is deprecated; use jax.extend.backend.get_backend.


43-43: Check file paths or fixtures for the missing NWB file.
The test fails because the NWB file is not found. Ensure correct fixture usage or local test data.

Would you like to verify the path with a shell script to list available test files in the repository?

🧰 Tools
🪛 GitHub Actions: CI

[error] 43-43: FileNotFoundError: [Errno 2] Unable to synchronously open file (unable to open file: name = '/home/runner/work/stac-mjx/tests/data/test_rodent_mocap_1000_frames.nwb', errno = 2, error message = 'No such file or directory')

stac_mjx/compute_stac.py (8)

13-14: Function signature updated with StacCore parameter

This change aligns with the PR objective of transitioning from global variables to a StacCore object that encapsulates the optimization methods. The new parameter allows for customization of the optimization process through configurable hyperparameters like FTOL.


55-56: Method call updated to use StacCore object

The call has been correctly updated from a global method to the method on the StacCore object, allowing access to the encapsulated optimization logic and hyperparameters.


82-83: Method call updated to use StacCore object

Consistent with the first change, this call has been properly updated to use the StacCore object's method.


107-108: Function signature updated with StacCore parameter

Similar to the root_optimization function, the offset_optimization signature has been updated to include the StacCore object parameter, maintaining consistency across the API.


151-152: Method call updated to use StacCore object's m_opt

The m_opt method call has been correctly updated to use the StacCore object, aligning with the PR objective of encapsulating previously global optimization methods.


179-180: Function signature updated with StacCore parameter

The pose_optimization function signature has been consistently updated to include the StacCore object parameter, completing the refactoring across all optimization functions.


220-221: Method call updated to use StacCore object

This call within the pose_optimization function has been correctly updated to use the StacCore object's q_opt method.


237-238: Method call updated to use StacCore object

The second q_opt call within the pose_optimization function has been properly updated to use the StacCore object's method.

Comment on lines +1 to +8
import pytest
import stac_mjx
from dm_control import mjcf
import dm_control
from pathlib import Path
import mujoco
from stac_mjx.utils import mjx_load
import stac_mjx
Copy link
Contributor

Choose a reason for hiding this comment

Th 8000 e reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unused imports.
Static analysis flags unused imports (pytest, dm_control, mujoco, etc.) and a redefinition of stac_mjx. Consider removing extraneous imports to improve clarity and abide by lint rules.

- import pytest
- import dm_control
- import mujoco
- from stac_mjx.utils import mjx_load
- import stac_mjx
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import pytest
import stac_mjx
from dm_control import mjcf
import dm_control
from pathlib import Path
import mujoco
from stac_mjx.utils import mjx_load
import stac_mjx
import stac_mjx
from dm_control import mjcf
from pathlib import Path
🧰 Tools
🪛 Ruff (0.8.2)

1-1: pytest imported but unused

Remove unused import: pytest

(F401)


3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)

@Joshjppark Joshjppark closed this Mar 10, 2025
@Joshjppark Joshjppark reopened this Mar 10, 2025
Copy link
codecov bot commented Mar 10, 2025

Codecov Report

Attention: Patch coverage is 44.11765% with 19 lines in your changes missing coverage. Please review.

Project coverage is 45.13%. Comparing base (2a7f543) to head (26a6fad).
Report is 16 commits behind head on main.

Files with missing lines Patch % Lines
stac_mjx/stac_core.py 54.16% 11 Missing ⚠️
stac_mjx/compute_stac.py 0.00% 5 Missing ⚠️
stac_mjx/stac.py 40.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #89      +/-   ##
==========================================
+ Coverage   44.83%   45.13%   +0.30%     
==========================================
  Files           9        9              
  Lines         678      689      +11     
==========================================
+ Hits          304      311       +7     
- Misses        374      378       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
tests/test_stac_core.py (1)

39-57: 💡 Verification agent

🧩 Analysis chain

Test function has commented out assertions and lacks validation.

The test loads configurations and data but doesn't actually execute the core functionality it's meant to test as the call to run_stac is commented out. This makes the test ineffective for validating the compilation behavior.

Either uncomment the critical lines or add explicit comments explaining why the test is designed this way (perhaps it's intentionally a partial test that only checks initial conditions).


🌐 Web query:

What are best practices for handling long-running tests in Python?

💡 Result:

To handle long-running tests in Python effectively, developers should focus on optimization strategies, efficient resource management, and smart test execution. Here are key best practices:

Identify Performance Bottlenecks

  • Profile test durations using pytest's --durations flag to pinpoint slow tests[1][13].
  • Analyze test collection time by restricting test discovery to relevant directories or using -k for keyword filtering[1][6].

Optimize Test Execution

  • Parallelize tests with pytest-xdist to leverage multi-core systems[1][6][7].
  • Run subsets selectively using file paths or test markers to avoid unnecessary executions[1][6].
  • Implement incremental testing to run only tests affected by code changes (requires custom tooling or plugins like pytest-testmon)[7].

Improve Test Efficiency

  • Mock external dependencies (APIs, databases) to eliminate I/O delays[5][6][17].
  • Replace time.sleep() with conditional polling or asynchronous waiting[1][6].
  • Use session/module-scoped fixtures to minimize repeated setup/teardown[1][5].

Manage Long-Running Tests

  • Set timeouts with pytest-timeout to prevent hanging tests (via decorators or CLI)[2].
  • Separate slow tests into dedicated suites for scheduled/on-demand execution[5][17].
  • Leverage background tasks in frameworks like FastAPI for non-blocking workflows[9].

Maintain Test Health

  • Avoid redundant assertions by testing one concern per method[5].
  • Profile regularly to catch new performance issues early[1][6].
  • Optimize database interactions with transaction rollbacks or in-memory databases[1][6].

For critical systems, consider asynchronous execution patterns and state management for reliable long-running processes[8][11]. Always balance test coverage with execution speed—fast feedback loops are crucial for developer productivity[3][5][17].

Citations:


Action Required: Update the Test to Clearly Address Long-Running Behavior

  • The test currently does not execute the core functionality because the call to run_stac and its associated assertions are commented out.
  • Given that the test is intentionally disabled due to long runtime without a GPU, consider using a pytest marker (for example, @pytest.mark.slow or @pytest.mark.skipif) to clearly indicate that this is a long-running test rather than simply commenting it out.
  • If the decision to omit these assertions is intentional (e.g., to reduce execution time during regular testing), please add an explicit comment documenting the rationale and any conditions under which the full test should be run (such as in a dedicated performance testing suite).
🧹 Nitpick comments (1)
tests/test_stac_core.py (1)

16-37: Unused function parameter and missing documentation.

The mouse_config parameter isn't used in the function and there's no docstring explaining the purpose of the test.

-def test_stac_core_obj(config, mouse_config):
+def test_stac_core_obj(config):
+    """Test that StacCore objects are created with correct types and tolerance values."""

Also, consider adding assertions with messages to make test failures more informative.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c79d04 and b80c566.

📒 Files selected for processing (2)
  • stac_mjx/stac_core.py (3 hunks)
  • tests/test_stac_core.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
tests/test_stac_core.py

1-1: pytest imported but unused

Remove unused import: pytest

(F401)


3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Tests (ubuntu-latest, Python 3.11)
  • GitHub Check: Lint
🔇 Additional comments (7)
tests/test_stac_core.py (1)

1-11: Remove unused imports to improve code clarity.

Several imports in this file are unused and should be removed to comply with linting rules:

-import pytest
 import stac_mjx
-from dm_control import mjcf
-import dm_control
 from pathlib import Path
-import mujoco
-from stac_mjx.utils import mjx_load
-import stac_mjx
 import optax
 import jaxopt

The stac_mjx module is imported twice (lines 2 and 8).

🧰 Tools
🪛 Ruff (0.8.2)

1-1: pytest imported but unused

Remove unused import: pytest

(F401)


3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)

stac_mjx/stac_core.py (6)

148-151: Implementation of squared_error function looks good.

The squared_error function is a simple utility function that computes the sum of squared elements in a vector, which is appropriate for its use in the optimization.


153-187: Well-structured optimization function with proper error handling.

The _q_opt function correctly applies JIT compilation with static arguments for the solver, which allows for better performance by reusing compilations when only the data changes but not the solver. The error handling is also properly implemented to catch optimization failures.


189-230: Good use of partial JIT for optimization function.

The _m_opt function correctly applies partial JIT compilation with static_argnames for the solver parameter, which improves performance when reusing the function with the same solver but different data.


233-256: Well-documented class initialization with configurable tolerance.

The StacCore class provides a clear encapsulation of the optimization solvers with proper documentation. The tolerance parameter for the q_solver is correctly implemented, allowing for configuration of the FTOL hyperparameter as required.


257-286: Well-designed wrapper method for optimization.

The q_opt method provides a clean interface to the underlying _q_opt function, passing the class's solver instance along with the other parameters. This design effectively encapsulates the optimization logic.


287-329: Comprehensive documentation for m_opt method.

The m_opt method is well-documented with clear parameter descriptions and properly delegates to the _m_opt function with the class's solver instance.

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
tests/test_stac_core.py (1)

39-57: Consider enabling the commented test assertions

The test is designed to verify JIT compilation cache sizes, but the assertions after running run_stac are commented out, making this test incomplete.

If the test is too slow without a GPU, consider:

  1. Adding a proper skip condition using pytest markers
  2. Or including a clear comment explaining why assertions are disabled
def test_stac_core_compilations():
    # tests cache sizes of jit compiled functions
-   # run time is long without gpu so commented out
-   # tests after run_stac
+   # NOTE: Full test requires GPU and is slow.
+   # Uncomment the assertions below when running with GPU support.

    config = stac_mjx.load_configs(TEST_DIR / "configs")
    stac_mjx.enable_xla_flags()

    assert stac_mjx.stac_core.m_loss._cache_size() == 0
    assert stac_mjx.stac_core._m_opt._cache_size() == 0
    assert stac_mjx.stac_core._q_opt._cache_size() == 0

    kp_data, sorted_kp_names = stac_mjx.load_mocap(config, base_path=PROJECT_DIR)
+   
+   # Skip full test if running without GPU
+   import os
+   if os.environ.get("TEST_WITH_GPU") != "1":
+       return
+       
    # _, _ = stac_mjx.run_stac(config, kp_data, sorted_kp_names, base_path=PROJECT_DIR)

    # assert stac_mjx.stac_core.m_loss._cache_size() == 0
    # assert stac_mjx.stac_core._q_opt._cache_size() == 2
    # assert stac_mjx.stac_core._m_opt._cache_size() == 2
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b80c566 and 958d357.

📒 Files selected for processing (2)
  • stac_mjx/stac_core.py (3 hunks)
  • tests/test_stac_core.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
tests/test_stac_core.py

1-1: pytest imported but unused

Remove unused import: pytest

(F401)


3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Tests (ubuntu-latest, Python 3.11)
  • GitHub Check: Lint
🔇 Additional comments (9)
tests/test_stac_core.py (2)

1-8: Remove unused imports.

Several imports are flagged as unused by the static analyzer. Consider removing these to improve code cleanliness.

- import pytest
- import stac_mjx
- from dm_control import mjcf
- import dm_control
from pathlib import Path
- import mujoco
- from stac_mjx.utils import mjx_load
- import stac_mjx
+ import stac_mjx
import optax
import jaxopt
🧰 Tools
🪛 Ruff (0.8.2)

1-1: pytest imported but unused

Remove unused import: pytest

(F401)


3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)


16-37: Unit testing of StacCore object initialization - LGTM!

The test function properly verifies:

  1. The instance type is correct
  2. Instance variables have the expected types
  3. The tolerance parameter is correctly applied to the q_solver

This effectively validates the new StacCore functionality and the FTOL parameter implementation.

stac_mjx/stac_core.py (7)

7-7: Good addition of partial import for JIT optimization.

The partial decorator allows for better optimization of JIT-compiled functions with static arguments. This is a good practice for performance improvement when using JAX.


148-151: Function reintroduction looks good.

The squared_error function has been reintroduced as a separate utility function, which makes the code more modular and easier to maintain.


153-187: Good refactoring of q_opt into _q_opt with partial JIT.

The refactoring of q_opt into a private function _q_opt with @partial(jit, static_argnames=["q_solver"]) is a good improvement. It allows the solver to be passed as an argument while maintaining JIT optimization by marking it as a static argument.

The error handling is also well-maintained in this refactoring.


189-231: Good refactoring of m_opt into _m_opt with partial JIT.

Similar to the q_opt refactoring, moving the logic to a private function with partial JIT optimization is a good approach. The function maintains the same core logic while allowing the solver to be passed as an argument.


233-255: Well-designed StacCore class with good documentation.

The new StacCore class effectively encapsulates the optimization components that were previously global variables. The class documentation and constructor documentation are clear and informative.

The implementation of the FTOL parameter as a tolerance for the q_solver addresses the requirements from issue #27 mentioned in the PR objectives.


256-285: Good wrapper implementation for q_opt.

This wrapper method properly delegates to the private _q_opt function while passing the instance's q_solver. The documentation is clear and explains the function's purpose well.


286-329: Good wrapper implementation for m_opt with thorough documentation.

The m_opt wrapper method is well-implemented and includes comprehensive documentation that explains parameters and return values. This maintains the same interface while encapsulating the implementation details.

Comment on lines 12 to 13
TEST_DIR = Path(__file__).parent
PROJECT_DIR = TEST_DIR.parent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad pattern here -- use fixtures instead of hardcoding even relative paths

Copy link
Contributor
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
tests/test_stac_core.py (1)

46-64: 🛠️ Refactor suggestion

Improve test completeness and robustness.

The test has commented-out assertions that don't run, making it incomplete. Additionally, it accesses internal functions with leading underscores (_cache_size(), _m_opt, etc.) which could change.

  1. Consider moving the long-running tests to a separate file or using pytest markers to conditionally run them.
  2. Avoid accessing internal implementation details (functions with leading underscores).
-def test_stac_core_compilations(TEST_DIR, PROJECT_DIR):
+@pytest.mark.slow
+def test_stac_core_compilations(test_dir, project_dir):
     # tests cache sizes of jit compiled functions
-    # run time is long without gpu so commented out
-    # tests after run_stac
 
-    config = stac_mjx.load_configs(TEST_DIR / "configs")
+    config = stac_mjx.load_configs(test_dir / "configs")
     stac_mjx.enable_xla_flags()
 
-    assert stac_mjx.stac_core.m_loss._cache_size() == 0
-    assert stac_mjx.stac_core._m_opt._cache_size() == 0
-    assert stac_mjx.stac_core._q_opt._cache_size() == 0
+    # Create a minimal test case that doesn't require complete run_stac
+    stac_core_obj = stac_mjx.stac_core.StacCore(tol=config.model.FTOL)
+    
+    # Test some basic functionality that can validate the JIT compilation
+    # For example, test if functions are callable or if minimal inputs produce expected outputs
+    # Without accessing internal implementation details
 
-    kp_data, sorted_kp_names = stac_mjx.load_mocap(config, base_path=PROJECT_DIR)
-    # _, _ = stac_mjx.run_stac(config, kp_data, sorted_kp_names, base_path=PROJECT_DIR)
-
-    # assert stac_mjx.stac_core.m_loss._cache_size() == 0
-    # assert stac_mjx.stac_core._q_opt._cache_size() == 2
-    # assert stac_mjx.stac_core._m_opt._cache_size() == 2
+    # If we need to test cache functionality, we should create a public API
+    # or use proper test doubles/mocks

Alternatively, if the runtime is an issue, create a separate test file with the @pytest.mark.slow marker:

# tests/test_stac_core_slow.py
import pytest

@pytest.mark.slow
def test_full_stac_compilation(test_dir, project_dir):
    # Full test with run_stac that can be skipped in regular test runs
    config = stac_mjx.load_configs(test_dir / "configs")
    stac_mjx.enable_xla_flags()
    
    kp_data, sorted_kp_names = stac_mjx.load_mocap(config, base_path=project_dir)
    _, _ = stac_mjx.run_stac(config, kp_data, sorted_kp_names, base_path=project_dir)
    
    # Add assertions here to validate the run
♻️ Duplicate comments (1)
tests/test_stac_core.py (1)

1-11: 🛠️ Refactor suggestion

Clean up unused and duplicate imports.

Several imports are identified by static analysis as unused or duplicate:

  • Duplicate import of stac_mjx (lines 2 and 8)
  • Unused imports of dm_control.mjcf, dm_control, mujoco, and stac_mjx.utils.mjx_load
import pytest
import stac_mjx
-from dm_control import mjcf
-import dm_control
from pathlib import Path
-import mujoco
-from stac_mjx.utils import mjx_load
-import stac_mjx
import optax
import jaxopt
🧰 Tools
🪛 Ruff (0.8.2)

3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)

🧹 Nitpick comments (2)
tests/test_stac_core.py (2)

13-20: Follow pytest naming conventions for fixtures.

Fixture names should be lowercase and descriptive. Also, consider moving common test fixtures to a conftest.py file for reuse across multiple test files.

@pytest.fixture
-def TEST_DIR():
+def test_dir():
    return Path(__file__).parent

@pytest.fixture
-def PROJECT_DIR():
+def project_dir():
    return Path(__file__).parent.parent

32-38: Avoid directly accessing internal implementation details.

The test is checking against specific internal implementation types (._src) which makes the tests brittle to internal changes in the libraries. Consider checking against more stable interfaces.

-    assert isinstance(
-        stac_core_obj.opt, optax._src.base.GradientTransformationExtraArgs
-    )
-    assert isinstance(
-        stac_core_obj.q_solver, jaxopt._src.projected_gradient.ProjectedGradient
-    )
-    assert isinstance(stac_core_obj.m_solver, jaxopt._src.optax_wrapper.OptaxSolver)
+    # Check that the attributes exist and are of the expected high-level types
+    assert hasattr(stac_core_obj, 'opt')
+    assert hasattr(stac_core_obj, 'q_solver')
+    assert hasattr(stac_core_obj, 'm_solver')
+    
+    # Optionally check that they implement expected interfaces
+    assert hasattr(stac_core_obj.q_solver, 'tol')
+    assert hasattr(stac_core_obj.m_solver, 'update')
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2400a08 and bbb20b5.

📒 Files selected for processing (1)
  • tests/test_stac_core.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
tests/test_stac_core.py

3-3: dm_control.mjcf imported but unused

Remove unused import: dm_control.mjcf

(F401)


4-4: dm_control imported but unused

Remove unused import: dm_control

(F401)


6-6: mujoco imported but unused

Remove unused import: mujoco

(F401)


7-7: stac_mjx.utils.mjx_load imported but unused

Remove unused import: stac_mjx.utils.mjx_load

(F401)


8-8: Redefinition of unused stac_mjx from line 2

Remove definition: stac_mjx

(F811)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Lint
  • GitHub Check: Tests (ubuntu-latest, Python 3.11)
🔇 Additional comments (1)
tests/test_stac_core.py (1)

25-26:

❓ Verification inconclusive

Use hardcoded paths with caution.

Loading configurations from a relative path can be brittle and cause failures when tests are run from different directories. Consider using a more robust method to locate test configurations.

Are there other tests that use a similar pattern? You might want to create a shared fixture for configuration files.


🏁 Script executed:

#!/bin/bash
# Find other tests that use TEST_DIR / "configs"
rg -l "TEST_DIR.*configs" tests/

Length of output: 58


Ensure Reliable Configuration Path Usage

  • The pattern TEST_DIR / "configs" is currently only present in tests/test_stac_core.py (lines 25-26).
  • Using a relative path to load test configurations can be brittle if tests are executed from a directory other than the repository root.
  • Consider refactoring this approach by centralizing configuration path resolution—perhaps via a shared fixture or explicit absolute path determination—to guard against potential issues in different execution contexts.

Copy link
Collaborator
@charles-zhng charles-zhng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on my end--looks great! just the suggested variable name change and feel free to merge 👍

q_solver = ProjectedGradient(fun=q_loss, projection=projection_box, maxiter=250)
m_solver = OptaxSolver(opt=opt, fun=m_loss, maxiter=2000)
self.q_solver = ProjectedGradient(
fun=q_loss, projection=projection_box, maxiter=250, tol=tol
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change variable name to q_tol throughout so we can have an m_tol later

@Joshjppark Joshjppark merged commit 4d4395a into main Apr 14, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0