openscvx 0.5.3.dev36__tar.gz → 0.5.3.dev38__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 (439) hide show
  1. {openscvx-0.5.3.dev36/openscvx.egg-info → openscvx-0.5.3.dev38}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/relative_loitering.py +0 -1
  3. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/_version.py +3 -3
  4. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/problem.py +6 -9
  5. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/augmentation.py +31 -35
  6. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/builder.py +5 -10
  7. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/constraint.py +46 -2
  8. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/expr.py +43 -0
  9. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/stl.py +13 -1
  10. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/stljax.py +11 -1
  11. openscvx-0.5.3.dev38/openscvx/symbolic/lowerers/jax/_lowerer.py +122 -0
  12. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/logic.py +16 -6
  13. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/vmap.py +14 -4
  14. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38/openscvx.egg-info}/PKG-INFO +1 -1
  15. openscvx-0.5.3.dev38/openscvx.egg-info/scm_version.json +8 -0
  16. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_augmentation.py +74 -34
  17. openscvx-0.5.3.dev36/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -56
  18. openscvx-0.5.3.dev36/openscvx.egg-info/scm_version.json +0 -8
  19. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/assets/logo.svg +0 -0
  20. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/release-drafter.yml +0 -0
  21. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/_docs.yml +0 -0
  22. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/_extra.yml +0 -0
  23. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/branch-name.yml +0 -0
  24. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/docs.yml +0 -0
  25. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/lint.yml +0 -0
  26. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/nightly.yml +0 -0
  27. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/release-drafter.yml +0 -0
  28. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/release.yml +0 -0
  29. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-cvxpygen.yml +0 -0
  30. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-examples.yml +0 -0
  31. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-lie.yml +0 -0
  32. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-mjx.yml +0 -0
  33. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-qpax.yml +0 -0
  34. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests.yml +0 -0
  35. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.gitignore +0 -0
  36. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.gitmodules +0 -0
  37. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/CONTRIBUTING.md +0 -0
  38. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/LICENSE +0 -0
  39. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/README.md +0 -0
  40. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/constraint_reformulation.md +0 -0
  41. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/control_parameterization.md +0 -0
  42. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/discretization.md +0 -0
  43. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/ocp.md +0 -0
  44. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/scvx.md +0 -0
  45. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/time_dilation.md +0 -0
  46. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/batching_jit_grad.md +0 -0
  47. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
  48. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/lowering_architecture.md +0 -0
  49. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  50. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/00_introduction.md +0 -0
  51. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  52. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  53. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  54. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  55. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/05_visualization.md +0 -0
  56. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/06_logic.md +0 -0
  57. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/07_lie.md +0 -0
  58. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/08_mpcc.md +0 -0
  59. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  60. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/favicon.png +0 -0
  61. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ct-scvx_dark.png +0 -0
  62. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ct-scvx_light.png +0 -0
  63. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ctcs_dark.png +0 -0
  64. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ctcs_light.png +0 -0
  65. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/problem_class_dark.png +0 -0
  66. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/problem_class_light.png +0 -0
  67. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/logo.svg +0 -0
  68. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/openscvx_logo_square.png +0 -0
  69. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/viser-client/index.html +0 -0
  70. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  71. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  72. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/citation.md +0 -0
  73. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/examples.md +0 -0
  74. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/index.md +0 -0
  75. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/javascripts/mathjax.js +0 -0
  76. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/versions.json +0 -0
  77. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/_viser_embed_export.py +0 -0
  78. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/brachistochrone.py +0 -0
  79. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/brachistochrone_batched.py +0 -0
  80. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/flappy_bird.py +0 -0
  81. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/hypersensitive.py +0 -0
  82. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/impulsive.py +0 -0
  83. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/stl_integer_variable.py +0 -0
  84. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/stl_or.py +0 -0
  85. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/aircraft/dynamic_soaring.py +0 -0
  86. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/aircraft/supersonic_time_to_climb.py +0 -0
  87. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/7_dof_arm.py +0 -0
  88. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/_camera.py +0 -0
  89. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/_render.py +0 -0
  90. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/_sensor_view.py +0 -0
  91. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/dr_vp_polytope.py +0 -0
  92. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  93. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/logo.py +0 -0
  94. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  95. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/3_dof_arm.py +0 -0
  96. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/7_dof_arm.py +0 -0
  97. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/7_dof_arm_collision.py +0 -0
  98. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/7_dof_arm_vp.py +0 -0
  99. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  100. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  101. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  102. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car.py +0 -0
  103. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_disjoint.py +0 -0
  104. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  105. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_obstacle_stl.py +0 -0
  106. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_stl_or.py +0 -0
  107. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_waypoint_stl.py +0 -0
  108. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/double_integrator/_plotting.py +0 -0
  109. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/double_integrator/moving_safe_zones.py +0 -0
  110. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  111. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/cinema_vp.py +0 -0
  112. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/cinema_vp_nodal.py +0 -0
  113. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_double_integrator.py +0 -0
  114. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_vp.py +0 -0
  115. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_vp_nodal.py +0 -0
  116. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_vp_polytope.py +0 -0
  117. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/drone_racing.py +0 -0
  118. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/drone_racing_batched_gates.py +0 -0
  119. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo.py +0 -0
  120. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/acl_logo.svg +0 -0
  121. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  122. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  123. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  124. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/multi_agent_circle_swap.py +0 -0
  125. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance.py +0 -0
  126. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  127. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  128. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  129. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/openscvx_logo.py +0 -0
  130. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax.py +0 -0
  131. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax_pick_place.py +0 -0
  132. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax_viewplanning.py +0 -0
  133. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax_waypoint.py +0 -0
  134. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/cartpole_mjx.py +0 -0
  135. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/double_cartpole_mjx.py +0 -0
  136. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/skydio_x2_mjx.py +0 -0
  137. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  138. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/triple_cartpole_game.py +0 -0
  139. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/triple_cartpole_mjx.py +0 -0
  140. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/double_integrator_discrete.py +0 -0
  141. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/double_integrator_drone_racing.py +0 -0
  142. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  143. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  144. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  145. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/plotting.py +0 -0
  146. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/plotting_viser.py +0 -0
  147. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  148. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  149. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  150. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  151. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  152. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  153. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  154. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  155. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/cinema_vp_realtime.py +0 -0
  156. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/drone_racing_realtime.py +0 -0
  157. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/dubins_car_realtime.py +0 -0
  158. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  159. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/3DoF_pdg.py +0 -0
  160. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/6DoF_pdg.py +0 -0
  161. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  162. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/ascent_launch_vehicle.py +0 -0
  163. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/halo_orbit.py +0 -0
  164. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/hohmann_transfer.py +0 -0
  165. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/let_transfer.py +0 -0
  166. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/proxops_cw.py +0 -0
  167. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/ctlos_cine.gif +0 -0
  168. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/ctlos_dr.gif +0 -0
  169. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/dtlos_cine.gif +0 -0
  170. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/dtlos_dr.gif +0 -0
  171. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/openscvx_logo.svg +0 -0
  172. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/openscvx_logo_square.png +0 -0
  173. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/oscvx_structure_full_dark.svg +0 -0
  174. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/video_preview.png +0 -0
  175. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/__init__.py +0 -0
  176. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/custom.css +0 -0
  177. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  178. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  179. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  180. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/home.html +0 -0
  181. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/main.html +0 -0
  182. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-diagram.html +0 -0
  183. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-dropin-banner.html +0 -0
  184. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-hero.html +0 -0
  185. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-pipeline.html +0 -0
  186. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-viser-strip.html +0 -0
  187. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/mkdocs.yml +0 -0
  188. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/__init__.py +0 -0
  189. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/__main__.py +0 -0
  190. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/__init__.py +0 -0
  191. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/__init__.py +0 -0
  192. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
  193. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  194. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
  195. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/base.py +0 -0
  196. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  197. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  198. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/base.py +0 -0
  199. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/history.py +0 -0
  200. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/hyperparams.py +0 -0
  201. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/loop.py +0 -0
  202. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/optimization_results.py +0 -0
  203. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/penalty.py +0 -0
  204. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/scvx/__init__.py +0 -0
  205. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/scvx/iteration.py +0 -0
  206. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
  207. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/state.py +0 -0
  208. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/weights.py +0 -0
  209. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/config.py +0 -0
  210. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/__init__.py +0 -0
  211. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/base.py +0 -0
  212. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/discretize_linearize.py +0 -0
  213. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/linearize_discretize.py +0 -0
  214. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  215. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  216. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  217. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  218. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/__init__.py +0 -0
  219. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/byof.py +0 -0
  220. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/lowering.py +0 -0
  221. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/validation.py +0 -0
  222. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/init/__init__.py +0 -0
  223. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/init/interpolation.py +0 -0
  224. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/init/inverse_kinematics.py +0 -0
  225. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/__init__.py +0 -0
  226. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/_utils.py +0 -0
  227. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/base.py +0 -0
  228. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/frax.py +0 -0
  229. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/menagerie.py +0 -0
  230. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/mjx.py +0 -0
  231. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrators/__init__.py +0 -0
  232. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrators/diffrax.py +0 -0
  233. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrators/runge_kutta.py +0 -0
  234. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/loader.py +0 -0
  235. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/__init__.py +0 -0
  236. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/cvxpy_constraints.py +0 -0
  237. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/cvxpy_variables.py +0 -0
  238. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/dynamics.py +0 -0
  239. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/jax_constraints.py +0 -0
  240. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/parameters.py +0 -0
  241. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/problem.py +0 -0
  242. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/unified.py +0 -0
  243. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/__init__.py +0 -0
  244. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/plotting.py +0 -0
  245. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/publication.py +0 -0
  246. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/scp_iteration.py +0 -0
  247. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/__init__.py +0 -0
  248. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/animated.py +0 -0
  249. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/coordinates.py +0 -0
  250. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/orbits.py +0 -0
  251. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/plotly_integration.py +0 -0
  252. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/primitives.py +0 -0
  253. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/scp.py +0 -0
  254. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/server.py +0 -0
  255. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/propagation/__init__.py +0 -0
  256. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/propagation/post_processing.py +0 -0
  257. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/propagation/propagation.py +0 -0
  258. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/__init__.py +0 -0
  259. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/base.py +0 -0
  260. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/cones.py +0 -0
  261. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
  262. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  263. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/ptr_solver.py +0 -0
  264. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  265. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/__init__.py +0 -0
  266. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/affine.py +0 -0
  267. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/canonicalize.py +0 -0
  268. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/constraint_set.py +0 -0
  269. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/__init__.py +0 -0
  270. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/arithmetic.py +0 -0
  271. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/array.py +0 -0
  272. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/control.py +0 -0
  273. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  274. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  275. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/se3.py +0 -0
  276. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/so3.py +0 -0
  277. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/linalg.py +0 -0
  278. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/logic.py +0 -0
  279. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/math.py +0 -0
  280. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/parameter.py +0 -0
  281. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/spatial.py +0 -0
  282. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/state.py +0 -0
  283. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/time.py +0 -0
  284. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/variable.py +0 -0
  285. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/vmap.py +0 -0
  286. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/hashing.py +0 -0
  287. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lower.py +0 -0
  288. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/__init__.py +0 -0
  289. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  290. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  291. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  292. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  293. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  294. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  295. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  296. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  297. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  298. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  299. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  300. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  301. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  302. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  303. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  304. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  305. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  306. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  307. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  308. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  309. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  310. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  311. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  312. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  313. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  314. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  315. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/__init__.py +0 -0
  316. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/_registry.py +0 -0
  317. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/array.py +0 -0
  318. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/constraint.py +0 -0
  319. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/lie.py +0 -0
  320. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/linalg.py +0 -0
  321. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/logic.py +0 -0
  322. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/math.py +0 -0
  323. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/parser.py +0 -0
  324. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/spatial.py +0 -0
  325. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/stl.py +0 -0
  326. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/stljax.py +0 -0
  327. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/tokenizer.py +0 -0
  328. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/preprocessing.py +0 -0
  329. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/problem.py +0 -0
  330. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/sparsity.py +0 -0
  331. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/unified.py +0 -0
  332. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/__init__.py +0 -0
  333. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/cache.py +0 -0
  334. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/caching.py +0 -0
  335. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/printing.py +0 -0
  336. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/profiling.py +0 -0
  337. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/utils.py +0 -0
  338. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/SOURCES.txt +0 -0
  339. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/dependency_links.txt +0 -0
  340. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/entry_points.txt +0 -0
  341. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/requires.txt +0 -0
  342. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/scm_file_list.json +0 -0
  343. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/top_level.txt +0 -0
  344. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/pyproject.toml +0 -0
  345. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/scripts/gen_example_pages.py +0 -0
  346. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/scripts/gen_ref_pages.py +0 -0
  347. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  348. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/setup.cfg +0 -0
  349. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/__init__.py +0 -0
  350. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/__init__.py +0 -0
  351. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/_iteration_helpers.py +0 -0
  352. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/__init__.py +0 -0
  353. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
  354. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
  355. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
  356. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  357. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  358. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_iteration_fn_parity.py +0 -0
  359. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_make_solve_loop.py +0 -0
  360. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/brachistochrone_analytical.py +0 -0
  361. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/conftest.py +0 -0
  362. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/__init__.py +0 -0
  363. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_brachistochrone.py +0 -0
  364. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_impulsive.py +0 -0
  365. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_multishot_propagation.py +0 -0
  366. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_batched_brachistochrone.py +0 -0
  367. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_batched_cvxpy_export_errors.py +0 -0
  368. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_batched_export_roundtrip.py +0 -0
  369. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_bare_brachistochrone.py +0 -0
  370. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_jit_brachistochrone.py +0 -0
  371. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_vmap_brachistochrone.py +0 -0
  372. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_vmap_converged_no_drift.py +0 -0
  373. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/fixtures/brachistochrone.json +0 -0
  374. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/fixtures/brachistochrone.yaml +0 -0
  375. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/hohmann_analytical.py +0 -0
  376. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/integrations/__init__.py +0 -0
  377. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/integrations/test_mjx.py +0 -0
  378. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/integrations/test_mjx_dynamics.py +0 -0
  379. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/__init__.py +0 -0
  380. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/_iteration_callback_helpers.py +0 -0
  381. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  382. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  383. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  384. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  385. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  386. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  387. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  388. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_subproblem_pytree.py +0 -0
  389. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/__init__.py +0 -0
  390. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/__init__.py +0 -0
  391. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_arithmetic.py +0 -0
  392. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_array.py +0 -0
  393. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_constraint.py +0 -0
  394. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_expr.py +0 -0
  395. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_lie.py +0 -0
  396. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_linalg.py +0 -0
  397. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_logic.py +0 -0
  398. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_math.py +0 -0
  399. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_node_reference.py +0 -0
  400. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_parameters.py +0 -0
  401. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_scaling.py +0 -0
  402. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_spatial.py +0 -0
  403. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_stl.py +0 -0
  404. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_variable.py +0 -0
  405. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_vmap.py +0 -0
  406. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/__init__.py +0 -0
  407. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_array.py +0 -0
  408. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_constraint.py +0 -0
  409. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_lie.py +0 -0
  410. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_linalg.py +0 -0
  411. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_load.py +0 -0
  412. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_logic.py +0 -0
  413. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_math.py +0 -0
  414. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_parser.py +0 -0
  415. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_spatial.py +0 -0
  416. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_stl.py +0 -0
  417. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_tokenizer.py +0 -0
  418. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_vmap.py +0 -0
  419. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_gmsr.py +0 -0
  420. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_hashing.py +0 -0
  421. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_lower_cvxpy.py +0 -0
  422. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_lower_jax.py +0 -0
  423. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_preprocessing.py +0 -0
  424. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_sparsity.py +0 -0
  425. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_unified.py +0 -0
  426. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_autotuning.py +0 -0
  427. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_cvxpygen_optional.py +0 -0
  428. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_discretization.py +0 -0
  429. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_examples.py +0 -0
  430. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_expert.py +0 -0
  431. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_init.py +0 -0
  432. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_integrators.py +0 -0
  433. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_loader.py +0 -0
  434. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_optimization_results.py +0 -0
  435. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_plotting.py +0 -0
  436. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_post_process_batched_tau_clamp.py +0 -0
  437. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_propagation.py +0 -0
  438. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_results_parameters.py +0 -0
  439. {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/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.dev36
3
+ Version: 0.5.3.dev38
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
@@ -353,7 +353,6 @@ def build_relative_loitering_problem(
353
353
  time=time,
354
354
  constraints=constraints,
355
355
  N=n_nodes,
356
- licq_min=0.0,
357
356
  licq_max=1e-8,
358
357
  discretizer={
359
358
  "ode_solver": "Dopri8",
@@ -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.dev36'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev36')
21
+ __version__ = version = '0.5.3.dev38'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev38')
23
23
 
24
- __commit_id__ = commit_id = 'g1eddc1a14'
24
+ __commit_id__ = commit_id = 'g235acbb25'
@@ -340,8 +340,7 @@ class Problem:
340
340
  dynamics_prop: Optional[dict] = None,
341
341
  states_prop: Optional[List[State]] = None,
342
342
  algebraic_prop: Optional[dict] = None,
343
- licq_min: Union[float, Dict[int, float]] = 0.0,
344
- licq_max: Union[float, Dict[int, float]] = 1e-4,
343
+ licq_max: float = 1e-4,
345
344
  algorithm: Optional[Union[Algorithm, dict]] = None,
346
345
  discretizer: Optional[Union[Discretizer, dict]] = None,
347
346
  solver: Optional[Union[ConvexSolver, dict]] = None,
@@ -373,12 +372,11 @@ class Problem:
373
372
  Only specify additional states beyond optimization states. Used with dynamics_prop.
374
373
  algebraic_prop (dict, optional): Dictionary mapping names to symbolic expressions
375
374
  for outputs evaluated (not integrated) during propagation.
376
- licq_min: Minimum LICQ constraint value. Defaults to 0.0.
377
- Either a scalar (applied to all CTCS groups) or a dict
378
- mapping CTCS group ``idx`` to per-group bounds.
379
- licq_max: Maximum LICQ constraint value. Defaults to 1e-4.
380
- Either a scalar (applied to all CTCS groups) or a dict
381
- mapping CTCS group ``idx`` to per-group bounds.
375
+ licq_max: Problem-wide upper bound for CTCS augmented states
376
+ (default: 1e-4). Serves as the default for all constraint
377
+ groups; a ``licq_max`` set on an individual constraint (via
378
+ ``ctcs(...)`` or ``.over(...)``) overrides it for that
379
+ constraint's augmented state.
382
380
  algorithm: SCP algorithm configuration. Accepts:
383
381
 
384
382
  - ``None`` — uses ``PenalizedTrustRegion()`` with defaults.
@@ -539,7 +537,6 @@ class Problem:
539
537
  controls=controls,
540
538
  N=N,
541
539
  time=time,
542
- licq_min=licq_min,
543
540
  licq_max=licq_max,
544
541
  dynamics_prop_extra=dynamics_prop,
545
542
  states_prop_extra=states_prop,
@@ -54,7 +54,7 @@ Example:
54
54
  # controls_aug includes original controls + time dilation
55
55
  """
56
56
 
57
- from typing import Dict, List, Optional, Tuple, Union
57
+ from typing import Dict, List, Optional, Tuple
58
58
 
59
59
  import numpy as np
60
60
 
@@ -448,8 +448,7 @@ def augment_dynamics_with_ctcs(
448
448
  N: int,
449
449
  xdelta: Optional[Expr] = None,
450
450
  *,
451
- licq_min: Union[float, Dict[int, float]] = 0.0,
452
- licq_max: Union[float, Dict[int, float]] = 1e-4,
451
+ licq_max: float = 1e-4,
453
452
  ) -> Tuple[Expr, Optional[Expr], List[State], List[Control]]:
454
453
  """Augment dynamics with continuous-time constraint satisfaction states.
455
454
 
@@ -467,18 +466,20 @@ def augment_dynamics_with_ctcs(
467
466
  aug_dot = penalty(g(x, u)) # For each constraint group
468
467
  time_dot = 1.0
469
468
 
469
+ Each augmented state is bounded to [0, licq_max], where the group's bound
470
+ is taken from its member constraints' ``licq_max`` attribute (constraints in
471
+ a group must agree) and falls back to the problem-wide ``licq_max`` when no
472
+ member specifies one.
473
+
470
474
  Args:
471
475
  xdot: Original dynamics expression for states
472
476
  states: List of state variables (must include a state named "time")
473
477
  controls: List of control variables
474
478
  constraints_ctcs: List of CTCS constraints (should be sorted and grouped)
475
479
  N: Number of discretization nodes
476
- licq_min: Minimum bound for augmented states (default: 0.0).
477
- Either a scalar (applied to all groups) or a dict mapping
478
- CTCS group ``idx`` to per-group bounds.
479
- licq_max: Maximum bound for augmented states (default: 1e-4).
480
- Either a scalar (applied to all groups) or a dict mapping
481
- CTCS group ``idx`` to per-group bounds.
480
+ licq_max: Problem-wide default upper bound for augmented states
481
+ (default: 1e-4). Per-constraint ``licq_max`` values override it
482
+ for their group.
482
483
 
483
484
  Returns:
484
485
  Tuple of:
@@ -489,6 +490,8 @@ def augment_dynamics_with_ctcs(
489
490
 
490
491
  Raises:
491
492
  ValueError: If no state named "time" is found in the states list
493
+ ValueError: If constraints sharing an augmented state specify
494
+ conflicting ``licq_max`` values
492
495
 
493
496
  Example:
494
497
  Augment dynamics with CTCS penalty states:
@@ -509,6 +512,9 @@ def augment_dynamics_with_ctcs(
509
512
  states_aug includes x, time, and _ctcs_aug_0,
510
513
  controls_aug includes u and _time_dilation
511
514
  """
515
+ if licq_max <= 0:
516
+ raise ValueError(f"licq_max must be a positive number, got {licq_max!r}")
517
+
512
518
  # Save if discrete dynamics is null
513
519
  discrete_dynamics_set = xdelta is not None
514
520
 
@@ -535,24 +541,6 @@ def augment_dynamics_with_ctcs(
535
541
  penalty_groups[ctcs.idx] = []
536
542
  penalty_groups[ctcs.idx].append(ctcs)
537
543
 
538
- # Validate dict-valued licq_min / licq_max keys against actual groups.
539
- valid_ids = set(penalty_groups.keys())
540
- for name, val in [("licq_min", licq_min), ("licq_max", licq_max)]:
541
- if isinstance(val, dict):
542
- unknown = set(val.keys()) - valid_ids
543
- if unknown:
544
- raise ValueError(
545
- f"{name} dict contains unknown CTCS group idx: {unknown}. "
546
- f"Valid idx values: {sorted(valid_ids)}"
547
- )
548
- missing = valid_ids - set(val.keys())
549
- if missing:
550
- raise ValueError(
551
- f"{name} dict is missing entries for CTCS group idx: "
552
- f"{sorted(missing)}. When using a dict, all groups must "
553
- f"have an entry. Valid idx values: {sorted(valid_ids)}"
554
- )
555
-
556
544
  # Create augmented state expressions for each group and corresponding
557
545
  # augmented state variables. For discrete dynamics, preserve these states
558
546
  # by identity mapping across impulsive updates.
@@ -566,17 +554,25 @@ def augment_dynamics_with_ctcs(
566
554
  augmented_state_expr = Add(*penalty_terms)
567
555
  augmented_state_exprs.append(augmented_state_expr)
568
556
 
569
- # Resolve per-group LICQ bounds
570
- idx_min = licq_min[idx] if isinstance(licq_min, dict) else licq_min
571
- idx_max = licq_max[idx] if isinstance(licq_max, dict) else licq_max
557
+ # Resolve the group's LICQ bound from its member constraints:
558
+ # explicit values must agree; otherwise fall back to the
559
+ # problem-wide default.
560
+ explicit = {c.licq_max for c in penalty_terms if c.licq_max is not None}
561
+ if len(explicit) > 1:
562
+ raise ValueError(
563
+ f"CTCS constraints sharing augmented state idx={idx} specify "
564
+ f"conflicting licq_max values: {sorted(explicit)}. Constraints "
565
+ f"in the same group must agree on licq_max; set the same value "
566
+ f"on each, or separate them into different groups via idx."
567
+ )
568
+ group_licq_max = explicit.pop() if explicit else licq_max
572
569
 
573
570
  aug_var = State(f"_ctcs_aug_{idx}", shape=(1,))
574
- aug_var.initial = np.array([idx_min]) # Set initial to respect bounds
571
+ aug_var.initial = np.array([0.0])
575
572
  aug_var.final = [("free", 0)]
576
- aug_var.min = np.array([idx_min])
577
- aug_var.max = np.array([idx_max])
578
- # Set guess to idx_min as well
579
- aug_var.guess = np.full([N, 1], idx_min) # N x num augmented states
573
+ aug_var.min = np.array([0.0])
574
+ aug_var.max = np.array([group_licq_max])
575
+ aug_var.guess = np.zeros([N, 1]) # N x num augmented states
580
576
  states_augmented.append(aug_var)
581
577
  augmented_state_exprs_discrete.append(aug_var)
582
578
 
@@ -29,7 +29,7 @@ Pipeline stages:
29
29
  See `preprocess_symbolic_problem()` for the main entry point.
30
30
  """
31
31
 
32
- from typing import Dict, List, Optional, Tuple, Union
32
+ from typing import Dict, List, Optional, Tuple
33
33
 
34
34
  import numpy as np
35
35
 
@@ -71,8 +71,7 @@ def preprocess_symbolic_problem(
71
71
  controls: List[Control],
72
72
  N: int,
73
73
  time: Time,
74
- licq_min: Union[float, Dict[int, float]] = 0.0,
75
- licq_max: Union[float, Dict[int, float]] = 1e-4,
74
+ licq_max: float = 1e-4,
76
75
  dynamics_prop_extra: dict = None,
77
76
  dynamics_discrete: dict = None,
78
77
  states_prop_extra: List[State] = None,
@@ -106,12 +105,9 @@ def preprocess_symbolic_problem(
106
105
  controls: List of user-defined Control objects (should NOT include time dilation)
107
106
  N: Number of discretization nodes in the trajectory
108
107
  time: Time configuration object specifying time bounds and constraints
109
- licq_min: Minimum bound for CTCS augmented states (default: 0.0).
110
- Either a scalar (applied to all groups) or a dict mapping
111
- CTCS group ``idx`` to per-group bounds.
112
- licq_max: Maximum bound for CTCS augmented states (default: 1e-4).
113
- Either a scalar (applied to all groups) or a dict mapping
114
- CTCS group ``idx`` to per-group bounds.
108
+ licq_max: Problem-wide default upper bound for CTCS augmented states
109
+ (default: 1e-4). Per-constraint ``licq_max`` values override it
110
+ for their group.
115
111
  dynamics_prop_extra: Optional dictionary of additional dynamics for propagation-only
116
112
  states (default: None)
117
113
  states_prop_extra: Optional list of additional State objects for propagation only
@@ -350,7 +346,6 @@ def preprocess_symbolic_problem(
350
346
  constraints.ctcs,
351
347
  N,
352
348
  xdelta=dynamics_discrete_concat,
353
- licq_min=licq_min,
354
349
  licq_max=licq_max,
355
350
  )
356
351
 
@@ -127,6 +127,7 @@ class Constraint(Expr):
127
127
  penalty: str = "squared_relu",
128
128
  idx: Optional[int] = None,
129
129
  check_nodally: bool = False,
130
+ licq_max: Optional[float] = None,
130
131
  ) -> "CTCS":
131
132
  """Apply this constraint over a continuous interval using CTCS.
132
133
 
@@ -135,11 +136,22 @@ class Constraint(Expr):
135
136
  penalty: Penalty function type ("squared_relu", "huber", "smooth_relu")
136
137
  idx: Optional grouping index for multiple augmented states
137
138
  check_nodally: Whether to also enforce this constraint nodally
139
+ licq_max: Optional upper bound on the augmented state that accumulates
140
+ this constraint's violation penalty. Constraints sharing an
141
+ augmented state must agree on the value; groups without one use
142
+ the problem-wide ``licq_max`` (a ``Problem`` argument).
138
143
 
139
144
  Returns:
140
145
  CTCS constraint wrapping this constraint with interval specification
141
146
  """
142
- return CTCS(self, penalty=penalty, nodes=interval, idx=idx, check_nodally=check_nodally)
147
+ return CTCS(
148
+ self,
149
+ penalty=penalty,
150
+ nodes=interval,
151
+ idx=idx,
152
+ check_nodally=check_nodally,
153
+ licq_max=licq_max,
154
+ )
143
155
 
144
156
  def convex(self) -> "Constraint":
145
157
  """Mark this constraint as convex for CVXPy lowering.
@@ -609,6 +621,11 @@ class CTCS(Expr):
609
621
  an augmented state. If None, auto-assigned based on node intervals.
610
622
  check_nodally: Whether to also enforce the constraint at discrete nodes for
611
623
  additional numerical robustness (creates both continuous and nodal constraints)
624
+ licq_max: Optional upper bound on the augmented state accumulating this
625
+ constraint's violation penalty. Smaller values enforce the constraint
626
+ more strictly between nodes. Constraints sharing an augmented state
627
+ must agree on the value; groups without one use the problem-wide
628
+ ``licq_max`` (a ``Problem`` argument).
612
629
 
613
630
  Example:
614
631
  Single augmented state (default behavior - same node interval):
@@ -642,6 +659,7 @@ class CTCS(Expr):
642
659
  nodes: Optional[Tuple[int, int]] = None,
643
660
  idx: Optional[int] = None,
644
661
  check_nodally: bool = False,
662
+ licq_max: Optional[float] = None,
645
663
  ):
646
664
  """Initialize a CTCS constraint.
647
665
 
@@ -662,11 +680,16 @@ class CTCS(Expr):
662
680
  check_nodally: If True, also enforce the constraint at discrete nodes for
663
681
  numerical stability (creates both continuous and nodal constraints).
664
682
  Defaults to False.
683
+ licq_max: Optional upper bound on the augmented state accumulating this
684
+ constraint's violation penalty. Constraints sharing an augmented
685
+ state must agree on the value; groups without one use the
686
+ problem-wide ``licq_max`` (a ``Problem`` argument).
665
687
 
666
688
  Raises:
667
689
  TypeError: If constraint is not a Constraint instance
668
690
  ValueError: If nodes is not None or a 2-tuple of integers
669
691
  ValueError: If nodes[0] >= nodes[1] (invalid interval)
692
+ ValueError: If licq_max is not a positive number
670
693
  """
671
694
  if not isinstance(constraint, Constraint):
672
695
  raise TypeError("CTCS must wrap a Constraint")
@@ -683,12 +706,19 @@ class CTCS(Expr):
683
706
  if nodes[0] >= nodes[1]:
684
707
  raise ValueError("CTCS node range must have start < end")
685
708
 
709
+ if licq_max is not None:
710
+ if not isinstance(licq_max, (int, float)) or licq_max <= 0:
711
+ raise ValueError(f"licq_max must be a positive number, got {licq_max!r}")
712
+ licq_max = float(licq_max)
713
+
686
714
  self.constraint = constraint
687
715
  self.penalty = penalty
688
716
  self.nodes = nodes # (start, end) node range or None for all nodes
689
717
  self.idx = idx # Optional grouping index for multiple augmented states
690
718
  # Whether to also enforce this constraint nodally for numerical stability
691
719
  self.check_nodally = check_nodally
720
+ # Upper bound on the augmented state; None defers to the group default
721
+ self.licq_max = licq_max
692
722
 
693
723
  def children(self) -> List[Expr]:
694
724
  """Return the wrapped constraint as the only child.
@@ -711,6 +741,7 @@ class CTCS(Expr):
711
741
  nodes=self.nodes,
712
742
  idx=self.idx,
713
743
  check_nodally=self.check_nodally,
744
+ licq_max=self.licq_max,
714
745
  )
715
746
 
716
747
  def check_shape(self) -> Tuple[int, ...]:
@@ -767,6 +798,11 @@ class CTCS(Expr):
767
798
  hasher.update(b"None")
768
799
  # Hash check_nodally
769
800
  hasher.update(b"1" if self.check_nodally else b"0")
801
+ # Hash licq_max
802
+ if self.licq_max is not None:
803
+ hasher.update(struct.pack(">d", self.licq_max))
804
+ else:
805
+ hasher.update(b"None")
770
806
  # Hash the wrapped constraint
771
807
  self.constraint._hash_into(hasher)
772
808
 
@@ -794,6 +830,7 @@ class CTCS(Expr):
794
830
  nodes=interval,
795
831
  idx=self.idx,
796
832
  check_nodally=self.check_nodally,
833
+ licq_max=self.licq_max,
797
834
  )
798
835
 
799
836
  def __repr__(self) -> str:
@@ -809,6 +846,8 @@ class CTCS(Expr):
809
846
  parts.append(f"idx={self.idx}")
810
847
  if self.check_nodally:
811
848
  parts.append(f"check_nodally={self.check_nodally}")
849
+ if self.licq_max is not None:
850
+ parts.append(f"licq_max={self.licq_max}")
812
851
  return f"CTCS({', '.join(parts)})"
813
852
 
814
853
  def penalty_expr(self) -> Expr:
@@ -861,6 +900,7 @@ def ctcs(
861
900
  nodes: Optional[Tuple[int, int]] = None,
862
901
  idx: Optional[int] = None,
863
902
  check_nodally: bool = False,
903
+ licq_max: Optional[float] = None,
864
904
  ) -> CTCS:
865
905
  """Helper function to create CTCS (Continuous-Time Constraint Satisfaction) constraints.
866
906
 
@@ -876,6 +916,10 @@ def ctcs(
876
916
  idx: Optional grouping index for multiple augmented states
877
917
  check_nodally: Whether to also enforce constraint at discrete nodes.
878
918
  Defaults to False.
919
+ licq_max: Optional upper bound on the augmented state accumulating this
920
+ constraint's violation penalty. Constraints sharing an augmented
921
+ state must agree on the value; groups without one use the
922
+ problem-wide ``licq_max`` (a ``Problem`` argument).
879
923
 
880
924
  Returns:
881
925
  CTCS: A CTCS constraint wrapping the input constraint
@@ -899,4 +943,4 @@ def ctcs(
899
943
 
900
944
  altitude_constraint = (altitude >= 10).over((0, 100), penalty="huber")
901
945
  """
902
- return CTCS(constraint, penalty, nodes, idx, check_nodally)
946
+ return CTCS(constraint, penalty, nodes, idx, check_nodally, licq_max)
@@ -63,8 +63,10 @@ Example:
63
63
  canonical = expr.canonicalize() # Simplifies to: x + x
64
64
  """
65
65
 
66
+ import functools
66
67
  import hashlib
67
68
  import struct
69
+ import threading
68
70
  from typing import TYPE_CHECKING, Callable, List, Tuple, Union
69
71
 
70
72
  if TYPE_CHECKING:
@@ -72,6 +74,40 @@ if TYPE_CHECKING:
72
74
 
73
75
  import numpy as np
74
76
 
77
+ # Per-thread memo for canonicalize(). The memo canonicalizes each node once and
78
+ # returns the same object to every parent, preserving sharing.
79
+ _canon_state = threading.local()
80
+
81
+
82
+ def _memoized_canonicalize(fn: Callable) -> Callable:
83
+ """Wrap a subclass ``canonicalize`` so shared subexpressions are reused.
84
+
85
+ Keyed by ``id(self)``; the node is held alive in the memo for the duration of
86
+ the pass so its id cannot be recycled, with an identity guard on lookup. The
87
+ top-level call owns the memo and clears it on exit, so each independent
88
+ canonicalize pass starts fresh.
89
+ """
90
+
91
+ @functools.wraps(fn)
92
+ def wrapper(self):
93
+ memo = getattr(_canon_state, "memo", None)
94
+ owns = memo is None
95
+ if owns:
96
+ memo = {}
97
+ _canon_state.memo = memo
98
+ try:
99
+ entry = memo.get(id(self))
100
+ if entry is not None and entry[0] is self:
101
+ return entry[1]
102
+ result = fn(self)
103
+ memo[id(self)] = (self, result)
104
+ return result
105
+ finally:
106
+ if owns:
107
+ _canon_state.memo = None
108
+
109
+ return wrapper
110
+
75
111
 
76
112
  class Expr:
77
113
  """Base class for symbolic expressions in optimization problems.
@@ -101,6 +137,13 @@ class Expr:
101
137
  # Give Expr objects higher priority than numpy arrays in operations
102
138
  __array_priority__ = 1000
103
139
 
140
+ def __init_subclass__(cls, **kwargs):
141
+ # Wrap each subclass's own canonicalize() with identity memoization so a
142
+ # shared DAG node is canonicalized once rather than re-expanded per parent.
143
+ super().__init_subclass__(**kwargs)
144
+ if "canonicalize" in cls.__dict__:
145
+ cls.canonicalize = _memoized_canonicalize(cls.__dict__["canonicalize"])
146
+
104
147
  def __le__(self, other):
105
148
  from .constraint import Inequality
106
149
 
@@ -310,6 +310,7 @@ class STLExpr(Expr):
310
310
  penalty: str = "smooth_relu",
311
311
  idx: Optional[int] = None,
312
312
  check_nodally: bool = False,
313
+ licq_max: Optional[float] = None,
313
314
  interval_type: IntervalKind = "nodes",
314
315
  ) -> "CTCS":
315
316
  """Apply this STL expression over an enforcement interval using CTCS.
@@ -323,6 +324,10 @@ class STLExpr(Expr):
323
324
  penalty: Penalty function type for CTCS
324
325
  idx: Optional grouping index for multiple augmented states
325
326
  check_nodally: Whether to also enforce at discrete nodes
327
+ licq_max: Optional upper bound on the augmented state accumulating
328
+ this constraint's violation penalty. Constraints sharing an
329
+ augmented state must agree on the value; groups without one use
330
+ the problem-wide ``licq_max`` (a ``Problem`` argument).
326
331
 
327
332
  Returns:
328
333
  Continuous-time constraint satisfaction wrapper
@@ -359,6 +364,7 @@ class STLExpr(Expr):
359
364
  nodes=(coerced.start, coerced.end),
360
365
  idx=idx,
361
366
  check_nodally=check_nodally,
367
+ licq_max=licq_max,
362
368
  )
363
369
 
364
370
  def at(self, nodes: Union[list, tuple]) -> "NodalConstraint":
@@ -863,6 +869,7 @@ class Always(_TemporalSTLExpr):
863
869
  penalty: str = "smooth_relu",
864
870
  idx: Optional[int] = None,
865
871
  check_nodally: bool = False,
872
+ licq_max: Optional[float] = None,
866
873
  interval_type: IntervalKind = "nodes",
867
874
  ) -> "CTCS":
868
875
  """Convert this ``Always`` to a ``CTCS`` constraint.
@@ -876,6 +883,10 @@ class Always(_TemporalSTLExpr):
876
883
  penalty: CTCS penalty function name.
877
884
  idx: Optional grouping index for multiple augmented states.
878
885
  check_nodally: Whether to additionally enforce at discrete nodes.
886
+ licq_max: Optional upper bound on the augmented state accumulating
887
+ this constraint's violation penalty. Constraints sharing an
888
+ augmented state must agree on the value; groups without one use
889
+ the problem-wide ``licq_max`` (a ``Problem`` argument).
879
890
 
880
891
  Returns:
881
892
  A ``CTCS`` constraint enforcing the inner predicate over the
@@ -903,7 +914,7 @@ class Always(_TemporalSTLExpr):
903
914
 
904
915
  if isinstance(self.predicate, STLExpr):
905
916
  return self.predicate.over(
906
- chosen, penalty=penalty, idx=idx, check_nodally=check_nodally
917
+ chosen, penalty=penalty, idx=idx, check_nodally=check_nodally, licq_max=licq_max
907
918
  )
908
919
 
909
920
  from .constraint import CTCS
@@ -914,6 +925,7 @@ class Always(_TemporalSTLExpr):
914
925
  nodes=(chosen.start, chosen.end),
915
926
  idx=idx,
916
927
  check_nodally=check_nodally,
928
+ licq_max=licq_max,
917
929
  )
918
930
 
919
931
  def __repr__(self) -> str:
@@ -59,6 +59,7 @@ class STLJaxExpr(Expr):
59
59
  penalty: str = "squared_relu",
60
60
  idx: Optional[int] = None,
61
61
  check_nodally: bool = False,
62
+ licq_max: Optional[float] = None,
62
63
  ) -> "CTCS":
