openscvx 0.5.3.dev24__tar.gz → 0.5.3.dev26__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 (420) hide show
  1. {openscvx-0.5.3.dev24/openscvx.egg-info → openscvx-0.5.3.dev26}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UnderTheHood/batching_jit_grad.md +21 -9
  3. openscvx-0.5.3.dev26/docs/UnderTheHood/custom_algorithms_autotuners.md +223 -0
  4. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/mkdocs.yml +2 -1
  5. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/_version.py +3 -3
  6. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/__init__.py +18 -11
  7. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/__init__.py +3 -0
  8. openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/acceptance_ratio.py +234 -0
  9. openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +74 -0
  10. openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/augmented_lagrangian.py +287 -0
  11. openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/base.py +259 -0
  12. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/constant_proximal_weight.py +14 -16
  13. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +23 -20
  14. openscvx-0.5.3.dev26/openscvx/algorithms/base.py +254 -0
  15. openscvx-0.5.3.dev26/openscvx/algorithms/history.py +303 -0
  16. openscvx-0.5.3.dev26/openscvx/algorithms/hyperparams.py +96 -0
  17. openscvx-0.5.3.dev26/openscvx/algorithms/loop.py +81 -0
  18. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/optimization_results.py +8 -8
  19. openscvx-0.5.3.dev26/openscvx/algorithms/penalty.py +109 -0
  20. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/iteration.py +31 -75
  21. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/penalized_trust_region.py +54 -94
  22. openscvx-0.5.3.dev26/openscvx/algorithms/state.py +345 -0
  23. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/problem.py +8 -13
  24. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/cvxpy_ptr_solver.py +17 -0
  25. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/caching.py +9 -1
  26. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/printing.py +0 -5
  27. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26/openscvx.egg-info}/PKG-INFO +1 -1
  28. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/SOURCES.txt +10 -0
  29. openscvx-0.5.3.dev26/tests/algorithms/autotuner/test_defaults_agreement.py +137 -0
  30. openscvx-0.5.3.dev26/tests/algorithms/autotuner/test_hyper_overrides.py +324 -0
  31. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/test_update_weights_jit.py +36 -40
  32. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_parity.py +48 -0
  33. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_make_solve_loop.py +25 -3
  34. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_autotuning.py +149 -114
  35. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_discretization.py +1 -1
  36. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_brachistochrone.py +31 -2
  37. openscvx-0.5.3.dev24/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -198
  38. openscvx-0.5.3.dev24/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -402
  39. openscvx-0.5.3.dev24/openscvx/algorithms/base.py +0 -1079
  40. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/assets/logo.svg +0 -0
  41. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/release-drafter.yml +0 -0
  42. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/_docs.yml +0 -0
  43. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/branch-name.yml +0 -0
  44. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/docs.yml +0 -0
  45. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/lint.yml +0 -0
  46. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/nightly.yml +0 -0
  47. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/release-drafter.yml +0 -0
  48. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/release.yml +0 -0
  49. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/tests-integration.yml +0 -0
  50. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/tests-unit.yml +0 -0
  51. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.gitignore +0 -0
  52. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.gitmodules +0 -0
  53. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/CONTRIBUTING.md +0 -0
  54. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/LICENSE +0 -0
  55. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/README.md +0 -0
  56. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/constraint_reformulation.md +0 -0
  57. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/control_parameterization.md +0 -0
  58. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/discretization.md +0 -0
  59. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/ocp.md +0 -0
  60. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/scvx.md +0 -0
  61. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/time_dilation.md +0 -0
  62. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UnderTheHood/lowering_architecture.md +0 -0
  63. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  64. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/00_introduction.md +0 -0
  65. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  66. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  67. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  68. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  69. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/05_visualization.md +0 -0
  70. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/06_logic.md +0 -0
  71. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/07_lie.md +0 -0
  72. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/08_mpcc.md +0 -0
  73. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  74. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/favicon.png +0 -0
  75. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_dark.png +0 -0
  76. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_light.png +0 -0
  77. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_dark.png +0 -0
  78. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_light.png +0 -0
  79. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_dark.png +0 -0
  80. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_light.png +0 -0
  81. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/logo.svg +0 -0
  82. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/openscvx_logo_square.png +0 -0
  83. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/viser-client/index.html +0 -0
  84. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  85. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  86. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/citation.md +0 -0
  87. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/examples.md +0 -0
  88. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/index.md +0 -0
  89. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/javascripts/mathjax.js +0 -0
  90. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/versions.json +0 -0
  91. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/_viser_embed_export.py +0 -0
  92. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone.py +0 -0
  93. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone_batched.py +0 -0
  94. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/flappy_bird.py +0 -0
  95. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/hypersensitive.py +0 -0
  96. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/impulsive.py +0 -0
  97. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/stl_integer_variable.py +0 -0
  98. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/stl_or.py +0 -0
  99. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/7_dof_arm.py +0 -0
  100. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/_camera.py +0 -0
  101. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/_render.py +0 -0
  102. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/_sensor_view.py +0 -0
  103. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/dr_vp_polytope.py +0 -0
  104. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  105. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/logo.py +0 -0
  106. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  107. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/3_dof_arm.py +0 -0
  108. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm.py +0 -0
  109. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_collision.py +0 -0
  110. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_vp.py +0 -0
  111. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  112. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  113. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  114. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car.py +0 -0
  115. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_disjoint.py +0 -0
  116. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  117. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_stl.py +0 -0
  118. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_stl_or.py +0 -0
  119. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_waypoint_stl.py +0 -0
  120. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  121. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp.py +0 -0
  122. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp_nodal.py +0 -0
  123. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_double_integrator.py +0 -0
  124. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_vp.py +0 -0
  125. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_nodal.py +0 -0
  126. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_polytope.py +0 -0
  127. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/drone_racing.py +0 -0
  128. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/drone_racing_batched_gates.py +0 -0
  129. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo.py +0 -0
  130. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/acl_logo.svg +0 -0
  131. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  132. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  133. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  134. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance.py +0 -0
  135. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  136. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  137. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  138. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/openscvx_logo.py +0 -0
  139. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/cartpole_mjx.py +0 -0
  140. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/double_cartpole_mjx.py +0 -0
  141. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/skydio_x2_mjx.py +0 -0
  142. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  143. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_game.py +0 -0
  144. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_mjx.py +0 -0
  145. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_discrete.py +0 -0
  146. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_drone_racing.py +0 -0
  147. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  148. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  149. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  150. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/plotting.py +0 -0
  151. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/plotting_viser.py +0 -0
  152. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  153. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  154. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  155. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  156. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  157. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  158. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  159. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  160. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/cinema_vp_realtime.py +0 -0
  161. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/drone_racing_realtime.py +0 -0
  162. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/dubins_car_realtime.py +0 -0
  163. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  164. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/3DoF_pdg.py +0 -0
  165. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg.py +0 -0
  166. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  167. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/ascent_launch_vehicle.py +0 -0
  168. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/halo_orbit.py +0 -0
  169. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/hohmann_transfer.py +0 -0
  170. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/let_transfer.py +0 -0
  171. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/proxops_cw.py +0 -0
  172. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/relative_loitering.py +0 -0
  173. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/ctlos_cine.gif +0 -0
  174. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/ctlos_dr.gif +0 -0
  175. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/dtlos_cine.gif +0 -0
  176. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/dtlos_dr.gif +0 -0
  177. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/openscvx_logo.svg +0 -0
  178. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/openscvx_logo_square.png +0 -0
  179. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/oscvx_structure_full_dark.svg +0 -0
  180. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/video_preview.png +0 -0
  181. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/__init__.py +0 -0
  182. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/custom.css +0 -0
  183. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  184. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  185. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  186. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/home.html +0 -0
  187. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/main.html +0 -0
  188. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-diagram.html +0 -0
  189. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-dropin-banner.html +0 -0
  190. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-hero.html +0 -0
  191. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-pipeline.html +0 -0
  192. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-viser-strip.html +0 -0
  193. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/__init__.py +0 -0
  194. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/__main__.py +0 -0
  195. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/__init__.py +0 -0
  196. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/weights.py +0 -0
  197. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/config.py +0 -0
  198. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/__init__.py +0 -0
  199. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/base.py +0 -0
  200. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/discretize_linearize.py +0 -0
  201. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize.py +0 -0
  202. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  203. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  204. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  205. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  206. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/__init__.py +0 -0
  207. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/byof.py +0 -0
  208. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/lowering.py +0 -0
  209. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/validation.py +0 -0
  210. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/init/__init__.py +0 -0
  211. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/init/interpolation.py +0 -0
  212. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/init/inverse_kinematics.py +0 -0
  213. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/__init__.py +0 -0
  214. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/base.py +0 -0
  215. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/menagerie.py +0 -0
  216. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/mjx.py +0 -0
  217. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrators/__init__.py +0 -0
  218. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrators/diffrax.py +0 -0
  219. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrators/runge_kutta.py +0 -0
  220. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/loader.py +0 -0
  221. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/__init__.py +0 -0
  222. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_constraints.py +0 -0
  223. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_variables.py +0 -0
  224. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/dynamics.py +0 -0
  225. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/jax_constraints.py +0 -0
  226. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/parameters.py +0 -0
  227. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/problem.py +0 -0
  228. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/unified.py +0 -0
  229. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/__init__.py +0 -0
  230. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/plotting.py +0 -0
  231. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/publication.py +0 -0
  232. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/scp_iteration.py +0 -0
  233. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/__init__.py +0 -0
  234. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/animated.py +0 -0
  235. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/coordinates.py +0 -0
  236. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/orbits.py +0 -0
  237. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/plotly_integration.py +0 -0
  238. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/primitives.py +0 -0
  239. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/scp.py +0 -0
  240. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/server.py +0 -0
  241. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/propagation/__init__.py +0 -0
  242. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/propagation/post_processing.py +0 -0
  243. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/propagation/propagation.py +0 -0
  244. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/__init__.py +0 -0
  245. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/base.py +0 -0
  246. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/cones.py +0 -0
  247. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  248. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/ptr_solver.py +0 -0
  249. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  250. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/__init__.py +0 -0
  251. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/affine.py +0 -0
  252. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/augmentation.py +0 -0
  253. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/builder.py +0 -0
  254. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/canonicalize.py +0 -0
  255. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/constraint_set.py +0 -0
  256. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/__init__.py +0 -0
  257. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/arithmetic.py +0 -0
  258. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/array.py +0 -0
  259. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/constraint.py +0 -0
  260. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/control.py +0 -0
  261. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/expr.py +0 -0
  262. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  263. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  264. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/se3.py +0 -0
  265. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/so3.py +0 -0
  266. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/linalg.py +0 -0
  267. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/logic.py +0 -0
  268. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/math.py +0 -0
  269. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/parameter.py +0 -0
  270. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/spatial.py +0 -0
  271. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/state.py +0 -0
  272. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stl.py +0 -0
  273. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stljax.py +0 -0
  274. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/time.py +0 -0
  275. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/variable.py +0 -0
  276. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/vmap.py +0 -0
  277. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/hashing.py +0 -0
  278. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lower.py +0 -0
  279. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/__init__.py +0 -0
  280. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  281. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  282. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  283. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  284. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  285. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  286. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  287. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  288. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  289. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  290. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  291. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  292. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  293. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  294. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  295. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  296. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  297. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  298. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  299. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  300. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  301. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  302. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  303. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  304. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  305. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  306. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  307. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  308. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  309. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/__init__.py +0 -0
  310. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/_registry.py +0 -0
  311. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/array.py +0 -0
  312. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/constraint.py +0 -0
  313. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/lie.py +0 -0
  314. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/linalg.py +0 -0
  315. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/logic.py +0 -0
  316. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/math.py +0 -0
  317. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/parser.py +0 -0
  318. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/spatial.py +0 -0
  319. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stl.py +0 -0
  320. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stljax.py +0 -0
  321. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/tokenizer.py +0 -0
  322. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/preprocessing.py +0 -0
  323. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/problem.py +0 -0
  324. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/sparsity.py +0 -0
  325. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/unified.py +0 -0
  326. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/__init__.py +0 -0
  327. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/cache.py +0 -0
  328. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/profiling.py +0 -0
  329. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/utils.py +0 -0
  330. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/dependency_links.txt +0 -0
  331. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/entry_points.txt +0 -0
  332. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/requires.txt +0 -0
  333. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/top_level.txt +0 -0
  334. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/pyproject.toml +0 -0
  335. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/scripts/gen_example_pages.py +0 -0
  336. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/scripts/gen_ref_pages.py +0 -0
  337. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  338. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/setup.cfg +0 -0
  339. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/__init__.py +0 -0
  340. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/_marks.py +0 -0
  341. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/__init__.py +0 -0
  342. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/_iteration_helpers.py +0 -0
  343. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/__init__.py +0 -0
  344. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  345. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  346. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/brachistochrone_analytical.py +0 -0
  347. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/conftest.py +0 -0
  348. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/expr/__init__.py +0 -0
  349. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/expr/test_gmsr.py +0 -0
  350. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.json +0 -0
  351. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.yaml +0 -0
  352. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/hohmann_analytical.py +0 -0
  353. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/integrations/__init__.py +0 -0
  354. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx.py +0 -0
  355. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx_dynamics.py +0 -0
  356. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/__init__.py +0 -0
  357. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/_iteration_callback_helpers.py +0 -0
  358. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  359. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  360. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  361. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  362. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  363. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  364. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  365. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_subproblem_pytree.py +0 -0
  366. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/__init__.py +0 -0
  367. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/__init__.py +0 -0
  368. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_arithmetic.py +0 -0
  369. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_array.py +0 -0
  370. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_constraint.py +0 -0
  371. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_expr.py +0 -0
  372. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_lie.py +0 -0
  373. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_linalg.py +0 -0
  374. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_logic.py +0 -0
  375. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_math.py +0 -0
  376. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_node_reference.py +0 -0
  377. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_parameters.py +0 -0
  378. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_scaling.py +0 -0
  379. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_spatial.py +0 -0
  380. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_stl.py +0 -0
  381. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_variable.py +0 -0
  382. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_vmap.py +0 -0
  383. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/__init__.py +0 -0
  384. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_array.py +0 -0
  385. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_constraint.py +0 -0
  386. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_lie.py +0 -0
  387. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_linalg.py +0 -0
  388. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_load.py +0 -0
  389. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_logic.py +0 -0
  390. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_math.py +0 -0
  391. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_parser.py +0 -0
  392. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_spatial.py +0 -0
  393. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_stl.py +0 -0
  394. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_tokenizer.py +0 -0
  395. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_vmap.py +0 -0
  396. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_augmentation.py +0 -0
  397. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_hashing.py +0 -0
  398. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_cvxpy.py +0 -0
  399. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_jax.py +0 -0
  400. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_preprocessing.py +0 -0
  401. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_sparsity.py +0 -0
  402. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_unified.py +0 -0
  403. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_brachistochrone.py +0 -0
  404. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_cvxpygen_optional.py +0 -0
  405. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_examples.py +0 -0
  406. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_expert.py +0 -0
  407. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_impulsive.py +0 -0
  408. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_init.py +0 -0
  409. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_integrators.py +0 -0
  410. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_loader.py +0 -0
  411. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_optimization_results.py +0 -0
  412. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_plotting.py +0 -0
  413. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_propagation.py +0 -0
  414. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
  415. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_export_roundtrip.py +0 -0
  416. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_inference.py +0 -0
  417. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
  418. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
  419. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
  420. {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/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.dev24
3
+ Version: 0.5.3.dev26
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
@@ -161,15 +161,27 @@ The batch runs until its slowest element converges or exhausts its own cap;
161
161
  finished elements are frozen, not re-iterated, so each element matches the
162
162
  corresponding single `solve_jax` run.
163
163
 
164
- **New autotuners batch for free.** An autotuner's tunable knobs follow the
165
- same derivation: declare them as fields on a `HyperParams` subclass — bare
166
- annotations, no decorator; subclassing applies the frozen-dataclass transform
167
- and the JAX pytree registration, and the annotation picks the dtype (`int`
168
- gets the iteration counter's, `float` the problem's) assign an instance to
169
- `self.hyper`, and read `state.hyper.<field>` inside `update_weights` (see the
170
- `AutotuningBase` docstring). The declaration is the registration — each field
171
- immediately works as a `solve_jax` override, a `solve_batched` sweep target,
172
- and a runtime input of the exported artifact, with zero edits anywhere else:
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:
173
185
 
174
186
  ```python
175
187
  from openscvx.algorithms import AutotuningBase, HyperParams
@@ -0,0 +1,223 @@
1
+ # Custom Algorithms and Autotuners
2
+
3
+ OpenSCvx solves through a pluggable SCP loop: an **algorithm** owns the
4
+ iteration (how a subproblem is built, when the loop is converged) and an
5
+ **autotuner** owns the penalty-weight update applied each step. Both are
6
+ ordinary Python classes behind small abstract bases — `Algorithm` and
7
+ `AutotuningBase`, importable from `openscvx.algorithms` — so swapping either
8
+ out is a subclass, not a fork.
9
+
10
+ Most users never touch these: the default
11
+ `PenalizedTrustRegion` + `AugmentedLagrangian` pair covers the common case.
12
+ Reach for this page when you want a different penalty schedule, a different
13
+ convergence rule, or a whole new SCP variant — and you want it to keep
14
+ working under `solve()`, `solve_jax()`, and `solve_batched()` alike.
15
+
16
+ Both bases live under `openscvx.algorithms`:
17
+
18
+ ```python
19
+ from openscvx.algorithms import Algorithm, AutotuningBase, HyperParams
20
+ ```
21
+
22
+ ## A custom autotuner
23
+
24
+ An autotuner is a **pure functional update on the iterate**. Its one required
25
+ method, `update_weights`, takes the current `AlgorithmState`, the just-solved
26
+ subproblem `candidate`, the constraints, settings, and parameters, and returns
27
+ the *next* `AlgorithmState`:
28
+
29
+ ```python
30
+ import jax.numpy as jnp
31
+ from openscvx.algorithms import AdaptiveStateCode, AutotuningBase, HyperParams
32
+
33
+
34
+ class MyHyper(HyperParams):
35
+ ramp: float = 2.0
36
+
37
+
38
+ class MyAutotuner(AutotuningBase):
39
+ COMPUTES_ACCEPTANCE_METRICS = False # this tuner never rejects an iterate
40
+
41
+ def __init__(self, ramp: float = 2.0):
42
+ self.hyper = MyHyper(ramp=ramp) # assign self.hyper FIRST
43
+
44
+ def update_weights(self, state, candidate, nodal_constraints, settings, params):
45
+ return state.replace(
46
+ # accept the candidate: its trajectory becomes the next iterate
47
+ x=candidate.x,
48
+ u=candidate.u,
49
+ x_prop=candidate.x_prop,
50
+ x_prop_plus=candidate.x_prop_plus,
51
+ # ramp the proximal weight every iteration
52
+ lam_prox=state.lam_prox * state.hyper.ramp,
53
+ # jnp.int32, not bare asarray: the code must keep the state field's
54
+ # strong int32 dtype or the lax.while_loop carry check fails.
55
+ adaptive_state_code=jnp.int32(AdaptiveStateCode.ACCEPT_HIGHER),
56
+ )
57
+ ```
58
+
59
+ Three rules carry the whole contract.
60
+
61
+ ### The returned state *is* the next iterate
62
+
63
+ The SCP loop discards everything except what `update_weights` returns.
64
+ Accepting the subproblem's candidate therefore means **carrying its
65
+ trajectory onto the returned state** — `x` / `u` / `x_prop` / `x_prop_plus`
66
+ from `candidate` — while rejecting means keeping the previous fields and
67
+ adjusting only the weights.
68
+
69
+ !!! warning "The silent no-op"
70
+ An update that never copies the candidate produces a solver that runs to
71
+ `k_max` without the iterate ever moving — no error, just a flat history.
72
+ If a custom tuner seems to "not converge," check that the accept branch
73
+ copies all four trajectory fields.
74
+
75
+ Express any accept/reject branching with `jax.lax.cond` or `jnp.where`, not a
76
+ Python `if` on iterate values: `update_weights` is traced (it runs inside the
77
+ `lax.while_loop` of `solve_jax` / `solve_batched`, vmapped per batch element),
78
+ so it must not mutate `state` or `candidate`, raise on data-dependent
79
+ conditions, or return strings.
80
+
81
+ ### Declare tunable knobs as `HyperParams`, not `self` attributes
82
+
83
+ A numeric knob a user might sweep (a ramp factor, a relaxation iteration) must
84
+ **not** be read off `self` inside `update_weights` — a plain Python attribute
85
+ is baked into the trace and invisible to every override channel. Declare it on
86
+ a `HyperParams` subclass, assign an instance to `self.hyper`, and read it from
87
+ `state.hyper`.
88
+
89
+ The declaration *is* the registration. With nothing else, the field becomes:
90
+
91
+ * a **per-solve override** — `problem.solve_jax(algorithm={"ramp": 1.5})`;
92
+ * a **batchable sweep target** —
93
+ `problem.solve_batched(algorithm={"ramp": jnp.linspace(1.1, 2.0, 8)})`;
94
+ * a **runtime input** of the exported `solve_batched` artifact, so changing it
95
+ needs no recompile.
96
+
97
+ !!! danger "Assign `self.hyper` first"
98
+ Declared knobs are also readable and writable as bare attributes
99
+ (`autotuner.ramp = 3.0`) for ergonomics — a proxy on `AutotuningBase`
100
+ routes the access into `hyper`. That proxy only works once `self.hyper`
101
+ exists, so assign it as the **first** line of `__init__`. A knob assigned
102
+ before `hyper` exists lands as a plain instance attribute the proxy cannot
103
+ see, and your override channels silently break.
104
+
105
+ ### Acceptance metrics are opt-in
106
+
107
+ `COMPUTES_ACCEPTANCE_METRICS` (default `True`) tells the loop whether
108
+ `update_weights` produces a predicted/actual reduction and an acceptance
109
+ ratio. The loop records and prints those diagnostics only when it is `True`.
110
+ A tuner that never rejects an iterate — like the built-in
111
+ `ConstantProximalWeight` and `RampProximalWeight` — sets it `False`.
112
+
113
+ To add columns to the iteration table, set the class attribute `COLUMNS` to a
114
+ list of `openscvx.utils.printing.Column` specs; the algorithm concatenates
115
+ them into its own table via `get_columns`.
116
+
117
+ ## A custom algorithm
118
+
119
+ An `Algorithm` owns the SCP iteration end to end: it *builds* the JAX-pure
120
+ iteration body, *stores* it, and *drives* it one step at a time. All iteration
121
+ state lives on `AlgorithmState` (JAX-traceable) and `AlgorithmHistory`
122
+ (Python-side) threaded explicitly through `step()` — avoid storing mutable
123
+ iteration state on `self`.
124
+
125
+ The surface is six methods. `converged` has a working default; the other five
126
+ are abstract.
127
+
128
+ ### `__init__` — end with `super().__init__`
129
+
130
+ The base records the weights, autotuner, and convergence parameters. Every
131
+ parameter is required, so the ABC is not yet another place defaults are
132
+ declared — your subclass owns the user-facing defaults and forwards them:
133
+
134
+ ```python
135
+ from openscvx.algorithms import Algorithm
136
+ from openscvx.algorithms.weights import Weights
137
+ from openscvx.algorithms import AugmentedLagrangian
138
+
139
+
140
+ class MyAlgorithm(Algorithm):
141
+ def __init__(self, autotuner=None, k_max=200, **weight_kwargs):
142
+ super().__init__(
143
+ weights=Weights.build(**weight_kwargs),
144
+ autotuner=autotuner if autotuner is not None else AugmentedLagrangian(),
145
+ k_max=k_max,
146
+ t_max=None,
147
+ ep_tr=1e-4,
148
+ ep_vb=1e-4,
149
+ ep_vc=1e-8,
150
+ )
151
+ ```
152
+
153
+ ### `build_iteration` — fuse the step
154
+
155
+ `Problem` assembles the discretization solvers, lowered constraints, and
156
+ convex-solver callback, then asks the algorithm to fuse them into one JAX-pure
157
+ `(state, params) -> (next_state, diagnostics)` body. The algorithm owns this
158
+ because the fusion is algorithm-specific (which autotuner runs, which penalty
159
+ terms are assembled). PTR's implementation is a thin wrapper around
160
+ `make_scp_iteration` (`openscvx/algorithms/scvx/iteration.py`) that threads its
161
+ `autotuner` into the fused body. The returned body must advance `state.k` by
162
+ one per call — every solve path terminates on `k` reaching `k_max`.
163
+
164
+ ### `initialize` and `step` — store, then drive
165
+
166
+ `Problem.initialize()` builds and JIT-warms the body, then hands it back via
167
+ `initialize(iteration_fn, emitter)` for the algorithm to store. `step()` is the
168
+ Python-loop driver: it calls the stored body, records the per-iteration
169
+ diagnostics into `history`, emits progress, and returns
170
+ `(next_state, converged)`.
171
+
172
+ ### `converged` — the one-method convergence hook
173
+
174
+ `converged(state)` is the only piece of convergence policy that is
175
+ algorithm-specific; it has a concrete default, so override it only to change
176
+ the rule:
177
+
178
+ ```python
179
+ def converged(self, state):
180
+ return state.J_vc < state.ep_vc # custom: virtual control alone
181
+ ```
182
+
183
+ The default — every metric below its threshold — is algorithm-agnostic, since
184
+ `AlgorithmState` carries `J_tr` / `J_vb` / `J_vc` and the `ep_*` tolerances
185
+ generically.
186
+
187
+ !!! note "Honored on every solve path"
188
+ The override is honored on **all three** solve paths. `step()` routes
189
+ through it on the Python `solve()` path, and the `lax.while_loop` harness
190
+ (`openscvx/algorithms/loop.py`) takes it as the loop predicate for
191
+ `solve_jax` / `solve_batched`, where it is vmapped per batch element. It
192
+ must therefore be JAX-traceable. An override implies a subclass, hence a
193
+ distinct class name that the export cache key already folds in — so a
194
+ changed predicate invalidates stale batched artifacts on its own.
195
+
196
+ By contrast, `t_max` (the wall-clock time limit) is honored **only** on the
197
+ Python `solve()` path; the JAX loop terminates on `k_max` and `converged`
198
+ alone, since there is no wall-clock probe inside a trace.
199
+
200
+ ### `get_columns` and `citation`
201
+
202
+ `get_columns(verbosity)` returns the iteration-table columns to print —
203
+ implementations typically concatenate the algorithm's own columns with the
204
+ autotuner's `COLUMNS` and filter by each column's `min_verbosity`.
205
+ `citation()` returns a list of BibTeX strings for the algorithm.
206
+
207
+ ## Using a custom class
208
+
209
+ Pass either to the `Problem` constructor — the algorithm directly, an
210
+ autotuner through the algorithm:
211
+
212
+ ```python
213
+ import openscvx as ox
214
+
215
+ problem = ox.Problem(
216
+ ...,
217
+ algorithm=MyAlgorithm(autotuner=MyAutotuner(ramp=1.5)),
218
+ )
219
+ ```
220
+
221
+ The default `PenalizedTrustRegion` lives at
222
+ `openscvx/algorithms/scvx/penalized_trust_region.py` and is the reference
223
+ implementation to read alongside this guide.
@@ -198,4 +198,5 @@ nav:
198
198
  - Under the Hood:
199
199
  - 'UnderTheHood/vectorization_and_vmapping.md'
200
200
  - 'UnderTheHood/lowering_architecture.md'
201
- - 'UnderTheHood/batching_jit_grad.md'
201
+ - 'UnderTheHood/batching_jit_grad.md'
202
+ - 'UnderTheHood/custom_algorithms_autotuners.md'
@@ -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.dev24'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev24')
21
+ __version__ = version = '0.5.3.dev26'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev26')
23
23
 
24
- __commit_id__ = commit_id = 'gba72d9b80'
24
+ __commit_id__ = commit_id = 'g053a32537'
@@ -5,9 +5,11 @@ for solving non-convex trajectory optimization problems through iterative convex
5
5
  approximation.
6
6
 
7
7
  All algorithms inherit from :class:`Algorithm`, enabling pluggable algorithm
8
- implementations and custom SCvx variants. Immutable components (solver,
9
- discretization_solver, jax_constraints, etc.) are stored during ``initialize()``;
10
- mutable configuration (params, settings) is passed per-step.
8
+ implementations and custom SCvx variants. An algorithm builds its fused,
9
+ JAX-pure iteration body (``build_iteration``), stores it along with the
10
+ diagnostics emitter (``initialize``), drives it one step at a time on the
11
+ Python path (``step``), and owns its convergence policy (``converged``) —
12
+ honored identically by ``solve()``, ``solve_jax()``, and ``solve_batched()``.
11
13
 
12
14
  The iterate carry is split into two objects:
13
15
 
@@ -37,6 +39,8 @@ from typing import Annotated, Any, Dict, List, Optional, Union
37
39
  from pydantic import BaseModel, ConfigDict, Field, field_validator
38
40
 
39
41
  from .autotuner import (
42
+ AcceptanceRatioAutotuner,
43
+ AcceptanceRatioHyper,
40
44
  AdaptiveProximalWeight,
41
45
  AdaptiveProximalWeightSpec,
42
46
  AugmentedLagrangian,
@@ -46,18 +50,18 @@ from .autotuner import (
46
50
  RampProximalWeight,
47
51
  RampProximalWeightSpec,
48
52
  )
49
- from .base import (
53
+ from .autotuner.base import AutotuningBase
54
+ from .base import Algorithm
55
+ from .history import AlgorithmHistory, DiscretizationResult
56
+ from .hyperparams import HyperParams
57
+ from .optimization_results import OptimizationResults
58
+ from .scvx import PenalizedTrustRegion
59
+ from .state import (
50
60
  AdaptiveStateCode,
51
- Algorithm,
52
- AlgorithmHistory,
53
61
  AlgorithmState,
54
- AutotuningBase,
55
- DiscretizationResult,
56
- HyperParams,
62
+ CandidateIterate,
57
63
  adaptive_state_code_to_str,
58
64
  )
59
- from .optimization_results import OptimizationResults
60
- from .scvx import PenalizedTrustRegion
61
65
  from .weights import Weights
62
66
 
63
67
  # ---------------------------------------------------------------------------
@@ -138,6 +142,7 @@ __all__ = [
138
142
  "AlgorithmHistory",
139
143
  "AlgorithmState",
140
144
  "AdaptiveStateCode",
145
+ "CandidateIterate",
141
146
  "adaptive_state_code_to_str",
142
147
  "DiscretizationResult",
143
148
  "Weights",
@@ -147,6 +152,8 @@ __all__ = [
147
152
  "PenalizedTrustRegion",
148
153
  "AutotuningBase",
149
154
  "HyperParams",
155
+ "AcceptanceRatioAutotuner",
156
+ "AcceptanceRatioHyper",
150
157
  "AugmentedLagrangian",
151
158
  "AdaptiveProximalWeight",
152
159
  "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,234 @@
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 ..penalty import calculate_nonlinear_penalty
33
+ from ..state import AdaptiveStateCode
34
+ from .base import AutotuningBase, LamCostRelaxHyper
35
+
36
+ if TYPE_CHECKING:
37
+ from openscvx.lowered import LoweredJaxConstraints
38
+
39
+ from ..state import AlgorithmState, CandidateIterate
40
+
41
+
42
+ class AcceptanceRatioHyper(LamCostRelaxHyper):
43
+ """Knobs shared by every acceptance-ratio autotuner.
44
+
45
+ Extends the shared :class:`LamCostRelaxHyper` ``lam_cost`` relaxation knobs
46
+ with the acceptance-ratio decision thresholds and the ``lam_prox`` clips.
47
+ """
48
+
49
+ gamma_1: float = 2.0
50
+ gamma_2: float = 0.5
51
+ eta_0: float = 1e-2
52
+ eta_1: float = 1e-1
53
+ eta_2: float = 0.8
54
+ lam_prox_min: float = 1e-3
55
+ lam_prox_max: float = 1e4
56
+
57
+
58
+ class AcceptanceRatioAutotuner(AutotuningBase):
59
+ """Four-bucket acceptance-ratio update on ``lam_prox``.
60
+
61
+ The acceptance ratio :math:`\\rho` (actual over predicted nonlinear
62
+ reduction) selects one of four buckets — ``REJECT`` / ``ACCEPT_HIGHER`` /
63
+ ``ACCEPT_CONSTANT`` / ``ACCEPT_LOWER`` — via a ``jnp.where`` cascade so the
64
+ whole update traces under ``jax.jit``. Subclasses supply the multiplier
65
+ rule (how ``lam_vc`` / ``lam_vb_*`` respond on acceptance) through
66
+ :meth:`_update_multipliers`, and must assign an
67
+ :class:`AcceptanceRatioHyper` (or subclass) instance to ``self.hyper`` in
68
+ ``__init__`` — the shared body reads its knobs off ``state.hyper``.
69
+
70
+ ``update_weights`` is a pure functional update on the
71
+ :class:`AlgorithmState` pytree; see the base-class contract.
72
+ """
73
+
74
+ COLUMNS: List[Column] = [
75
+ Column("J_nonlin", "J_nonlin", 8, "{: .1e}", None, Verbosity.STANDARD),
76
+ Column("J_lin", "J_lin", 8, "{: .1e}", None, Verbosity.STANDARD),
77
+ Column("pred_reduction", "pred_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
78
+ Column("actual_reduction", "act_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
79
+ Column(
80
+ "acceptance_ratio",
81
+ "acc_ratio",
82
+ 9,
83
+ "{: .2e}",
84
+ color_acceptance_ratio,
85
+ Verbosity.STANDARD,
86
+ ),
87
+ Column("lam_prox", "lam_prox", 8, "{: .1e}", min_verbosity=Verbosity.FULL),
88
+ Column("adaptive_state", "Adaptive", 16, "{}", color_adaptive_state, Verbosity.FULL),
89
+ ]
90
+
91
+ def _update_multipliers(
92
+ self,
93
+ state: "AlgorithmState",
94
+ candidate: "CandidateIterate",
95
+ nodal_constraints: "LoweredJaxConstraints",
96
+ params: dict,
97
+ settings: Config,
98
+ new_lam_prox: jnp.ndarray,
99
+ ) -> dict:
100
+ """Return the multiplier-weight updates to apply on an accepted iterate.
101
+
102
+ Each returned entry maps an :class:`AlgorithmState` field name
103
+ (``lam_vc`` / ``lam_vb_nodal`` / ``lam_vb_cross``) to its updated
104
+ value, computed against the *candidate* trajectory; the shared body
105
+ gates each by acceptance (a rejected iterate keeps the previous value).
106
+ The default holds every multiplier constant — return ``{}``.
107
+ """
108
+ return {}
109
+
110
+ def update_weights(
111
+ self,
112
+ state: "AlgorithmState",
113
+ candidate: "CandidateIterate",
114
+ nodal_constraints: "LoweredJaxConstraints",
115
+ settings: Config,
116
+ params: dict,
117
+ ) -> "AlgorithmState":
118
+ """Return the next-iterate state per the acceptance-ratio rules.
119
+
120
+ Pure functional update — see class docstring.
121
+ """
122
+ candidate_x_prop = candidate.x_prop_plus[1:]
123
+ nonlin_cost, nonlin_pen, nodal_pen = calculate_nonlinear_penalty(
124
+ candidate_x_prop,
125
+ candidate.x,
126
+ candidate.u,
127
+ state.lam_vc,
128
+ state.lam_vb_nodal,
129
+ state.lam_vb_cross,
130
+ state.lam_cost,
131
+ nodal_constraints,
132
+ params,
133
+ settings,
134
+ )
135
+ J_nonlin = nonlin_cost + nonlin_pen + nodal_pen
136
+
137
+ lam_cost_next = self._relaxed_lam_cost(state)
138
+
139
+ def first_iter(state):
140
+ # Iter 1: accept unconditionally, leave weights at their init values,
141
+ # only refresh trajectory + propagation fields.
142
+ return state.replace(
143
+ x=candidate.x,
144
+ u=candidate.u,
145
+ x_prop=candidate.x_prop,
146
+ x_prop_plus=candidate.x_prop_plus,
147
+ lam_cost=lam_cost_next,
148
+ J_nonlin=J_nonlin,
149
+ adaptive_state_code=jnp.asarray(int(AdaptiveStateCode.INITIAL), dtype=jnp.int32),
150
+ )
151
+
152
+ def later_iter(state):
153
+ # Recompute the previous iterate's J_nonlin from the pytree fields
154
+ # (state.x/state.u were the *previous* accepted iterate).
155
+ prev_x_prop = state.x_prop_plus[1:]
156
+ prev_cost, prev_pen, prev_nodal_pen = calculate_nonlinear_penalty(
157
+ prev_x_prop,
158
+ state.x,
159
+ state.u,
160
+ state.lam_vc,
161
+ state.lam_vb_nodal,
162
+ state.lam_vb_cross,
163
+ state.lam_cost,
164
+ nodal_constraints,
165
+ params,
166
+ settings,
167
+ )
168
+ prev_J_nonlin = prev_cost + prev_pen + prev_nodal_pen
169
+
170
+ actual = prev_J_nonlin - J_nonlin
171
+ predicted = prev_J_nonlin - candidate.J_lin
172
+ # If predicted reduction is exactly zero, force the reject bucket
173
+ # (rho = -inf) deterministically instead of raising.
174
+ safe_pred = jnp.where(predicted == 0.0, 1.0, predicted)
175
+ rho = jnp.where(predicted == 0.0, -jnp.inf, actual / safe_pred)
176
+
177
+ is_reject = rho < state.hyper.eta_0
178
+ is_accept_higher = (rho >= state.hyper.eta_0) & (rho < state.hyper.eta_1)
179
+ is_accept_constant = (rho >= state.hyper.eta_1) & (rho < state.hyper.eta_2)
180
+ # is_accept_lower implicit (else)
181
+ accepted = ~is_reject
182
+
183
+ # Compute both lam_prox candidates and gate.
184
+ lp_higher = jnp.minimum(state.hyper.lam_prox_max, state.hyper.gamma_1 * state.lam_prox)
185
+ lp_lower = jnp.maximum(state.hyper.lam_prox_min, state.hyper.gamma_2 * state.lam_prox)
186
+ new_lam_prox = jnp.where(
187
+ is_reject | is_accept_higher,
188
+ lp_higher,
189
+ jnp.where(is_accept_constant, state.lam_prox, lp_lower),
190
+ )
191
+
192
+ # Multiplier (virtual-control / virtual-buffer) updates: computed
193
+ # against the *candidate* trajectory and gated by `accepted`. Reject
194
+ # keeps the previous values (so the next subproblem doesn't see a
195
+ # bumped penalty that wasn't earned). The default hook returns {} —
196
+ # multipliers held constant.
197
+ multiplier_updates = self._update_multipliers(
198
+ state, candidate, nodal_constraints, params, settings, new_lam_prox
199
+ )
200
+ gated_multipliers = {
201
+ name: jnp.where(accepted, value, getattr(state, name))
202
+ for name, value in multiplier_updates.items()
203
+ }
204
+
205
+ code = jnp.where(
206
+ is_reject,
207
+ jnp.int32(AdaptiveStateCode.REJECT),
208
+ jnp.where(
209
+ is_accept_higher,
210
+ jnp.int32(AdaptiveStateCode.ACCEPT_HIGHER),
211
+ jnp.where(
212
+ is_accept_constant,
213
+ jnp.int32(AdaptiveStateCode.ACCEPT_CONSTANT),
214
+ jnp.int32(AdaptiveStateCode.ACCEPT_LOWER),
215
+ ),
216
+ ),
217
+ )
218
+
219
+ return state.replace(
220
+ x=jnp.where(accepted, candidate.x, state.x),
221
+ u=jnp.where(accepted, candidate.u, state.u),
222
+ x_prop=jnp.where(accepted, candidate.x_prop, state.x_prop),
223
+ x_prop_plus=jnp.where(accepted, candidate.x_prop_plus, state.x_prop_plus),
224
+ lam_prox=new_lam_prox,
225
+ lam_cost=lam_cost_next,
226
+ J_nonlin=jnp.where(accepted, J_nonlin, state.J_nonlin),
227
+ predicted_reduction=predicted,
228
+ actual_reduction=actual,
229
+ acceptance_ratio=rho,
230
+ adaptive_state_code=code,
231
+ **gated_multipliers,
232
+ )
233
+
234
+ 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))