openscvx 2.dev4__tar.gz → 2.dev5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. {openscvx-2.dev4/openscvx.egg-info → openscvx-2.dev5}/PKG-INFO +1 -1
  2. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mjx/cartpole_mjx.py +13 -19
  3. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mjx/double_cartpole_mjx.py +9 -18
  4. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mjx/skydio_x2_mjx.py +14 -21
  5. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mjx/triple_cartpole_3d_mjx.py +9 -18
  6. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mjx/triple_cartpole_mjx.py +10 -19
  7. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/__init__.py +4 -0
  8. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/_version.py +3 -3
  9. openscvx-2.dev5/openscvx/integrations/__init__.py +66 -0
  10. openscvx-2.dev5/openscvx/integrations/base.py +89 -0
  11. openscvx-2.dev5/openscvx/integrations/mjx.py +496 -0
  12. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/problem.py +13 -4
  13. {openscvx-2.dev4 → openscvx-2.dev5/openscvx.egg-info}/PKG-INFO +1 -1
  14. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx.egg-info/SOURCES.txt +2 -0
  15. {openscvx-2.dev4 → openscvx-2.dev5}/tests/integrations/test_mjx.py +2 -69
  16. openscvx-2.dev5/tests/integrations/test_mjx_dynamics.py +542 -0
  17. openscvx-2.dev4/openscvx/integrations/__init__.py +0 -62
  18. openscvx-2.dev4/openscvx/integrations/mjx.py +0 -323
  19. {openscvx-2.dev4 → openscvx-2.dev5}/.github/assets/logo.svg +0 -0
  20. {openscvx-2.dev4 → openscvx-2.dev5}/.github/release-drafter.yml +0 -0
  21. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/_docs.yml +0 -0
  22. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/branch-name.yml +0 -0
  23. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/docs.yml +0 -0
  24. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/lint.yml +0 -0
  25. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/nightly.yml +0 -0
  26. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/release-drafter.yml +0 -0
  27. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/release.yml +0 -0
  28. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/tests-integration.yml +0 -0
  29. {openscvx-2.dev4 → openscvx-2.dev5}/.github/workflows/tests-unit.yml +0 -0
  30. {openscvx-2.dev4 → openscvx-2.dev5}/.gitignore +0 -0
  31. {openscvx-2.dev4 → openscvx-2.dev5}/.gitmodules +0 -0
  32. {openscvx-2.dev4 → openscvx-2.dev5}/CONTRIBUTING.md +0 -0
  33. {openscvx-2.dev4 → openscvx-2.dev5}/LICENSE +0 -0
  34. {openscvx-2.dev4 → openscvx-2.dev5}/README.md +0 -0
  35. {openscvx-2.dev4 → openscvx-2.dev5}/docs/Foundations/constraint_reformulation.md +0 -0
  36. {openscvx-2.dev4 → openscvx-2.dev5}/docs/Foundations/control_parameterization.md +0 -0
  37. {openscvx-2.dev4 → openscvx-2.dev5}/docs/Foundations/discretization.md +0 -0
  38. {openscvx-2.dev4 → openscvx-2.dev5}/docs/Foundations/ocp.md +0 -0
  39. {openscvx-2.dev4 → openscvx-2.dev5}/docs/Foundations/scvx.md +0 -0
  40. {openscvx-2.dev4 → openscvx-2.dev5}/docs/Foundations/time_dilation.md +0 -0
  41. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UnderTheHood/lowering_architecture.md +0 -0
  42. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  43. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/00_introduction.md +0 -0
  44. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  45. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  46. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  47. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  48. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/05_visualization.md +0 -0
  49. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/06_logic.md +0 -0
  50. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/07_lie.md +0 -0
  51. {openscvx-2.dev4 → openscvx-2.dev5}/docs/UsersGuide/08_mpcc.md +0 -0
  52. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/favicon.png +0 -0
  53. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/images/ct-scvx_dark.png +0 -0
  54. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/images/ct-scvx_light.png +0 -0
  55. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/images/ctcs_dark.png +0 -0
  56. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/images/ctcs_light.png +0 -0
  57. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/images/problem_class_dark.png +0 -0
  58. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/images/problem_class_light.png +0 -0
  59. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/logo.svg +0 -0
  60. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/openscvx_logo_square.png +0 -0
  61. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/viser-client/index.html +0 -0
  62. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  63. {openscvx-2.dev4 → openscvx-2.dev5}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  64. {openscvx-2.dev4 → openscvx-2.dev5}/docs/citation.md +0 -0
  65. {openscvx-2.dev4 → openscvx-2.dev5}/docs/examples.md +0 -0
  66. {openscvx-2.dev4 → openscvx-2.dev5}/docs/index.md +0 -0
  67. {openscvx-2.dev4 → openscvx-2.dev5}/docs/javascripts/mathjax.js +0 -0
  68. {openscvx-2.dev4 → openscvx-2.dev5}/docs/versions.json +0 -0
  69. {openscvx-2.dev4 → openscvx-2.dev5}/examples/_viser_embed_export.py +0 -0
  70. {openscvx-2.dev4 → openscvx-2.dev5}/examples/abstract/brachistochrone.py +0 -0
  71. {openscvx-2.dev4 → openscvx-2.dev5}/examples/abstract/hypersensitive.py +0 -0
  72. {openscvx-2.dev4 → openscvx-2.dev5}/examples/abstract/impulsive.py +0 -0
  73. {openscvx-2.dev4 → openscvx-2.dev5}/examples/abstract/stl_integer_variable.py +0 -0
  74. {openscvx-2.dev4 → openscvx-2.dev5}/examples/abstract/stl_or.py +0 -0
  75. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/7_dof_arm.py +0 -0
  76. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/_camera.py +0 -0
  77. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/_render.py +0 -0
  78. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/_sensor_view.py +0 -0
  79. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/dr_vp_polytope.py +0 -0
  80. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  81. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/logo.py +0 -0
  82. {openscvx-2.dev4 → openscvx-2.dev5}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  83. {openscvx-2.dev4 → openscvx-2.dev5}/examples/arm/3_dof_arm.py +0 -0
  84. {openscvx-2.dev4 → openscvx-2.dev5}/examples/arm/7_dof_arm.py +0 -0
  85. {openscvx-2.dev4 → openscvx-2.dev5}/examples/arm/7_dof_arm_collision.py +0 -0
  86. {openscvx-2.dev4 → openscvx-2.dev5}/examples/arm/7_dof_arm_vp.py +0 -0
  87. {openscvx-2.dev4 → openscvx-2.dev5}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  88. {openscvx-2.dev4 → openscvx-2.dev5}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  89. {openscvx-2.dev4 → openscvx-2.dev5}/examples/car/dubins_car.py +0 -0
  90. {openscvx-2.dev4 → openscvx-2.dev5}/examples/car/dubins_car_disjoint.py +0 -0
  91. {openscvx-2.dev4 → openscvx-2.dev5}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  92. {openscvx-2.dev4 → openscvx-2.dev5}/examples/car/dubins_car_obstacle_stl.py +0 -0
  93. {openscvx-2.dev4 → openscvx-2.dev5}/examples/car/dubins_car_stl_or.py +0 -0
  94. {openscvx-2.dev4 → openscvx-2.dev5}/examples/car/dubins_car_waypoint_stl.py +0 -0
  95. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/cinema_vp.py +0 -0
  96. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/dr_double_integrator.py +0 -0
  97. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/dr_vp.py +0 -0
  98. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/dr_vp_nodal.py +0 -0
  99. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/dr_vp_polytope.py +0 -0
  100. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/drone_racing.py +0 -0
  101. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/logo.py +0 -0
  102. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/logo_utils/acl_logo.svg +0 -0
  103. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  104. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/obstacle_avoidance.py +0 -0
  105. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  106. {openscvx-2.dev4 → openscvx-2.dev5}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  107. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mjx/triple_cartpole_game.py +0 -0
  108. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mpc/double_integrator_discrete.py +0 -0
  109. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mpc/double_integrator_drone_racing.py +0 -0
  110. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  111. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  112. {openscvx-2.dev4 → openscvx-2.dev5}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  113. {openscvx-2.dev4 → openscvx-2.dev5}/examples/plotting.py +0 -0
  114. {openscvx-2.dev4 → openscvx-2.dev5}/examples/plotting_viser.py +0 -0
  115. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  116. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  117. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  118. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  119. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  120. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  121. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  122. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  123. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/cinema_vp_realtime.py +0 -0
  124. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/drone_racing_realtime.py +0 -0
  125. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/dubins_car_realtime.py +0 -0
  126. {openscvx-2.dev4 → openscvx-2.dev5}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  127. {openscvx-2.dev4 → openscvx-2.dev5}/examples/rocket/3DoF_pdg.py +0 -0
  128. {openscvx-2.dev4 → openscvx-2.dev5}/examples/rocket/6DoF_pdg.py +0 -0
  129. {openscvx-2.dev4 → openscvx-2.dev5}/examples/spacecraft/halo_orbit.py +0 -0
  130. {openscvx-2.dev4 → openscvx-2.dev5}/examples/spacecraft/hohmann_transfer.py +0 -0
  131. {openscvx-2.dev4 → openscvx-2.dev5}/examples/spacecraft/let_transfer.py +0 -0
  132. {openscvx-2.dev4 → openscvx-2.dev5}/examples/spacecraft/proxops_cw.py +0 -0
  133. {openscvx-2.dev4 → openscvx-2.dev5}/figures/ctlos_cine.gif +0 -0
  134. {openscvx-2.dev4 → openscvx-2.dev5}/figures/ctlos_dr.gif +0 -0
  135. {openscvx-2.dev4 → openscvx-2.dev5}/figures/dtlos_cine.gif +0 -0
  136. {openscvx-2.dev4 → openscvx-2.dev5}/figures/dtlos_dr.gif +0 -0
  137. {openscvx-2.dev4 → openscvx-2.dev5}/figures/openscvx_logo.svg +0 -0
  138. {openscvx-2.dev4 → openscvx-2.dev5}/figures/openscvx_logo_square.png +0 -0
  139. {openscvx-2.dev4 → openscvx-2.dev5}/figures/oscvx_structure_full_dark.svg +0 -0
  140. {openscvx-2.dev4 → openscvx-2.dev5}/figures/video_preview.png +0 -0
  141. {openscvx-2.dev4 → openscvx-2.dev5}/material/__init__.py +0 -0
  142. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/assets/stylesheets/custom.css +0 -0
  143. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  144. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  145. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  146. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/home.html +0 -0
  147. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/main.html +0 -0
  148. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/partials/home-diagram.html +0 -0
  149. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/partials/home-dropin-banner.html +0 -0
  150. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/partials/home-hero.html +0 -0
  151. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/partials/home-pipeline.html +0 -0
  152. {openscvx-2.dev4 → openscvx-2.dev5}/material/overrides/partials/home-viser-strip.html +0 -0
  153. {openscvx-2.dev4 → openscvx-2.dev5}/mkdocs.yml +0 -0
  154. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/__main__.py +0 -0
  155. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/__init__.py +0 -0
  156. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/augmented_lagrangian.py +0 -0
  157. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/base.py +0 -0
  158. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/constant_proximal_weight.py +0 -0
  159. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/optimization_results.py +0 -0
  160. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/penalized_trust_region.py +0 -0
  161. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/ramp_proximal_weight.py +0 -0
  162. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/algorithms/weights.py +0 -0
  163. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/config.py +0 -0
  164. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/__init__.py +0 -0
  165. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/base.py +0 -0
  166. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/discretize_linearize.py +0 -0
  167. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/linearize_discretize.py +0 -0
  168. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  169. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  170. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  171. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  172. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/expert/__init__.py +0 -0
  173. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/expert/byof.py +0 -0
  174. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/expert/lowering.py +0 -0
  175. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/expert/validation.py +0 -0
  176. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/init/__init__.py +0 -0
  177. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/init/interpolation.py +0 -0
  178. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/init/inverse_kinematics.py +0 -0
  179. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/integrations/menagerie.py +0 -0
  180. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/integrators/__init__.py +0 -0
  181. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/integrators/diffrax.py +0 -0
  182. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/integrators/runge_kutta.py +0 -0
  183. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/loader.py +0 -0
  184. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/__init__.py +0 -0
  185. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/cvxpy_constraints.py +0 -0
  186. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/cvxpy_variables.py +0 -0
  187. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/dynamics.py +0 -0
  188. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/jax_constraints.py +0 -0
  189. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/parameters.py +0 -0
  190. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/problem.py +0 -0
  191. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/lowered/unified.py +0 -0
  192. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/__init__.py +0 -0
  193. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/plotting.py +0 -0
  194. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/scp_iteration.py +0 -0
  195. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/viser/__init__.py +0 -0
  196. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/viser/animated.py +0 -0
  197. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/viser/orbits.py +0 -0
  198. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/viser/plotly_integration.py +0 -0
  199. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/viser/primitives.py +0 -0
  200. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/viser/scp.py +0 -0
  201. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/plotting/viser/server.py +0 -0
  202. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/propagation/__init__.py +0 -0
  203. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/propagation/post_processing.py +0 -0
  204. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/propagation/propagation.py +0 -0
  205. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/solvers/__init__.py +0 -0
  206. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/solvers/base.py +0 -0
  207. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/solvers/ptr_solver.py +0 -0
  208. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/__init__.py +0 -0
  209. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/augmentation.py +0 -0
  210. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/builder.py +0 -0
  211. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/constraint_set.py +0 -0
  212. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/__init__.py +0 -0
  213. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/arithmetic.py +0 -0
  214. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/array.py +0 -0
  215. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/constraint.py +0 -0
  216. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/control.py +0 -0
  217. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/expr.py +0 -0
  218. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  219. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  220. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/lie/se3.py +0 -0
  221. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/lie/so3.py +0 -0
  222. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/linalg.py +0 -0
  223. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/logic.py +0 -0
  224. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/math.py +0 -0
  225. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/parameter.py +0 -0
  226. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/spatial.py +0 -0
  227. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/state.py +0 -0
  228. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/stl.py +0 -0
  229. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/stljax.py +0 -0
  230. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/time.py +0 -0
  231. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/variable.py +0 -0
  232. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/expr/vmap.py +0 -0
  233. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/hashing.py +0 -0
  234. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lower.py +0 -0
  235. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/__init__.py +0 -0
  236. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  237. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  238. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  239. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  240. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  241. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  242. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  243. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  244. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  245. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  246. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  247. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  248. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  249. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  250. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  251. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  252. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  253. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  254. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  255. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  256. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  257. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  258. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  259. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  260. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  261. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  262. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  263. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  264. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  265. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/__init__.py +0 -0
  266. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/_registry.py +0 -0
  267. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/array.py +0 -0
  268. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/constraint.py +0 -0
  269. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/lie.py +0 -0
  270. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/linalg.py +0 -0
  271. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/logic.py +0 -0
  272. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/math.py +0 -0
  273. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/parser.py +0 -0
  274. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/spatial.py +0 -0
  275. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/stl.py +0 -0
  276. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/stljax.py +0 -0
  277. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/parser/tokenizer.py +0 -0
  278. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/preprocessing.py +0 -0
  279. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/problem.py +0 -0
  280. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/sparsity.py +0 -0
  281. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/symbolic/unified.py +0 -0
  282. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/utils/__init__.py +0 -0
  283. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/utils/cache.py +0 -0
  284. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/utils/caching.py +0 -0
  285. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/utils/printing.py +0 -0
  286. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/utils/profiling.py +0 -0
  287. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx/utils/utils.py +0 -0
  288. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx.egg-info/dependency_links.txt +0 -0
  289. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx.egg-info/entry_points.txt +0 -0
  290. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx.egg-info/requires.txt +0 -0
  291. {openscvx-2.dev4 → openscvx-2.dev5}/openscvx.egg-info/top_level.txt +0 -0
  292. {openscvx-2.dev4 → openscvx-2.dev5}/pyproject.toml +0 -0
  293. {openscvx-2.dev4 → openscvx-2.dev5}/scripts/gen_example_pages.py +0 -0
  294. {openscvx-2.dev4 → openscvx-2.dev5}/scripts/gen_ref_pages.py +0 -0
  295. {openscvx-2.dev4 → openscvx-2.dev5}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  296. {openscvx-2.dev4 → openscvx-2.dev5}/setup.cfg +0 -0
  297. {openscvx-2.dev4 → openscvx-2.dev5}/tests/__init__.py +0 -0
  298. {openscvx-2.dev4 → openscvx-2.dev5}/tests/brachistochrone_analytical.py +0 -0
  299. {openscvx-2.dev4 → openscvx-2.dev5}/tests/expr/__init__.py +0 -0
  300. {openscvx-2.dev4 → openscvx-2.dev5}/tests/expr/test_gmsr.py +0 -0
  301. {openscvx-2.dev4 → openscvx-2.dev5}/tests/fixtures/brachistochrone.json +0 -0
  302. {openscvx-2.dev4 → openscvx-2.dev5}/tests/fixtures/brachistochrone.yaml +0 -0
  303. {openscvx-2.dev4 → openscvx-2.dev5}/tests/hohmann_analytical.py +0 -0
  304. {openscvx-2.dev4 → openscvx-2.dev5}/tests/integrations/__init__.py +0 -0
  305. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/__init__.py +0 -0
  306. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/__init__.py +0 -0
  307. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_arithmetic.py +0 -0
  308. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_array.py +0 -0
  309. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_constraint.py +0 -0
  310. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_expr.py +0 -0
  311. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_lie.py +0 -0
  312. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_linalg.py +0 -0
  313. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_logic.py +0 -0
  314. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_math.py +0 -0
  315. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_node_reference.py +0 -0
  316. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_parameters.py +0 -0
  317. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_scaling.py +0 -0
  318. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_spatial.py +0 -0
  319. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_stl.py +0 -0
  320. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_variable.py +0 -0
  321. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/expr/test_vmap.py +0 -0
  322. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/__init__.py +0 -0
  323. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_array.py +0 -0
  324. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_constraint.py +0 -0
  325. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_lie.py +0 -0
  326. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_linalg.py +0 -0
  327. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_load.py +0 -0
  328. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_logic.py +0 -0
  329. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_math.py +0 -0
  330. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_parser.py +0 -0
  331. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_spatial.py +0 -0
  332. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_stl.py +0 -0
  333. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_tokenizer.py +0 -0
  334. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/parser/test_vmap.py +0 -0
  335. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/test_augmentation.py +0 -0
  336. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/test_hashing.py +0 -0
  337. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/test_lower_cvxpy.py +0 -0
  338. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/test_lower_jax.py +0 -0
  339. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/test_preprocessing.py +0 -0
  340. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/test_sparsity.py +0 -0
  341. {openscvx-2.dev4 → openscvx-2.dev5}/tests/symbolic/test_unified.py +0 -0
  342. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_autotuning.py +0 -0
  343. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_brachistochrone.py +0 -0
  344. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_cvxpygen_optional.py +0 -0
  345. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_discretization.py +0 -0
  346. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_examples.py +0 -0
  347. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_expert.py +0 -0
  348. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_impulsive.py +0 -0
  349. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_init.py +0 -0
  350. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_integrators.py +0 -0
  351. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_loader.py +0 -0
  352. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_optimization_results.py +0 -0
  353. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_plotting.py +0 -0
  354. {openscvx-2.dev4 → openscvx-2.dev5}/tests/test_propagation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 2.dev4
