openscvx 0.5.3.dev47__tar.gz → 0.5.3.dev48__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 (468) hide show
  1. {openscvx-0.5.3.dev47/openscvx.egg-info → openscvx-0.5.3.dev48}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/Foundations/constraint_reformulation.md +34 -2
  3. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/02_drone_racing_constraints.md +1 -0
  4. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/__init__.py +9 -0
  5. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/_version.py +3 -3
  6. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/augmentation.py +6 -4
  7. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/constraint.py +64 -14
  8. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/stl.py +4 -3
  9. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/stljax.py +4 -3
  10. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48/openscvx.egg-info}/PKG-INFO +1 -1
  11. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx.egg-info/scm_version.json +2 -2
  12. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_constraint.py +88 -0
  13. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_augmentation.py +27 -1
  14. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_hashing.py +47 -9
  15. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/assets/logo.svg +0 -0
  16. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/release-drafter.yml +0 -0
  17. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/_docs.yml +0 -0
  18. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/_extra.yml +0 -0
  19. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/branch-name.yml +0 -0
  20. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/docs.yml +0 -0
  21. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/lint.yml +0 -0
  22. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/nightly.yml +0 -0
  23. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/release-drafter.yml +0 -0
  24. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/release.yml +0 -0
  25. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/tests-cvxpygen.yml +0 -0
  26. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/tests-examples.yml +0 -0
  27. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/tests-lie.yml +0 -0
  28. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/tests-mjx.yml +0 -0
  29. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/tests-qpax.yml +0 -0
  30. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.github/workflows/tests.yml +0 -0
  31. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.gitignore +0 -0
  32. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/.gitmodules +0 -0
  33. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/CITATION.cff +0 -0
  34. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/CONTRIBUTING.md +0 -0
  35. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/LICENSE +0 -0
  36. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/README.md +0 -0
  37. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/Foundations/control_parameterization.md +0 -0
  38. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/Foundations/discretization.md +0 -0
  39. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/Foundations/ocp.md +0 -0
  40. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/Foundations/scvx.md +0 -0
  41. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/Foundations/time_dilation.md +0 -0
  42. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UnderTheHood/batching_jit_grad.md +0 -0
  43. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
  44. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UnderTheHood/lowering_architecture.md +0 -0
  45. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  46. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/00_introduction.md +0 -0
  47. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  48. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  49. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  50. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/05_visualization.md +0 -0
  51. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/06_logic.md +0 -0
  52. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/07_lie.md +0 -0
  53. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/08_mpcc.md +0 -0
  54. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  55. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/favicon.png +0 -0
  56. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/images/ct-scvx_dark.png +0 -0
  57. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/images/ct-scvx_light.png +0 -0
  58. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/images/ctcs_dark.png +0 -0
  59. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/images/ctcs_light.png +0 -0
  60. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/images/problem_class_dark.png +0 -0
  61. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/images/problem_class_light.png +0 -0
  62. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/logo.svg +0 -0
  63. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/openscvx_logo_square.png +0 -0
  64. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/viser-client/index.html +0 -0
  65. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  66. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  67. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/changelog.md +0 -0
  68. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/citation.md +0 -0
  69. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/examples.md +0 -0
  70. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/index.md +0 -0
  71. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/installation.md +0 -0
  72. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/javascripts/mathjax.js +0 -0
  73. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/llms.txt +0 -0
  74. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/docs/versions.json +0 -0
  75. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/_viser_embed_export.py +0 -0
  76. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/abstract/brachistochrone.py +0 -0
  77. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/abstract/brachistochrone_batched.py +0 -0
  78. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/abstract/flappy_bird.py +0 -0
  79. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/abstract/hypersensitive.py +0 -0
  80. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/abstract/impulsive.py +0 -0
  81. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/abstract/stl_integer_variable.py +0 -0
  82. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/abstract/stl_or.py +0 -0
  83. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/aircraft/dynamic_soaring.py +0 -0
  84. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/aircraft/supersonic_time_to_climb.py +0 -0
  85. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/7_dof_arm.py +0 -0
  86. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/_camera.py +0 -0
  87. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/_render.py +0 -0
  88. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/_sensor_view.py +0 -0
  89. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/dr_vp_polytope.py +0 -0
  90. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  91. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/logo.py +0 -0
  92. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  93. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/arm/3_dof_arm.py +0 -0
  94. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/arm/7_dof_arm.py +0 -0
  95. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/arm/7_dof_arm_collision.py +0 -0
  96. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/arm/7_dof_arm_vp.py +0 -0
  97. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  98. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  99. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  100. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/car/dubins_car.py +0 -0
  101. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/car/dubins_car_disjoint.py +0 -0
  102. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  103. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/car/dubins_car_obstacle_stl.py +0 -0
  104. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/car/dubins_car_stl_or.py +0 -0
  105. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/car/dubins_car_waypoint_stl.py +0 -0
  106. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/double_integrator/_plotting.py +0 -0
  107. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/double_integrator/moving_safe_zones.py +0 -0
  108. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  109. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/boresight_trace_mpcc.py +0 -0
  110. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/cinema_vp.py +0 -0
  111. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/cinema_vp_nodal.py +0 -0
  112. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/dr_double_integrator.py +0 -0
  113. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/dr_vp.py +0 -0
  114. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/dr_vp_nodal.py +0 -0
  115. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/dr_vp_polytope.py +0 -0
  116. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/drone_racing.py +0 -0
  117. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/drone_racing_batched_gates.py +0 -0
  118. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/logo.py +0 -0
  119. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/logo_utils/acl_logo.svg +0 -0
  120. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/logo_utils/circle.svg +0 -0
  121. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  122. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  123. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  124. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/multi_agent_circle_swap.py +0 -0
  125. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/obstacle_avoidance.py +0 -0
  126. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  127. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  128. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  129. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/drone/openscvx_logo.py +0 -0
  130. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/frax/panda_frax.py +0 -0
  131. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/frax/panda_frax_pick_place.py +0 -0
  132. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/frax/panda_frax_viewplanning.py +0 -0
  133. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/frax/panda_frax_waypoint.py +0 -0
  134. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/frax/ur5e_assets/ur5e.urdf +0 -0
  135. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/frax/ur5e_pen_trace.py +0 -0
  136. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/frax/ur5e_pen_trace_mpcc.py +0 -0
  137. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mjx/cartpole_mjx.py +0 -0
  138. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mjx/double_cartpole_mjx.py +0 -0
  139. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mjx/skydio_x2_mjx.py +0 -0
  140. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  141. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mjx/triple_cartpole_game.py +0 -0
  142. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mjx/triple_cartpole_mjx.py +0 -0
  143. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mpc/double_integrator_discrete.py +0 -0
  144. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mpc/double_integrator_drone_racing.py +0 -0
  145. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  146. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  147. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  148. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/plotting.py +0 -0
  149. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/plotting_viser.py +0 -0
  150. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  151. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  152. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  153. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  154. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  155. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  156. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  157. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  158. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/cinema_vp_realtime.py +0 -0
  159. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/drone_racing_realtime.py +0 -0
  160. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/dubins_car_realtime.py +0 -0
  161. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  162. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/rocket/3DoF_pdg.py +0 -0
  163. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/rocket/6DoF_pdg.py +0 -0
  164. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  165. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/rocket/ascent_launch_vehicle.py +0 -0
  166. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/spacecraft/halo_orbit.py +0 -0
  167. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/spacecraft/hohmann_transfer.py +0 -0
  168. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/spacecraft/let_transfer.py +0 -0
  169. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/spacecraft/proxops_cw.py +0 -0
  170. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/examples/spacecraft/relative_loitering.py +0 -0
  171. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/ctlos_cine.gif +0 -0
  172. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/ctlos_dr.gif +0 -0
  173. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/dtlos_cine.gif +0 -0
  174. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/dtlos_dr.gif +0 -0
  175. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/openscvx_logo.svg +0 -0
  176. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/openscvx_logo_square.png +0 -0
  177. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/oscvx_structure_full_dark.svg +0 -0
  178. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/figures/video_preview.png +0 -0
  179. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/__init__.py +0 -0
  180. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/assets/stylesheets/custom.css +0 -0
  181. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  182. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  183. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  184. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/home.html +0 -0
  185. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/main.html +0 -0
  186. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/partials/home-diagram.html +0 -0
  187. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/partials/home-dropin-banner.html +0 -0
  188. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/partials/home-hero.html +0 -0
  189. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/partials/home-pipeline.html +0 -0
  190. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/partials/home-viser-strip.html +0 -0
  191. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/material/overrides/sitemap.xml +0 -0
  192. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/mkdocs.yml +0 -0
  193. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/__main__.py +0 -0
  194. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/__init__.py +0 -0
  195. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/autotuner/__init__.py +0 -0
  196. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
  197. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  198. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
  199. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/autotuner/base.py +0 -0
  200. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  201. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  202. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/base.py +0 -0
  203. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/history.py +0 -0
  204. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/hyperparams.py +0 -0
  205. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/loop.py +0 -0
  206. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/optimization_results.py +0 -0
  207. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/penalty.py +0 -0
  208. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/scvx/__init__.py +0 -0
  209. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/scvx/iteration.py +0 -0
  210. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
  211. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/state.py +0 -0
  212. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/algorithms/weights.py +0 -0
  213. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/config.py +0 -0
  214. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/__init__.py +0 -0
  215. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/base.py +0 -0
  216. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/discretize_linearize.py +0 -0
  217. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/linearize_discretize.py +0 -0
  218. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  219. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  220. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  221. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  222. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/expert/__init__.py +0 -0
  223. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/expert/byof.py +0 -0
  224. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/expert/lowering.py +0 -0
  225. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/expert/validation.py +0 -0
  226. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/init/__init__.py +0 -0
  227. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/init/interpolation.py +0 -0
  228. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/init/inverse_kinematics.py +0 -0
  229. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrations/__init__.py +0 -0
  230. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrations/_utils.py +0 -0
  231. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrations/base.py +0 -0
  232. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrations/frax.py +0 -0
  233. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrations/menagerie.py +0 -0
  234. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrations/mjx.py +0 -0
  235. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrators/__init__.py +0 -0
  236. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrators/diffrax.py +0 -0
  237. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/integrators/runge_kutta.py +0 -0
  238. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/loader.py +0 -0
  239. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/__init__.py +0 -0
  240. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/cvxpy_constraints.py +0 -0
  241. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/cvxpy_variables.py +0 -0
  242. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/dynamics.py +0 -0
  243. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/jax_constraints.py +0 -0
  244. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/parameters.py +0 -0
  245. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/problem.py +0 -0
  246. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/lowered/unified.py +0 -0
  247. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/__init__.py +0 -0
  248. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/plotting.py +0 -0
  249. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/publication.py +0 -0
  250. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/scp_iteration.py +0 -0
  251. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/__init__.py +0 -0
  252. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/animated.py +0 -0
  253. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/coordinates.py +0 -0
  254. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/orbits.py +0 -0
  255. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/plotly_integration.py +0 -0
  256. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/primitives.py +0 -0
  257. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/scp.py +0 -0
  258. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/plotting/viser/server.py +0 -0
  259. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/problem.py +0 -0
  260. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/propagation/__init__.py +0 -0
  261. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/propagation/post_processing.py +0 -0
  262. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/propagation/propagation.py +0 -0
  263. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/solvers/__init__.py +0 -0
  264. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/solvers/base.py +0 -0
  265. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/solvers/cones.py +0 -0
  266. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
  267. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  268. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/solvers/ptr_solver.py +0 -0
  269. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  270. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/__init__.py +0 -0
  271. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/affine.py +0 -0
  272. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/builder.py +0 -0
  273. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/canonicalize.py +0 -0
  274. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/constraint_set.py +0 -0
  275. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/__init__.py +0 -0
  276. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/arithmetic.py +0 -0
  277. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/array.py +0 -0
  278. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/control.py +0 -0
  279. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/expr.py +0 -0
  280. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  281. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  282. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/lie/se3.py +0 -0
  283. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/lie/so3.py +0 -0
  284. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/linalg.py +0 -0
  285. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/logic.py +0 -0
  286. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/math.py +0 -0
  287. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/parameter.py +0 -0
  288. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/spatial.py +0 -0
  289. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/state.py +0 -0
  290. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/time.py +0 -0
  291. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/variable.py +0 -0
  292. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/expr/vmap.py +0 -0
  293. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/hashing.py +0 -0
  294. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lower.py +0 -0
  295. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/__init__.py +0 -0
  296. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  297. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  298. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  299. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  300. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  301. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  302. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  303. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  304. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  305. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  306. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  307. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  308. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  309. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  310. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  311. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  312. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  313. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  314. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  315. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  316. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  317. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  318. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  319. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  320. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  321. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  322. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  323. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  324. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  325. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/__init__.py +0 -0
  326. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/_lowerer.py +0 -0
  327. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/_registry.py +0 -0
  328. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/arithmetic.py +0 -0
  329. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/array.py +0 -0
  330. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/constraint.py +0 -0
  331. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/control.py +0 -0
  332. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/expr.py +0 -0
  333. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/formulation.py +0 -0
  334. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/lie.py +0 -0
  335. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/linalg.py +0 -0
  336. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/logic.py +0 -0
  337. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/math.py +0 -0
  338. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/spatial.py +0 -0
  339. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/state.py +0 -0
  340. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/stl.py +0 -0
  341. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/lowerers/latex/vmap.py +0 -0
  342. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/__init__.py +0 -0
  343. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/_registry.py +0 -0
  344. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/array.py +0 -0
  345. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/constraint.py +0 -0
  346. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/lie.py +0 -0
  347. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/linalg.py +0 -0
  348. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/logic.py +0 -0
  349. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/math.py +0 -0
  350. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/parser.py +0 -0
  351. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/spatial.py +0 -0
  352. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/stl.py +0 -0
  353. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/stljax.py +0 -0
  354. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/parser/tokenizer.py +0 -0
  355. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/preprocessing.py +0 -0
  356. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/problem.py +0 -0
  357. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/sparsity.py +0 -0
  358. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/symbolic/unified.py +0 -0
  359. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/utils/__init__.py +0 -0
  360. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/utils/cache.py +0 -0
  361. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/utils/caching.py +0 -0
  362. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/utils/printing.py +0 -0
  363. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/utils/profiling.py +0 -0
  364. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx/utils/utils.py +0 -0
  365. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx.egg-info/SOURCES.txt +0 -0
  366. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx.egg-info/dependency_links.txt +0 -0
  367. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx.egg-info/entry_points.txt +0 -0
  368. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx.egg-info/requires.txt +0 -0
  369. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx.egg-info/scm_file_list.json +0 -0
  370. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/openscvx.egg-info/top_level.txt +0 -0
  371. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/pyproject.toml +0 -0
  372. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/scripts/gen_example_pages.py +0 -0
  373. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/scripts/gen_ref_pages.py +0 -0
  374. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  375. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/scripts/mkdocs_seo_hook.py +0 -0
  376. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/setup.cfg +0 -0
  377. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/__init__.py +0 -0
  378. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/__init__.py +0 -0
  379. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/_iteration_helpers.py +0 -0
  380. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/autotuner/__init__.py +0 -0
  381. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
  382. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
  383. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
  384. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  385. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  386. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/test_iteration_fn_parity.py +0 -0
  387. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/algorithms/test_make_solve_loop.py +0 -0
  388. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/brachistochrone_analytical.py +0 -0
  389. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/conftest.py +0 -0
  390. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/__init__.py +0 -0
  391. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_brachistochrone.py +0 -0
  392. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_impulsive.py +0 -0
  393. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_multishot_propagation.py +0 -0
  394. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_solve_batched_brachistochrone.py +0 -0
  395. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_solve_batched_cvxpy_export_errors.py +0 -0
  396. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_solve_batched_export_roundtrip.py +0 -0
  397. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_solve_jax_bare_brachistochrone.py +0 -0
  398. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_solve_jax_jit_brachistochrone.py +0 -0
  399. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_solve_jax_vmap_brachistochrone.py +0 -0
  400. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/e2e/test_solve_jax_vmap_converged_no_drift.py +0 -0
  401. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/fixtures/brachistochrone.json +0 -0
  402. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/fixtures/brachistochrone.yaml +0 -0
  403. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/hohmann_analytical.py +0 -0
  404. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/integrations/__init__.py +0 -0
  405. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/integrations/test_mjx.py +0 -0
  406. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/integrations/test_mjx_dynamics.py +0 -0
  407. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/__init__.py +0 -0
  408. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/_iteration_callback_helpers.py +0 -0
  409. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  410. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  411. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  412. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  413. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  414. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  415. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  416. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/solvers/test_subproblem_pytree.py +0 -0
  417. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/__init__.py +0 -0
  418. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/__init__.py +0 -0
  419. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_arithmetic.py +0 -0
  420. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_array.py +0 -0
  421. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_expr.py +0 -0
  422. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_lie.py +0 -0
  423. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_linalg.py +0 -0
  424. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_logic.py +0 -0
  425. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_math.py +0 -0
  426. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_node_reference.py +0 -0
  427. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_parameters.py +0 -0
  428. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_scaling.py +0 -0
  429. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_spatial.py +0 -0
  430. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_stl.py +0 -0
  431. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_variable.py +0 -0
  432. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/expr/test_vmap.py +0 -0
  433. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/__init__.py +0 -0
  434. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_array.py +0 -0
  435. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_constraint.py +0 -0
  436. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_lie.py +0 -0
  437. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_linalg.py +0 -0
  438. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_load.py +0 -0
  439. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_logic.py +0 -0
  440. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_math.py +0 -0
  441. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_parser.py +0 -0
  442. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_spatial.py +0 -0
  443. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_stl.py +0 -0
  444. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_tokenizer.py +0 -0
  445. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/parser/test_vmap.py +0 -0
  446. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_gmsr.py +0 -0
  447. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_latex_formulation.py +0 -0
  448. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_lower_cvxpy.py +0 -0
  449. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_lower_jax.py +0 -0
  450. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_lower_latex.py +0 -0
  451. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_preprocessing.py +0 -0
  452. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_sparsity.py +0 -0
  453. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/symbolic/test_unified.py +0 -0
  454. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_autotuning.py +0 -0
  455. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_cvxpygen_optional.py +0 -0
  456. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_discretization.py +0 -0
  457. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_examples.py +0 -0
  458. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_expert.py +0 -0
  459. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_init.py +0 -0
  460. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_initialize_syncs_guesses.py +0 -0
  461. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_integrators.py +0 -0
  462. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_loader.py +0 -0
  463. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_optimization_results.py +0 -0
  464. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_plotting.py +0 -0
  465. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_post_process_batched_tau_clamp.py +0 -0
  466. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_propagation.py +0 -0
  467. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_results_parameters.py +0 -0
  468. {openscvx-0.5.3.dev47 → openscvx-0.5.3.dev48}/tests/test_solve_batched_inference.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev47
