openscvx 0.5.3.dev23__tar.gz → 0.5.3.dev25__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 (412) hide show
  1. {openscvx-0.5.3.dev23/openscvx.egg-info → openscvx-0.5.3.dev25}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UnderTheHood/batching_jit_grad.md +142 -10
  3. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/brachistochrone_batched.py +17 -5
  4. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/6DoF_pdg_batched_ic.py +8 -9
  5. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/_version.py +3 -3
  6. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/__init__.py +8 -0
  7. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/autotuner/__init__.py +3 -0
  8. openscvx-0.5.3.dev25/openscvx/algorithms/autotuner/acceptance_ratio.py +245 -0
  9. openscvx-0.5.3.dev25/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +74 -0
  10. openscvx-0.5.3.dev25/openscvx/algorithms/autotuner/augmented_lagrangian.py +287 -0
  11. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/autotuner/constant_proximal_weight.py +20 -9
  12. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +28 -13
  13. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/base.py +393 -143
  14. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/optimization_results.py +6 -6
  15. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/scvx/iteration.py +15 -20
  16. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/scvx/penalized_trust_region.py +28 -50
  17. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/problem.py +600 -267
  18. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/cvxpy_ptr_solver.py +17 -0
  19. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/caching.py +13 -9
  20. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/printing.py +0 -5
  21. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25/openscvx.egg-info}/PKG-INFO +1 -1
  22. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/SOURCES.txt +3 -0
  23. openscvx-0.5.3.dev25/tests/algorithms/autotuner/test_hyper_overrides.py +325 -0
  24. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/autotuner/test_update_weights_jit.py +38 -20
  25. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_algorithm_state_pytree.py +16 -2
  26. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_iteration_fn_jit.py +11 -5
  27. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_iteration_fn_parity.py +48 -0
  28. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_make_solve_loop.py +4 -2
  29. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/_iteration_callback_helpers.py +4 -1
  30. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_autotuning.py +59 -17
  31. openscvx-0.5.3.dev25/tests/test_solve_batched_brachistochrone.py +468 -0
  32. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_batched_export_roundtrip.py +27 -9
  33. openscvx-0.5.3.dev25/tests/test_solve_batched_inference.py +340 -0
  34. openscvx-0.5.3.dev23/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -192
  35. openscvx-0.5.3.dev23/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -385
  36. openscvx-0.5.3.dev23/tests/test_solve_batched_brachistochrone.py +0 -71
  37. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/assets/logo.svg +0 -0
  38. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/release-drafter.yml +0 -0
  39. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/_docs.yml +0 -0
  40. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/branch-name.yml +0 -0
  41. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/docs.yml +0 -0
  42. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/lint.yml +0 -0
  43. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/nightly.yml +0 -0
  44. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/release-drafter.yml +0 -0
  45. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/release.yml +0 -0
  46. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/tests-integration.yml +0 -0
  47. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/tests-unit.yml +0 -0
  48. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.gitignore +0 -0
  49. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.gitmodules +0 -0
  50. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/CONTRIBUTING.md +0 -0
  51. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/LICENSE +0 -0
  52. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/README.md +0 -0
  53. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/constraint_reformulation.md +0 -0
  54. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/control_parameterization.md +0 -0
  55. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/discretization.md +0 -0
  56. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/ocp.md +0 -0
  57. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/scvx.md +0 -0
  58. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/time_dilation.md +0 -0
  59. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UnderTheHood/lowering_architecture.md +0 -0
  60. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  61. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/00_introduction.md +0 -0
  62. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  63. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  64. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  65. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  66. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/05_visualization.md +0 -0
  67. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/06_logic.md +0 -0
  68. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/07_lie.md +0 -0
  69. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/08_mpcc.md +0 -0
  70. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  71. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/favicon.png +0 -0
  72. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ct-scvx_dark.png +0 -0
  73. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ct-scvx_light.png +0 -0
  74. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ctcs_dark.png +0 -0
  75. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ctcs_light.png +0 -0
  76. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/problem_class_dark.png +0 -0
  77. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/problem_class_light.png +0 -0
  78. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/logo.svg +0 -0
  79. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/openscvx_logo_square.png +0 -0
  80. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/viser-client/index.html +0 -0
  81. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  82. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  83. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/citation.md +0 -0
  84. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/examples.md +0 -0
  85. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/index.md +0 -0
  86. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/javascripts/mathjax.js +0 -0
  87. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/versions.json +0 -0
  88. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/_viser_embed_export.py +0 -0
  89. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/brachistochrone.py +0 -0
  90. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/flappy_bird.py +0 -0
  91. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/hypersensitive.py +0 -0
  92. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/impulsive.py +0 -0
  93. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/stl_integer_variable.py +0 -0
  94. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/stl_or.py +0 -0
  95. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/7_dof_arm.py +0 -0
  96. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/_camera.py +0 -0
  97. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/_render.py +0 -0
  98. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/_sensor_view.py +0 -0
  99. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/dr_vp_polytope.py +0 -0
  100. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  101. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/logo.py +0 -0
  102. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  103. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/3_dof_arm.py +0 -0
  104. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/7_dof_arm.py +0 -0
  105. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/7_dof_arm_collision.py +0 -0
  106. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/7_dof_arm_vp.py +0 -0
  107. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  108. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  109. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  110. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car.py +0 -0
  111. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_disjoint.py +0 -0
  112. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  113. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_obstacle_stl.py +0 -0
  114. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_stl_or.py +0 -0
  115. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_waypoint_stl.py +0 -0
  116. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  117. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/cinema_vp.py +0 -0
  118. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/cinema_vp_nodal.py +0 -0
  119. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_double_integrator.py +0 -0
  120. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_vp.py +0 -0
  121. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_vp_nodal.py +0 -0
  122. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_vp_polytope.py +0 -0
  123. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/drone_racing.py +0 -0
  124. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/drone_racing_batched_gates.py +0 -0
  125. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo.py +0 -0
  126. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/acl_logo.svg +0 -0
  127. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  128. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  129. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  130. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance.py +0 -0
  131. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  132. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  133. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  134. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/openscvx_logo.py +0 -0
  135. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/cartpole_mjx.py +0 -0
  136. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/double_cartpole_mjx.py +0 -0
  137. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/skydio_x2_mjx.py +0 -0
  138. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  139. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/triple_cartpole_game.py +0 -0
  140. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/triple_cartpole_mjx.py +0 -0
  141. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/double_integrator_discrete.py +0 -0
  142. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/double_integrator_drone_racing.py +0 -0
  143. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  144. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  145. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  146. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/plotting.py +0 -0
  147. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/plotting_viser.py +0 -0
  148. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  149. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  150. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  151. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  152. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  153. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  154. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  155. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  156. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/cinema_vp_realtime.py +0 -0
  157. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/drone_racing_realtime.py +0 -0
  158. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/dubins_car_realtime.py +0 -0
  159. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  160. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/3DoF_pdg.py +0 -0
  161. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/6DoF_pdg.py +0 -0
  162. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/ascent_launch_vehicle.py +0 -0
  163. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/halo_orbit.py +0 -0
  164. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/hohmann_transfer.py +0 -0
  165. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/let_transfer.py +0 -0
  166. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/proxops_cw.py +0 -0
  167. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/relative_loitering.py +0 -0
  168. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/ctlos_cine.gif +0 -0
  169. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/ctlos_dr.gif +0 -0
  170. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/dtlos_cine.gif +0 -0
  171. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/dtlos_dr.gif +0 -0
  172. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/openscvx_logo.svg +0 -0
  173. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/openscvx_logo_square.png +0 -0
  174. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/oscvx_structure_full_dark.svg +0 -0
  175. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/video_preview.png +0 -0
  176. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/__init__.py +0 -0
  177. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/custom.css +0 -0
  178. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  179. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  180. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  181. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/home.html +0 -0
  182. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/main.html +0 -0
  183. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-diagram.html +0 -0
  184. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-dropin-banner.html +0 -0
  185. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-hero.html +0 -0
  186. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-pipeline.html +0 -0
  187. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-viser-strip.html +0 -0
  188. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/mkdocs.yml +0 -0
  189. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/__init__.py +0 -0
  190. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/__main__.py +0 -0
  191. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/scvx/__init__.py +0 -0
  192. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/weights.py +0 -0
  193. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/config.py +0 -0
  194. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/__init__.py +0 -0
  195. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/base.py +0 -0
  196. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/discretize_linearize.py +0 -0
  197. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/linearize_discretize.py +0 -0
  198. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  199. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  200. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  201. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  202. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/__init__.py +0 -0
  203. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/byof.py +0 -0
  204. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/lowering.py +0 -0
  205. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/validation.py +0 -0
  206. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/init/__init__.py +0 -0
  207. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/init/interpolation.py +0 -0
  208. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/init/inverse_kinematics.py +0 -0
  209. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/__init__.py +0 -0
  210. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/base.py +0 -0
  211. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/menagerie.py +0 -0
  212. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/mjx.py +0 -0
  213. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrators/__init__.py +0 -0
  214. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrators/diffrax.py +0 -0
  215. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrators/runge_kutta.py +0 -0
  216. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/loader.py +0 -0
  217. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/__init__.py +0 -0
  218. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/cvxpy_constraints.py +0 -0
  219. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/cvxpy_variables.py +0 -0
  220. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/dynamics.py +0 -0
  221. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/jax_constraints.py +0 -0
  222. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/parameters.py +0 -0
  223. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/problem.py +0 -0
  224. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/unified.py +0 -0
  225. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/__init__.py +0 -0
  226. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/plotting.py +0 -0
  227. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/publication.py +0 -0
  228. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/scp_iteration.py +0 -0
  229. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/__init__.py +0 -0
  230. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/animated.py +0 -0
  231. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/coordinates.py +0 -0
  232. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/orbits.py +0 -0
  233. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/plotly_integration.py +0 -0
  234. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/primitives.py +0 -0
  235. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/scp.py +0 -0
  236. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/server.py +0 -0
  237. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/propagation/__init__.py +0 -0
  238. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/propagation/post_processing.py +0 -0
  239. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/propagation/propagation.py +0 -0
  240. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/__init__.py +0 -0
  241. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/base.py +0 -0
  242. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/cones.py +0 -0
  243. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  244. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/ptr_solver.py +0 -0
  245. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  246. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/__init__.py +0 -0
  247. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/affine.py +0 -0
  248. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/augmentation.py +0 -0
  249. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/builder.py +0 -0
  250. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/canonicalize.py +0 -0
  251. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/constraint_set.py +0 -0
  252. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/__init__.py +0 -0
  253. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/arithmetic.py +0 -0
  254. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/array.py +0 -0
  255. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/constraint.py +0 -0
  256. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/control.py +0 -0
  257. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/expr.py +0 -0
  258. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  259. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  260. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/se3.py +0 -0
  261. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/so3.py +0 -0
  262. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/linalg.py +0 -0
  263. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/logic.py +0 -0
  264. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/math.py +0 -0
  265. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/parameter.py +0 -0
  266. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/spatial.py +0 -0
  267. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/state.py +0 -0
  268. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/stl.py +0 -0
  269. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/stljax.py +0 -0
  270. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/time.py +0 -0
  271. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/variable.py +0 -0
  272. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/vmap.py +0 -0
  273. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/hashing.py +0 -0
  274. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lower.py +0 -0
  275. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/__init__.py +0 -0
  276. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  277. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  278. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  279. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  280. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  281. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  282. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  283. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  284. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  285. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  286. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  287. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  288. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  289. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  290. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  291. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  292. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  293. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  294. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  295. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  296. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  297. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  298. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  299. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  300. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  301. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  302. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  303. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  304. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  305. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/__init__.py +0 -0
  306. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/_registry.py +0 -0
  307. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/array.py +0 -0
  308. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/constraint.py +0 -0
  309. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/lie.py +0 -0
  310. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/linalg.py +0 -0
  311. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/logic.py +0 -0
  312. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/math.py +0 -0
  313. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/parser.py +0 -0
  314. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/spatial.py +0 -0
  315. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/stl.py +0 -0
  316. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/stljax.py +0 -0
  317. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/tokenizer.py +0 -0
  318. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/preprocessing.py +0 -0
  319. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/problem.py +0 -0
  320. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/sparsity.py +0 -0
  321. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/unified.py +0 -0
  322. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/__init__.py +0 -0
  323. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/cache.py +0 -0
  324. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/profiling.py +0 -0
  325. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/utils.py +0 -0
  326. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/dependency_links.txt +0 -0
  327. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/entry_points.txt +0 -0
  328. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/requires.txt +0 -0
  329. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/top_level.txt +0 -0
  330. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/pyproject.toml +0 -0
  331. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/scripts/gen_example_pages.py +0 -0
  332. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/scripts/gen_ref_pages.py +0 -0
  333. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  334. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/setup.cfg +0 -0
  335. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/__init__.py +0 -0
  336. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/_marks.py +0 -0
  337. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/__init__.py +0 -0
  338. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/_iteration_helpers.py +0 -0
  339. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/autotuner/__init__.py +0 -0
  340. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/brachistochrone_analytical.py +0 -0
  341. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/conftest.py +0 -0
  342. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/expr/__init__.py +0 -0
  343. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/expr/test_gmsr.py +0 -0
  344. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/fixtures/brachistochrone.json +0 -0
  345. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/fixtures/brachistochrone.yaml +0 -0
  346. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/hohmann_analytical.py +0 -0
  347. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/integrations/__init__.py +0 -0
  348. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/integrations/test_mjx.py +0 -0
  349. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/integrations/test_mjx_dynamics.py +0 -0
  350. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/__init__.py +0 -0
  351. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  352. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  353. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  354. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  355. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  356. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  357. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  358. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_subproblem_pytree.py +0 -0
  359. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/__init__.py +0 -0
  360. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/__init__.py +0 -0
  361. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_arithmetic.py +0 -0
  362. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_array.py +0 -0
  363. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_constraint.py +0 -0
  364. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_expr.py +0 -0
  365. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_lie.py +0 -0
  366. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_linalg.py +0 -0
  367. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_logic.py +0 -0
  368. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_math.py +0 -0
  369. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_node_reference.py +0 -0
  370. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_parameters.py +0 -0
  371. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_scaling.py +0 -0
  372. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_spatial.py +0 -0
  373. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_stl.py +0 -0
  374. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_variable.py +0 -0
  375. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_vmap.py +0 -0
  376. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/__init__.py +0 -0
  377. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_array.py +0 -0
  378. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_constraint.py +0 -0
  379. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_lie.py +0 -0
  380. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_linalg.py +0 -0
  381. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_load.py +0 -0
  382. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_logic.py +0 -0
  383. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_math.py +0 -0
  384. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_parser.py +0 -0
  385. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_spatial.py +0 -0
  386. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_stl.py +0 -0
  387. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_tokenizer.py +0 -0
  388. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_vmap.py +0 -0
  389. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_augmentation.py +0 -0
  390. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_hashing.py +0 -0
  391. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_lower_cvxpy.py +0 -0
  392. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_lower_jax.py +0 -0
  393. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_preprocessing.py +0 -0
  394. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_sparsity.py +0 -0
  395. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_unified.py +0 -0
  396. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_brachistochrone.py +0 -0
  397. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_cvxpygen_optional.py +0 -0
  398. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_discretization.py +0 -0
  399. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_examples.py +0 -0
  400. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_expert.py +0 -0
  401. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_impulsive.py +0 -0
  402. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_init.py +0 -0
  403. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_integrators.py +0 -0
  404. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_loader.py +0 -0
  405. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_optimization_results.py +0 -0
  406. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_plotting.py +0 -0
  407. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_propagation.py +0 -0
  408. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
  409. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
  410. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
  411. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
  412. {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_jax_vmap_converged_no_drift.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev23
3
+ Version: 0.5.3.dev25
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
@@ -60,7 +60,7 @@ that one difference is the whole point.
60
60
  no outer `vmap` rule (`call_exported` cannot be batched), so an exported
61
61
  artifact can never be re-vmapped, and every fresh process re-traces and
62
62
  re-compiles the entire loop.
63
- * `solve_batched(x0_stack, xf_stack)` — *the library* owns the axis. The vmap
63
+ * `solve_batched(x_initial=x0_batch)` — *the library* owns the axis. The vmap
64
64
  is applied **inside** the method, before any export, so the whole loop lowers
65
65
  to ordinary batched XLA ops and serializes cleanly. Under
66
66
  `save_compiled=True` it is written to the solver cache on the first run and
@@ -74,10 +74,131 @@ problem.initialize()
74
74
 
75
75
  # First process: traces, exports, writes <cache>/compiled_solve_batched_<hash>.jax
76
76
  # Later processes: deserialize-and-.call, no compile.
77
- batched = problem.solve_batched(x0_stack, xf_stack, params)
77
+ batched = problem.solve_batched(x_initial=x0_batch, parameters=params)
78
78
  # batched.x.shape == (B, N, n_states) — same pytree jax.vmap(solve_jax) returns.
79
79
  ```
80
80
 
81
+ ### One rule: add a leading batch axis to whatever varies
82
+
83
+ `solve_batched` takes exactly `solve_jax`'s arguments. Every batchable input
84
+ has a *declared* (unbatched) shape the library knows — `(n_x,)` for the
85
+ boundary pins, `(N, n_x)` / `(N, n_u)` for the trajectory guesses, the
86
+ parameter's stored shape for each parameter, and `()` for the SCP
87
+ hyperparameters. An argument that matches its declared shape is **shared** by
88
+ every batch element; one with exactly one extra leading axis is **batched**
89
+ along it. Rank against the declared shape decides — never the leading-axis
90
+ value — so a shared `(B, n)` matrix parameter is never misread as batched.
91
+ (`B` in these shape patterns is plain notation for the batch size, not
92
+ syntax: it is never passed anywhere — like `jax.vmap`, the library reads it
93
+ off the leading axis of whatever you batched and cross-checks that all
94
+ batched inputs agree.)
95
+
96
+ ```python
97
+ results = problem.solve_batched(
98
+ x_initial=x0_batch, # (B, n_x): rank = declared+1 -> batched
99
+ parameters={
100
+ "gate_center": centers, # (B, 3) vs declared (3,) -> batched
101
+ "gate_radius": 0.5, # declared shape -> shared
102
+ },
103
+ )
104
+ ```
105
+
106
+ For the rare entry the rank rule cannot express — e.g. batching a declared
107
+ rank-1 parameter element-wise — pass an explicit `in_axes` in `jax.vmap`'s
108
+ vocabulary, including its prefix semantics (`0` = batched along the leading
109
+ axis, `None` = shared; a prefix applies to everything below it; partial specs
110
+ fall back to the rank rule):
111
+
112
+ ```python
113
+ results = problem.solve_batched(
114
+ parameters={"weights": w}, # (B,) is also w's declared shape...
115
+ in_axes={"parameters": {"weights": 0}}, # ...so say "batched" explicitly
116
+ )
117
+
118
+ results = problem.solve_batched(parameters=params, in_axes={"parameters": 0})
119
+ # prefix: every passed parameter is batched, exactly like jax.vmap's
120
+ # pytree-prefix in_axes; a bare in_axes=0 batches every passed input.
121
+ ```
122
+
123
+ One deliberate divergence from `jax.vmap`: the *default* is "infer by rank",
124
+ not `0`-everything — an all-shared batched solve has no batch axis to find,
125
+ and inference is what makes mixed shared/batched dicts ergonomic.
126
+
127
+ ### Hyperparameter sweeps: the `algorithm` dict
128
+
129
+ Solve-time mirrors construction-time: the `Problem` constructor configures
130
+ the SCP algorithm with a dict (`algorithm={"ep_tr": 1e-5, "lam_prox": 1.0}`),
131
+ and the solve methods take the same box with the same names as per-solve,
132
+ batchable inputs. Every `AlgorithmState` field is a runtime input riding the
133
+ state pytree, and the `algorithm` dict reaches any of them by name —
134
+ convergence thresholds (`ep_tr` / `ep_vb` / `ep_vc`), penalty weights
135
+ (`lam_prox` / `lam_vc` / `lam_cost`), the seed iterate, autotuner
136
+ hyperparameters. There is no whitelist: the field declaration is the
137
+ registration, and the `AlgorithmState` attribute docs are the reference.
138
+ (`max_iters` survives as a named kwarg — sugar for `algorithm={"k_max":
139
+ ...}`; passing both raises, as does an entry that shadows any other named
140
+ kwarg's field. Construction-only keys of the constructor dict — `autotuner`,
141
+ `t_max` — raise pointing back at the constructor.)
142
+
143
+ * On `solve_jax`, each value matches the field's shape, or is a scalar
144
+ broadcast to it: `solve_jax(algorithm={"ep_tr": 1e-6, "lam_prox": 2.0})`
145
+ retraces nothing.
146
+ * On `solve_batched`, each value follows the rank rule against the field's
147
+ shape, plus two **fill** forms for array-shaped fields: a scalar (shared)
148
+ or a `(B,)` vector (one scalar per element, broadcast to the field shape).
149
+ Exact shapes win when both parse; `in_axes={"algorithm": {name: 0}}`
150
+ forces the per-element reading. All against one cached artifact:
151
+
152
+ ```python
153
+ B = 8 # batch size. Just an int for building the arrays below — there is no
154
+ # B argument; solve_batched infers it from the leading-axis lengths.
155
+ sweep = problem.solve_batched(algorithm={"ep_tr": jnp.logspace(-6, -3, B)})
156
+ weights = problem.solve_batched(algorithm={"lam_prox": jnp.array([0.5, 1.0, 4.0])})
157
+ budgets = problem.solve_batched(max_iters=jnp.array([5, 10, 20])) # per-element caps
158
+ ```
159
+
160
+ The batch runs until its slowest element converges or exhausts its own cap;
161
+ finished elements are frozen, not re-iterated, so each element matches the
162
+ corresponding single `solve_jax` run.
163
+
164
+ **Every built-in autotuner knob batches for free.** All numeric knobs of the
165
+ built-in autotuners are declared hyperparameters — the trust-region factors
166
+ (`gamma_1` / `gamma_2`), the acceptance thresholds (`eta_0` / `eta_1` /
167
+ `eta_2`), the weight clips, the cost-relaxation schedule — so any of them is a
168
+ `solve_jax` override and a `solve_batched` sweep target by name:
169
+
170
+ ```python
171
+ # sweep the trust-region growth factor across a batch, one cached artifact
172
+ results = problem.solve_batched(algorithm={"gamma_1": jnp.linspace(1.5, 3.0, B)})
173
+ ```
174
+
175
+ **New autotuners batch the same way.** A custom autotuner's tunable knobs
176
+ follow the same derivation: declare them as fields on a `HyperParams` subclass
177
+ — bare annotations, no decorator; subclassing applies the frozen-dataclass
178
+ transform and the JAX pytree registration, and the annotation picks the dtype
179
+ (`int` gets the iteration counter's, `float` the problem's) — assign an
180
+ instance to `self.hyper`, and read `state.hyper.<field>` inside
181
+ `update_weights` (see the `AutotuningBase` docstring). The declaration is the
182
+ registration — each field immediately works as a `solve_jax` override, a
183
+ `solve_batched` sweep target, and a runtime input of the exported artifact,
184
+ with zero edits anywhere else:
185
+
186
+ ```python
187
+ from openscvx.algorithms import AutotuningBase, HyperParams
188
+
189
+ class MyHyper(HyperParams):
190
+ ramp: float = 2.0
191
+
192
+ class MyAutotuner(AutotuningBase):
193
+ def __init__(self, ramp: float = 2.0):
194
+ self.hyper = MyHyper(ramp=ramp)
195
+
196
+ def update_weights(self, state, ...):
197
+ ...state.hyper.ramp...
198
+
199
+ results = problem.solve_batched(algorithm={"ramp": jnp.linspace(1.5, 3.0, B)})
200
+ ```
201
+
81
202
  Pick `solve_batched` when **cross-process cold-start dominates** — short-lived
82
203
  processes (CI sweeps, notebook restarts, deployed workers) that otherwise pay
83
204
  the compile every launch. Pick `jax.vmap(solve_jax)` for everything in-program,
@@ -111,15 +232,21 @@ object contributing through its own `_hash_into` (the same protocol the symbolic
111
232
  layer uses):
112
233
 
113
234
  * the convex backend class + its `solver_args`,
114
- * the algorithm + autotuner + convergence thresholds + initial weights,
235
+ * the algorithm + autotuner + initial weights,
115
236
  * the discretizer scheme (class + hold type + ODE solver),
116
237
  * the state/control scaling matrices `inv_S_x` / `inv_S_u`,
117
- * the fixed batch size `B` (the artifact is exported at one `B`), and
238
+ * the fixed batch size `B` (the artifact is exported at one `B`),
239
+ * the per-parameter shared/batched split (baked into the `jax.vmap` program),
240
+ and
118
241
  * the JAX version (exported artifacts are not guaranteed to survive an
119
242
  incompatible jax bump).
120
243
 
121
- Change any of these — backend, a tolerance, `k_max`, a state bound — and you get
122
- a different cache path, so a stale artifact is never reused.
244
+ Change any of these — backend, a penalty weight, a state bound, which
245
+ parameters are batched — and you get a different cache path, so a stale
246
+ artifact is never reused. Everything the `algorithm` dict can reach — convergence
247
+ thresholds, `max_iters`, weights, autotuner hyperparameters — is deliberately
248
+ *not* in the key: those are runtime inputs on the state pytree, so one
249
+ artifact serves every setting of them.
123
250
 
124
251
  `examples/abstract/brachistochrone_batched.py` shows both paths side by side;
125
252
  re-running it is itself the cross-process demo.
@@ -158,10 +285,15 @@ problem.solve_jax(
158
285
  parameters=None, # parameters dict for this solve; falls back to
159
286
  # ``self._parameters``
160
287
  *,
161
- max_iters=None, # SCP iteration cap; non-default rebuilds the
162
- # cached ``lax.while_loop`` closure (one extra
163
- # trace; subsequent calls at the same cap hit
164
- # the cache)
288
+ x_guess=None, # (N, n_x) state trajectory warm-start
289
+ u_guess=None, # (N, n_u) control trajectory warm-start
290
+ max_iters=None, # SCP iteration cap; sugar for algorithm={"k_max": ...};
291
+ # falls back to the configured k_max
292
+ algorithm=None, # any AlgorithmState field by name (ep_tr, lam_prox,
293
+ # ...) — the constructor's algorithm-dict names;
294
+ # values match the field shape or fill it from a
295
+ # scalar. Runtime inputs on the state pytree — no
296
+ # value forces a retrace
165
297
  )
166
298
  ```
167
299
 
@@ -6,7 +6,7 @@ starting x-coordinate — and contrasts the two batching entry points:
6
6
  * ``jax.vmap(problem.solve_jax)`` — the caller owns the batch axis. Maximally
7
7
  idiomatic, composes with ``grad`` / ``scan``, but in-process JIT only: every
8
8
  fresh process re-traces and re-compiles the whole SCP loop.
9
- * ``problem.solve_batched(x0_stack, xf_stack)`` — the library owns the batch
9
+ * ``problem.solve_batched(x_initial=...)`` — the library owns the batch
10
10
  axis, so the whole vmapped loop is a single function that ``jax.export`` can
11
11
  serialize. Under ``save_compiled=True`` it is written to the solver cache on
12
12
  the first run and deserialized on later runs, skipping that compile. Reach
@@ -140,16 +140,28 @@ if __name__ == "__main__":
140
140
  # The same batched solve, but ``solve_batched`` owns the vmap so the whole
141
141
  # loop is one exportable artifact. Under ``save_compiled=True`` it lands in
142
142
  # the solver cache on the first run; re-run this script (a fresh process) to
143
- # see it deserialized instead of recompiled. ``xf`` is shared across the
144
- # batch, so broadcast the default terminal pin to the same leading axis.
143
+ # see it deserialized instead of recompiled. One rule: ``x_initial`` is
144
+ # ``(B, n_x)`` one extra leading axis so it is batched; the terminal
145
+ # pin is omitted, so every element shares the default.
145
146
  export_problem = build_problem()
146
147
  export_problem.settings.sim.save_compiled = True
147
148
  export_problem.initialize()
148
149
 
149
- x_term_stack = jnp.broadcast_to(export_problem.state.x_term_pin, x_initial_stack.shape)
150
- batched = export_problem.solve_batched(x_initial_stack, x_term_stack)
150
+ batched = export_problem.solve_batched(x_initial=x_initial_stack)
151
151
 
152
152
  print(f"\nsolve_batched (save_compiled=True) over {x_initial_stack.shape[0]} ICs:")
153
153
  print(f" result.x.shape: {batched.x.shape}")
154
154
  print(f" result.t_final: {np.asarray(batched.t_final).reshape(-1)}")
155
155
  print(f" result.converged: {np.asarray(batched.converged)}")
156
+
157
+ # Algorithm knobs batch by the same rule, through the `algorithm` dict —
158
+ # the same names as the Problem constructor's algorithm config. ep_tr is
159
+ # a scalar field, so a (B,) vector sweeps the convergence tolerance per
160
+ # element — same artifact, no recompile, since the knobs are runtime
161
+ # inputs on the state pytree. The batch size is never passed: it is read
162
+ # off the array's leading axis (4 tolerances -> B = 4).
163
+ sweep = export_problem.solve_batched(
164
+ algorithm={"ep_tr": jnp.logspace(-4, -1, 4), "ep_vc": 1e-7}
165
+ )
166
+ print(f" ep_tr sweep t_final: {np.asarray(sweep.t_final).reshape(-1)}")
167
+ print(f" ep_tr sweep converged: {np.asarray(sweep.converged)}")
@@ -2,7 +2,7 @@
2
2
 
3
3
  Runs ``N_BATCH`` SCP solves in parallel, each starting from a different random
4
4
  initial position drawn uniformly within the position bounds. Per-batch ICs are
5
- passed through ``x0_stack``: position is declared ``Fix`` at the symbolic level
5
+ passed through ``x_initial``: position is declared ``Fix`` at the symbolic level
6
6
  (so the solver consumes ``x_init_pin``), then each batch row overwrites the
7
7
  position slice with the sampled values. This avoids the per-iteration
8
8
  ``(position == parameter).convex()`` constraint while still enforcing the full
@@ -110,7 +110,7 @@ mass.final = [ox.Maximize(1.5)]
110
110
  position = ox.State("position", shape=(3,))
111
111
  position.max = [10.0, 10.0, 10.0]
112
112
  position.min = [-10.0, -10.0, -10.0]
113
- # Fix so x0_stack pins are consumed; per-batch values overwrite these defaults.
113
+ # Fix so x_initial pins are consumed; per-batch values overwrite these defaults.
114
114
  position.initial = [7.5, 4.5, 2.5]
115
115
  position.final = [0.0, ox.Free(0.0), ox.Free(0.0)]
116
116
 
@@ -193,7 +193,7 @@ constraint_exprs = []
193
193
  for st in states:
194
194
  constraint_exprs.extend([ox.ctcs(st <= st.max), ox.ctcs(st.min <= st)])
195
195
 
196
- # Initial position via x0_stack (Fix BC); terminal lateral via convex constraint.
196
+ # Initial position via x_initial pins (Fix BC); terminal lateral via convex constraint.
197
197
  constraint_exprs.append((position[1:3] == final_position).convex().at([N - 1]))
198
198
 
199
199
  constraint_exprs.append(ox.ctcs(1.0 * (mass - m_dry) >= 0))
@@ -414,15 +414,14 @@ if __name__ == "__main__":
414
414
  print(f"Sampled {N_BATCH} initial positions (alt ∈ [3, 9] m, lat ∈ [-7, 7] m)")
415
415
 
416
416
  # ── Compile + solve ───────────────────────────────────────────────────────
417
+ # x_initial is (B, n_x) — one extra leading axis — so it is batched; the
418
+ # terminal pin is omitted, so every element shares the default.
417
419
  default_init = np.asarray(problem.state.x_init_pin)
418
- x0_stack = np.broadcast_to(default_init, (N_BATCH, default_init.shape[0])).copy()
419
- x0_stack[:, POSITION_SLICE] = ic_batch
420
- x0_stack = jnp.asarray(x0_stack)
421
- xf_pin = np.asarray(problem.state.x_term_pin)
422
- xf_stack = jnp.broadcast_to(xf_pin, (N_BATCH, xf_pin.shape[0]))
420
+ x_initial = np.broadcast_to(default_init, (N_BATCH, default_init.shape[0])).copy()
421
+ x_initial[:, POSITION_SLICE] = ic_batch
423
422
 
424
423
  print("Compiling and running solve_batched …")
425
- results = problem.solve_batched(x0_stack=x0_stack, xf_stack=xf_stack)
424
+ results = problem.solve_batched(x_initial=jnp.asarray(x_initial))
426
425
 
427
426
  # ── Post-process: propagate all B solutions through nonlinear dynamics ────
428
427
  print("Post-processing (nonlinear propagation) …")
@@ -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 = '0.5.3.dev23'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev23')
21
+ __version__ = version = '0.5.3.dev25'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev25')
23
23
 
24
- __commit_id__ = commit_id = 'g107a1d50b'
24
+ __commit_id__ = commit_id = 'ge4b992a50'
@@ -37,6 +37,8 @@ from typing import Annotated, Any, Dict, List, Optional, Union
37
37
  from pydantic import BaseModel, ConfigDict, Field, field_validator
38
38
 
39
39
  from .autotuner import (
40
+ AcceptanceRatioAutotuner,
41
+ AcceptanceRatioHyper,
40
42
  AdaptiveProximalWeight,
41
43
  AdaptiveProximalWeightSpec,
42
44
  AugmentedLagrangian,
@@ -52,7 +54,9 @@ from .base import (
52
54
  AlgorithmHistory,
53
55
  AlgorithmState,
54
56
  AutotuningBase,
57
+ CandidateIterate,
55
58
  DiscretizationResult,
59
+ HyperParams,
56
60
  adaptive_state_code_to_str,
57
61
  )
58
62
  from .optimization_results import OptimizationResults
@@ -137,6 +141,7 @@ __all__ = [
137
141
  "AlgorithmHistory",
138
142
  "AlgorithmState",
139
143
  "AdaptiveStateCode",
144
+ "CandidateIterate",
140
145
  "adaptive_state_code_to_str",
141
146
  "DiscretizationResult",
142
147
  "Weights",
@@ -145,6 +150,9 @@ __all__ = [
145
150
  # PTR algorithm
146
151
  "PenalizedTrustRegion",
147
152
  "AutotuningBase",
153
+ "HyperParams",
154
+ "AcceptanceRatioAutotuner",
155
+ "AcceptanceRatioHyper",
148
156
  "AugmentedLagrangian",
149
157
  "AdaptiveProximalWeight",
150
158
  "ConstantProximalWeight",
@@ -1,11 +1,14 @@
1
1
  """SCP weight autotuning strategies."""
2
2
 
3
+ from .acceptance_ratio import AcceptanceRatioAutotuner, AcceptanceRatioHyper
3
4
  from .adaptive_proximal_weight import AdaptiveProximalWeight, AdaptiveProximalWeightSpec
4
5
  from .augmented_lagrangian import AugmentedLagrangian, AugmentedLagrangianSpec
5
6
  from .constant_proximal_weight import ConstantProximalWeight, ConstantProximalWeightSpec
6
7
  from .ramp_proximal_weight import RampProximalWeight, RampProximalWeightSpec
7
8
 
8
9
  __all__ = [
10
+ "AcceptanceRatioAutotuner",
11
+ "AcceptanceRatioHyper",
9
12
  "AdaptiveProximalWeight",
10
13
  "AdaptiveProximalWeightSpec",
11
14
  "AugmentedLagrangian",
@@ -0,0 +1,245 @@
1
+ """Acceptance-ratio autotuner family.
2
+
3
+ The acceptance-ratio autotuners share one decision rule: an acceptance ratio
4
+ :math:`\\rho` between the predicted and actual reduction of the nonlinear
5
+ objective drives a four-bucket update of the trust-region weight ``lam_prox``
6
+ (``REJECT`` / ``ACCEPT_HIGHER`` / ``ACCEPT_CONSTANT`` / ``ACCEPT_LOWER``). What
7
+ differs between members is the *multiplier* rule — how the virtual-control and
8
+ virtual-buffer weights (``lam_vc`` / ``lam_vb_*``) respond once an iterate is
9
+ accepted.
10
+
11
+ :class:`AcceptanceRatioAutotuner` owns the shared decision body and exposes a
12
+ single :meth:`AcceptanceRatioAutotuner._update_multipliers` hook for the
13
+ multiplier rule; subclasses supply only that hook.
14
+ :class:`AdaptiveProximalWeight` is the hook-default (multipliers held
15
+ constant); :class:`AugmentedLagrangian` overrides it with the
16
+ constraint-violation update.
17
+ """
18
+
19
+ from typing import TYPE_CHECKING, List
20
+
21
+ import jax
22
+ import jax.numpy as jnp
23
+
24
+ from openscvx.config import Config
25
+ from openscvx.utils.printing import (
26
+ Column,
27
+ Verbosity,
28
+ color_acceptance_ratio,
29
+ color_adaptive_state,
30
+ )
31
+
32
+ from ..base import AdaptiveStateCode, AutotuningBase, HyperParams
33
+
34
+ if TYPE_CHECKING:
35
+ from openscvx.lowered import LoweredJaxConstraints
36
+
37
+ from ..base import AlgorithmState, CandidateIterate
38
+
39
+
40
+ class AcceptanceRatioHyper(HyperParams):
41
+ """Knobs shared by every acceptance-ratio autotuner.
42
+
43
+ ``lam_cost_drop`` is the iteration after which ``lam_cost`` relaxation
44
+ applies (``state.k > lam_cost_drop``): ``-1`` relaxes from the first
45
+ iteration, and the default ``lam_cost_relax=1.0`` makes that a no-op.
46
+ """
47
+
48
+ gamma_1: float = 2.0
49
+ gamma_2: float = 0.5
50
+ eta_0: float = 1e-2
51
+ eta_1: float = 1e-1
52
+ eta_2: float = 0.8
53
+ lam_prox_min: float = 1e-3
54
+ lam_prox_max: float = 1e4
55
+ lam_cost_drop: int = -1
56
+ lam_cost_relax: float = 1.0
57
+
58
+
59
+ class AcceptanceRatioAutotuner(AutotuningBase):
60
+ """Four-bucket acceptance-ratio update on ``lam_prox``.
61
+
62
+ The acceptance ratio :math:`\\rho` (actual over predicted nonlinear
63
+ reduction) selects one of four buckets — ``REJECT`` / ``ACCEPT_HIGHER`` /
64
+ ``ACCEPT_CONSTANT`` / ``ACCEPT_LOWER`` — via a ``jnp.where`` cascade so the
65
+ whole update traces under ``jax.jit``. Subclasses supply the multiplier
66
+ rule (how ``lam_vc`` / ``lam_vb_*`` respond on acceptance) through
67
+ :meth:`_update_multipliers`, and must assign an
68
+ :class:`AcceptanceRatioHyper` (or subclass) instance to ``self.hyper`` in
69
+ ``__init__`` — the shared body reads its knobs off ``state.hyper``.
70
+
71
+ ``update_weights`` is a pure functional update on the
72
+ :class:`AlgorithmState` pytree; see the base-class contract.
73
+ """
74
+
75
+ COLUMNS: List[Column] = [
76
+ Column("J_nonlin", "J_nonlin", 8, "{: .1e}", None, Verbosity.STANDARD),
77
+ Column("J_lin", "J_lin", 8, "{: .1e}", None, Verbosity.STANDARD),
78
+ Column("pred_reduction", "pred_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
79
+ Column("actual_reduction", "act_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
80
+ Column(
81
+ "acceptance_ratio",
82
+ "acc_ratio",
83
+ 9,
84
+ "{: .2e}",
85
+ color_acceptance_ratio,
86
+ Verbosity.STANDARD,
87
+ ),
88
+ Column("lam_prox", "lam_prox", 8, "{: .1e}", min_verbosity=Verbosity.FULL),
89
+ Column("adaptive_state", "Adaptive", 16, "{}", color_adaptive_state, Verbosity.FULL),
90
+ ]
91
+
92
+ def _update_multipliers(
93
+ self,
94
+ state: "AlgorithmState",
95
+ candidate: "CandidateIterate",
96
+ nodal_constraints: "LoweredJaxConstraints",
97
+ params: dict,
98
+ settings: Config,
99
+ new_lam_prox: jnp.ndarray,
100
+ ) -> dict:
101
+ """Return the multiplier-weight updates to apply on an accepted iterate.
102
+
103
+ Each returned entry maps an :class:`AlgorithmState` field name
104
+ (``lam_vc`` / ``lam_vb_nodal`` / ``lam_vb_cross``) to its updated
105
+ value, computed against the *candidate* trajectory; the shared body
106
+ gates each by acceptance (a rejected iterate keeps the previous value).
107
+ The default holds every multiplier constant — return ``{}``.
108
+ """
109
+ return {}
110
+
111
+ def update_weights(
112
+ self,
113
+ state: "AlgorithmState",
114
+ candidate: "CandidateIterate",
115
+ nodal_constraints: "LoweredJaxConstraints",
116
+ settings: Config,
117
+ params: dict,
118
+ ) -> "AlgorithmState":
119
+ """Return the next-iterate state per the acceptance-ratio rules.
120
+
121
+ Pure functional update — see class docstring.
122
+ """
123
+ candidate_x_prop = candidate.x_prop_plus[1:]
124
+ nonlin_cost, nonlin_pen, nodal_pen = self.calculate_nonlinear_penalty(
125
+ candidate_x_prop,
126
+ candidate.x,
127
+ candidate.u,
128
+ state.lam_vc,
129
+ state.lam_vb_nodal,
130
+ state.lam_vb_cross,
131
+ state.lam_cost,
132
+ nodal_constraints,
133
+ params,
134
+ settings,
135
+ )
136
+ J_nonlin = nonlin_cost + nonlin_pen + nodal_pen
137
+
138
+ # Cost relaxation: when state.k > hyper.lam_cost_drop, scale
139
+ # state.lam_cost; otherwise reset to the algorithm's initial weight
140
+ # (carried on the pytree as state.lam_cost_init, broadcast at
141
+ # from_settings()). Both constants ride the pytree so per-solve
142
+ # overrides and vmap sweeps reach the traced body. Scalar
143
+ # lam_cost_relax preserves the user-specified per-state weight ratios.
144
+ lam_cost_next = jnp.where(
145
+ state.k > state.hyper.lam_cost_drop,
146
+ state.lam_cost * state.hyper.lam_cost_relax,
147
+ state.lam_cost_init,
148
+ )
149
+
150
+ def first_iter(state):
151
+ # Iter 1: accept unconditionally, leave weights at their init values,
152
+ # only refresh trajectory + propagation fields.
153
+ return state.replace(
154
+ x=candidate.x,
155
+ u=candidate.u,
156
+ x_prop=candidate.x_prop,
157
+ x_prop_plus=candidate.x_prop_plus,
158
+ lam_cost=lam_cost_next,
159
+ J_nonlin=J_nonlin,
160
+ adaptive_state_code=jnp.asarray(int(AdaptiveStateCode.INITIAL), dtype=jnp.int32),
161
+ )
162
+
163
+ def later_iter(state):
164
+ # Recompute the previous iterate's J_nonlin from the pytree fields
165
+ # (state.x/state.u were the *previous* accepted iterate).
166
+ prev_x_prop = state.x_prop_plus[1:]
167
+ prev_cost, prev_pen, prev_nodal_pen = self.calculate_nonlinear_penalty(
168
+ prev_x_prop,
169
+ state.x,
170
+ state.u,
171
+ state.lam_vc,
172
+ state.lam_vb_nodal,
173
+ state.lam_vb_cross,
174
+ state.lam_cost,
175
+ nodal_constraints,
176
+ params,
177
+ settings,
178
+ )
179
+ prev_J_nonlin = prev_cost + prev_pen + prev_nodal_pen
180
+
181
+ actual = prev_J_nonlin - J_nonlin
182
+ predicted = prev_J_nonlin - candidate.J_lin
183
+ # If predicted reduction is exactly zero, force the reject bucket
184
+ # (rho = -inf) deterministically instead of raising.
185
+ safe_pred = jnp.where(predicted == 0.0, 1.0, predicted)
186
+ rho = jnp.where(predicted == 0.0, -jnp.inf, actual / safe_pred)
187
+
188
+ is_reject = rho < state.hyper.eta_0
189
+ is_accept_higher = (rho >= state.hyper.eta_0) & (rho < state.hyper.eta_1)
190
+ is_accept_constant = (rho >= state.hyper.eta_1) & (rho < state.hyper.eta_2)
191
+ # is_accept_lower implicit (else)
192
+ accepted = ~is_reject
193
+
194
+ # Compute both lam_prox candidates and gate.
195
+ lp_higher = jnp.minimum(state.hyper.lam_prox_max, state.hyper.gamma_1 * state.lam_prox)
196
+ lp_lower = jnp.maximum(state.hyper.lam_prox_min, state.hyper.gamma_2 * state.lam_prox)
197
+ new_lam_prox = jnp.where(
198
+ is_reject | is_accept_higher,
199
+ lp_higher,
200
+ jnp.where(is_accept_constant, state.lam_prox, lp_lower),
201
+ )
202
+
203
+ # Multiplier (virtual-control / virtual-buffer) updates: computed
204
+ # against the *candidate* trajectory and gated by `accepted`. Reject
205
+ # keeps the previous values (so the next subproblem doesn't see a
206
+ # bumped penalty that wasn't earned). The default hook returns {} —
207
+ # multipliers held constant.
208
+ multiplier_updates = self._update_multipliers(
209
+ state, candidate, nodal_constraints, params, settings, new_lam_prox
210
+ )
211
+ gated_multipliers = {
212
+ name: jnp.where(accepted, value, getattr(state, name))
213
+ for name, value in multiplier_updates.items()
214
+ }
215
+
216
+ code = jnp.where(
217
+ is_reject,
218
+ jnp.int32(AdaptiveStateCode.REJECT),
219
+ jnp.where(
220
+ is_accept_higher,
221
+ jnp.int32(AdaptiveStateCode.ACCEPT_HIGHER),
222
+ jnp.where(
223
+ is_accept_constant,
224
+ jnp.int32(AdaptiveStateCode.ACCEPT_CONSTANT),
225
+ jnp.int32(AdaptiveStateCode.ACCEPT_LOWER),
226
+ ),
227
+ ),
228
+ )
229
+
230
+ return state.replace(
231
+ x=jnp.where(accepted, candidate.x, state.x),
232
+ u=jnp.where(accepted, candidate.u, state.u),
233
+ x_prop=jnp.where(accepted, candidate.x_prop, state.x_prop),
234
+ x_prop_plus=jnp.where(accepted, candidate.x_prop_plus, state.x_prop_plus),
235
+ lam_prox=new_lam_prox,
236
+ lam_cost=lam_cost_next,
237
+ J_nonlin=jnp.where(accepted, J_nonlin, state.J_nonlin),
238
+ predicted_reduction=predicted,
239
+ actual_reduction=actual,
240
+ acceptance_ratio=rho,
241
+ adaptive_state_code=code,
242
+ **gated_multipliers,
243
+ )
244
+
245
+ return jax.lax.cond(state.k == 1, first_iter, later_iter, state)
@@ -0,0 +1,74 @@
1
+ """Adaptive proximal-weight autotuner.
2
+
3
+ Same acceptance-ratio decision logic as the rest of the family for
4
+ ``lam_prox``, but ``lam_vc`` and ``lam_vb_*`` are held constant at their
5
+ current values — the default multiplier hook.
6
+ """
7
+
8
+ from typing import Literal
9
+
10
+ from pydantic import BaseModel, ConfigDict
11
+
12
+ from .acceptance_ratio import AcceptanceRatioAutotuner, AcceptanceRatioHyper
13
+
14
+
15
+ class AdaptiveProximalWeight(AcceptanceRatioAutotuner):
16
+ """PTR-style proximal adaptation with fixed virtual-penalty weights.
17
+
18
+ Inherits the four-bucket acceptance-ratio update on ``lam_prox`` from
19
+ :class:`~openscvx.algorithms.autotuner.acceptance_ratio.AcceptanceRatioAutotuner`
20
+ and keeps the default multiplier hook, so the virtual-control and
21
+ virtual-buffer weights are carried unchanged.
22
+
23
+ ``update_weights`` is a pure functional update on the
24
+ :class:`AlgorithmState` pytree; see the base-class contract.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ gamma_1: float = 2.0,
30
+ gamma_2: float = 0.5,
31
+ eta_0: float = 1e-2,
32
+ eta_1: float = 1e-1,
33
+ eta_2: float = 0.8,
34
+ lam_prox_min: float = 1e-3,
35
+ lam_prox_max: float = 1e4,
36
+ lam_cost_drop: int = -1,
37
+ lam_cost_relax: float = 1.0,
38
+ ):
39
+ self.hyper = AcceptanceRatioHyper(
40
+ gamma_1=gamma_1,
41
+ gamma_2=gamma_2,
42
+ eta_0=eta_0,
43
+ eta_1=eta_1,
44
+ eta_2=eta_2,
45
+ lam_prox_min=lam_prox_min,
46
+ lam_prox_max=lam_prox_max,
47
+ lam_cost_drop=lam_cost_drop,
48
+ lam_cost_relax=lam_cost_relax,
49
+ )
50
+
51
+
52
+ # =============================================================================
53
+ # Pydantic spec for dict / YAML validation
54
+ # =============================================================================
55
+
56
+
57
+ class AdaptiveProximalWeightSpec(BaseModel):
58
+ """Validates AdaptiveProximalWeight configuration from dict/YAML input."""
59
+
60
+ type: Literal["AdaptiveProximalWeight"] = "AdaptiveProximalWeight"
61
+ gamma_1: float = 2.0
62
+ gamma_2: float = 0.5
63
+ eta_0: float = 1e-2
64
+ eta_1: float = 1e-1
65
+ eta_2: float = 0.8
66
+ lam_prox_min: float = 1e-3
67
+ lam_prox_max: float = 1e4
68
+ lam_cost_drop: int = -1
69
+ lam_cost_relax: float = 1.0
70
+
71
+ model_config = ConfigDict(extra="forbid")
72
+
73
+ def build(self) -> AdaptiveProximalWeight:
74
+ return AdaptiveProximalWeight(**self.model_dump(exclude={"type"}, exclude_unset=True))