openscvx 0.5.3.dev15__tar.gz → 0.5.3.dev16__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 (382) hide show
  1. {openscvx-0.5.3.dev15/openscvx.egg-info → openscvx-0.5.3.dev16}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UnderTheHood/lowering_architecture.md +18 -8
  3. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/_version.py +3 -3
  4. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/base.py +39 -7
  5. openscvx-0.5.3.dev16/openscvx/algorithms/scvx/iteration.py +369 -0
  6. openscvx-0.5.3.dev16/openscvx/algorithms/scvx/penalized_trust_region.py +330 -0
  7. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/problem.py +51 -51
  8. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/cvxpy_ptr_solver.py +33 -2
  9. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/qpax_ptr_solver.py +37 -26
  10. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/caching.py +25 -17
  11. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16/openscvx.egg-info}/PKG-INFO +1 -1
  12. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/SOURCES.txt +5 -0
  13. openscvx-0.5.3.dev16/tests/algorithms/_iteration_helpers.py +27 -0
  14. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/autotuner/test_update_weights_jit.py +1 -0
  15. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/test_algorithm_state_pytree.py +1 -0
  16. openscvx-0.5.3.dev16/tests/algorithms/test_iteration_fn_jit.py +47 -0
  17. openscvx-0.5.3.dev16/tests/algorithms/test_iteration_fn_parity.py +64 -0
  18. openscvx-0.5.3.dev16/tests/algorithms/test_make_solve_loop.py +41 -0
  19. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/_iteration_callback_helpers.py +86 -0
  20. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_moreau.py +5 -4
  21. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_qpax.py +12 -11
  22. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_vmap.py +3 -2
  23. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_moreau_ptr_solver.py +3 -1
  24. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_qpax_ptr_solver.py +9 -3
  25. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_autotuning.py +1 -0
  26. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_brachistochrone.py +10 -21
  27. openscvx-0.5.3.dev15/openscvx/algorithms/scvx/penalized_trust_region.py +0 -794
  28. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/assets/logo.svg +0 -0
  29. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/release-drafter.yml +0 -0
  30. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/_docs.yml +0 -0
  31. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/branch-name.yml +0 -0
  32. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/docs.yml +0 -0
  33. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/lint.yml +0 -0
  34. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/nightly.yml +0 -0
  35. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/release-drafter.yml +0 -0
  36. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/release.yml +0 -0
  37. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/tests-integration.yml +0 -0
  38. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/tests-unit.yml +0 -0
  39. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.gitignore +0 -0
  40. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.gitmodules +0 -0
  41. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/CONTRIBUTING.md +0 -0
  42. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/LICENSE +0 -0
  43. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/README.md +0 -0
  44. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/constraint_reformulation.md +0 -0
  45. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/control_parameterization.md +0 -0
  46. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/discretization.md +0 -0
  47. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/ocp.md +0 -0
  48. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/scvx.md +0 -0
  49. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/time_dilation.md +0 -0
  50. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  51. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/00_introduction.md +0 -0
  52. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  53. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  54. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  55. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  56. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/05_visualization.md +0 -0
  57. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/06_logic.md +0 -0
  58. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/07_lie.md +0 -0
  59. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/08_mpcc.md +0 -0
  60. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  61. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/favicon.png +0 -0
  62. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ct-scvx_dark.png +0 -0
  63. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ct-scvx_light.png +0 -0
  64. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ctcs_dark.png +0 -0
  65. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ctcs_light.png +0 -0
  66. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/problem_class_dark.png +0 -0
  67. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/problem_class_light.png +0 -0
  68. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/logo.svg +0 -0
  69. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/openscvx_logo_square.png +0 -0
  70. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/viser-client/index.html +0 -0
  71. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  72. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  73. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/citation.md +0 -0
  74. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/examples.md +0 -0
  75. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/index.md +0 -0
  76. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/javascripts/mathjax.js +0 -0
  77. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/versions.json +0 -0
  78. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/_viser_embed_export.py +0 -0
  79. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/brachistochrone.py +0 -0
  80. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/hypersensitive.py +0 -0
  81. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/impulsive.py +0 -0
  82. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/stl_integer_variable.py +0 -0
  83. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/stl_or.py +0 -0
  84. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/7_dof_arm.py +0 -0
  85. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/_camera.py +0 -0
  86. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/_render.py +0 -0
  87. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/_sensor_view.py +0 -0
  88. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/dr_vp_polytope.py +0 -0
  89. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  90. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/logo.py +0 -0
  91. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  92. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/3_dof_arm.py +0 -0
  93. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/7_dof_arm.py +0 -0
  94. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/7_dof_arm_collision.py +0 -0
  95. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/7_dof_arm_vp.py +0 -0
  96. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  97. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  98. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car.py +0 -0
  99. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_disjoint.py +0 -0
  100. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  101. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_obstacle_stl.py +0 -0
  102. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_stl_or.py +0 -0
  103. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_waypoint_stl.py +0 -0
  104. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/cinema_vp.py +0 -0
  105. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_double_integrator.py +0 -0
  106. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_vp.py +0 -0
  107. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_vp_nodal.py +0 -0
  108. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_vp_polytope.py +0 -0
  109. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/drone_racing.py +0 -0
  110. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/logo.py +0 -0
  111. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/logo_utils/acl_logo.svg +0 -0
  112. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  113. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/obstacle_avoidance.py +0 -0
  114. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  115. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  116. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/cartpole_mjx.py +0 -0
  117. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/double_cartpole_mjx.py +0 -0
  118. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/skydio_x2_mjx.py +0 -0
  119. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  120. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/triple_cartpole_game.py +0 -0
  121. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/triple_cartpole_mjx.py +0 -0
  122. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/double_integrator_discrete.py +0 -0
  123. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/double_integrator_drone_racing.py +0 -0
  124. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  125. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  126. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  127. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/plotting.py +0 -0
  128. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/plotting_viser.py +0 -0
  129. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  130. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  131. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  132. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  133. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  134. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  135. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  136. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  137. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/cinema_vp_realtime.py +0 -0
  138. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/drone_racing_realtime.py +0 -0
  139. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/dubins_car_realtime.py +0 -0
  140. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  141. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/rocket/3DoF_pdg.py +0 -0
  142. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/rocket/6DoF_pdg.py +0 -0
  143. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/halo_orbit.py +0 -0
  144. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/hohmann_transfer.py +0 -0
  145. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/let_transfer.py +0 -0
  146. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/proxops_cw.py +0 -0
  147. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/relative_loitering.py +0 -0
  148. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/ctlos_cine.gif +0 -0
  149. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/ctlos_dr.gif +0 -0
  150. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/dtlos_cine.gif +0 -0
  151. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/dtlos_dr.gif +0 -0
  152. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/openscvx_logo.svg +0 -0
  153. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/openscvx_logo_square.png +0 -0
  154. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/oscvx_structure_full_dark.svg +0 -0
  155. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/video_preview.png +0 -0
  156. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/__init__.py +0 -0
  157. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/custom.css +0 -0
  158. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  159. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  160. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  161. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/home.html +0 -0
  162. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/main.html +0 -0
  163. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-diagram.html +0 -0
  164. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-dropin-banner.html +0 -0
  165. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-hero.html +0 -0
  166. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-pipeline.html +0 -0
  167. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-viser-strip.html +0 -0
  168. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/mkdocs.yml +0 -0
  169. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/__init__.py +0 -0
  170. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/__main__.py +0 -0
  171. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/__init__.py +0 -0
  172. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/__init__.py +0 -0
  173. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  174. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
  175. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  176. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  177. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/optimization_results.py +0 -0
  178. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/scvx/__init__.py +0 -0
  179. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/weights.py +0 -0
  180. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/config.py +0 -0
  181. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/__init__.py +0 -0
  182. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/base.py +0 -0
  183. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/discretize_linearize.py +0 -0
  184. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/linearize_discretize.py +0 -0
  185. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  186. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  187. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  188. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  189. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/__init__.py +0 -0
  190. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/byof.py +0 -0
  191. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/lowering.py +0 -0
  192. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/validation.py +0 -0
  193. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/init/__init__.py +0 -0
  194. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/init/interpolation.py +0 -0
  195. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/init/inverse_kinematics.py +0 -0
  196. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/__init__.py +0 -0
  197. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/base.py +0 -0
  198. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/menagerie.py +0 -0
  199. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/mjx.py +0 -0
  200. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrators/__init__.py +0 -0
  201. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrators/diffrax.py +0 -0
  202. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrators/runge_kutta.py +0 -0
  203. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/loader.py +0 -0
  204. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/__init__.py +0 -0
  205. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/cvxpy_constraints.py +0 -0
  206. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/cvxpy_variables.py +0 -0
  207. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/dynamics.py +0 -0
  208. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/jax_constraints.py +0 -0
  209. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/parameters.py +0 -0
  210. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/problem.py +0 -0
  211. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/unified.py +0 -0
  212. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/__init__.py +0 -0
  213. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/plotting.py +0 -0
  214. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/scp_iteration.py +0 -0
  215. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/__init__.py +0 -0
  216. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/animated.py +0 -0
  217. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/orbits.py +0 -0
  218. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/plotly_integration.py +0 -0
  219. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/primitives.py +0 -0
  220. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/scp.py +0 -0
  221. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/server.py +0 -0
  222. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/propagation/__init__.py +0 -0
  223. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/propagation/post_processing.py +0 -0
  224. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/propagation/propagation.py +0 -0
  225. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/__init__.py +0 -0
  226. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/base.py +0 -0
  227. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  228. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/ptr_solver.py +0 -0
  229. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/__init__.py +0 -0
  230. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/augmentation.py +0 -0
  231. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/builder.py +0 -0
  232. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/constraint_set.py +0 -0
  233. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/__init__.py +0 -0
  234. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/arithmetic.py +0 -0
  235. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/array.py +0 -0
  236. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/constraint.py +0 -0
  237. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/control.py +0 -0
  238. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/expr.py +0 -0
  239. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  240. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  241. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/se3.py +0 -0
  242. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/so3.py +0 -0
  243. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/linalg.py +0 -0
  244. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/logic.py +0 -0
  245. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/math.py +0 -0
  246. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/parameter.py +0 -0
  247. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/spatial.py +0 -0
  248. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/state.py +0 -0
  249. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/stl.py +0 -0
  250. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/stljax.py +0 -0
  251. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/time.py +0 -0
  252. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/variable.py +0 -0
  253. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/vmap.py +0 -0
  254. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/hashing.py +0 -0
  255. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lower.py +0 -0
  256. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/__init__.py +0 -0
  257. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  258. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  259. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  260. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  261. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  262. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  263. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  264. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  265. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  266. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  267. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  268. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  269. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  270. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  271. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  272. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  273. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  274. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  275. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  276. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  277. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  278. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  279. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  280. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  281. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  282. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  283. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  284. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  285. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  286. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/__init__.py +0 -0
  287. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/_registry.py +0 -0
  288. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/array.py +0 -0
  289. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/constraint.py +0 -0
  290. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/lie.py +0 -0
  291. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/linalg.py +0 -0
  292. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/logic.py +0 -0
  293. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/math.py +0 -0
  294. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/parser.py +0 -0
  295. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/spatial.py +0 -0
  296. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/stl.py +0 -0
  297. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/stljax.py +0 -0
  298. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/tokenizer.py +0 -0
  299. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/preprocessing.py +0 -0
  300. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/problem.py +0 -0
  301. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/sparsity.py +0 -0
  302. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/unified.py +0 -0
  303. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/__init__.py +0 -0
  304. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/cache.py +0 -0
  305. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/printing.py +0 -0
  306. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/profiling.py +0 -0
  307. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/utils.py +0 -0
  308. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/dependency_links.txt +0 -0
  309. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/entry_points.txt +0 -0
  310. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/requires.txt +0 -0
  311. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/top_level.txt +0 -0
  312. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/pyproject.toml +0 -0
  313. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/scripts/gen_example_pages.py +0 -0
  314. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/scripts/gen_ref_pages.py +0 -0
  315. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  316. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/setup.cfg +0 -0
  317. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/__init__.py +0 -0
  318. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/_marks.py +0 -0
  319. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/__init__.py +0 -0
  320. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/autotuner/__init__.py +0 -0
  321. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/brachistochrone_analytical.py +0 -0
  322. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/conftest.py +0 -0
  323. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/expr/__init__.py +0 -0
  324. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/expr/test_gmsr.py +0 -0
  325. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/fixtures/brachistochrone.json +0 -0
  326. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/fixtures/brachistochrone.yaml +0 -0
  327. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/hohmann_analytical.py +0 -0
  328. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/integrations/__init__.py +0 -0
  329. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/integrations/test_mjx.py +0 -0
  330. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/integrations/test_mjx_dynamics.py +0 -0
  331. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/__init__.py +0 -0
  332. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  333. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  334. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_subproblem_pytree.py +0 -0
  335. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/__init__.py +0 -0
  336. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/__init__.py +0 -0
  337. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_arithmetic.py +0 -0
  338. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_array.py +0 -0
  339. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_constraint.py +0 -0
  340. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_expr.py +0 -0
  341. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_lie.py +0 -0
  342. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_linalg.py +0 -0
  343. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_logic.py +0 -0
  344. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_math.py +0 -0
  345. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_node_reference.py +0 -0
  346. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_parameters.py +0 -0
  347. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_scaling.py +0 -0
  348. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_spatial.py +0 -0
  349. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_stl.py +0 -0
  350. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_variable.py +0 -0
  351. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_vmap.py +0 -0
  352. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/__init__.py +0 -0
  353. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_array.py +0 -0
  354. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_constraint.py +0 -0
  355. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_lie.py +0 -0
  356. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_linalg.py +0 -0
  357. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_load.py +0 -0
  358. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_logic.py +0 -0
  359. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_math.py +0 -0
  360. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_parser.py +0 -0
  361. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_spatial.py +0 -0
  362. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_stl.py +0 -0
  363. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_tokenizer.py +0 -0
  364. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_vmap.py +0 -0
  365. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_augmentation.py +0 -0
  366. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_hashing.py +0 -0
  367. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_lower_cvxpy.py +0 -0
  368. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_lower_jax.py +0 -0
  369. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_preprocessing.py +0 -0
  370. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_sparsity.py +0 -0
  371. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_unified.py +0 -0
  372. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_cvxpygen_optional.py +0 -0
  373. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_discretization.py +0 -0
  374. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_examples.py +0 -0
  375. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_expert.py +0 -0
  376. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_impulsive.py +0 -0
  377. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_init.py +0 -0
  378. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_integrators.py +0 -0
  379. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_loader.py +0 -0
  380. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_optimization_results.py +0 -0
  381. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_plotting.py +0 -0
  382. {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_propagation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev15
3
+ Version: 0.5.3.dev16
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
@@ -168,18 +168,28 @@ of the abstract `PTRSolver` base. Three backends ship today:
168
168
  | Backend | Class | Selector | Notes |
169
169
  |---------|-------|----------|-------|
170
170
  | CVXPy (default) | `CVXPyPTRSolver` | `solver={"backend": "cvxpy"}` (default) | DCP graph via CVXPy, dispatched to QOCO / CLARABEL / etc. Supports user `.convex()` constraints, cross-node constraints, CTCS, and impulsive controls. Optional cvxpygen code generation. |
171
- | QPAX | `QPAXPTRSolver` | `solver={"backend": "qpax"}` | JAX-native QP via `qpax.solve_qp`. Flat `(Q, q, A, b, G, h)` assembly. Supports box / dynamics (continuous and impulsive) / CTCS / boundary-Fix; **rejects** user `.convex()` and cross-node at `initialize()` with a clear "use `CVXPyPTRSolver`" message. Enables a path toward an end-to-end JAX-differentiable SCP loop in follow-up work. |
171
+ | QPAX | `QPAXPTRSolver` | `solver={"backend": "qpax"}` | JAX-native QP via `qpax.solve_qp`. Flat `(Q, q, A, b, G, h)` assembly. Supports box / dynamics (continuous and impulsive) / CTCS / boundary-Fix; **rejects** user `.convex()` and cross-node at `initialize()` with a clear "use `CVXPyPTRSolver`" message. The `iteration_callback` uses `qpax.solve_qp`, whose convergence flag maps to a `status_code` so a diverged solve fails loudly (chosen over the differentiable `solve_qp_primal`, which exposes no such flag). |
172
172
  | Moreau | `MoreauPTRSolver` | `solver={"backend": "moreau"}` | JAX-native conic solver (`moreau.jax.Solver`). Sparse CSR assembly; SOC epigraphs for the L1 / pos PTR penalties (fewer variables and rows than QPAX). Warm-starts between SCP iterations. Same supported subset as QPAX (continuous and impulsive dynamics). Paves the way for user `.convex()` SOC support in a follow-up. |
173
173
 
174
174
  Each backend exposes two per-iteration entry points: the historical NumPy
175
- `update_*` + `solve()` stages used by today's Python-side SCP loop, and a
175
+ `update_*` + `solve()` stages (kept for direct / interactive solver use), and a
176
176
  JAX-pure `iteration_callback()` built once at `initialize()`. The callback
177
- returns a `(state, SubproblemData) -> SubproblemSolution` callable; all
178
- three backends emit the same input/output pytree shape so the callable
179
- composes with `jax.jit` and `jax.vmap` (CVXPy via `jax.pure_callback` with
180
- `vmap_method="sequential"` — its batched solves are serial). The downstream
181
- batchable-`Problem.solve()` work wraps this callback in `lax.while_loop` to
182
- keep the entire SCP iteration on the JAX boundary.
177
+ returns a `(state, SubproblemData) -> SubproblemSolution` callable; all three
178
+ backends emit the same input/output pytree shape (CVXPy host-calls via
179
+ `jax.pure_callback`).
180
+
181
+ `Problem.initialize()` fuses that callback with discretization, constraint
182
+ linearization, the SCP metrics, and the autotuner into one JAX function —
183
+ `iteration_fn`, built by `make_scp_iteration`
184
+ (`openscvx/algorithms/scvx/iteration.py`). A single JIT'd `iteration_fn` call
185
+ per iteration replaces the former per-step NumPy↔JAX stitching, and the Python
186
+ SCP loop now drives that one fused body. Forward propagation stays a separate
187
+ JAX export, used only by `post_process()` — so a compiled problem holds **one
188
+ `iteration_fn` plus one propagation export**, not three discretization /
189
+ propagation exports stitched together in Python. Because `iteration_fn` is a
190
+ registered pytree in and out, it also composes with `jax.jit`; `make_solve_loop`
191
+ wraps it in `lax.while_loop` as the primitive for a future fully-JAX-driven
192
+ solve.
183
193
 
184
194
  Picking a backend at construction time:
185
195
 
@@ -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.dev15'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev15')
21
+ __version__ = version = '0.5.3.dev16'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev16')
23
23
 