3
+ Version: 2.dev5
4
4
  Summary: A general Python-based successive convexification implementation which uses a JAX backend.
5
5
  Author-email: Chris Hayner and Griffin Norris <haynec@uw.edu>
6
6
  License: Apache Software License
@@ -34,7 +34,6 @@ except ImportError:
34
34
  sys.exit(1)
35
35
 
36
36
  import openscvx as ox
37
- from openscvx.integrations import mjx_byof
38
37
 
39
38
  CARTPOLE_XML = """
40
39
  <mujoco model="cartpole">
@@ -69,36 +68,32 @@ n_u = int(mjx_model.nu)
69
68
  n = 60
70
69
  total_time = 3.0
71
70
 
72
- qpos = ox.State("qpos", shape=(n_q,))
71
+ # ── MJX dynamics as a first-class adapter ─────────────────────────────────────
72
+ # `MjxDynamics` builds default qpos / qvel / ctrl State and Control objects
73
+ # matching the model's nq / nv / nu and routes the MJX forward dynamics into
74
+ # the BYOF channel internally — no separate `byof=` plumbing required.
75
+ dyn = ox.MjxDynamics(mjx_model)
76
+ qpos, qvel = dyn.states
77
+ (ctrl,) = dyn.controls
78
+
73
79
  qpos.min = np.array([-3.0, -2.0 * np.pi])
74
80
  qpos.max = np.array([3.0, 2.0 * np.pi])
75
81
  qpos.initial = np.array([0.0, np.pi])
76
82
  qpos.final = np.array([0.0, 0.0])
77
83
 
78
- qvel = ox.State("qvel", shape=(n_v,))
79
84
  qvel.min = np.array([-10.0, -15.0])
80
85
  qvel.max = np.array([10.0, 15.0])
81
86
  qvel.initial = np.array([0.0, 0.0])
82
87
  qvel.final = np.array([0.0, 0.0])
83
88
 
84
- ctrl = ox.Control("ctrl", shape=(n_u,))
85
89
  ctrl.min = np.array([-1.0])
86
90
  ctrl.max = np.array([1.0])
87
91
  ctrl.guess = np.zeros((n, n_u))
88
92
 
89
- states = [qpos, qvel]
90
- controls = [ctrl]
91
-
92
- dynamics = {
93
- "qpos": qvel,
94
- }
95
-
96
- byof: ox.ByofSpec = {"dynamics": mjx_byof(mjx_model, qpos=qpos, qvel=qvel, ctrl=ctrl)}
97
-
98
93
  constraints = []
99
- for state in states:
94
+ for state in dyn.states:
100
95
  constraints.extend([ox.ctcs(state <= state.max), ox.ctcs(state.min <= state)])
101
- for control in controls:
96
+ for control in dyn.controls:
102
97
  constraints.extend([ox.ctcs(control <= control.max), ox.ctcs(control.min <= control)])
103
98
 
104
99
  theta_guess = np.linspace(np.pi, 0.0, n)
@@ -115,13 +110,12 @@ time = ox.Time(
115
110
  )
116
111
 
117
112
  problem = ox.Problem(
118
- dynamics=dynamics,
119
- states=states,
120
- controls=controls,
113
+ dynamics=dyn,
114
+ states=dyn.states,
115
+ controls=dyn.controls,
121
116
  time=time,
122
117
  constraints=constraints,
123
118
  N=n,
124
- byof=byof,
125
119
  algorithm={
126
120
  "lam_prox": 1e-1,
127
121
  "lam_cost": 1e-2,
@@ -34,8 +34,6 @@ except ImportError:
34
34
  sys.exit(1)
35
35
 
36
36
  import openscvx as ox
37
- from openscvx import ByofSpec
38
- from openscvx.integrations import mjx_byof
39
37
 
40
38
  L1, L2 = 0.5, 0.4 # link lengths (m)
41
39
 
@@ -81,32 +79,26 @@ n_u = int(mjx_model.nu) # 1: cart force
81
79
  n = 400
82
80
  total_time = 2.5
83
81
 
84
- # ── State / control definitions ───────────────────────────────────────────────
85
- qpos = ox.State("qpos", shape=(n_q,))
82
+ # ── MJX dynamics adapter ──────────────────────────────────────────────────────
83
+ dyn = ox.MjxDynamics(mjx_model)
84
+ qpos, qvel = dyn.states
85
+ (ctrl,) = dyn.controls
86
+ ctrl.parameterization = "ZOH"
87
+
86
88
  qpos.min = np.array([-8.0, -2 * np.pi, -2 * np.pi])
87
89
  qpos.max = np.array([8.0, 2 * np.pi, 2 * np.pi])
88
90
  qpos.initial = np.array([0.0, np.pi, 0.0]) # cart at origin, link1 hanging down
89
91
  qpos.final = [ox.Free(0.0), 0.0, 0.0] # cart free, both links upright
90
92
 
91
- qvel = ox.State("qvel", shape=(n_v,))
92
93
  qvel.min = np.array([-12.0, -12.0, -12.0])
93
94
  qvel.max = np.array([12.0, 12.0, 12.0])
94
95
  qvel.initial = np.zeros(n_v)
95
96
  qvel.final = [0.0, 0.0, 0.0]
96
97
 
97
- ctrl = ox.Control("ctrl", shape=(n_u,), parameterization="ZOH")
98
98
  ctrl.min = np.array([-2.0])
99
99
  ctrl.max = np.array([2.0])
100
100
  ctrl.guess = np.zeros((n, n_u))
101
101
 
102
- states = [qpos, qvel]
103
- controls = [ctrl]
104
-
105
- # ── Dynamics: position kinematics symbolically, velocity via MJX ──────────────
106
- dynamics: dict = {"qpos": qvel} # nq == nv, valid for all-revolute/prismatic joints
107
-
108
- byof: ByofSpec = {"dynamics": mjx_byof(mjx_model, qpos=qpos, qvel=qvel, ctrl=ctrl)}
109
-
110
102
  # ── Constraints (CTCS on state / control bounds) ───────────────────────────────
111
103
  constraints = []
112
104
 
@@ -123,13 +115,12 @@ time = ox.Time(
123
115
  )
124
116
 
125
117
  problem = ox.Problem(
126
- dynamics=dynamics,
127
- states=states,
128
- controls=controls,
118
+ dynamics=dyn,
119
+ states=dyn.states,
120
+ controls=dyn.controls,
129
121
  time=time,
130
122
  constraints=constraints,
131
123
  N=n,
132
- byof=byof,
133
124
  algorithm={
134
125
  "lam_prox": 1e-1,
135
126
  "lam_cost": 0e0,
@@ -51,8 +51,7 @@ from examples.plotting_viser import (
51
51
  create_animated_plotting_server,
52
52
  create_scp_animated_plotting_server,
53
53
  )
54
- from openscvx import ByofSpec, Problem
55
- from openscvx.integrations import mjx_byof
54
+ from openscvx import Problem
56
55
  from openscvx.utils import gen_vertices, rot
57
56
 
58
57
  HOVER_CTRL = 3.2495625 # N per motor for level hover (from menagerie keyframe)
@@ -78,33 +77,28 @@ n_u = int(mjx_model.nu) # 4 — rotor thrusts
78
77
  n = 22
79
78
  total_time = 24.0
80
79
 
81
- # ── State / control definitions ───────────────────────────────────────────────
82
- qpos = ox.State("qpos", shape=(n_q,))
80
+ # ── MJX dynamics adapter ──────────────────────────────────────────────────────
81
+ # The free joint has nq=7 but nv=6 (quaternion adds one extra position DOF).
82
+ # MjxDynamics detects nq > nv and automatically routes quaternion kinematics
83
+ # for "qpos" alongside the MJX "qvel" dynamics through the BYOF channel.
84
+ dyn = ox.MjxDynamics(mjx_model)
85
+ qpos, qvel = dyn.states
86
+ (ctrl,) = dyn.controls
87
+
83
88
  qpos.min = np.array([-200.0, -100.0, 15.0, -1.0, -1.0, -1.0, -1.0])
84
89
  qpos.max = np.array([200.0, 100.0, 200.0, 1.0, 1.0, 1.0, 1.0])
85
90
  qpos.initial = np.concatenate([START_POS, HOVER_QUAT])
86
91
  qpos.final = [10.0, 0.0, 20.0, ("free", 1.0), ("free", 0.0), ("free", 0.0), ("free", 0.0)]
87
92
 
88
- qvel = ox.State("qvel", shape=(n_v,))
89
93
  qvel.min = np.array([-100.0, -100.0, -100.0, -10.0, -10.0, -10.0])
90
94
  qvel.max = np.array([100.0, 100.0, 100.0, 10.0, 10.0, 10.0])
91
95
  qvel.initial = np.zeros(n_v)
92
96
  qvel.final = [("free", 0.0)] * n_v
93
97
 
94
- ctrl = ox.Control("ctrl", shape=(n_u,))
95
98
  ctrl.min = np.zeros(n_u)
96
99
  ctrl.max = 13.0 * np.ones(n_u)
97
100
  ctrl.guess = HOVER_CTRL * np.ones((n, n_u))
98
101
 
99
- states = [qpos, qvel]
100
- controls = [ctrl]
101
-
102
- # ── Dynamics via BYOF ─────────────────────────────────────────────────────────
103
- # The free joint has nq=7 but nv=6 (quaternion adds one extra position DOF).
104
- # nq=7, nv=6 (free joint): mjx_byof detects nq > nv and automatically
105
- # includes quaternion kinematics for "qpos" alongside the MJX "qvel" dynamics.
106
- byof: ByofSpec = {"dynamics": mjx_byof(mjx_model, qpos=qpos, qvel=qvel, ctrl=ctrl)}
107
-
108
102
  # ── Gate parameters (matching examples/drone/drone_racing.py) ───────────────
109
103
  n_gates = 10
110
104
  initial_gate_centers = [
@@ -135,9 +129,9 @@ gate_centers = np.array(modified_centers)
135
129
 
136
130
  # ── Constraints ───────────────────────────────────────────────────────────────
137
131
  constraints = []
138
- for state in states:
132
+ for state in dyn.states:
139
133
  constraints.extend([ox.ctcs(state <= state.max), ox.ctcs(state.min <= state)])
140
- for control in controls:
134
+ for control in dyn.controls:
141
135
  constraints.extend([ox.ctcs(control <= control.max), ox.ctcs(control.min <= control)])
142
136
 
143
137
  # Enforce sequential gate traversal using nodal constraints on qpos position.
@@ -172,13 +166,12 @@ time = ox.Time(
172
166
  )
173
167
 
174
168
  problem = Problem(
175
- dynamics={}, # all dynamics go through BYOF
176
- states=states,
177
- controls=controls,
169
+ dynamics=dyn,
170
+ states=dyn.states,
171
+ controls=dyn.controls,
178
172
  time=time,
179
173
  constraints=constraints,
180
174
  N=n,
181
- byof=byof,
182
175
  algorithm={
183
176
  "lam_prox": 1e-1,
184
177
  "lam_cost": 1e-2,
@@ -57,8 +57,7 @@ except ImportError:
57
57
  sys.exit(1)
58
58
 
59
59
  import openscvx as ox
60
- from openscvx import ByofSpec, Problem
61
- from openscvx.integrations import mjx_byof
60
+ from openscvx import Problem
62
61
 
63
62
  L1, L2, L3 = 0.5, 0.4, 0.3 # link lengths (m)
64
63
 
@@ -122,8 +121,11 @@ IDX_A1, IDX_B1 = 2, 3
122
121
  IDX_A2, IDX_B2 = 4, 5
123
122
  IDX_A3, IDX_B3 = 6, 7
124
123
 
125
- # ── State / control definitions ───────────────────────────────────────────────
126
- qpos = ox.State("qpos", shape=(n_q,))
124
+ # ── MJX dynamics adapter ──────────────────────────────────────────────────────
125
+ dyn = ox.MjxDynamics(mjx_model)
126
+ qpos, qvel = dyn.states
127
+ (ctrl,) = dyn.controls
128
+
127
129
  qpos.min = np.array(
128
130
  [-8.0, -8.0, -2 * np.pi, -2 * np.pi, -2 * np.pi, -2 * np.pi, -2 * np.pi, -2 * np.pi]
129
131
  )
@@ -142,25 +144,15 @@ qpos.final = [
142
144
  0.0, # link 3 upright
143
145
  ]
144
146
 
145
- qvel = ox.State("qvel", shape=(n_v,))
146
147
  qvel.min = np.full(n_v, -12.0)
147
148
  qvel.max = np.full(n_v, 12.0)
148
149
  qvel.initial = np.zeros(n_v)
149
150
  qvel.final = [0.0] * n_v
150
151
 
151
- ctrl = ox.Control("ctrl", shape=(n_u,))
152
152
  ctrl.min = np.array([-2.0, -2.0])
153
153
  ctrl.max = np.array([2.0, 2.0])
154
154
  ctrl.guess = np.zeros((n, n_u))
155
155
 
156
- states = [qpos, qvel]
157
- controls = [ctrl]
158
-
159
- # ── Dynamics: position kinematics symbolically, velocity via MJX ──────────────
160
- dynamics: dict = {"qpos": qvel} # nq == nv
161
-
162
- byof: ByofSpec = {"dynamics": mjx_byof(mjx_model, qpos=qpos, qvel=qvel, ctrl=ctrl)}
163
-
164
156
  # ── Constraints (CTCS on state / control bounds) ─────────────────────────────
165
157
  constraints = []
166
158
 
@@ -179,13 +171,12 @@ time = ox.Time(
179
171
  )
180
172
 
181
173
  problem = Problem(
182
- dynamics=dynamics,
183
- states=states,
184
- controls=controls,
174
+ dynamics=dyn,
175
+ states=dyn.states,
176
+ controls=dyn.controls,
185
177
  time=time,
186
178
  constraints=constraints,
187
179
  N=n,
188
- byof=byof,
189
180
  algorithm={
190
181
  "lam_prox": 1e-1,
191
182
  "lam_cost": 0e0,
@@ -35,8 +35,7 @@ except ImportError:
35
35
  sys.exit(1)
36
36
 
37
37
  import openscvx as ox
38
- from openscvx import ByofSpec, Problem
39
- from openscvx.integrations import mjx_byof
38
+ from openscvx import Problem
40
39
 
41
40
  L1, L2, L3 = 0.5, 0.4, 0.3 # link lengths (m)
42
41
 
@@ -88,35 +87,28 @@ n_u = int(mjx_model.nu) # 1: cart force
88
87
  n = 60 # more nodes → finer resolution near the unstable upright equilibrium
89
88
  total_time = 2.5
90
89
 
91
- # ── State / control definitions ───────────────────────────────────────────────
92
- qpos = ox.State("qpos", shape=(n_q,))
90
+ # ── MJX dynamics adapter ──────────────────────────────────────────────────────
91
+ dyn = ox.MjxDynamics(mjx_model)
92
+ qpos, qvel = dyn.states
93
+ (ctrl,) = dyn.controls
94
+
93
95
  qpos.min = np.array([-100.0, -2 * np.pi, -2 * np.pi, -2 * np.pi])
94
96
  qpos.max = np.array([100.0, 2 * np.pi, 2 * np.pi, 2 * np.pi])
95
97
  qpos.initial = np.array([0.0, np.pi, 0.0, 0.0]) # all links hanging down
96
98
  qpos.final = [ox.Free(0.0), 0.0, 0.0, 0.0] # all links upright
97
99
 
98
- qvel = ox.State("qvel", shape=(n_v,))
99
100
  qvel.min = np.array([-12.0, -12.0, -12.0, -12.0])
100
101
  qvel.max = np.array([12.0, 12.0, 12.0, 12.0])
101
102
  qvel.initial = np.zeros(n_v)
102
103
  qvel.final = [0.0, 0.0, 0.0, 0.0]
103
104
 
104
- ctrl = ox.Control("ctrl", shape=(n_u,))
105
105
  ctrl.min = np.array([-3.0])
106
106
  ctrl.max = np.array([3.0])
107
107
  ctrl.guess = np.zeros((n, n_u))
108
108
 
109
- states = [qpos, qvel]
110
- controls = [ctrl]
111
-
112
- # ── Dynamics: position kinematics symbolically, velocity via MJX ──────────────
113
- dynamics: dict = {"qpos": qvel} # nq==nv so this is always valid
114
-
115
- byof: ByofSpec = {"dynamics": mjx_byof(mjx_model, qpos=qpos, qvel=qvel, ctrl=ctrl)}
116
-
117
109
  # ── Constraints (CTCS on state / control bounds) ───────────────────────────────
118
110
  constraints = []
119
- for state in states:
111
+ for state in dyn.states:
120
112
  constraints.extend([ox.ctcs(state <= state.max), ox.ctcs(state.min <= state)])
121
113
 
122
114
  # ── Initial guess: linearly swing θ₁ from π → 0, others stay 0 ───────────────
@@ -132,13 +124,12 @@ time = ox.Time(
132
124
  )
133
125
 
134
126
  problem = Problem(
135
- dynamics=dynamics,
136
- states=states,
137
- controls=controls,
127
+ dynamics=dyn,
128
+ states=dyn.states,
129
+ controls=dyn.controls,
138
130
  time=time,
139
131
  constraints=constraints,
140
132
  N=n,
141
- byof=byof,
142
133
  algorithm={
143
134
  "lam_prox": 1e0,
144
135
  "lam_cost": 0e0,
@@ -25,6 +25,7 @@ from openscvx.discretization import (
25
25
  VectorizeDiscretizeLinearize,
26
26
  )
27
27
  from openscvx.expert import ByofSpec
28
+ from openscvx.integrations import DynamicsAdapter, MjxDynamics
28
29
  from openscvx.loader import load_dict, load_json, load_yaml
29
30
  from openscvx.problem import Problem
30
31
  from openscvx.solvers import PTRSolver
@@ -176,6 +177,9 @@ __all__ = [
176
177
  "lie",
177
178
  # Expert mode types
178
179
  "ByofSpec",
180
+ # External-backend dynamics adapters
181
+ "DynamicsAdapter",
182
+ "MjxDynamics",
179
183
  # Discretization
180
184
  "DiscretizeLinearizeVectorize",
181
185
  "LinearizeDiscretize",
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.dev4'
22
- __version_tuple__ = version_tuple = (2, 'dev4')
21
+ __version__ = version = '2.dev5'
22
+ __version_tuple__ = version_tuple = (2, 'dev5')
23
23
 
24
- __commit_id__ = commit_id = 'g85f47e152'
24
+ __commit_id__ = commit_id = 'g4161a5a13'
@@ -0,0 +1,66 @@
1
+ """External-backend dynamics adapters for OpenSCvx.
2
+
3
+ The recommended entry-point is `MjxDynamics`, which goes directly into the
4
+ ``dynamics=`` slot of `Problem` and constructs the matching State/Control
5
+ objects for the user. Free-joint quaternion kinematics for floating-base
6
+ models (drones, humanoids) are detected and handled automatically::
7
+
8
+ from openscvx.integrations import MjxDynamics
9
+
10
+ dyn = MjxDynamics(mjx_model)
11
+ problem = ox.Problem(
12
+ dynamics=dyn,
13
+ states=dyn.states,
14
+ controls=dyn.controls,
15
+ ...
16
+ )
17
+
18
+ For advanced users who need custom State/Control names (or to interleave
19
+ them with extra custom states), `mjx_dynamics` is exposed as the underlying
20
+ BYOF callable factory — assemble your own ``byof["dynamics"]`` dict from it.
21
+
22
+ All MJX symbols delegate lazily so ``mujoco.mjx`` is only imported when
23
+ actually used. The ``menagerie`` submodule is also loaded lazily.
24
+
25
+ Example — cartpole (``nq == nv``)::
26
+
27
+ from openscvx.integrations import MjxDynamics
28
+
29
+ dyn = MjxDynamics(mjx_model)
30
+ problem = ox.Problem(dynamics=dyn, states=dyn.states, controls=dyn.controls, ...)
31
+
32
+ Example — quadrotor with free joint (``nq=7``, ``nv=6``)::
33
+
34
+ from openscvx.integrations import MjxDynamics
35
+
36
+ dyn = MjxDynamics(mjx_model)
37
+ problem = ox.Problem(dynamics=dyn, states=dyn.states, controls=dyn.controls, ...)
38
+ """
39
+
40
+ from typing import Any
41
+
42
+ from .base import DynamicsAdapter
43
+ from .mjx import MjxDynamics
44
+
45
+
46
+ def mjx_dynamics(*args: Any, **kwargs: Any) -> Any:
47
+ """Lazy delegate; imports ``mujoco.mjx`` on first call."""
48
+ from .mjx import mjx_dynamics as _mjx_dynamics
49
+
50
+ return _mjx_dynamics(*args, **kwargs)
51
+
52
+
53
+ def __getattr__(name: str) -> Any:
54
+ if name == "menagerie":
55
+ from . import menagerie
56
+
57
+ return menagerie
58
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
59
+
60
+
61
+ __all__ = [
62
+ "DynamicsAdapter",
63
+ "MjxDynamics",
64
+ "mjx_dynamics",
65
+ "menagerie",
66
+ ]
@@ -0,0 +1,89 @@
1
+ """Base class for external-backend dynamics adapters.
2
+
3
+ A `DynamicsAdapter` is the easy on-ramp for users who want to plug an
4
+ external physics backend (MuJoCo MJX, Brax, Drake, ...) into OpenSCvx without
5
+ manually constructing State/Control objects with matching shapes or routing
6
+ raw JAX callables through the expert ``byof`` channel.
7
+
8
+ The intended call site is::
9
+
10
+ dyn = ox.MjxDynamics(mjx_model)
11
+ problem = ox.Problem(
12
+ dynamics=dyn,
13
+ states=dyn.states,
14
+ controls=dyn.controls,
15
+ ...
16
+ )
17
+
18
+ Internally, `Problem` detects the adapter, calls `DynamicsAdapter.expand`,
19
+ and merges the resulting BYOF callables into the user's ``byof`` dict (if
20
+ any). Everything downstream sees ordinary ``dynamics`` and ``byof`` dicts.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import copy
26
+ from abc import ABC, abstractmethod
27
+ from typing import TYPE_CHECKING, Tuple
28
+
29
+ if TYPE_CHECKING:
30
+ from openscvx.symbolic.expr.control import Control
31
+ from openscvx.symbolic.expr.state import State
32
+
33
+
34
+ class DynamicsAdapter(ABC):
35
+ """Abstract base class for external-backend dynamics adapters.
36
+
37
+ Subclasses describe the State/Control objects they synthesize on
38
+ ``.states`` / ``.controls`` and implement `expand` to return the
39
+ two-channel ``(dynamics_dict, byof_dict)`` representation consumed by
40
+ `Problem`.
41
+
42
+ The split mirrors the existing two-channel API: ``dynamics_dict`` carries
43
+ symbolic Expr entries (e.g. ``{"qpos": qvel}``) while ``byof_dict`` carries
44
+ raw JAX callables under the ``"dynamics"`` key. Either or both may be
45
+ empty, but ``expand()`` should never silently produce overlapping keys.
46
+ """
47
+
48
+ states: list["State"]
49
+ controls: list["Control"]
50
+
51
+ @abstractmethod
52
+ def expand(self) -> Tuple[dict, dict]:
53
+ """Return ``(dynamics_dict, byof_dict)`` in OpenSCvx's internal form.
54
+
55
+ ``dynamics_dict`` maps state names to symbolic ``Expr`` derivatives
56
+ (the same shape as the ``dynamics=`` argument to ``Problem``).
57
+ ``byof_dict`` has the same shape as the ``byof=`` argument: its
58
+ ``"dynamics"`` key (if present) maps state names to raw JAX callables.
59
+ """
60
+
61
+
62
+ def _merge_byof(user_byof: dict | None, extra_byof: dict) -> dict:
63
+ """Merge an adapter-synthesized BYOF dict into a user-provided one.
64
+
65
+ Only the ``"dynamics"`` sub-dict is deep-merged; other keys are taken
66
+ verbatim from whichever side provides them. Raises ``ValueError`` on any
67
+ key collision under ``"dynamics"`` — a user passing both
68
+ ``dynamics=ox.MjxDynamics(...)`` and ``byof={"dynamics": {"qvel": ...}}``
69
+ almost certainly has a bug, and silent override would mask it.
70
+ """
71
+ if not user_byof:
72
+ return copy.copy(extra_byof)
73
+
74
+ merged = dict(user_byof)
75
+ extra_dyn = extra_byof.get("dynamics", {})
76
+ user_dyn = user_byof.get("dynamics", {})
77
+
78
+ if extra_dyn:
79
+ collisions = set(user_dyn) & set(extra_dyn)
80
+ if collisions:
81
+ raise ValueError(
82
+ "DynamicsAdapter produced byof['dynamics'] entries that "
83
+ f"collide with user-provided byof['dynamics']: {sorted(collisions)}. "
84
+ "Drop the duplicate keys from your byof dict, or drop the adapter "
85
+ "and assemble byof['dynamics'] manually for full control."
86
+ )
87
+ merged["dynamics"] = {**user_dyn, **extra_dyn}
88
+
89
+ return merged