3
+ Version: 0.5.3.dev48
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
@@ -29,8 +29,8 @@ $$
29
29
  $$
30
30
 
31
31
  where the default penalty is the squared ReLU $\max(0, g_j)^2$ (Huber and smooth
32
- ReLU are also available), and $s$ is the [time-dilation](time_dilation.md)
33
- factor. Because the integrand is non-negative, $y$ is monotonically
32
+ ReLU are also available, or you can [write your own](#custom-penalties)), and $s$
33
+ is the [time-dilation](time_dilation.md) factor. Because the integrand is non-negative, $y$ is monotonically
34
34
  non-decreasing and accumulates *any* violation occurring between nodes.
35
35
 
36
36
  Enforcing $y \equiv 0$ then drives every penalty — and hence every constraint —
@@ -66,6 +66,38 @@ different intervals get separate states. The bound $y_{\max}$ is the constraint'
66
66
  After solving, the achieved continuous-time violation is reported as
67
67
  `results.ctcs_violation`.
68
68
 
69
+ ## Custom penalties
70
+
71
+ The built-in penalties are selected by name — `"squared_relu"` (the default),
72
+ `"huber"`, and `"smooth_relu"` — which fixes their shape and their internal
73
+ constants. When you want to tune those constants or shape the penalty yourself,
74
+ pass a callable instead:
75
+
76
+ ```python
77
+ # Widen Huber's quadratic region — not expressible with the string form.
78
+ ox.ctcs(altitude >= 10, penalty=lambda r: ox.Huber(ox.PositivePart(r), delta=0.5))
79
+
80
+ # Quadratic near the boundary, with a linear tail that keeps pushing far out.
81
+ ox.ctcs(
82
+ speed <= v_max,
83
+ penalty=lambda r: ox.Square(ox.PositivePart(r)) + 0.1 * ox.PositivePart(r),
84
+ )
85
+ ```
86
+
87
+ The callable receives the canonicalized residual $g_j(x, u)$ — the constraint
88
+ already rearranged into $g_j \le 0$ form, so `speed <= v_max` arrives as
89
+ `speed - v_max` — and returns the expression to integrate. That result is summed
90
+ to a scalar, so a vector-valued residual may produce a vector-valued penalty. The
91
+ callable runs once, when the problem is built; from there its expression is
92
+ differentiated, sparsified, and cached exactly like a built-in penalty.
93
+
94
+ The body must be built from openscvx operations: `ox.PositivePart`, `ox.Square`,
95
+ `ox.Huber` (tunable `delta`), `ox.SmoothReLU` (tunable `c`), and ordinary
96
+ arithmetic on expressions. Reaching for `jax.numpy` instead — `jnp.maximum(r, 0)`
97
+ — returns an array rather than an expression and is rejected when the problem is
98
+ built: the penalty has to stay symbolic to be lowered into the augmented
99
+ dynamics.
100
+
69
101
  ## Related reading
70
102
 
71
103
  - [Optimal Control Problem](ocp.md) — where the CTCS reset-and-bound constraints
@@ -138,6 +138,7 @@ obstacle_constraint = (diff.T @ diff >= safe_distance**2).over((5, 10))
138
138
  ```
139
139
 
140
140
  The `.over()` method also accepts optional parameters for the penalty function type (`penalty`), grouping index (`idx`), and whether to also check nodally (`check_nodally`).
141
+ `penalty` takes one of the built-in names (`"squared_relu"`, `"huber"`, `"smooth_relu"`) or a callable that builds a penalty of your own from the constraint residual; see [Custom penalties](../Foundations/constraint_reformulation.md#custom-penalties).
141
142
 
142
143
  !!! note
143
144
  You can also directly instantiate `NodalConstraint` or `CTCS` objects if you prefer:
@@ -60,6 +60,7 @@ from openscvx.symbolic.expr import (
60
60
  Fixed,
61
61
  Free,
62
62
  Hstack,
63
+ Huber,
63
64
  Index,
64
65
  Inequality,
65
66
  Inv,
@@ -76,9 +77,12 @@ from openscvx.symbolic.expr import (
76
77
  Neg,
77
78
  NodalConstraint,
78
79
  Parameter,
80
+ PositivePart,
79
81
  Power,
80
82
  Sin,
83
+ SmoothReLU,
81
84
  Sqrt,
85
+ Square,
82
86
  Stack,
83
87
  State,
84
88
  Sub,
@@ -185,6 +189,11 @@ __all__ = [
185
189
  "NodalConstraint",
186
190
  "CTCS",
187
191
  "ctcs",
192
+ # Penalty function building blocks
193
+ "PositivePart",
194
+ "Square",
195
+ "Huber",
196
+ "SmoothReLU",
188
197
  # Data parallelism
189
198
  "Vmap",
190
199
  # LaTeX rendering
@@ -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.dev47'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev47')
21
+ __version__ = version = '0.5.3.dev48'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev48')
23
23
 
24
- __commit_id__ = commit_id = 'g983a4068f'
24
+ __commit_id__ = commit_id = 'g48a1a73ba'
@@ -215,13 +215,15 @@ def separate_constraints(constraint_set: ConstraintSet, n_nodes: int) -> Constra
215
215
  "Cross-node constraints should be specified as bare Constraint objects. "
216
216
  f"Constraint: {c.constraint}"
217
217
  )
218
- # Validate that CTCS constraints are not equality constraints
219
- # CTCS penalty functions (squared_relu, huber, smooth_relu) are designed
220
- # for inequality constraints only
218
+ # Validate that CTCS constraints are not equality constraints: the
219
+ # augmented state integrates a one-sided violation penalty, which
220
+ # only certifies satisfaction of an inequality
221
221
  if isinstance(c.constraint, Equality):
222
222
  raise ValueError(
223
223
  f"CTCS constraints cannot be equality constraints. "
224
- f"CTCS uses penalty functions designed for inequality constraints. "
224
+ f"A CTCS penalty measures violation of an inequality (how far the "
225
+ f"residual is above zero), so it cannot detect an equality being "
226
+ f"missed from below. "
225
227
  f"For equality constraints, use nodal constraints with .convex() instead.\n"
226
228
  f"Constraint: {c.constraint}"
227
229
  )
@@ -37,7 +37,7 @@ Example:
37
37
 
38
38
  import hashlib
39
39
  import struct
40
- from typing import List, Optional, Tuple, Union
40
+ from typing import Callable, List, Optional, Tuple, Union
41
41
 
42
42
  import numpy as np
43
43
 
@@ -124,7 +124,7 @@ class Constraint(Expr):
124
124
  def over(
125
125
  self,
126
126
  interval: tuple[int, int],
127
- penalty: str = "squared_relu",
127
+ penalty: Union[str, Callable[[Expr], "Expr"]] = "squared_relu",
128
128
  idx: Optional[int] = None,
129
129
  check_nodally: bool = False,
130
130
  licq_max: Optional[float] = None,
@@ -133,7 +133,10 @@ class Constraint(Expr):
133
133
 
134
134
  Args:
135
135
  interval: Tuple of (start, end) node indices for the continuous interval
136
- penalty: Penalty function type ("squared_relu", "huber", "smooth_relu")
136
+ penalty: Built-in penalty name ("squared_relu", "huber", "smooth_relu")
137
+ or a callable that receives the constraint residual as an ``Expr``
138
+ and returns the penalty ``Expr``, e.g.
139
+ ``lambda r: ox.Huber(ox.PositivePart(r), delta=0.5)``.
137
140
  idx: Optional grouping index for multiple augmented states
138
141
  check_nodally: Whether to also enforce this constraint nodally
139
142
  licq_max: Optional upper bound on the augmented state that accumulates
@@ -611,9 +614,20 @@ class CTCS(Expr):
611
614
  - **huber**: Huber(PositivePart(lhs)) - less sensitive to outliers than squared
612
615
  - **smooth_relu**: SmoothReLU(lhs) - smooth approximation of ReLU
613
616
 
617
+ A penalty may also be written as a callable that receives the constraint
618
+ residual ``r`` (the canonical left-hand side, satisfying ``r <= 0``) as a
619
+ symbolic ``Expr`` and returns the penalty ``Expr``. This is how penalty
620
+ parameters are tuned::
621
+
622
+ ox.ctcs(altitude >= 10, penalty=lambda r: ox.Huber(ox.PositivePart(r), delta=0.5))
623
+
624
+ The callable is applied once, at problem-build time; the resulting
625
+ expression is summed and integrated exactly like a built-in penalty.
626
+
614
627
  Attributes:
615
628
  constraint: The wrapped Constraint (typically Inequality) to enforce continuously
616
- penalty: Penalty function type ('squared_relu', 'huber', or 'smooth_relu')
629
+ penalty: Penalty function name ('squared_relu', 'huber', or 'smooth_relu')
630
+ or a callable ``Expr -> Expr`` applied to the constraint residual
617
631
  nodes: Optional (start, end) tuple specifying the interval for enforcement,
618
632
  or None to enforce over the entire trajectory
619
633
  idx: Optional grouping index for managing multiple augmented states.
@@ -655,7 +669,7 @@ class CTCS(Expr):
655
669
  def __init__(
656
670
  self,
657
671
  constraint: Constraint,
658
- penalty: str = "squared_relu",
672
+ penalty: Union[str, Callable[[Expr], Expr]] = "squared_relu",
659
673
  nodes: Optional[Tuple[int, int]] = None,
660
674
  idx: Optional[int] = None,
661
675
  check_nodally: bool = False,
@@ -665,10 +679,14 @@ class CTCS(Expr):
665
679
 
666
680
  Args:
667
681
  constraint: The Constraint to enforce continuously (typically an Inequality)
668
- penalty: Penalty function type. Options:
682
+ penalty: Penalty function name. Options:
669
683
  - 'squared_relu': Square(PositivePart(lhs)) - default, smooth, differentiable
670
684
  - 'huber': Huber(PositivePart(lhs)) - robust to outliers
671
685
  - 'smooth_relu': SmoothReLU(lhs) - smooth ReLU approximation
686
+
687
+ Alternatively a callable ``Expr -> Expr`` that receives the
688
+ constraint residual and returns the penalty expression, e.g.
689
+ ``lambda r: ox.Huber(ox.PositivePart(r), delta=0.5)``.
672
690
  nodes: Optional (start, end) tuple of node indices defining the enforcement interval.
673
691
  None means enforce over the entire trajectory. Must satisfy start < end.
674
692
  CTCS constraints with the same nodes are automatically grouped together.
@@ -780,12 +798,16 @@ class CTCS(Expr):
780
798
  def _hash_into(self, hasher: "hashlib._Hash") -> None:
781
799
  """Hash CTCS including all its parameters.
782
800
 
801
+ The penalty is hashed through the expression it builds rather than
802
+ through its spelling, so callable and named penalties hash alike and
803
+ two problems agree exactly when the same penalty tree gets lowered.
804
+
783
805
  Args:
784
806
  hasher: A hashlib hash object to update
785
807
  """
786
808
  hasher.update(b"CTCS")
787
- # Hash penalty type
788
- hasher.update(self.penalty.encode())
809
+ # Hash the penalty by what it builds, not how it was spelled
810
+ self.penalty_expr()._hash_into(hasher)
789
811
  # Hash nodes interval
790
812
  if self.nodes is not None:
791
813
  hasher.update(struct.pack(">ii", self.nodes[0], self.nodes[1]))
@@ -837,9 +859,14 @@ class CTCS(Expr):
837
859
  """String representation of the CTCS constraint.
838
860
 
839
861
  Returns:
840
- str: String showing constraint, penalty type, and optional parameters
862
+ str: String showing constraint, penalty, and optional parameters
841
863
  """
842
- parts = [f"{self.constraint!r}", f"penalty={self.penalty!r}"]
864
+ penalty = (
865
+ repr(self.penalty)
866
+ if isinstance(self.penalty, str)
867
+ else getattr(self.penalty, "__name__", repr(self.penalty))
868
+ )
869
+ parts = [f"{self.constraint!r}", f"penalty={penalty}"]
843
870
  if self.nodes is not None:
844
871
  parts.append(f"nodes={self.nodes}")
845
872
  if self.idx is not None:
@@ -863,11 +890,15 @@ class CTCS(Expr):
863
890
  s_aug_i(t) = 0 for all t, we ensure all penalties in the group are zero,
864
891
  which strictly enforces all constraints in the group continuously.
865
892
 
893
+ A callable penalty is applied here, once, to the residual expression; the
894
+ result is an ordinary Expr and rides the rest of the pipeline unchanged.
895
+
866
896
  Returns:
867
897
  Expr: Sum of the penalty function applied to the constraint violation
868
898
 
869
899
  Raises:
870
- ValueError: If an unknown penalty type is specified
900
+ ValueError: If an unknown penalty name is given, or if a callable
901
+ penalty returns something other than an Expr
871
902
 
872
903
  Note:
873
904
  This method is used internally during problem compilation to create
@@ -876,7 +907,18 @@ class CTCS(Expr):
876
907
  """
877
908
  lhs = self.constraint.lhs
878
909
 
879
- if self.penalty == "squared_relu":
910
+ if callable(self.penalty):
911
+ penalty = self.penalty(lhs)
912
+ if not isinstance(penalty, Expr):
913
+ raise ValueError(
914
+ f"CTCS penalty callable returned {type(penalty).__name__}, not a "
915
+ f"symbolic expression. The callable receives the constraint residual "
916
+ f"as an Expr and must return one built from openscvx operations, e.g. "
917
+ f"lambda r: ox.Square(ox.PositivePart(r)). Computing on the residual "
918
+ f"with jax.numpy or numpy will not work — the penalty is composed "
919
+ f"symbolically and only lowered to JAX later."
920
+ )
921
+ elif self.penalty == "squared_relu":
880
922
  from openscvx.symbolic.expr.math import PositivePart, Square
881
923
 
882
924
  penalty = Square(PositivePart(lhs))
@@ -896,7 +938,7 @@ class CTCS(Expr):
896
938
 
897
939
  def ctcs(
898
940
  constraint: Constraint,
899
- penalty: str = "squared_relu",
941
+ penalty: Union[str, Callable[[Expr], Expr]] = "squared_relu",
900
942
  nodes: Optional[Tuple[int, int]] = None,
901
943
  idx: Optional[int] = None,
902
944
  check_nodally: bool = False,
@@ -909,7 +951,8 @@ def ctcs(
909
951
 
910
952
  Args:
911
953
  constraint: The Constraint to enforce continuously
912
- penalty: Penalty function type ('squared_relu', 'huber', or 'smooth_relu').
954
+ penalty: Penalty function name ('squared_relu', 'huber', or 'smooth_relu'),
955
+ or a callable ``Expr -> Expr`` receiving the constraint residual.
913
956
  Defaults to 'squared_relu'.
914
957
  nodes: Optional (start, end) tuple of node indices for enforcement interval.
915
958
  None enforces over entire trajectory.
@@ -942,5 +985,12 @@ def ctcs(
942
985
  Also equivalent to using .over() method on constraint:
943
986
 
944
987
  altitude_constraint = (altitude >= 10).over((0, 100), penalty="huber")
988
+
989
+ Tuning a penalty with a callable:
990
+
991
+ altitude_constraint = ctcs(
992
+ altitude >= 10,
993
+ penalty=lambda r: ox.Huber(ox.PositivePart(r), delta=0.5),
994
+ )
945
995
  """
946
996
  return CTCS(constraint, penalty, nodes, idx, check_nodally, licq_max)
@@ -57,7 +57,7 @@ See also:
57
57
  """
58
58
 
59
59
  from dataclasses import dataclass
60
- from typing import TYPE_CHECKING, Optional, Tuple, Union
60
+ from typing import TYPE_CHECKING, Callable, Optional, Tuple, Union
61
61
 
62
62
  import numpy as np
63
63
 
@@ -307,7 +307,7 @@ class STLExpr(Expr):
307
307
  def over(
308
308
  self,
309
309
  interval: "IntervalLike",
310
- penalty: str = "smooth_relu",
310
+ penalty: Union[str, Callable[[Expr], Expr]] = "smooth_relu",
311
311
  idx: Optional[int] = None,
312
312
  check_nodally: bool = False,
313
313
  licq_max: Optional[float] = None,
@@ -321,7 +321,8 @@ class STLExpr(Expr):
321
321
  discretization indices and produces a :class:`NodeInterval`;
322
322
  ``"seconds"`` treats them as wall-time and produces a
323
323
  :class:`TimeInterval` (lowering not yet implemented).
324
- penalty: Penalty function type for CTCS
324
+ penalty: CTCS penalty function name, or a callable ``Expr -> Expr``
325
+ receiving the constraint residual (see :class:`CTCS`)
325
326
  idx: Optional grouping index for multiple augmented states
326
327
  check_nodally: Whether to also enforce at discrete nodes
327
328
  licq_max: Optional upper bound on the augmented state accumulating
@@ -9,7 +9,7 @@ STL operators accept Constraint objects (predicates) and extract robustness
9
9
  expressions which are lowered to STLJax during compilation.
10
10
  """
11
11
 
12
- from typing import TYPE_CHECKING, Optional, Tuple, Union
12
+ from typing import TYPE_CHECKING, Callable, Optional, Tuple, Union
13
13
 
14
14
  import numpy as np
15
15
 
@@ -56,7 +56,7 @@ class STLJaxExpr(Expr):
56
56
  def over(
57
57
  self,
58
58
  interval: tuple[int, int],
59
- penalty: str = "squared_relu",
59
+ penalty: Union[str, Callable[[Expr], Expr]] = "squared_relu",
60
60
  idx: Optional[int] = None,
61
61
  check_nodally: bool = False,
62
62
  licq_max: Optional[float] = None,
@@ -68,7 +68,8 @@ class STLJaxExpr(Expr):
68
68
 
69
69
  Args:
70
70
  interval: Tuple of (start, end) node indices for enforcement interval
71
- penalty: Penalty function type for CTCS
71
+ penalty: CTCS penalty function name, or a callable ``Expr -> Expr``
72
+ receiving the constraint residual (see :class:`CTCS`)
72
73
  idx: Optional grouping index for multiple augmented states
73
74
  check_nodally: Whether to also enforce at discrete nodes
74
75
  licq_max: Optional upper bound on the augmented state accumulating
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev47
3
+ Version: 0.5.3.dev48
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "tag": "0.5.2",
3
- "distance": 47,
4
- "node": "g983a4068ffb9b5a83d2654e485500e7842ae2c6d",
3
+ "distance": 48,
4
+ "node": "g48a1a73bab7e7655a8f28ace13dd29c1e2f6a88b",
5
5
  "dirty": false,
6
6
  "branch": "main",
7
7
  "node_date": "2026-08-10"
@@ -1121,6 +1121,94 @@ def test_ctcs_unknown_penalty():
1121
1121
  ctcs_constraint.penalty_expr()
1122
1122
 
1123
1123
 
1124
+ # --- CTCS: Callable Penalties ---
1125
+
1126
+
1127
+ def test_ctcs_callable_penalty_builds_expected_ast():
1128
+ """A callable penalty is applied to the residual and summed."""
1129
+ x = Variable("x", shape=(2,))
1130
+ constraint = x <= 1.0
1131
+
1132
+ ctcs_constraint = CTCS(constraint, penalty=lambda r: Square(PositivePart(r)))
1133
+ penalty = ctcs_constraint.penalty_expr()
1134
+
1135
+ assert isinstance(penalty, Sum)
1136
+ assert isinstance(penalty.operand, Square)
1137
+ assert isinstance(penalty.operand.x, PositivePart)
1138
+ assert penalty.operand.x.x is constraint.lhs
1139
+
1140
+
1141
+ def test_ctcs_callable_penalty_carries_parameters():
1142
+ """A callable penalty can tune parameters the named penalties hardcode."""
1143
+ x = Variable("x", shape=(2,))
1144
+ constraint = x <= 1.0
1145
+
1146
+ ctcs_constraint = CTCS(constraint, penalty=lambda r: Huber(PositivePart(r), delta=0.5))
1147
+ penalty = ctcs_constraint.penalty_expr()
1148
+
1149
+ assert isinstance(penalty.operand, Huber)
1150
+ assert penalty.operand.delta == 0.5
1151
+ # The named 'huber' penalty leaves delta at its default
1152
+ assert CTCS(constraint, penalty="huber").penalty_expr().operand.delta != 0.5
1153
+
1154
+
1155
+ def test_ctcs_callable_penalty_must_return_expr():
1156
+ """A callable penalty returning a non-Expr should say how to fix it."""
1157
+ import jax.numpy as jnp
1158
+
1159
+ x = Variable("x", shape=(1,))
1160
+ constraint = x <= 0.0
1161
+
1162
+ with pytest.raises(ValueError, match="must return one built from openscvx operations"):
1163
+ CTCS(constraint, penalty=lambda r: 42.0).penalty_expr()
1164
+
1165
+ with pytest.raises(ValueError, match="jax.numpy or numpy will not work"):
1166
+ CTCS(constraint, penalty=lambda r: jnp.maximum(0.0, 1.0)).penalty_expr()
1167
+
1168
+
1169
+ def test_ctcs_callable_penalty_rejected_at_build_time():
1170
+ """Shape checking surfaces a bad callable penalty when the problem is built."""
1171
+ x = State("x", (3,))
1172
+ constraint = x <= np.ones((3,))
1173
+
1174
+ with pytest.raises(ValueError, match="penalty expression validation failed"):
1175
+ ctcs(constraint, penalty=lambda r: 42.0).check_shape()
1176
+
1177
+
1178
+ def test_ctcs_callable_penalty_repr():
1179
+ """CTCS repr should name a callable penalty rather than dumping its address."""
1180
+ x = Variable("x", shape=(3,))
1181
+ constraint = x <= 1.5
1182
+
1183
+ def wide_huber(r):
1184
+ return Huber(PositivePart(r), delta=0.5)
1185
+
1186
+ assert repr(CTCS(constraint, penalty=wide_huber)) == (
1187
+ "CTCS(Var('x') <= Const(1.5), penalty=wide_huber)"
1188
+ )
1189
+ assert repr(CTCS(constraint, penalty=lambda r: Square(r))) == (
1190
+ "CTCS(Var('x') <= Const(1.5), penalty=<lambda>)"
1191
+ )
1192
+
1193
+
1194
+ def test_ctcs_over_preserves_callable_penalty():
1195
+ """A callable penalty survives .over() on both Constraint and CTCS."""
1196
+ x = Variable("x", shape=(2,))
1197
+
1198
+ def wide_huber(r):
1199
+ return Huber(PositivePart(r), delta=0.5)
1200
+
1201
+ ctcs_constraint = (x <= 1.0).over((0, 10), penalty=wide_huber)
1202
+ assert ctcs_constraint.penalty is wide_huber
1203
+ assert ctcs_constraint.nodes == (0, 10)
1204
+
1205
+ retimed = ctcs_constraint.over((10, 20))
1206
+ assert retimed.penalty is wide_huber
1207
+ assert retimed.nodes == (10, 20)
1208
+
1209
+ assert ctcs_constraint.canonicalize().penalty is wide_huber
1210
+
1211
+
1124
1212
  # --- CTCS: Shape Checking ---
1125
1213
 
1126
1214
 
@@ -582,6 +582,29 @@ def test_inequality_constraint_penalty_activation():
582
582
  )
583
583
 
584
584
 
585
+ def test_callable_penalty_matches_hand_built_expression():
586
+ """A callable penalty lowers to the same values as the expression it builds."""
587
+ limit = 1.0
588
+ x = jnp.array([-2.0, 0.0, 1.0, 1.5, 4.0])
589
+
590
+ state = State("x", (5,))
591
+ state._slice = slice(0, 5)
592
+
593
+ constraint = state - limit <= 0
594
+
595
+ ctcs_constraint = CTCS(constraint, penalty=lambda r: Huber(PositivePart(r), delta=0.5))
596
+ from_callable = lower_to_jax(ctcs_constraint.penalty_expr())(x, None, None, None)
597
+
598
+ hand_built = lower_to_jax(Sum(Huber(PositivePart(constraint.lhs), delta=0.5)))(
599
+ x, None, None, None
600
+ )
601
+
602
+ assert jnp.allclose(from_callable, hand_built)
603
+ # And it is genuinely a different penalty from the built-in huber
604
+ built_in = lower_to_jax(CTCS(constraint, penalty="huber").penalty_expr())(x, None, None, None)
605
+ assert not jnp.allclose(from_callable, built_in)
606
+
607
+
585
608
  def test_reverse_inequality_constraint_penalty():
586
609
  """Test penalties for x >= limit (satisfied when x >= limit)."""
587
610
  # Constraint: x >= 2.0, equivalent to 2.0 <= x
@@ -1552,9 +1575,12 @@ def test_ctcs_equality_rejected():
1552
1575
  with pytest.raises(ValueError) as exc_info:
1553
1576
  separate_constraints(constraint_set, n_nodes=n_nodes)
1554
1577
 
1555
- # Check error message is helpful
1578
+ # Check error message is helpful: it names the cause and the alternative,
1579
+ # without enumerating penalty names (penalties may be user-defined)
1556
1580
  msg = str(exc_info.value)
1557
1581
  assert "CTCS constraints cannot be equality" in msg
1582
+ assert "violation of an inequality" in msg
1583
+ assert ".convex()" in msg
1558
1584
 
1559
1585
 
1560
1586
  def test_nonconvex_inequality_still_accepted():
@@ -22,7 +22,7 @@ from openscvx.symbolic.expr import (
22
22
  )
23
23
  from openscvx.symbolic.expr.constraint import CTCS
24
24
  from openscvx.symbolic.expr.linalg import Norm
25
- from openscvx.symbolic.expr.math import Cos, Huber, Sin, SmoothReLU
25
+ from openscvx.symbolic.expr.math import Cos, Huber, PositivePart, Sin, SmoothReLU, Square
26
26
  from openscvx.symbolic.hashing import hash_symbolic_problem
27
27
 
28
28
 
@@ -528,8 +528,8 @@ def test_ctcs_same_params():
528
528
  y = State("y", (2,))
529
529
  y._slice = slice(0, 2)
530
530
 
531
- ctcs1 = CTCS(x <= 5, penalty="l2")
532
- ctcs2 = CTCS(y <= 5, penalty="l2")
531
+ ctcs1 = CTCS(x <= 5, penalty="huber")
532
+ ctcs2 = CTCS(y <= 5, penalty="huber")
533
533
 
534
534
  assert hash_expr(ctcs1) == hash_expr(ctcs2)
535
535
 
@@ -539,10 +539,48 @@ def test_ctcs_different_penalty():
539
539
  x = State("x", (2,))
540
540
  x._slice = slice(0, 2)
541
541
 
542
- ctcs_l2 = CTCS(x <= 5, penalty="l2")
543
- ctcs_l1 = CTCS(x <= 5, penalty="l1")
542
+ ctcs_squared = CTCS(x <= 5, penalty="squared_relu")
543
+ ctcs_huber = CTCS(x <= 5, penalty="huber")
544
544
 
545
- assert hash_expr(ctcs_l2) != hash_expr(ctcs_l1)
545
+ assert hash_expr(ctcs_squared) != hash_expr(ctcs_huber)
546
+
547
+
548
+ def test_ctcs_same_callable_penalty():
549
+ """CTCS with the same callable penalty should hash the same."""
550
+ x = State("x", (2,))
551
+ x._slice = slice(0, 2)
552
+
553
+ y = State("y", (2,))
554
+ y._slice = slice(0, 2)
555
+
556
+ ctcs1 = CTCS(x <= 5, penalty=lambda r: Huber(PositivePart(r), delta=0.5))
557
+ ctcs2 = CTCS(y <= 5, penalty=lambda r: Huber(PositivePart(r), delta=0.5))
558
+
559
+ assert hash_expr(ctcs1) == hash_expr(ctcs2)
560
+
561
+
562
+ def test_ctcs_different_callable_penalty():
563
+ """CTCS callable penalties that build different trees should hash differently."""
564
+ x = State("x", (2,))
565
+ x._slice = slice(0, 2)
566
+
567
+ ctcs_wide = CTCS(x <= 5, penalty=lambda r: Huber(PositivePart(r), delta=0.5))
568
+ ctcs_narrow = CTCS(x <= 5, penalty=lambda r: Huber(PositivePart(r), delta=0.1))
569
+ ctcs_squared = CTCS(x <= 5, penalty=lambda r: Square(PositivePart(r)))
570
+
571
+ assert hash_expr(ctcs_wide) != hash_expr(ctcs_narrow)
572
+ assert hash_expr(ctcs_wide) != hash_expr(ctcs_squared)
573
+
574
+
575
+ def test_ctcs_callable_penalty_matches_equivalent_name():
576
+ """A callable that rebuilds a named penalty hashes like the named penalty."""
577
+ x = State("x", (2,))
578
+ x._slice = slice(0, 2)
579
+
580
+ ctcs_named = CTCS(x <= 5, penalty="squared_relu")
581
+ ctcs_callable = CTCS(x <= 5, penalty=lambda r: Square(PositivePart(r)))
582
+
583
+ assert hash_expr(ctcs_named) == hash_expr(ctcs_callable)
546
584
 
547
585
 
548
586
  def test_ctcs_with_nodes():
@@ -932,9 +970,9 @@ def test_problem_ctcs_constraint_order_invariant():
932
970
 
933
971
  # Create CTCS constraints in the specified order
934
972
  constraints_map = {
935
- "ctcs_norm": CTCS(Norm(x) <= 3.0, penalty="l2"),
936
- "ctcs_x0": CTCS(x[0] >= -1.0, penalty="l1"),
937
- "ctcs_x1": CTCS(x[1] <= 2.0, penalty="l2"),
973
+ "ctcs_norm": CTCS(Norm(x) <= 3.0, penalty="squared_relu"),
974
+ "ctcs_x0": CTCS(x[0] >= -1.0, penalty="huber"),
975
+ "ctcs_x1": CTCS(x[1] <= 2.0, penalty="squared_relu"),
938
976
  }
939
977
  ordered_constraints = [constraints_map[name] for name in constraint_order]
940
978