24
- __commit_id__ = commit_id = 'ge47b6d19c'
24
+ __commit_id__ = commit_id = 'gb2479bf05'
@@ -29,7 +29,6 @@ from openscvx.utils.printing import Column
29
29
  if TYPE_CHECKING:
30
30
  from openscvx.config import Config
31
31
  from openscvx.lowered.jax_constraints import LoweredJaxConstraints
32
- from openscvx.solvers import ConvexSolver
33
32
 
34
33
  from .weights import Weights
35
34
 
@@ -373,6 +372,16 @@ class AlgorithmState:
373
372
  actual_reduction: Actual reduction in ``J_nonlin`` for this iter.
374
373
  acceptance_ratio: ``actual_reduction / predicted_reduction``.
375
374
  adaptive_state_code: :class:`AdaptiveStateCode` value as ``int32``.
375
+ x_init_pin: Initial-state boundary condition, shape ``(n_states,)``.
376
+ ``jnp.nan`` where the state is not pinned at t0 (``initial_type``
377
+ is not ``"Fix"``). Carried on the pytree — rather than read from
378
+ ``settings`` — so the fused SCP iteration body assembles the
379
+ subproblem's initial boundary rows as a pure function of state,
380
+ and a future ``jax.vmap`` over problems can batch boundary
381
+ conditions per element.
382
+ x_term_pin: Terminal-state boundary condition, shape ``(n_states,)``.
383
+ ``jnp.nan`` where the state is not pinned at tf (``final_type`` is
384
+ not ``"Fix"``).
376
385
  """
377
386
 
378
387
  x: jnp.ndarray
@@ -394,6 +403,8 @@ class AlgorithmState:
394
403
  actual_reduction: jnp.ndarray
395
404
  acceptance_ratio: jnp.ndarray
396
405
  adaptive_state_code: jnp.ndarray
406
+ x_init_pin: jnp.ndarray
407
+ x_term_pin: jnp.ndarray
397
408
 
398
409
  # Field order is the source of truth for tree_flatten / tree_unflatten;
399
410
  # keep _FIELDS in sync with the dataclass field declarations above.
@@ -417,6 +428,8 @@ class AlgorithmState:
417
428
  "actual_reduction",
418
429
  "acceptance_ratio",
419
430
  "adaptive_state_code",
431
+ "x_init_pin",
432
+ "x_term_pin",
420
433
  )
421
434
 
422
435
  def replace(self, **changes) -> "AlgorithmState":
@@ -475,6 +488,17 @@ class AlgorithmState:
475
488
  else:
476
489
  lam_cost_init = np.full(n_states, weights.lam_cost)
477
490
 
491
+ # Boundary-condition pins: the physical value where the state is fixed
492
+ # at t0 / tf, ``nan`` elsewhere. The subproblem only reads these at
493
+ # ``"Fix"`` entries, so the sentinel marks "unpinned" without poisoning
494
+ # any value the solver consumes.
495
+ x_initial = np.asarray(settings.sim.x.initial, dtype=float).reshape(-1)
496
+ x_final = np.asarray(settings.sim.x.final, dtype=float).reshape(-1)
497
+ init_fixed = np.asarray(settings.sim.x.initial_type) == "Fix"
498
+ final_fixed = np.asarray(settings.sim.x.final_type) == "Fix"
499
+ x_init_pin = np.where(init_fixed, x_initial, np.nan)
500
+ x_term_pin = np.where(final_fixed, x_final, np.nan)
501
+
478
502
  return cls(
479
503
  x=put(jnp.asarray(settings.sim.x.guess, dtype=f)),
480
504
  u=put(jnp.asarray(settings.sim.u.guess, dtype=f)),
@@ -495,6 +519,8 @@ class AlgorithmState:
495
519
  actual_reduction=put(jnp.asarray(0.0, dtype=f)),
496
520
  acceptance_ratio=put(jnp.asarray(0.0, dtype=f)),
497
521
  adaptive_state_code=put(jnp.asarray(int(AdaptiveStateCode.INITIAL), dtype=i)),
522
+ x_init_pin=put(jnp.asarray(x_init_pin, dtype=f)),
523
+ x_term_pin=put(jnp.asarray(x_term_pin, dtype=f)),
498
524
  )
499
525
 
500
526
 
@@ -798,15 +824,21 @@ class Algorithm(ABC):
798
824
  @abstractmethod
799
825
  def initialize(
800
826
  self,
801
- solver: "ConvexSolver",
802
- discretization_solver: callable,
803
- jax_constraints: "LoweredJaxConstraints",
827
+ iteration_fn: Callable,
804
828
  emitter: callable,
805
- params: dict,
829
+ jax_constraints: "LoweredJaxConstraints",
806
830
  settings: "Config",
807
- discretization_solver_impulsive: Optional[Callable] = None,
808
831
  ) -> None:
809
- """Initialize the algorithm and store compiled infrastructure."""
832
+ """Store the fused SCP iteration body and per-iteration infrastructure.
833
+
834
+ Args:
835
+ iteration_fn: The JAX-pure ``(state, params) -> (next_state,
836
+ diagnostics)`` body built by
837
+ :func:`~openscvx.algorithms.scvx.iteration.make_scp_iteration`.
838
+ emitter: Per-iteration diagnostics sink (printing queue / no-op).
839
+ jax_constraints: Lowered JAX constraints the body operates over.
840
+ settings: Problem configuration.
841
+ """
810
842
  raise NotImplementedError
811
843
 
812
844
  @abstractmethod
@@ -0,0 +1,369 @@
1
+ """One fused, JAX-pure SCP iteration body.
2
+
3
+ Historically a single SCP step was stitched together in Python: ``Problem``
4
+ exported three separate JAX callables (continuous discretization, impulsive
5
+ discretization, propagation) and :meth:`PenalizedTrustRegion._subproblem`
6
+ invoked each one, copied NumPy out of every result, pushed the data through
7
+ the solver's ``update_*`` methods, and finally called ``solver.solve()``. Every
8
+ step crossed the NumPy↔JAX boundary several times, and there was no batch axis
9
+ anywhere.
10
+
11
+ This module collapses that stitching into one function. :func:`make_scp_iteration`
12
+ returns a ``(state, params) -> (state, IterationDiagnostics)`` callable that, on
13
+ the JAX side end to end, discretizes the current iterate, linearizes the
14
+ constraints, packs a :class:`~openscvx.solvers.ptr_solver.SubproblemData`, hands
15
+ it to the backend's :meth:`~openscvx.solvers.ptr_solver.PTRSolver.iteration_callback`,
16
+ and folds the returned :class:`~openscvx.solvers.ptr_solver.SubproblemSolution`
17
+ through the autotuner — producing the next :class:`AlgorithmState`. The
18
+ :class:`IterationDiagnostics` riding alongside carry the host-side bookkeeping
19
+ (raw discretization matrices, trust-region / virtual-control matrices, cost,
20
+ status) that the Python-loop ``step()`` records into ``AlgorithmHistory`` and
21
+ emits, exactly as the legacy path did. Because state is a registered pytree, the
22
+ body composes with ``jax.jit`` and ``jax.vmap``.
23
+
24
+ :func:`make_solve_loop` wraps that body in a ``lax.while_loop`` keyed on the SCP
25
+ convergence metrics, projecting the diagnostics away so the loop carry stays
26
+ ``state -> state``. It exists as a primitive for tests and for the JAX-pure
27
+ ``.solve()`` path in follow-up work; today's ``Problem.solve()`` still drives the
28
+ body from a Python ``while`` loop, so behavior is unchanged.
29
+ """
30
+
31
+ from dataclasses import dataclass, fields
32
+ from typing import TYPE_CHECKING, Callable, Tuple
33
+
34
+ import jax
35
+ import jax.numpy as jnp
36
+ import numpy as np
37
+
38
+ from openscvx.solvers.ptr_solver import SubproblemData, SubproblemSolution
39
+
40
+ from ..base import AlgorithmState, CandidateIterate
41
+
42
+ if TYPE_CHECKING:
43
+ from openscvx.config import Config
44
+ from openscvx.lowered import LoweredJaxConstraints
45
+
46
+ from ..base import AutotuningBase
47
+
48
+
49
+ @jax.tree_util.register_pytree_node_class
50
+ @dataclass(frozen=True)
51
+ class IterationDiagnostics:
52
+ """Host-side bookkeeping produced alongside the next :class:`AlgorithmState`.
53
+
54
+ These ride beside the state out of :func:`make_scp_iteration` so the
55
+ Python-loop ``step()`` can populate :class:`AlgorithmHistory` and the
56
+ emitter exactly as the legacy ``_subproblem`` did — the data they carry is
57
+ not on the JAX-traceable state pytree (raw discretization matrices are
58
+ large and host-only; cost / status / ``J_lin`` come from the subproblem
59
+ solve). :func:`make_solve_loop` projects them away.
60
+
61
+ Attributes:
62
+ cost: Boundary-weighted objective at the candidate (scalar) — the
63
+ ``cost[-1]`` the emitter prints.
64
+ status: Subproblem :class:`StatusCode` as ``int32``.
65
+ J_lin: Subproblem optimal (linearized) cost (scalar).
66
+ V: Raw continuous discretization matrix of the candidate.
67
+ W: Raw impulsive discretization matrix of the candidate.
68
+ TR: Scaled trust-region step matrix, shape ``(n_x + n_u, N)``.
69
+ VC: Scaled virtual-control matrix, shape ``(N-1, n_x)``.
70
+ """
71
+
72
+ cost: jnp.ndarray
73
+ status: jnp.ndarray
74
+ J_lin: jnp.ndarray
75
+ V: jnp.ndarray
76
+ W: jnp.ndarray
77
+ TR: jnp.ndarray
78
+ VC: jnp.ndarray
79
+
80
+ def tree_flatten(self):
81
+ children = tuple(getattr(self, f.name) for f in fields(self))
82
+ return children, None
83
+
84
+ @classmethod
85
+ def tree_unflatten(cls, aux, children):
86
+ return cls(*children)
87
+
88
+
89
+ def make_scp_iteration(
90
+ dis_continuous: Callable,
91
+ dis_impulsive: Callable,
92
+ jax_constraints: "LoweredJaxConstraints",
93
+ solver_callback: Callable[[AlgorithmState, SubproblemData], SubproblemSolution],
94
+ autotuner: "AutotuningBase",
95
+ settings: "Config",
96
+ ) -> Callable[[AlgorithmState, dict], Tuple[AlgorithmState, IterationDiagnostics]]:
97
+ """Build one JAX-pure SCP iteration body.
98
+
99
+ The returned ``iteration_fn(state, params)`` performs a single SCP step and
100
+ returns ``(next_state, diagnostics)``. It is the fused mirror of the legacy
101
+ discretize → linearize → solve → autotune pipeline:
102
+
103
+ 1. Discretize the continuous dynamics about the current iterate
104
+ (``state.x`` / ``state.u``) → ``A_d, B_d, C_d, x_prop``.
105
+ 2. Discretize the impulsive/discrete dynamics about the propagated nodes →
106
+ ``x_prop_plus, D_d, E_d``.
107
+ 3. Evaluate every nodal / cross-node constraint and its gradients.
108
+ 4. Pack the linearization, penalty weights, and boundary pins into a
109
+ :class:`SubproblemData`.
110
+ 5. Hand it to ``solver_callback`` (the backend's ``iteration_callback``),
111
+ which returns a :class:`SubproblemSolution`.
112
+ 6. Compute the ``J_tr / J_vb / J_vc`` metrics and fold the candidate through
113
+ the autotuner to produce the next state, alongside an
114
+ :class:`IterationDiagnostics`.
115
+
116
+ The current-iterate discretization (steps 1–2) is recomputed every call
117
+ rather than read from a carried ``state.x_prop``; see the plan's decision
118
+ log. The discretization solvers are built by the caller (``Problem``) and
119
+ captured here so the caching policy stays in its own layer; the constraint
120
+ linearizers, per-backend solver callback, autotuner, and settings are
121
+ likewise closure constants.
122
+
123
+ Args:
124
+ dis_continuous: Continuous discretization solver,
125
+ ``(x, u, params) -> (A_d, B_d, C_d, x_prop, V)``. A ``jax.jit``
126
+ callable (vmappable) or a ``jax.export`` wrapper (``.call``).
127
+ dis_impulsive: Impulsive discretization solver,
128
+ ``(x_nodes, u, params) -> (x_prop_plus, D_d, E_d, W)``.
129
+ jax_constraints: Lowered nodal / cross-node JAX constraints.
130
+ solver_callback: ``(state, SubproblemData) -> SubproblemSolution`` from
131
+ the convex backend's :meth:`iteration_callback`.
132
+ autotuner: Weight-update strategy applied to the candidate.
133
+ settings: Problem configuration (scaling matrices, boundary types).
134
+
135
+ Returns:
136
+ ``iteration_fn(state, params) -> (next_state, diagnostics)``.
137
+ """
138
+ N = settings.sim.n
139
+ n_x = settings.sim.n_states
140
+ n_u = settings.sim.n_controls
141
+ n_nodal = len(jax_constraints.nodal)
142
+
143
+ # Accept either a bare ``jax.jit`` callable or a ``jax.export`` wrapper.
144
+ dis_continuous = dis_continuous.call if hasattr(dis_continuous, "call") else dis_continuous
145
+ dis_impulsive = dis_impulsive.call if hasattr(dis_impulsive, "call") else dis_impulsive
146
+
147
+ # Scaling matrices for the SCP convergence / diagnostic metrics (static).
148
+ inv_S_x = jnp.asarray(settings.sim.inv_S_x)
149
+ inv_S_u = jnp.asarray(settings.sim.inv_S_u)
150
+
151
+ # Boundary types drive the candidate cost reduction (static, host-side).
152
+ final_type = list(settings.sim.x.final_type)
153
+
154
+ # Node-0 prior recovery: fixed initial entries come from the boundary
155
+ # condition, free entries from the iterate. The impulsive discretization
156
+ # linearizes about the propagated nodes prefixed with this prior.
157
+ init_fixed = jnp.asarray(np.asarray(settings.sim.x.initial_type) == "Fix")
158
+ x_initial = jnp.asarray(np.asarray(settings.sim.x.initial, dtype=float))
159
+
160
+ def _discretize(x: jnp.ndarray, u: jnp.ndarray, params: dict):
161
+ """Discretize ``(x, u)`` through both dynamics; return propagation pieces.
162
+
163
+ Returns ``(A_d, B_d, C_d, x_prop, x_prop_plus, D_d, E_d, V, W)`` — ``V``
164
+ / ``W`` are the raw multi-shot matrices the history recorder unpacks.
165
+ """
166
+ A_d, B_d, C_d, x_prop, V = dis_continuous(x, u, params)
167
+ x0_prior = jnp.where(init_fixed, x_initial, x[0])
168
+ x_nodes_prior = jnp.concatenate([x0_prior[None, :], x_prop], axis=0)
169
+ x_prop_plus, D_d, E_d, W = dis_impulsive(x_nodes_prior, u, params)
170
+ return A_d, B_d, C_d, x_prop, x_prop_plus, D_d, E_d, V, W
171
+
172
+ def _linearize_constraints(x: jnp.ndarray, u: jnp.ndarray, params: dict):
173
+ """Stack nodal / cross-node constraint values and gradients.
174
+
175
+ Nodal data is laid out ``(N, n_nodal[, ·])`` with zero-fill at nodes
176
+ outside each constraint's static ``nodes`` set — the backend assembly
177
+ closes over those node sets and skips the zeros.
178
+ """
179
+ nodal_g = jnp.zeros((N, n_nodal))
180
+ nodal_grad_x = jnp.zeros((N, n_nodal, n_x))
181
+ nodal_grad_u = jnp.zeros((N, n_nodal, n_u))
182
+ for c_idx, constraint in enumerate(jax_constraints.nodal):
183
+ g = jnp.squeeze(jnp.asarray(constraint.func(x, u, 0, params)))
184
+ if g.ndim == 0:
185
+ g = jnp.broadcast_to(g, (N,))
186
+ elif g.ndim > 1:
187
+ g = g.reshape(g.shape[0], -1).sum(axis=1)
188
+
189
+ grad_x = jnp.asarray(constraint.grad_g_x(x, u, 0, params))
190
+ if grad_x.ndim == 1:
191
+ grad_x = jnp.broadcast_to(grad_x, (N, grad_x.shape[0]))
192
+ elif grad_x.ndim > 2:
193
+ grad_x = grad_x.reshape(grad_x.shape[0], -1)[:, :n_x]
194
+
195
+ grad_u = jnp.asarray(constraint.grad_g_u(x, u, 0, params))
196
+ if grad_u.ndim == 1:
197
+ grad_u = jnp.broadcast_to(grad_u, (N, grad_u.shape[0]))
198
+ elif grad_u.ndim > 2:
199
+ grad_u = grad_u.reshape(grad_u.shape[0], -1)[:, :n_u]
200
+
201
+ nodes = jnp.asarray(constraint.nodes) if constraint.nodes is not None else jnp.arange(N)
202
+ nodal_g = nodal_g.at[nodes, c_idx].set(g[nodes])
203
+ nodal_grad_x = nodal_grad_x.at[nodes, c_idx].set(grad_x[nodes])
204
+ nodal_grad_u = nodal_grad_u.at[nodes, c_idx].set(grad_u[nodes])
205
+
206
+ if jax_constraints.cross_node:
207
+ cross_g = jnp.stack(
208
+ [jnp.asarray(c.func(x, u, params)) for c in jax_constraints.cross_node]
209
+ )
210
+ cross_grad_X = jnp.stack(
211
+ [jnp.asarray(c.grad_g_X(x, u, params)) for c in jax_constraints.cross_node]
212
+ )
213
+ cross_grad_U = jnp.stack(
214
+ [jnp.asarray(c.grad_g_U(x, u, params)) for c in jax_constraints.cross_node]
215
+ )
216
+ else:
217
+ cross_g = jnp.zeros((0,))
218
+ cross_grad_X = jnp.zeros((0, N, n_x))
219
+ cross_grad_U = jnp.zeros((0, N, n_u))
220
+
221
+ return nodal_g, nodal_grad_x, nodal_grad_u, cross_g, cross_grad_X, cross_grad_U
222
+
223
+ def _candidate_cost(x: jnp.ndarray) -> jnp.ndarray:
224
+ """Boundary-weighted reduction objective at the candidate's terminal node."""
225
+ cost = jnp.asarray(0.0)
226
+ for i, bc_type in enumerate(final_type):
227
+ if bc_type == "Minimize":
228
+ cost = cost + x[-1, i]
229
+ elif bc_type == "Maximize":
230
+ cost = cost - x[-1, i]
231
+ return cost
232
+
233
+ def iteration_fn(
234
+ state: AlgorithmState, params: dict
235
+ ) -> Tuple[AlgorithmState, IterationDiagnostics]:
236
+ # 1–2. Discretize the current iterate for the subproblem linearization.
237
+ A_d, B_d, C_d, x_prop, x_prop_plus, D_d, E_d, _, _ = _discretize(state.x, state.u, params)
238
+
239
+ # 3. Linearize the constraints about the current iterate.
240
+ (
241
+ nodal_g,
242
+ nodal_grad_x,
243
+ nodal_grad_u,
244
+ cross_g,
245
+ cross_grad_X,
246
+ cross_grad_U,
247
+ ) = _linearize_constraints(state.x, state.u, params)
248
+
249
+ # 4. Pack the subproblem inputs.
250
+ data = SubproblemData(
251
+ x_bar=state.x,
252
+ u_bar=state.u,
253
+ A_d=A_d,
254
+ B_d=B_d,
255
+ C_d=C_d,
256
+ x_prop=x_prop,
257
+ x_prop_plus=x_prop_plus,
258
+ D_d=D_d,
259
+ E_d=E_d,
260
+ nodal_g=nodal_g,
261
+ nodal_grad_x=nodal_grad_x,
262
+ nodal_grad_u=nodal_grad_u,
263
+ cross_g=cross_g,
264
+ cross_grad_X=cross_grad_X,
265
+ cross_grad_U=cross_grad_U,
266
+ lam_prox=state.lam_prox,
267
+ lam_cost=state.lam_cost,
268
+ lam_vc=state.lam_vc,
269
+ lam_vb_nodal=state.lam_vb_nodal,
270
+ lam_vb_cross=state.lam_vb_cross,
271
+ x_init=state.x_init_pin,
272
+ x_term=state.x_term_pin,
273
+ )
274
+
275
+ # 5. Solve the convex subproblem.
276
+ solution = solver_callback(state, data)
277
+
278
+ # 6a. Discretize the candidate for the autotuner's propagation fields
279
+ # and the history's raw discretization matrices.
280
+ _, _, _, cand_x_prop, cand_x_prop_plus, _, _, V_cand, W_cand = _discretize(
281
+ solution.x, solution.u, params
282
+ )
283
+ candidate = CandidateIterate()
284
+ candidate.x = solution.x
285
+ candidate.u = solution.u
286
+ candidate.x_prop = cand_x_prop
287
+ candidate.x_prop_plus = cand_x_prop_plus
288
+ candidate.J_lin = solution.cost
289
+
290
+ # 6b. SCP convergence metrics (scaled trust region / virtual control /
291
+ # virtual buffer), matching the legacy ``_subproblem`` reductions.
292
+ tr_x = inv_S_x @ (solution.x - state.x).T
293
+ tr_u = inv_S_u @ (solution.u - state.u).T
294
+ TR = jnp.concatenate([tr_x, tr_u], axis=0)
295
+ VC = jnp.abs(inv_S_x @ solution.nu.T).T
296
+ J_tr = jnp.sum(TR**2)
297
+ J_vc = jnp.sum(VC)
298
+ J_vb = jnp.sum(jnp.maximum(0.0, solution.nu_vb)) + jnp.sum(
299
+ jnp.maximum(0.0, solution.nu_vb_cross)
300
+ )
301
+ state = state.replace(
302
+ J_tr=jnp.asarray(J_tr, dtype=state.J_tr.dtype),
303
+ J_vb=jnp.asarray(J_vb, dtype=state.J_vb.dtype),
304
+ J_vc=jnp.asarray(J_vc, dtype=state.J_vc.dtype),
305
+ )
306
+
307
+ # 6c. Autotuner: pure functional update producing the next iterate.
308
+ next_state = autotuner.update_weights(state, candidate, jax_constraints, settings, params)
309
+ next_state = next_state.replace(k=state.k + 1)
310
+
311
+ diagnostics = IterationDiagnostics(
312
+ cost=_candidate_cost(solution.x),
313
+ status=solution.status_code,
314
+ J_lin=solution.cost,
315
+ V=V_cand,
316
+ W=W_cand,
317
+ TR=TR,
318
+ VC=VC,
319
+ )
320
+ return next_state, diagnostics
321
+
322
+ return iteration_fn
323
+
324
+
325
+ def _converged(state: AlgorithmState, ep_tr: float, ep_vb: float, ep_vc: float) -> jnp.ndarray:
326
+ """Boolean SCP convergence test from the metrics on ``state``."""
327
+ return (state.J_tr < ep_tr) & (state.J_vb < ep_vb) & (state.J_vc < ep_vc)
328
+
329
+
330
+ def make_solve_loop(
331
+ iteration_fn: Callable[[AlgorithmState, dict], Tuple[AlgorithmState, IterationDiagnostics]],
332
+ ep_tr: float,
333
+ ep_vb: float,
334
+ ep_vc: float,
335
+ k_max: int,
336
+ ) -> Callable[[AlgorithmState, dict], AlgorithmState]:
337
+ """Wrap ``iteration_fn`` in a ``lax.while_loop`` keyed on convergence.
338
+
339
+ The loop runs ``iteration_fn`` until either the SCP metrics fall below the
340
+ ``ep_*`` thresholds or the iteration counter ``state.k`` exceeds ``k_max`` —
341
+ matching the Python ``while`` loop in ``Problem.solve()``. The per-iteration
342
+ :class:`IterationDiagnostics` are projected away so the loop carry stays
343
+ ``state -> state`` (XLA dead-code-eliminates their host-only pieces). It
344
+ exists as a primitive for tests and the future JAX-pure ``.solve()`` path;
345
+ the public ``Problem.solve()`` continues to drive ``iteration_fn`` from
346
+ Python.
347
+
348
+ Args:
349
+ iteration_fn: A body built by :func:`make_scp_iteration`.
350
+ ep_tr: Convergence threshold on ``J_tr`` (trust-region step).
351
+ ep_vb: Convergence threshold on ``J_vb`` (virtual buffer).
352
+ ep_vc: Convergence threshold on ``J_vc`` (virtual control).
353
+ k_max: Maximum number of SCP iterations.
354
+
355
+ Returns:
356
+ ``solve_loop(state, params) -> final_state``.
357
+ """
358
+
359
+ def solve_loop(state: AlgorithmState, params: dict) -> AlgorithmState:
360
+ def cond(state: AlgorithmState) -> jnp.ndarray:
361
+ return (state.k <= k_max) & jnp.logical_not(_converged(state, ep_tr, ep_vb, ep_vc))
362
+
363
+ def body(state: AlgorithmState) -> AlgorithmState:
364
+ next_state, _ = iteration_fn(state, params)
365
+ return next_state
366
+
367
+ return jax.lax.while_loop(cond, body, state)
368
+
369
+ return solve_loop