63
64
  """Apply this STL expression over a continuous interval using CTCS.
64
65
 
@@ -70,6 +71,10 @@ class STLJaxExpr(Expr):
70
71
  penalty: Penalty function type for CTCS
71
72
  idx: Optional grouping index for multiple augmented states
72
73
  check_nodally: Whether to also enforce at discrete nodes
74
+ licq_max: Optional upper bound on the augmented state accumulating
75
+ this constraint's violation penalty. Constraints sharing an
76
+ augmented state must agree on the value; groups without one use
77
+ the problem-wide ``licq_max`` (a ``Problem`` argument).
73
78
 
74
79
  Returns:
75
80
  Continuous-time constraint satisfaction wrapper
@@ -89,7 +94,12 @@ class STLJaxExpr(Expr):
89
94
  constraint = Inequality(Neg(self), Constant(np.array(0.0)))
90
95
 
91
96
  return CTCS(
92
- constraint, penalty=penalty, nodes=interval, idx=idx, check_nodally=check_nodally
97
+ constraint,
98
+ penalty=penalty,
99
+ nodes=interval,
100
+ idx=idx,
101
+ check_nodally=check_nodally,
102
+ licq_max=licq_max,
93
103
  )
94
104
 
95
105
  def at(self, nodes: Union[list, tuple]) -> "NodalConstraint":
@@ -0,0 +1,122 @@
1
+ """JaxLowerer class definition.
2
+
3
+ The visitor methods that populate the registry live in sibling modules
4
+ (``arithmetic``, ``math``, ``linalg``, etc.) and are registered via
5
+ ``@visitor`` at import time.
6
+ """
7
+
8
+ from typing import Callable
9
+
10
+ import jax
11
+
12
+ from openscvx.symbolic.expr import Expr
13
+ from openscvx.symbolic.lowerers.jax._registry import dispatch
14
+
15
+ _MISSING = object()
16
+
17
+ # Value-memoization is only valid within a single JAX trace. Visitors bracket
18
+ # their nested trace with :func:`pause_memo` / :func:`resume_memo` so the wrapped
19
+ # closures recompute instead of returning a cross-trace value.
20
+ _memo_paused = [0]
21
+
22
+
23
+ def pause_memo() -> None:
24
+ """Disable value-memoization for the duration of a nested sub-trace."""
25
+ _memo_paused[0] += 1
26
+
27
+
28
+ def resume_memo() -> None:
29
+ """Re-enable value-memoization after a nested sub-trace finishes tracing."""
30
+ _memo_paused[0] -= 1
31
+
32
+
33
+ def _memoize_call(fn: Callable) -> Callable:
34
+ """Cache a lowered closure's result so it emits its subgraph once per trace.
35
+
36
+ Within a trace every node receives the same argument objects, so caching on
37
+ argument identity (``is``) lets a shared subexpression emit its subgraph once
38
+ instead of once per consumer. The cache only applies while tracing (at least
39
+ one positional argument is a JAX tracer); eager calls, keyword-argument
40
+ calls, and paused sections (nested sub-traces, see module note) bypass it.
41
+ """
42
+ last_args = None
43
+ last_val = _MISSING
44
+
45
+ def wrapped(*args, **kwargs):
46
+ nonlocal last_args, last_val
47
+ if kwargs or _memo_paused[0] or not any(isinstance(a, jax.core.Tracer) for a in args):
48
+ return fn(*args, **kwargs)
49
+ if (
50
+ last_val is not _MISSING
51
+ and last_args is not None
52
+ and len(last_args) == len(args)
53
+ and all(a is b for a, b in zip(last_args, args))
54
+ ):
55
+ return last_val
56
+ last_val = fn(*args)
57
+ last_args = args
58
+ return last_val
59
+
60
+ return wrapped
61
+
62
+
63
+ class JaxLowerer:
64
+ """JAX backend for lowering symbolic expressions to executable functions.
65
+
66
+ This class implements the visitor pattern for converting symbolic expression
67
+ AST nodes to JAX functions. Each expression type has a corresponding visitor
68
+ function decorated with @visitor that handles the lowering logic.
69
+
70
+ The lowering process is recursive: each visitor lowers its child expressions
71
+ first, then composes them into a JAX operation. All lowered functions have
72
+ a standardized signature (x, u, node, params) -> result.
73
+
74
+ Shared subexpressions are lowered once: :meth:`lower` caches the closure for
75
+ each AST node by object identity, and each closure is wrapped so it emits its
76
+ subgraph only once per trace (see :func:`_memoize_call`).
77
+
78
+ Example:
79
+ Set up the JaxLowerer and lower an expression to a JAX function::
80
+
81
+ lowerer = JaxLowerer()
82
+ expr = ox.Norm(x)**2 + 0.1 * ox.Norm(u)**2
83
+ f = lowerer.lower(expr)
84
+ result = f(x_val, u_val, node=0, params={})
85
+
86
+ Note:
87
+ A fresh lowerer is created per lowering pass; its node cache is keyed by
88
+ ``id(expr)`` and is valid only while the expression tree is alive.
89
+ """
90
+
91
+ def __init__(self) -> None:
92
+ # Maps id(expr) -> (expr, lowered closure) so each node is lowered once,
93
+ # no matter how many parents share it. Storing the expr itself keeps it
94
+ # alive: if it were garbage-collected, Python could reuse its id for a
95
+ # new node and the cache would return the wrong closure. The identity
96
+ # check on lookup guards against exactly that.
97
+ self._node_cache: dict[int, tuple[Expr, Callable]] = {}
98
+
99
+ def lower(self, expr: Expr) -> Callable:
100
+ """Lower a symbolic expression to a JAX function.
101
+
102
+ Main entry point for lowering. Delegates to dispatch() which looks up
103
+ the appropriate visitor method based on the expression type. Results are
104
+ memoized by node identity so shared subexpressions are lowered once.
105
+
106
+ Args:
107
+ expr: Symbolic expression to lower (any Expr subclass)
108
+
109
+ Returns:
110
+ JAX function with signature (x, u, node, params) -> result
111
+
112
+ Raises:
113
+ NotImplementedError: If no visitor exists for the expression type
114
+ ValueError: If the expression is malformed (e.g., State without slice)
115
+ """
116
+ eid = id(expr)
117
+ cached = self._node_cache.get(eid)
118
+ if cached is not None and cached[0] is expr:
119
+ return cached[1]
120
+ fn = _memoize_call(dispatch(self, expr))
121
+ self._node_cache[eid] = (expr, fn)
122
+ return fn