openscvx 0.5.3.dev25__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 (418) hide show
  1. {openscvx-0.5.3.dev25/openscvx.egg-info → openscvx-0.5.3.dev26}/PKG-INFO +1 -1
  2. openscvx-0.5.3.dev26/docs/UnderTheHood/custom_algorithms_autotuners.md +223 -0
  3. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/mkdocs.yml +2 -1
  4. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/_version.py +3 -3
  5. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/__init__.py +12 -11
  6. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/acceptance_ratio.py +10 -21
  7. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/augmented_lagrangian.py +1 -1
  8. openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/base.py +259 -0
  9. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/constant_proximal_weight.py +7 -14
  10. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +7 -13
  11. openscvx-0.5.3.dev26/openscvx/algorithms/base.py +254 -0
  12. openscvx-0.5.3.dev26/openscvx/algorithms/history.py +303 -0
  13. openscvx-0.5.3.dev26/openscvx/algorithms/hyperparams.py +96 -0
  14. openscvx-0.5.3.dev26/openscvx/algorithms/loop.py +81 -0
  15. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/optimization_results.py +8 -8
  16. openscvx-0.5.3.dev26/openscvx/algorithms/penalty.py +109 -0
  17. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/iteration.py +31 -75
  18. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/penalized_trust_region.py +31 -52
  19. openscvx-0.5.3.dev26/openscvx/algorithms/state.py +345 -0
  20. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/problem.py +6 -9
  21. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/caching.py +9 -1
  22. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26/openscvx.egg-info}/PKG-INFO +1 -1
  23. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/SOURCES.txt +8 -0
  24. openscvx-0.5.3.dev26/tests/algorithms/autotuner/test_defaults_agreement.py +137 -0
  25. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/test_hyper_overrides.py +16 -17
  26. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/test_update_weights_jit.py +9 -12
  27. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_make_solve_loop.py +25 -3
  28. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_autotuning.py +118 -104
  29. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_discretization.py +1 -1
  30. openscvx-0.5.3.dev25/openscvx/algorithms/base.py +0 -1162
  31. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/assets/logo.svg +0 -0
  32. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/release-drafter.yml +0 -0
  33. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/_docs.yml +0 -0
  34. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/branch-name.yml +0 -0
  35. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/docs.yml +0 -0
  36. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/lint.yml +0 -0
  37. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/nightly.yml +0 -0
  38. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/release-drafter.yml +0 -0
  39. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/release.yml +0 -0
  40. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/tests-integration.yml +0 -0
  41. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/tests-unit.yml +0 -0
  42. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.gitignore +0 -0
  43. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.gitmodules +0 -0
  44. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/CONTRIBUTING.md +0 -0
  45. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/LICENSE +0 -0
  46. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/README.md +0 -0
  47. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/constraint_reformulation.md +0 -0
  48. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/control_parameterization.md +0 -0
  49. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/discretization.md +0 -0
  50. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/ocp.md +0 -0
  51. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/scvx.md +0 -0
  52. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/time_dilation.md +0 -0
  53. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UnderTheHood/batching_jit_grad.md +0 -0
  54. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UnderTheHood/lowering_architecture.md +0 -0
  55. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  56. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/00_introduction.md +0 -0
  57. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  58. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  59. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  60. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  61. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/05_visualization.md +0 -0
  62. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/06_logic.md +0 -0
  63. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/07_lie.md +0 -0
  64. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/08_mpcc.md +0 -0
  65. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  66. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/favicon.png +0 -0
  67. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_dark.png +0 -0
  68. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_light.png +0 -0
  69. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_dark.png +0 -0
  70. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_light.png +0 -0
  71. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_dark.png +0 -0
  72. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_light.png +0 -0
  73. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/logo.svg +0 -0
  74. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/openscvx_logo_square.png +0 -0
  75. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/viser-client/index.html +0 -0
  76. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  77. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  78. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/citation.md +0 -0
  79. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/examples.md +0 -0
  80. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/index.md +0 -0
  81. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/javascripts/mathjax.js +0 -0
  82. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/versions.json +0 -0
  83. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/_viser_embed_export.py +0 -0
  84. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone.py +0 -0
  85. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone_batched.py +0 -0
  86. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/flappy_bird.py +0 -0
  87. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/hypersensitive.py +0 -0
  88. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/impulsive.py +0 -0
  89. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/stl_integer_variable.py +0 -0
  90. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/stl_or.py +0 -0
  91. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/7_dof_arm.py +0 -0
  92. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/_camera.py +0 -0
  93. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/_render.py +0 -0
  94. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/_sensor_view.py +0 -0
  95. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/dr_vp_polytope.py +0 -0
  96. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  97. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/logo.py +0 -0
  98. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  99. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/3_dof_arm.py +0 -0
  100. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm.py +0 -0
  101. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_collision.py +0 -0
  102. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_vp.py +0 -0
  103. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  104. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  105. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  106. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car.py +0 -0
  107. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_disjoint.py +0 -0
  108. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  109. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_stl.py +0 -0
  110. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_stl_or.py +0 -0
  111. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_waypoint_stl.py +0 -0
  112. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  113. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp.py +0 -0
  114. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp_nodal.py +0 -0
  115. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_double_integrator.py +0 -0
  116. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_vp.py +0 -0
  117. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_nodal.py +0 -0
  118. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_polytope.py +0 -0
  119. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/drone_racing.py +0 -0
  120. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/drone_racing_batched_gates.py +0 -0
  121. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo.py +0 -0
  122. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/acl_logo.svg +0 -0
  123. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  124. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  125. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  126. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance.py +0 -0
  127. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  128. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  129. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  130. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/openscvx_logo.py +0 -0
  131. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/cartpole_mjx.py +0 -0
  132. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/double_cartpole_mjx.py +0 -0
  133. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/skydio_x2_mjx.py +0 -0
  134. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  135. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_game.py +0 -0
  136. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_mjx.py +0 -0
  137. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_discrete.py +0 -0
  138. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_drone_racing.py +0 -0
  139. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  140. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  141. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  142. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/plotting.py +0 -0
  143. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/plotting_viser.py +0 -0
  144. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  145. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  146. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  147. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  148. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  149. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  150. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  151. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  152. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/cinema_vp_realtime.py +0 -0
  153. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/drone_racing_realtime.py +0 -0
  154. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/dubins_car_realtime.py +0 -0
  155. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  156. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/3DoF_pdg.py +0 -0
  157. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg.py +0 -0
  158. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  159. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/ascent_launch_vehicle.py +0 -0
  160. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/halo_orbit.py +0 -0
  161. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/hohmann_transfer.py +0 -0
  162. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/let_transfer.py +0 -0
  163. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/proxops_cw.py +0 -0
  164. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/relative_loitering.py +0 -0
  165. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/ctlos_cine.gif +0 -0
  166. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/ctlos_dr.gif +0 -0
  167. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/dtlos_cine.gif +0 -0
  168. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/dtlos_dr.gif +0 -0
  169. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/openscvx_logo.svg +0 -0
  170. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/openscvx_logo_square.png +0 -0
  171. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/oscvx_structure_full_dark.svg +0 -0
  172. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/video_preview.png +0 -0
  173. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/__init__.py +0 -0
  174. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/custom.css +0 -0
  175. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  176. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  177. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  178. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/home.html +0 -0
  179. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/main.html +0 -0
  180. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-diagram.html +0 -0
  181. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-dropin-banner.html +0 -0
  182. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-hero.html +0 -0
  183. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-pipeline.html +0 -0
  184. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-viser-strip.html +0 -0
  185. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/__init__.py +0 -0
  186. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/__main__.py +0 -0
  187. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/__init__.py +0 -0
  188. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  189. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/__init__.py +0 -0
  190. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/weights.py +0 -0
  191. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/config.py +0 -0
  192. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/__init__.py +0 -0
  193. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/base.py +0 -0
  194. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/discretize_linearize.py +0 -0
  195. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize.py +0 -0
  196. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  197. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  198. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  199. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  200. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/__init__.py +0 -0
  201. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/byof.py +0 -0
  202. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/lowering.py +0 -0
  203. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/validation.py +0 -0
  204. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/init/__init__.py +0 -0
  205. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/init/interpolation.py +0 -0
  206. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/init/inverse_kinematics.py +0 -0
  207. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/__init__.py +0 -0
  208. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/base.py +0 -0
  209. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/menagerie.py +0 -0
  210. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/mjx.py +0 -0
  211. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrators/__init__.py +0 -0
  212. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrators/diffrax.py +0 -0
  213. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrators/runge_kutta.py +0 -0
  214. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/loader.py +0 -0
  215. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/__init__.py +0 -0
  216. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_constraints.py +0 -0
  217. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_variables.py +0 -0
  218. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/dynamics.py +0 -0
  219. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/jax_constraints.py +0 -0
  220. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/parameters.py +0 -0
  221. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/problem.py +0 -0
  222. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/unified.py +0 -0
  223. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/__init__.py +0 -0
  224. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/plotting.py +0 -0
  225. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/publication.py +0 -0
  226. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/scp_iteration.py +0 -0
  227. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/__init__.py +0 -0
  228. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/animated.py +0 -0
  229. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/coordinates.py +0 -0
  230. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/orbits.py +0 -0
  231. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/plotly_integration.py +0 -0
  232. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/primitives.py +0 -0
  233. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/scp.py +0 -0
  234. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/server.py +0 -0
  235. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/propagation/__init__.py +0 -0
  236. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/propagation/post_processing.py +0 -0
  237. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/propagation/propagation.py +0 -0
  238. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/__init__.py +0 -0
  239. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/base.py +0 -0
  240. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/cones.py +0 -0
  241. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
  242. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  243. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/ptr_solver.py +0 -0
  244. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  245. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/__init__.py +0 -0
  246. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/affine.py +0 -0
  247. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/augmentation.py +0 -0
  248. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/builder.py +0 -0
  249. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/canonicalize.py +0 -0
  250. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/constraint_set.py +0 -0
  251. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/__init__.py +0 -0
  252. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/arithmetic.py +0 -0
  253. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/array.py +0 -0
  254. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/constraint.py +0 -0
  255. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/control.py +0 -0
  256. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/expr.py +0 -0
  257. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  258. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  259. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/se3.py +0 -0
  260. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/so3.py +0 -0
  261. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/linalg.py +0 -0
  262. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/logic.py +0 -0
  263. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/math.py +0 -0
  264. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/parameter.py +0 -0
  265. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/spatial.py +0 -0
  266. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/state.py +0 -0
  267. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stl.py +0 -0
  268. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stljax.py +0 -0
  269. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/time.py +0 -0
  270. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/variable.py +0 -0
  271. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/vmap.py +0 -0
  272. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/hashing.py +0 -0
  273. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lower.py +0 -0
  274. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/__init__.py +0 -0
  275. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  276. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  277. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  278. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  279. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  280. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  281. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  282. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  283. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  284. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  285. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  286. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  287. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  288. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  289. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  290. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  291. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  292. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  293. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  294. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  295. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  296. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  297. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  298. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  299. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  300. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  301. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  302. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  303. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  304. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/__init__.py +0 -0
  305. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/_registry.py +0 -0
  306. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/array.py +0 -0
  307. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/constraint.py +0 -0
  308. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/lie.py +0 -0
  309. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/linalg.py +0 -0
  310. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/logic.py +0 -0
  311. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/math.py +0 -0
  312. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/parser.py +0 -0
  313. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/spatial.py +0 -0
  314. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stl.py +0 -0
  315. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stljax.py +0 -0
  316. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/tokenizer.py +0 -0
  317. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/preprocessing.py +0 -0
  318. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/problem.py +0 -0
  319. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/sparsity.py +0 -0
  320. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/unified.py +0 -0
  321. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/__init__.py +0 -0
  322. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/cache.py +0 -0
  323. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/printing.py +0 -0
  324. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/profiling.py +0 -0
  325. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/utils.py +0 -0
  326. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/dependency_links.txt +0 -0
  327. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/entry_points.txt +0 -0
  328. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/requires.txt +0 -0
  329. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/top_level.txt +0 -0
  330. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/pyproject.toml +0 -0
  331. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/scripts/gen_example_pages.py +0 -0
  332. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/scripts/gen_ref_pages.py +0 -0
  333. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  334. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/setup.cfg +0 -0
  335. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/__init__.py +0 -0
  336. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/_marks.py +0 -0
  337. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/__init__.py +0 -0
  338. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/_iteration_helpers.py +0 -0
  339. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/__init__.py +0 -0
  340. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  341. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  342. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_parity.py +0 -0
  343. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/brachistochrone_analytical.py +0 -0
  344. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/conftest.py +0 -0
  345. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/expr/__init__.py +0 -0
  346. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/expr/test_gmsr.py +0 -0
  347. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.json +0 -0
  348. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.yaml +0 -0
  349. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/hohmann_analytical.py +0 -0
  350. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/integrations/__init__.py +0 -0
  351. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx.py +0 -0
  352. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx_dynamics.py +0 -0
  353. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/__init__.py +0 -0
  354. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/_iteration_callback_helpers.py +0 -0
  355. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  356. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  357. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  358. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  359. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  360. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  361. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  362. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_subproblem_pytree.py +0 -0
  363. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/__init__.py +0 -0
  364. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/__init__.py +0 -0
  365. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_arithmetic.py +0 -0
  366. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_array.py +0 -0
  367. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_constraint.py +0 -0
  368. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_expr.py +0 -0
  369. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_lie.py +0 -0
  370. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_linalg.py +0 -0
  371. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_logic.py +0 -0
  372. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_math.py +0 -0
  373. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_node_reference.py +0 -0
  374. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_parameters.py +0 -0
  375. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_scaling.py +0 -0
  376. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_spatial.py +0 -0
  377. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_stl.py +0 -0
  378. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_variable.py +0 -0
  379. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_vmap.py +0 -0
  380. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/__init__.py +0 -0
  381. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_array.py +0 -0
  382. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_constraint.py +0 -0
  383. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_lie.py +0 -0
  384. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_linalg.py +0 -0
  385. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_load.py +0 -0
  386. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_logic.py +0 -0
  387. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_math.py +0 -0
  388. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_parser.py +0 -0
  389. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_spatial.py +0 -0
  390. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_stl.py +0 -0
  391. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_tokenizer.py +0 -0
  392. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_vmap.py +0 -0
  393. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_augmentation.py +0 -0
  394. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_hashing.py +0 -0
  395. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_cvxpy.py +0 -0
  396. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_jax.py +0 -0
  397. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_preprocessing.py +0 -0
  398. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_sparsity.py +0 -0
  399. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_unified.py +0 -0
  400. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_brachistochrone.py +0 -0
  401. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_cvxpygen_optional.py +0 -0
  402. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_examples.py +0 -0
  403. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_expert.py +0 -0
  404. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_impulsive.py +0 -0
  405. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_init.py +0 -0
  406. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_integrators.py +0 -0
  407. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_loader.py +0 -0
  408. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_optimization_results.py +0 -0
  409. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_plotting.py +0 -0
  410. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_propagation.py +0 -0
  411. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_brachistochrone.py +0 -0
  412. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
  413. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_export_roundtrip.py +0 -0
  414. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_inference.py +0 -0
  415. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
  416. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
  417. {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
  418. {openscvx-0.5.3.dev25 → 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.dev25
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
@@ -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.dev25'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev25')
21
+ __version__ = version = '0.5.3.dev26'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev26')
23
23
 
24
- __commit_id__ = commit_id = 'ge4b992a50'
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
 
@@ -48,19 +50,18 @@ from .autotuner import (
48
50
  RampProximalWeight,
49
51
  RampProximalWeightSpec,
50
52
  )
51
- 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 (
52
60
  AdaptiveStateCode,
53
- Algorithm,
54
- AlgorithmHistory,
55
61
  AlgorithmState,
56
- AutotuningBase,
57
62
  CandidateIterate,
58
- DiscretizationResult,
59
- HyperParams,
60
63
  adaptive_state_code_to_str,
61
64
  )
62
- from .optimization_results import OptimizationResults
63
- from .scvx import PenalizedTrustRegion
64
65
  from .weights import Weights
65
66
 
66
67
  # ---------------------------------------------------------------------------
@@ -29,20 +29,21 @@ from openscvx.utils.printing import (
29
29
  color_adaptive_state,
30
30
  )
31
31
 
32
- from ..base import AdaptiveStateCode, AutotuningBase, HyperParams
32
+ from ..penalty import calculate_nonlinear_penalty
33
+ from ..state import AdaptiveStateCode
34
+ from .base import AutotuningBase, LamCostRelaxHyper
33
35
 
34
36
  if TYPE_CHECKING:
35
37
  from openscvx.lowered import LoweredJaxConstraints
36
38
 
37
- from ..base import AlgorithmState, CandidateIterate
39
+ from ..state import AlgorithmState, CandidateIterate
38
40
 
39
41
 
40
- class AcceptanceRatioHyper(HyperParams):
42
+ class AcceptanceRatioHyper(LamCostRelaxHyper):
41
43
  """Knobs shared by every acceptance-ratio autotuner.
42
44
 
43
- ``lam_cost_drop`` is the iteration after which ``lam_cost`` relaxation
44
- applies (``state.k > lam_cost_drop``): ``-1`` relaxes from the first
45
- iteration, and the default ``lam_cost_relax=1.0`` makes that a no-op.
45
+ Extends the shared :class:`LamCostRelaxHyper` ``lam_cost`` relaxation knobs
46
+ with the acceptance-ratio decision thresholds and the ``lam_prox`` clips.
46
47
  """
47
48
 
48
49
  gamma_1: float = 2.0
@@ -52,8 +53,6 @@ class AcceptanceRatioHyper(HyperParams):
52
53
  eta_2: float = 0.8
53
54
  lam_prox_min: float = 1e-3
54
55
  lam_prox_max: float = 1e4
55
- lam_cost_drop: int = -1
56
- lam_cost_relax: float = 1.0
57
56
 
58
57
 
59
58
  class AcceptanceRatioAutotuner(AutotuningBase):
@@ -121,7 +120,7 @@ class AcceptanceRatioAutotuner(AutotuningBase):
121
120
  Pure functional update — see class docstring.
122
121
  """
123
122
  candidate_x_prop = candidate.x_prop_plus[1:]
124
- nonlin_cost, nonlin_pen, nodal_pen = self.calculate_nonlinear_penalty(
123
+ nonlin_cost, nonlin_pen, nodal_pen = calculate_nonlinear_penalty(
125
124
  candidate_x_prop,
126
125
  candidate.x,
127
126
  candidate.u,
@@ -135,17 +134,7 @@ class AcceptanceRatioAutotuner(AutotuningBase):
135
134
  )
136
135
  J_nonlin = nonlin_cost + nonlin_pen + nodal_pen
137
136
 
138
- # Cost relaxation: when state.k > hyper.lam_cost_drop, scale
139
- # state.lam_cost; otherwise reset to the algorithm's initial weight
140
- # (carried on the pytree as state.lam_cost_init, broadcast at
141
- # from_settings()). Both constants ride the pytree so per-solve
142
- # overrides and vmap sweeps reach the traced body. Scalar
143
- # lam_cost_relax preserves the user-specified per-state weight ratios.
144
- lam_cost_next = jnp.where(
145
- state.k > state.hyper.lam_cost_drop,
146
- state.lam_cost * state.hyper.lam_cost_relax,
147
- state.lam_cost_init,
148
- )
137
+ lam_cost_next = self._relaxed_lam_cost(state)
149
138
 
150
139
  def first_iter(state):
151
140
  # Iter 1: accept unconditionally, leave weights at their init values,
@@ -164,7 +153,7 @@ class AcceptanceRatioAutotuner(AutotuningBase):
164
153
  # Recompute the previous iterate's J_nonlin from the pytree fields
165
154
  # (state.x/state.u were the *previous* accepted iterate).
166
155
  prev_x_prop = state.x_prop_plus[1:]
167
- prev_cost, prev_pen, prev_nodal_pen = self.calculate_nonlinear_penalty(
156
+ prev_cost, prev_pen, prev_nodal_pen = calculate_nonlinear_penalty(
168
157
  prev_x_prop,
169
158
  state.x,
170
159
  state.u,
@@ -18,7 +18,7 @@ from .acceptance_ratio import AcceptanceRatioAutotuner, AcceptanceRatioHyper
18
18
  if TYPE_CHECKING:
19
19
  from openscvx.lowered import LoweredJaxConstraints
20
20
 
21
- from ..base import AlgorithmState, CandidateIterate
21
+ from ..state import AlgorithmState, CandidateIterate
22
22
 
23
23
 
24
24
  class AugmentedLagrangianHyper(AcceptanceRatioHyper):
@@ -0,0 +1,259 @@
1
+ """Abstract base for autotuning strategies.
2
+
3
+ :class:`AutotuningBase` is the contract every penalty-weight update rule
4
+ implements: :py:meth:`~AutotuningBase.update_weights` is a pure functional
5
+ update on an :class:`~openscvx.algorithms.state.AlgorithmState` pytree, so the
6
+ SCP body composes with ``jax.jit`` / ``jax.vmap`` / ``jax.grad``. The base also
7
+ houses :class:`LamCostRelaxHyper`, the ``lam_cost`` relaxation knobs every
8
+ built-in autotuner shares, and :meth:`AutotuningBase._relaxed_lam_cost`, the
9
+ single implementation of that rule.
10
+
11
+ This module mirrors the package's ``base.py``-is-the-ABC idiom inside the
12
+ ``autotuner`` subpackage; the concrete autotuners live alongside it.
13
+ """
14
+
15
+ from abc import ABC, abstractmethod
16
+ from dataclasses import fields as dc_fields
17
+ from dataclasses import replace as dc_replace
18
+ from typing import TYPE_CHECKING, List
19
+
20
+ import jax.numpy as jnp
21
+
22
+ from openscvx.utils.printing import Column
23
+
24
+ from ..hyperparams import HyperParams
25
+
26
+ if TYPE_CHECKING:
27
+ import hashlib
28
+
29
+ from openscvx.config import Config
30
+ from openscvx.lowered.jax_constraints import LoweredJaxConstraints
31
+
32
+ from ..state import AlgorithmState, CandidateIterate
33
+
34
+
35
+ class LamCostRelaxHyper(HyperParams):
36
+ """``lam_cost`` relaxation knobs shared by every built-in autotuner.
37
+
38
+ Every autotuner relaxes ``lam_cost`` by the same rule (see
39
+ :meth:`AutotuningBase._relaxed_lam_cost`), so the two knobs that steer it
40
+ live here once instead of being re-declared per class. ``lam_cost_drop`` is
41
+ the iteration after which relaxation applies (``state.k > lam_cost_drop``):
42
+ ``-1`` relaxes from the first iteration, and the default
43
+ ``lam_cost_relax=1.0`` makes that a no-op.
44
+ """
45
+
46
+ lam_cost_drop: int = -1
47
+ lam_cost_relax: float = 1.0
48
+
49
+
50
+ class AutotuningBase(ABC):
51
+ """Base class for autotuning strategies in SCP algorithms.
52
+
53
+ Subclasses implement :py:meth:`update_weights` as a **pure functional
54
+ update** on an :class:`AlgorithmState` pytree. Concretely, an autotuner
55
+ must:
56
+
57
+ * Not mutate ``state`` or ``candidate``.
58
+ * Not return strings, raise on data-dependent conditions, or append to
59
+ Python lists at trace time.
60
+ * Express all branching on iterate values via ``jax.lax.cond`` /
61
+ ``jnp.where``.
62
+
63
+ The autotuner's per-iteration outcome is encoded as an
64
+ :class:`AdaptiveStateCode` int32 on the returned state; the SCP loop
65
+ converts that back to a human-readable label only on the Python-loop
66
+ printing path.
67
+
68
+ **The returned state IS the next iterate.** The SCP loop discards
69
+ everything except what ``update_weights`` returns, so accepting the
70
+ subproblem's candidate means carrying its trajectory onto the returned
71
+ state — ``x`` / ``u`` / ``x_prop`` / ``x_prop_plus`` from ``candidate`` —
72
+ while rejecting means keeping the previous fields and adjusting only the
73
+ weights. An update that never copies the candidate produces a solver that
74
+ runs to ``k_max`` without the iterate ever moving, silently.
75
+
76
+ **Declaring tunable hyperparameters.** A numeric knob a user might sweep
77
+ (a penalty ramp, a relaxation iteration) must not be read off ``self``
78
+ inside ``update_weights`` — a Python attribute is baked into the trace
79
+ and invisible to every override channel. Instead, declare it on a
80
+ :class:`HyperParams` subclass, assign an instance to ``self.hyper``, and
81
+ read it from ``state.hyper``::
82
+
83
+ class MyHyper(HyperParams):
84
+ ramp: float = 2.0
85
+
86
+ class MyAutotuner(AutotuningBase):
87
+ def __init__(self, ramp: float = 2.0):
88
+ self.hyper = MyHyper(ramp=ramp)
89
+
90
+ def update_weights(self, state, candidate, nodal_constraints, settings, params):
91
+ return state.replace(
92
+ # accept the candidate: it becomes the next iterate
93
+ x=candidate.x,
94
+ u=candidate.u,
95
+ x_prop=candidate.x_prop,
96
+ x_prop_plus=candidate.x_prop_plus,
97
+ lam_prox=state.lam_prox * state.hyper.ramp,
98
+ adaptive_state_code=...,
99
+ )
100
+
101
+ The declaration is the registration: the field becomes a per-solve
102
+ override (``solve_jax(algorithm={"ramp": ...})``), a batchable sweep
103
+ target (``solve_batched(algorithm={"ramp": jnp.linspace(...)})``), and a
104
+ runtime input of the exported batched artifact — with zero core edits.
105
+ Every numeric knob of the built-in autotuners is declared this way, so the
106
+ only configuration left outside ``hyper`` is structural choices that select
107
+ code paths (class attributes like ``COMPUTES_ACCEPTANCE_METRICS``); they
108
+ are part of the traced program, not data. For ergonomics, declared knobs
109
+ are still readable and writable as bare attributes
110
+ (``autotuner.ramp = 3.0``): the proxy below routes the access into
111
+ ``hyper`` so a constructor — or a test — may keep assigning knobs by name.
112
+ Assign ``self.hyper`` *first* in ``__init__``; a knob assigned before
113
+ ``hyper`` exists lands as a plain instance attribute the proxy cannot see.
114
+
115
+ Class Attributes:
116
+ COLUMNS: List of Column specs for autotuner-specific metrics to display.
117
+ Subclasses override this to add their own columns.
118
+ COMPUTES_ACCEPTANCE_METRICS: Whether ``update_weights`` computes a
119
+ predicted/actual reduction and the resulting acceptance ratio. The
120
+ SCP loop records and prints those diagnostics only when this is
121
+ ``True`` (the default); tuners that never reject an iterate — e.g.
122
+ :class:`~openscvx.algorithms.autotuner.constant_proximal_weight.ConstantProximalWeight`
123
+ and :class:`~openscvx.algorithms.autotuner.ramp_proximal_weight.RampProximalWeight`
124
+ — set it ``False``.
125
+ hyper: The autotuner's declared hyperparameters — a
126
+ :class:`HyperParams` instance carrying plain-Python defaults
127
+ (the empty base when it declares none). Snapshotted onto
128
+ ``AlgorithmState.hyper`` with array leaves (see
129
+ :meth:`AlgorithmState.from_settings`; ``int`` fields get ``k``'s
130
+ integer dtype, ``float`` fields the float dtype), which is what
131
+ ``update_weights`` reads at trace time.
132
+ """
133
+
134
+ COLUMNS: List[Column] = []
135
+ COMPUTES_ACCEPTANCE_METRICS: bool = True
136
+ hyper: HyperParams = HyperParams()
137
+
138
+ def __getattr__(self, name: str):
139
+ """Read a declared hyperparameter as a bare attribute.
140
+
141
+ Promoted knobs live on the frozen ``hyper`` container, but the
142
+ documented API and constructors still touch them by name
143
+ (``autotuner.lam_prox_max``). ``__getattr__`` fires only on failed
144
+ normal lookups, so real attributes (``COLUMNS``, ``hyper`` itself) are
145
+ unaffected; a name matching a ``hyper`` field resolves there.
146
+ """
147
+ hyper = self.__dict__.get("hyper")
148
+ if hyper is not None and name in {f.name for f in dc_fields(hyper)}:
149
+ return getattr(hyper, name)
150
+ raise AttributeError(f"{type(self).__name__!r} has no attribute {name!r}")
151
+
152
+ def __setattr__(self, name: str, value) -> None:
153
+ """Route a write to a declared hyperparameter into the frozen ``hyper``.
154
+
155
+ Without this, assigning a promoted knob as a bare attribute
156
+ (``autotuner.lam_prox_max = 1e6``) would silently shadow the ``hyper``
157
+ field and never reach the solve. A name matching a ``hyper`` field is
158
+ applied via :func:`dataclasses.replace`; every other attribute
159
+ (including ``hyper`` itself) is set normally, so constructors may keep
160
+ assigning knobs by name — they route into ``hyper``, provided
161
+ ``self.hyper`` was assigned first (see the class docstring).
162
+ """
163
+ hyper = self.__dict__.get("hyper")
164
+ if hyper is not None and name != "hyper" and name in {f.name for f in dc_fields(hyper)}:
165
+ # Clear any instance attribute shadowing the knob (left by an
166
+ # assignment made before ``hyper`` existed) so reads resolve
167
+ # through ``__getattr__`` to the value just written.
168
+ self.__dict__.pop(name, None)
169
+ super().__setattr__("hyper", dc_replace(hyper, **{name: value}))
170
+ else:
171
+ super().__setattr__(name, value)
172
+
173
+ def _hash_into(self, hasher: "hashlib._Hash") -> None:
174
+ """Contribute the autotuner's update rule to the ``solve_batched`` cache key.
175
+
176
+ The exported batched loop bakes in ``update_weights`` and every numeric
177
+ parameter that steers it (penalty ramps, acceptance thresholds, weight
178
+ clips). The default hashes the concrete class plus all instance
179
+ attributes — sufficient because autotuner parameters are plain
180
+ scalars. The ``hyper`` *values* are excluded: declared hyperparameters
181
+ ride ``AlgorithmState.hyper`` as runtime inputs, so one artifact serves
182
+ every setting of them (the same reasoning that keeps the ``ep_*``
183
+ thresholds out of the algorithm's hash). The ``hyper`` *schema* is
184
+ folded in, though: the ``hyper`` leaves map positionally onto the
185
+ exported artifact's avals, so a field reorder or addition silently
186
+ permutes runtime values against the wrong leaves. Hashing the field
187
+ names in declaration order turns such a change into a clean cache miss
188
+ and rebuild — this matters because :class:`LamCostRelaxHyper` moves
189
+ ``lam_cost_drop`` / ``lam_cost_relax`` to the *front* of the field
190
+ order. Folded in by :meth:`Algorithm._hash_into`; mirrors the symbolic
191
+ ``_hash_into`` protocol.
192
+ """
193
+ from openscvx.utils.caching import hash_value_into
194
+
195
+ hasher.update(type(self).__name__.encode())
196
+ for name in sorted(vars(self)):
197
+ if name == "hyper":
198
+ continue
199
+ hasher.update(name.encode())
200
+ hash_value_into(hasher, getattr(self, name))
201
+ # Schema, not values: the hyper field order/names fix the exported
202
+ # artifact's leaf layout, so a reorder must invalidate cached artifacts
203
+ # rather than silently permute runtime values onto the wrong avals.
204
+ for fld in dc_fields(self.hyper):
205
+ hasher.update(fld.name.encode())
206
+
207
+ @staticmethod
208
+ def _relaxed_lam_cost(state: "AlgorithmState") -> jnp.ndarray:
209
+ """``lam_cost`` for the next iterate per the shared relaxation rule.
210
+
211
+ When ``state.k > state.hyper.lam_cost_drop``, scale ``state.lam_cost``
212
+ by ``state.hyper.lam_cost_relax``; otherwise reset to the algorithm's
213
+ initial weight (carried on the pytree as ``state.lam_cost_init``,
214
+ broadcast at :meth:`AlgorithmState.from_settings`). Both constants ride
215
+ the pytree so per-solve overrides and ``vmap`` sweeps reach the traced
216
+ body; the scalar ``lam_cost_relax`` preserves the user-specified
217
+ per-state weight ratios. Shared verbatim by every built-in autotuner
218
+ via the :class:`LamCostRelaxHyper` knobs.
219
+ """
220
+ return jnp.where(
221
+ state.k > state.hyper.lam_cost_drop,
222
+ state.lam_cost * state.hyper.lam_cost_relax,
223
+ state.lam_cost_init,
224
+ )
225
+
226
+ @abstractmethod
227
+ def update_weights(
228
+ self,
229
+ state: "AlgorithmState",
230
+ candidate: "CandidateIterate",
231
+ nodal_constraints: "LoweredJaxConstraints",
232
+ settings: "Config",
233
+ params: dict,
234
+ ) -> "AlgorithmState":
235
+ """Return the next-iterate :class:`AlgorithmState`.
236
+
237
+ Must be JAX-traceable. See the class docstring for the contract.
238
+
239
+ Args:
240
+ state: Current-iterate pytree. Initial weights live on
241
+ ``state.lam_cost_init``; autotuners read from there rather than
242
+ from the algorithm's ``Weights`` object so the JIT'd closure
243
+ stays cache-stable across weight mutations.
244
+ candidate: Subproblem result (read-only here). On acceptance its
245
+ trajectory fields must be carried onto the returned state —
246
+ see the class docstring.
247
+ nodal_constraints: Lowered JAX constraints.
248
+ settings: Configuration object.
249
+ params: Problem parameter dictionary.
250
+
251
+ Returns:
252
+ The next-iterate :class:`AlgorithmState` — the SCP loop uses
253
+ nothing else, so an accepting update carries
254
+ ``candidate.x / u / x_prop / x_prop_plus`` onto it, while a
255
+ rejecting update keeps the previous fields and adjusts only the
256
+ weights. Its :py:attr:`AlgorithmState.adaptive_state_code` encodes
257
+ the autotuner's decision; the SCP loop records that into history
258
+ and maps it to a printable label.
259
+ """