openscvx 0.5.3.dev31__tar.gz → 0.5.3.dev32__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 (431) hide show
  1. {openscvx-0.5.3.dev31/openscvx.egg-info → openscvx-0.5.3.dev32}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/_version.py +3 -3
  3. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/autotuner/augmented_lagrangian.py +2 -2
  4. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/penalty.py +4 -2
  5. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/scvx/iteration.py +11 -2
  6. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/jax_constraints.py +8 -0
  7. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/solvers/cvxpy_ptr_solver.py +6 -3
  8. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/solvers/moreau_ptr_solver.py +6 -0
  9. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/solvers/qpax_ptr_solver.py +6 -0
  10. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/augmentation.py +0 -36
  11. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lower.py +3 -1
  12. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32/openscvx.egg-info}/PKG-INFO +1 -1
  13. openscvx-0.5.3.dev32/openscvx.egg-info/scm_version.json +8 -0
  14. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_qpax_ptr_solver.py +40 -0
  15. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/test_augmentation.py +12 -26
  16. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_autotuning.py +25 -0
  17. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_brachistochrone.py +71 -0
  18. openscvx-0.5.3.dev31/openscvx.egg-info/scm_version.json +0 -8
  19. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/assets/logo.svg +0 -0
  20. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/release-drafter.yml +0 -0
  21. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/_docs.yml +0 -0
  22. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/branch-name.yml +0 -0
  23. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/docs.yml +0 -0
  24. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/lint.yml +0 -0
  25. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/nightly.yml +0 -0
  26. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/release-drafter.yml +0 -0
  27. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/release.yml +0 -0
  28. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/tests-integration.yml +0 -0
  29. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.github/workflows/tests-unit.yml +0 -0
  30. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.gitignore +0 -0
  31. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/.gitmodules +0 -0
  32. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/CONTRIBUTING.md +0 -0
  33. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/LICENSE +0 -0
  34. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/README.md +0 -0
  35. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/Foundations/constraint_reformulation.md +0 -0
  36. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/Foundations/control_parameterization.md +0 -0
  37. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/Foundations/discretization.md +0 -0
  38. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/Foundations/ocp.md +0 -0
  39. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/Foundations/scvx.md +0 -0
  40. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/Foundations/time_dilation.md +0 -0
  41. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UnderTheHood/batching_jit_grad.md +0 -0
  42. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
  43. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UnderTheHood/lowering_architecture.md +0 -0
  44. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  45. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/00_introduction.md +0 -0
  46. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  47. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  48. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  49. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  50. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/05_visualization.md +0 -0
  51. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/06_logic.md +0 -0
  52. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/07_lie.md +0 -0
  53. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/08_mpcc.md +0 -0
  54. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  55. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/favicon.png +0 -0
  56. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/images/ct-scvx_dark.png +0 -0
  57. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/images/ct-scvx_light.png +0 -0
  58. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/images/ctcs_dark.png +0 -0
  59. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/images/ctcs_light.png +0 -0
  60. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/images/problem_class_dark.png +0 -0
  61. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/images/problem_class_light.png +0 -0
  62. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/logo.svg +0 -0
  63. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/openscvx_logo_square.png +0 -0
  64. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/viser-client/index.html +0 -0
  65. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  66. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  67. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/citation.md +0 -0
  68. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/examples.md +0 -0
  69. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/index.md +0 -0
  70. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/javascripts/mathjax.js +0 -0
  71. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/docs/versions.json +0 -0
  72. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/_viser_embed_export.py +0 -0
  73. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/abstract/brachistochrone.py +0 -0
  74. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/abstract/brachistochrone_batched.py +0 -0
  75. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/abstract/flappy_bird.py +0 -0
  76. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/abstract/hypersensitive.py +0 -0
  77. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/abstract/impulsive.py +0 -0
  78. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/abstract/stl_integer_variable.py +0 -0
  79. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/abstract/stl_or.py +0 -0
  80. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/aircraft/supersonic_time_to_climb.py +0 -0
  81. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/7_dof_arm.py +0 -0
  82. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/_camera.py +0 -0
  83. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/_render.py +0 -0
  84. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/_sensor_view.py +0 -0
  85. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/dr_vp_polytope.py +0 -0
  86. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  87. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/logo.py +0 -0
  88. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  89. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/arm/3_dof_arm.py +0 -0
  90. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/arm/7_dof_arm.py +0 -0
  91. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/arm/7_dof_arm_collision.py +0 -0
  92. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/arm/7_dof_arm_vp.py +0 -0
  93. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  94. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  95. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  96. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/car/dubins_car.py +0 -0
  97. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/car/dubins_car_disjoint.py +0 -0
  98. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  99. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/car/dubins_car_obstacle_stl.py +0 -0
  100. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/car/dubins_car_stl_or.py +0 -0
  101. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/car/dubins_car_waypoint_stl.py +0 -0
  102. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/double_integrator/_plotting.py +0 -0
  103. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/double_integrator/moving_safe_zones.py +0 -0
  104. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  105. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/cinema_vp.py +0 -0
  106. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/cinema_vp_nodal.py +0 -0
  107. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/dr_double_integrator.py +0 -0
  108. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/dr_vp.py +0 -0
  109. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/dr_vp_nodal.py +0 -0
  110. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/dr_vp_polytope.py +0 -0
  111. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/drone_racing.py +0 -0
  112. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/drone_racing_batched_gates.py +0 -0
  113. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/logo.py +0 -0
  114. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/logo_utils/acl_logo.svg +0 -0
  115. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  116. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  117. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  118. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/multi_agent_circle_swap.py +0 -0
  119. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/obstacle_avoidance.py +0 -0
  120. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  121. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  122. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  123. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/drone/openscvx_logo.py +0 -0
  124. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/frax/panda_frax.py +0 -0
  125. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/frax/panda_frax_pick_place.py +0 -0
  126. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/frax/panda_frax_viewplanning.py +0 -0
  127. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/frax/panda_frax_waypoint.py +0 -0
  128. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mjx/cartpole_mjx.py +0 -0
  129. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mjx/double_cartpole_mjx.py +0 -0
  130. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mjx/skydio_x2_mjx.py +0 -0
  131. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  132. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mjx/triple_cartpole_game.py +0 -0
  133. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mjx/triple_cartpole_mjx.py +0 -0
  134. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mpc/double_integrator_discrete.py +0 -0
  135. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mpc/double_integrator_drone_racing.py +0 -0
  136. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  137. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  138. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  139. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/plotting.py +0 -0
  140. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/plotting_viser.py +0 -0
  141. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  142. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  143. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  144. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  145. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  146. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  147. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  148. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  149. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/cinema_vp_realtime.py +0 -0
  150. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/drone_racing_realtime.py +0 -0
  151. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/dubins_car_realtime.py +0 -0
  152. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  153. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/rocket/3DoF_pdg.py +0 -0
  154. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/rocket/6DoF_pdg.py +0 -0
  155. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  156. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/rocket/ascent_launch_vehicle.py +0 -0
  157. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/spacecraft/halo_orbit.py +0 -0
  158. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/spacecraft/hohmann_transfer.py +0 -0
  159. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/spacecraft/let_transfer.py +0 -0
  160. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/spacecraft/proxops_cw.py +0 -0
  161. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/examples/spacecraft/relative_loitering.py +0 -0
  162. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/ctlos_cine.gif +0 -0
  163. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/ctlos_dr.gif +0 -0
  164. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/dtlos_cine.gif +0 -0
  165. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/dtlos_dr.gif +0 -0
  166. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/openscvx_logo.svg +0 -0
  167. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/openscvx_logo_square.png +0 -0
  168. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/oscvx_structure_full_dark.svg +0 -0
  169. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/figures/video_preview.png +0 -0
  170. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/__init__.py +0 -0
  171. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/assets/stylesheets/custom.css +0 -0
  172. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  173. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  174. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  175. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/home.html +0 -0
  176. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/main.html +0 -0
  177. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/partials/home-diagram.html +0 -0
  178. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/partials/home-dropin-banner.html +0 -0
  179. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/partials/home-hero.html +0 -0
  180. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/partials/home-pipeline.html +0 -0
  181. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/material/overrides/partials/home-viser-strip.html +0 -0
  182. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/mkdocs.yml +0 -0
  183. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/__init__.py +0 -0
  184. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/__main__.py +0 -0
  185. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/__init__.py +0 -0
  186. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/autotuner/__init__.py +0 -0
  187. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
  188. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  189. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/autotuner/base.py +0 -0
  190. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  191. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  192. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/base.py +0 -0
  193. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/history.py +0 -0
  194. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/hyperparams.py +0 -0
  195. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/loop.py +0 -0
  196. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/optimization_results.py +0 -0
  197. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/scvx/__init__.py +0 -0
  198. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
  199. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/state.py +0 -0
  200. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/algorithms/weights.py +0 -0
  201. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/config.py +0 -0
  202. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/__init__.py +0 -0
  203. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/base.py +0 -0
  204. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/discretize_linearize.py +0 -0
  205. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/linearize_discretize.py +0 -0
  206. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  207. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  208. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  209. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  210. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/expert/__init__.py +0 -0
  211. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/expert/byof.py +0 -0
  212. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/expert/lowering.py +0 -0
  213. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/expert/validation.py +0 -0
  214. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/init/__init__.py +0 -0
  215. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/init/interpolation.py +0 -0
  216. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/init/inverse_kinematics.py +0 -0
  217. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrations/__init__.py +0 -0
  218. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrations/_utils.py +0 -0
  219. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrations/base.py +0 -0
  220. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrations/frax.py +0 -0
  221. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrations/menagerie.py +0 -0
  222. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrations/mjx.py +0 -0
  223. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrators/__init__.py +0 -0
  224. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrators/diffrax.py +0 -0
  225. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/integrators/runge_kutta.py +0 -0
  226. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/loader.py +0 -0
  227. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/__init__.py +0 -0
  228. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/cvxpy_constraints.py +0 -0
  229. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/cvxpy_variables.py +0 -0
  230. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/dynamics.py +0 -0
  231. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/parameters.py +0 -0
  232. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/problem.py +0 -0
  233. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/lowered/unified.py +0 -0
  234. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/__init__.py +0 -0
  235. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/plotting.py +0 -0
  236. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/publication.py +0 -0
  237. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/scp_iteration.py +0 -0
  238. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/__init__.py +0 -0
  239. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/animated.py +0 -0
  240. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/coordinates.py +0 -0
  241. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/orbits.py +0 -0
  242. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/plotly_integration.py +0 -0
  243. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/primitives.py +0 -0
  244. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/scp.py +0 -0
  245. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/plotting/viser/server.py +0 -0
  246. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/problem.py +0 -0
  247. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/propagation/__init__.py +0 -0
  248. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/propagation/post_processing.py +0 -0
  249. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/propagation/propagation.py +0 -0
  250. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/solvers/__init__.py +0 -0
  251. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/solvers/base.py +0 -0
  252. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/solvers/cones.py +0 -0
  253. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/solvers/ptr_solver.py +0 -0
  254. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/__init__.py +0 -0
  255. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/affine.py +0 -0
  256. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/builder.py +0 -0
  257. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/canonicalize.py +0 -0
  258. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/constraint_set.py +0 -0
  259. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/__init__.py +0 -0
  260. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/arithmetic.py +0 -0
  261. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/array.py +0 -0
  262. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/constraint.py +0 -0
  263. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/control.py +0 -0
  264. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/expr.py +0 -0
  265. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  266. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  267. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/lie/se3.py +0 -0
  268. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/lie/so3.py +0 -0
  269. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/linalg.py +0 -0
  270. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/logic.py +0 -0
  271. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/math.py +0 -0
  272. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/parameter.py +0 -0
  273. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/spatial.py +0 -0
  274. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/state.py +0 -0
  275. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/stl.py +0 -0
  276. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/stljax.py +0 -0
  277. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/time.py +0 -0
  278. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/variable.py +0 -0
  279. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/expr/vmap.py +0 -0
  280. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/hashing.py +0 -0
  281. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/__init__.py +0 -0
  282. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  283. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  284. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  285. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  286. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  287. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  288. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  289. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  290. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  291. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  292. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  293. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  294. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  295. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  296. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  297. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  298. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  299. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  300. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  301. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  302. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  303. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  304. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  305. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  306. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  307. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  308. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  309. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  310. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  311. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/__init__.py +0 -0
  312. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/_registry.py +0 -0
  313. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/array.py +0 -0
  314. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/constraint.py +0 -0
  315. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/lie.py +0 -0
  316. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/linalg.py +0 -0
  317. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/logic.py +0 -0
  318. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/math.py +0 -0
  319. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/parser.py +0 -0
  320. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/spatial.py +0 -0
  321. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/stl.py +0 -0
  322. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/stljax.py +0 -0
  323. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/parser/tokenizer.py +0 -0
  324. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/preprocessing.py +0 -0
  325. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/problem.py +0 -0
  326. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/sparsity.py +0 -0
  327. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/symbolic/unified.py +0 -0
  328. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/utils/__init__.py +0 -0
  329. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/utils/cache.py +0 -0
  330. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/utils/caching.py +0 -0
  331. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/utils/printing.py +0 -0
  332. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/utils/profiling.py +0 -0
  333. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx/utils/utils.py +0 -0
  334. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx.egg-info/SOURCES.txt +0 -0
  335. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx.egg-info/dependency_links.txt +0 -0
  336. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx.egg-info/entry_points.txt +0 -0
  337. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx.egg-info/requires.txt +0 -0
  338. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx.egg-info/scm_file_list.json +0 -0
  339. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/openscvx.egg-info/top_level.txt +0 -0
  340. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/pyproject.toml +0 -0
  341. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/scripts/gen_example_pages.py +0 -0
  342. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/scripts/gen_ref_pages.py +0 -0
  343. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  344. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/setup.cfg +0 -0
  345. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/__init__.py +0 -0
  346. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/_marks.py +0 -0
  347. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/__init__.py +0 -0
  348. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/_iteration_helpers.py +0 -0
  349. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/autotuner/__init__.py +0 -0
  350. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
  351. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
  352. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
  353. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  354. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  355. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/test_iteration_fn_parity.py +0 -0
  356. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/algorithms/test_make_solve_loop.py +0 -0
  357. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/brachistochrone_analytical.py +0 -0
  358. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/conftest.py +0 -0
  359. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/expr/__init__.py +0 -0
  360. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/expr/test_gmsr.py +0 -0
  361. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/fixtures/brachistochrone.json +0 -0
  362. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/fixtures/brachistochrone.yaml +0 -0
  363. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/hohmann_analytical.py +0 -0
  364. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/integrations/__init__.py +0 -0
  365. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/integrations/test_mjx.py +0 -0
  366. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/integrations/test_mjx_dynamics.py +0 -0
  367. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/__init__.py +0 -0
  368. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/_iteration_callback_helpers.py +0 -0
  369. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  370. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  371. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  372. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  373. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  374. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  375. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/solvers/test_subproblem_pytree.py +0 -0
  376. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/__init__.py +0 -0
  377. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/__init__.py +0 -0
  378. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_arithmetic.py +0 -0
  379. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_array.py +0 -0
  380. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_constraint.py +0 -0
  381. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_expr.py +0 -0
  382. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_lie.py +0 -0
  383. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_linalg.py +0 -0
  384. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_logic.py +0 -0
  385. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_math.py +0 -0
  386. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_node_reference.py +0 -0
  387. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_parameters.py +0 -0
  388. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_scaling.py +0 -0
  389. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_spatial.py +0 -0
  390. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_stl.py +0 -0
  391. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_variable.py +0 -0
  392. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/expr/test_vmap.py +0 -0
  393. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/__init__.py +0 -0
  394. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_array.py +0 -0
  395. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_constraint.py +0 -0
  396. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_lie.py +0 -0
  397. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_linalg.py +0 -0
  398. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_load.py +0 -0
  399. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_logic.py +0 -0
  400. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_math.py +0 -0
  401. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_parser.py +0 -0
  402. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_spatial.py +0 -0
  403. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_stl.py +0 -0
  404. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_tokenizer.py +0 -0
  405. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/parser/test_vmap.py +0 -0
  406. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/test_hashing.py +0 -0
  407. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/test_lower_cvxpy.py +0 -0
  408. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/test_lower_jax.py +0 -0
  409. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/test_preprocessing.py +0 -0
  410. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/test_sparsity.py +0 -0
  411. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/symbolic/test_unified.py +0 -0
  412. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_cvxpygen_optional.py +0 -0
  413. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_discretization.py +0 -0
  414. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_examples.py +0 -0
  415. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_expert.py +0 -0
  416. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_impulsive.py +0 -0
  417. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_init.py +0 -0
  418. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_integrators.py +0 -0
  419. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_loader.py +0 -0
  420. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_multishot_propagation.py +0 -0
  421. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_optimization_results.py +0 -0
  422. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_plotting.py +0 -0
  423. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_propagation.py +0 -0
  424. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_batched_brachistochrone.py +0 -0
  425. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
  426. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_batched_export_roundtrip.py +0 -0
  427. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_batched_inference.py +0 -0
  428. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
  429. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
  430. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
  431. {openscvx-0.5.3.dev31 → openscvx-0.5.3.dev32}/tests/test_solve_jax_vmap_converged_no_drift.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev31
3
+ Version: 0.5.3.dev32
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
@@ -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.dev31'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev31')
21
+ __version__ = version = '0.5.3.dev32'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev32')
23
23
 
24
- __commit_id__ = commit_id = 'gdcb1cb9eb'
24
+ __commit_id__ = commit_id = 'gd1964080e'
@@ -206,7 +206,7 @@ class AugmentedLagrangian(AcceptanceRatioAutotuner):
206
206
 
207
207
  for idx, constraint in enumerate(nodal_constraints.nodal):
208
208
  g = constraint.func(candidate.x, candidate.u, 0, params)
209
- nu = jnp.maximum(0.0, g)
209
+ nu = jnp.abs(g) if constraint.is_equality else jnp.maximum(0.0, g)
210
210
 
211
211
  if constraint.nodes is not None:
212
212
  nodes_array = jnp.asarray(constraint.nodes)
@@ -245,7 +245,7 @@ class AugmentedLagrangian(AcceptanceRatioAutotuner):
245
245
 
246
246
  for idx, constraint in enumerate(nodal_constraints.cross_node):
247
247
  g = constraint.func(candidate.x, candidate.u, params)
248
- nu = jnp.sum(jnp.maximum(0.0, g))
248
+ nu = jnp.sum(jnp.abs(g) if constraint.is_equality else jnp.maximum(0.0, g))
249
249
  current = state.lam_vb_cross[idx]
250
250
  case1 = current + nu * scale
251
251
  case2 = current + (nu**2) / state.hyper.ep * scale
@@ -96,12 +96,14 @@ def calculate_nonlinear_penalty(
96
96
  else:
97
97
  g_filtered = g
98
98
  w = lam_vb_nodal[:, idx]
99
- nodal_penalty = nodal_penalty + jnp.sum(w * jnp.maximum(0.0, g_filtered))
99
+ viol = jnp.abs(g_filtered) if constraint.is_equality else jnp.maximum(0.0, g_filtered)
100
+ nodal_penalty = nodal_penalty + jnp.sum(w * viol)
100
101
 
101
102
  for idx, constraint in enumerate(nodal_constraints.cross_node):
102
103
  w = lam_vb_cross[idx]
103
104
  g = constraint.func(x_bar, u_bar, params)
104
- nodal_penalty = nodal_penalty + w * jnp.sum(jnp.maximum(0.0, g))
105
+ viol = jnp.abs(g) if constraint.is_equality else jnp.maximum(0.0, g)
106
+ nodal_penalty = nodal_penalty + w * jnp.sum(viol)
105
107
 
106
108
  cost = calculate_cost_from_state(x_bar, settings, lam_cost)
107
109
  x_diff = settings.sim.inv_S_x @ (x_bar[1:, :] - x_prop).T
@@ -145,6 +145,11 @@ def make_scp_iteration(
145
145
  n_u = settings.sim.n_controls
146
146
  n_nodal = len(jax_constraints.nodal)
147
147
 
148
+ # Equality columns measure violation two-sided (|nu_vb|); inequalities use
149
+ # the positive part. Built once at trace time as static boolean masks.
150
+ nodal_eq_mask = jnp.asarray([c.is_equality for c in jax_constraints.nodal], dtype=bool)
151
+ cross_eq_mask = jnp.asarray([c.is_equality for c in jax_constraints.cross_node], dtype=bool)
152
+
148
153
  # Accept either a bare ``jax.jit`` callable or a ``jax.export`` wrapper.
149
154
  dis_continuous = dis_continuous.call if hasattr(dis_continuous, "call") else dis_continuous
150
155
  dis_impulsive = dis_impulsive.call if hasattr(dis_impulsive, "call") else dis_impulsive
@@ -311,9 +316,13 @@ def make_scp_iteration(
311
316
  VC = jnp.abs(inv_S_x @ solution.nu.T).T
312
317
  J_tr = jnp.sum(TR**2)
313
318
  J_vc = jnp.sum(VC)
314
- J_vb = jnp.sum(jnp.maximum(0.0, solution.nu_vb)) + jnp.sum(
315
- jnp.maximum(0.0, solution.nu_vb_cross)
319
+ nodal_vb = jnp.where(
320
+ nodal_eq_mask, jnp.abs(solution.nu_vb), jnp.maximum(0.0, solution.nu_vb)
321
+ )
322
+ cross_vb = jnp.where(
323
+ cross_eq_mask, jnp.abs(solution.nu_vb_cross), jnp.maximum(0.0, solution.nu_vb_cross)
316
324
  )
325
+ J_vb = jnp.sum(nodal_vb) + jnp.sum(cross_vb)
317
326
  state = state.replace(
318
327
  J_tr=jnp.asarray(J_tr, dtype=state.J_tr.dtype),
319
328
  J_vb=jnp.asarray(J_vb, dtype=state.J_vb.dtype),
@@ -37,12 +37,19 @@ class LoweredNodalConstraint:
37
37
 
38
38
  nodes (Optional[List[int]]): List of node indices where this constraint applies.
39
39
  Set after lowering from NodalConstraint.
40
+
41
+ is_equality (bool): True if the source constraint was an ``Equality``
42
+ (``g == 0``), False for an ``Inequality`` (``g <= 0``). Controls the
43
+ virtual-buffer penalty shape downstream: equalities are penalized
44
+ two-sided (``|nu_vb|``), inequalities one-sided (``pos(nu_vb)``).
45
+ Defaults to False, preserving the inequality behavior.
40
46
  """
41
47
 
42
48
  func: Callable[[jnp.ndarray, jnp.ndarray], jnp.ndarray]
43
49
  grad_g_x: Optional[Callable[[jnp.ndarray, jnp.ndarray], jnp.ndarray]] = None
44
50
  grad_g_u: Optional[Callable[[jnp.ndarray, jnp.ndarray], jnp.ndarray]] = None
45
51
  nodes: Optional[List[int]] = None
52
+ is_equality: bool = False
46
53
 
47
54
 
48
55
  @dataclass
@@ -110,6 +117,7 @@ class LoweredCrossNodeConstraint:
110
117
  func: Callable[[jnp.ndarray, jnp.ndarray, dict], jnp.ndarray]
111
118
  grad_g_X: Callable[[jnp.ndarray, jnp.ndarray, dict], jnp.ndarray]
112
119
  grad_g_U: Callable[[jnp.ndarray, jnp.ndarray, dict], jnp.ndarray]
120
+ is_equality: bool = False
113
121
 
114
122
 
115
123
  @dataclass
@@ -490,18 +490,21 @@ class CVXPyPTRSolver(PTRSolver):
490
490
  # Virtual Control Slack
491
491
  cost += sum(cp.sum(lam_vc[i - 1] * cp.abs(nu[i - 1])) for i in range(1, settings.sim.n))
492
492
 
493
- # Virtual buffer penalty for nodal constraints (per-node weighting)
493
+ # Virtual buffer penalty for nodal constraints (per-node weighting).
494
+ # Equalities penalize |nu_vb|, inequalities penalize pos(nu_vb).
494
495
  idx_ncvx = 0
495
496
  if jax_constraints.nodal:
496
497
  for constraint in jax_constraints.nodal:
497
- cost += lam_vb_nodal[:, idx_ncvx] @ cp.pos(nu_vb[idx_ncvx])
498
+ pen = cp.abs if constraint.is_equality else cp.pos
499
+ cost += lam_vb_nodal[:, idx_ncvx] @ pen(nu_vb[idx_ncvx])
498
500
  idx_ncvx += 1
499
501
 
500
502
  # Virtual slack penalty for cross-node constraints
501
503
  idx_cross = 0
502
504
  if jax_constraints.cross_node:
503
505
  for constraint in jax_constraints.cross_node:
504
- cost += lam_vb_cross[idx_cross] * cp.pos(nu_vb_cross[idx_cross])
506
+ pen = cp.abs if constraint.is_equality else cp.pos
507
+ cost += lam_vb_cross[idx_cross] * pen(nu_vb_cross[idx_cross])
505
508
  idx_cross += 1
506
509
 
507
510
  return cost
@@ -490,6 +490,12 @@ class MoreauPTRSolver(PTRSolver):
490
490
  self._c_u_j = jnp.asarray(self._c_u, dtype=f)
491
491
  self._jax_dtype = f
492
492
 
493
+ if any(c.is_equality for c in jax_constraints.nodal):
494
+ raise NotImplementedError(
495
+ "MoreauPTRSolver does not support L1-penalized equality "
496
+ "constraints. Use CVXPyPTRSolver."
497
+ )
498
+
493
499
  self.layout = _ConicLayout(N=N, n_x=n_x, n_u=n_u, n_nodal=len(jax_constraints.nodal))
494
500
  self._jax_constraints = jax_constraints
495
501
  self._x_unified = x_unified
@@ -329,6 +329,12 @@ class QPAXPTRSolver(PTRSolver):
329
329
  self._c_u_j = jnp.asarray(self._c_u, dtype=f)
330
330
  self._jax_dtype = f
331
331
 
332
+ if any(c.is_equality for c in jax_constraints.nodal):
333
+ raise NotImplementedError(
334
+ "QPAXPTRSolver does not support L1-penalized equality "
335
+ "constraints. Use CVXPyPTRSolver."
336
+ )
337
+
332
338
  self.layout = _QPLayout(N=N, n_x=n_x, n_u=n_u, n_nodal=len(jax_constraints.nodal))
333
339
  self._jax_constraints = jax_constraints
334
340
  self._x_unified = x_unified
@@ -75,30 +75,6 @@ from openscvx.symbolic.expr.state import State
75
75
  from openscvx.symbolic.expr.time import Time
76
76
 
77
77
 
78
- def _check_nonconvex_equality(constraint: Constraint, context: str) -> None:
79
- """Raise a helpful error if constraint is a non-convex equality.
80
-
81
- Non-convex equality constraints are not supported.
82
-
83
- Args:
84
- constraint: The constraint to check
85
- context: Description of where this constraint appears (for error message)
86
-
87
- Raises:
88
- ValueError: If constraint is an Equality and not marked as convex
89
- """
90
- if isinstance(constraint, Equality) and not constraint.is_convex:
91
- raise ValueError(
92
- f"Non-convex equality constraint in {context}. "
93
- f"Equality constraints must be affine (linear) and marked as convex "
94
- f"using .convex(). For example:\n"
95
- f" (velocity.at(0) == velocity.at(n-1)).convex()\n"
96
- f"If your equality constraint is nonlinear, consider reformulating it "
97
- f"as two inequality constraints or using a different approach.\n"
98
- f"Constraint: {constraint}"
99
- )
100
-
101
-
102
78
  def sort_ctcs_constraints(
103
79
  constraints_ctcs: List[CTCS],
104
80
  ) -> Tuple[List[CTCS], List[Tuple[int, int]], int]:
@@ -265,9 +241,6 @@ def separate_constraints(constraint_set: ConstraintSet, n_nodes: int) -> Constra
265
241
  f"Constraint: {c.constraint}"
266
242
  )
267
243
 
268
- # Check for non-convex equality constraints
269
- _check_nonconvex_equality(c.constraint, "nodal constraint")
270
-
271
244
  # Regular nodal constraint - categorize by convexity
272
245
  if c.constraint.is_convex:
273
246
  constraint_set.nodal_convex.append(c)
@@ -277,9 +250,6 @@ def separate_constraints(constraint_set: ConstraintSet, n_nodes: int) -> Constra
277
250
  elif isinstance(c, Constraint):
278
251
  # Bare constraint - check if it's a cross-node constraint
279
252
  if _contains_node_reference(c):
280
- # Check for non-convex equality constraints
281
- _check_nonconvex_equality(c, "cross-node constraint")
282
-
283
253
  # Cross-node constraint: wrap in CrossNodeConstraint
284
254
  cross_node = CrossNodeConstraint(c)
285
255
  if c.is_convex:
@@ -287,9 +257,6 @@ def separate_constraints(constraint_set: ConstraintSet, n_nodes: int) -> Constra
287
257
  else:
288
258
  constraint_set.cross_node.append(cross_node)
289
259
  else:
290
- # Check for non-convex equality constraints
291
- _check_nonconvex_equality(c, "nodal constraint")
292
-
293
260
  # Regular constraint: apply at all nodes
294
261
  all_nodes = list(range(n_nodes))
295
262
  nodal_constraint = NodalConstraint(c, all_nodes)
@@ -310,9 +277,6 @@ def separate_constraints(constraint_set: ConstraintSet, n_nodes: int) -> Constra
310
277
  # Add nodal constraints from CTCS constraints that have check_nodally=True
311
278
  ctcs_nodal_constraints = get_nodal_constraints_from_ctcs(constraint_set.ctcs)
312
279
  for constraint, interval in ctcs_nodal_constraints:
313
- # Check for non-convex equality constraints
314
- _check_nonconvex_equality(constraint, "CTCS check_nodally constraint")
315
-
316
280
  # CTCS check_nodally constraints cannot have NodeReferences (validated above)
317
281
  # Convert CTCS interval (start, end) to list of nodes [start, start+1, ..., end-1]
318
282
  interval_nodes = list(range(interval[0], interval[1]))
@@ -73,7 +73,7 @@ from openscvx.lowered import (
73
73
  LoweredProblem,
74
74
  )
75
75
  from openscvx.symbolic.constraint_set import ConstraintSet
76
- from openscvx.symbolic.expr import Expr, NodeReference, traverse
76
+ from openscvx.symbolic.expr import Equality, Expr, NodeReference, traverse
77
77
  from openscvx.symbolic.expr.control import Control
78
78
  from openscvx.symbolic.unified import unify_controls, unify_states
79
79
 
@@ -628,6 +628,7 @@ def _lower_jax_constraints(
628
628
  grad_g_x=jax.vmap(jacfwd(fn, argnums=0), in_axes=(0, 0, None, None)),
629
629
  grad_g_u=jax.vmap(jacfwd(fn, argnums=1), in_axes=(0, 0, None, None)),
630
630
  nodes=constraints.nodal[i].nodes,
631
+ is_equality=isinstance(constraints.nodal[i].constraint, Equality),
631
632
  )
632
633
  lowered_nodal.append(constraint)
633
634
 
@@ -644,6 +645,7 @@ def _lower_jax_constraints(
644
645
  func=constraint_fn,
645
646
  grad_g_X=grad_g_X,
646
647
  grad_g_U=grad_g_U,
648
+ is_equality=isinstance(cross_node_constraint.constraint, Equality),
647
649
  )
648
650
  lowered_cross_node.append(cross_node_lowered)
649
651
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev31
3
+ Version: 0.5.3.dev32
4
4
  Summary: A general Python-based successive convexification implementation which uses a JAX backend.
5
5
  Author-email: Chris Hayner and Griffin Norris <haynec@uw.edu>
6
6
  License: Apache Software License
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.5.2",
3
+ "distance": 32,
4
+ "node": "gd1964080e22534c0d78eccd223de88e62365c296",
5
+ "dirty": false,
6
+ "branch": "main",
7
+ "node_date": "2026-07-01"
8
+ }
@@ -231,6 +231,46 @@ def test_qpax_rejects_user_convex_constraints():
231
231
  )
232
232
 
233
233
 
234
+ def test_qpax_rejects_nodal_equality():
235
+ """L1-penalized nodal equalities need a two-sided slack penalty, which the
236
+ QPAX one-sided positive-part reformulation can't express; lowering must
237
+ raise ``NotImplementedError`` naming CVXPyPTRSolver."""
238
+ n = 5
239
+ pos = ox.State("pos", shape=(2,))
240
+ pos.min = np.array([-10.0, -10.0])
241
+ pos.max = np.array([10.0, 10.0])
242
+ pos.initial = np.array([0.0, 0.0])
243
+ pos.final = np.array([3.0, 3.0])
244
+ vel = ox.State("vel", shape=(2,))
245
+ vel.min = np.array([-5.0, -5.0])
246
+ vel.max = np.array([5.0, 5.0])
247
+ vel.initial = np.array([0.0, 0.0])
248
+ vel.final = [("free", 0.0), ("free", 0.0)]
249
+ u = ox.Control("u", shape=(2,))
250
+ u.min = np.array([-3.0, -3.0])
251
+ u.max = np.array([3.0, 3.0])
252
+ u.guess = np.zeros((n, 2))
253
+ dyn = {"pos": vel, "vel": u}
254
+ time = ox.Time(initial=0.0, final=("minimize", 2.0), min=0.0, max=10.0)
255
+
256
+ eq_constraint = (pos == np.array([1.0, 1.0])).at([2])
257
+
258
+ with pytest.raises(
259
+ NotImplementedError,
260
+ match=r"QPAXPTRSolver does not support L1-penalized equality",
261
+ ):
262
+ Problem(
263
+ dynamics=dyn,
264
+ states=[pos, vel],
265
+ controls=[u],
266
+ time=time,
267
+ constraints=[eq_constraint],
268
+ N=n,
269
+ float_dtype="float64",
270
+ solver={"backend": "qpax"},
271
+ )
272
+
273
+
234
274
  # ============================================================================
235
275
  # Round-trip parity with CVXPyPTRSolver
236
276
  # ============================================================================
@@ -1442,28 +1442,21 @@ def test_regular_convex_constraint_without_node_reference_accepted():
1442
1442
  # =============================================================================
1443
1443
 
1444
1444
 
1445
- def test_nonconvex_cross_node_equality_rejected():
1446
- """Test that non-convex cross-node equality constraints are rejected with helpful error."""
1445
+ def test_nonconvex_cross_node_equality_accepted():
1446
+ """Non-convex cross-node equalities are accepted as soft L1-penalized constraints."""
1447
1447
  n_nodes = 10
1448
1448
  velocity = State("vel", shape=(3,))
1449
1449
 
1450
- # Create a non-convex cross-node equality (periodic boundary condition without .convex())
1451
1450
  cross_node_equality = velocity.at(0) == velocity.at(9)
1452
-
1453
- # Verify it's an Equality and not marked convex
1454
1451
  assert isinstance(cross_node_equality, Equality)
1455
1452
  assert not cross_node_equality.is_convex
1456
1453
 
1457
- # Should raise a helpful error
1458
1454
  constraint_set = ConstraintSet(unsorted=[cross_node_equality])
1459
- with pytest.raises(ValueError) as exc_info:
1460
- separate_constraints(constraint_set, n_nodes=n_nodes)
1455
+ result = separate_constraints(constraint_set, n_nodes=n_nodes)
1461
1456
 
1462
- # Check error message is helpful
1463
- msg = str(exc_info.value)
1464
- assert "Non-convex equality constraint" in msg
1465
- assert ".convex()" in msg
1466
- assert "cross-node" in msg
1457
+ # Routed into the non-convex cross-node list (penalized), not the convex list
1458
+ assert len(result.cross_node) == 1
1459
+ assert len(result.cross_node_convex) == 0
1467
1460
 
1468
1461
 
1469
1462
  def test_convex_cross_node_equality_accepted():
@@ -1486,28 +1479,21 @@ def test_convex_cross_node_equality_accepted():
1486
1479
  assert len(result.cross_node) == 0
1487
1480
 
1488
1481
 
1489
- def test_nonconvex_nodal_equality_rejected():
1490
- """Test that non-convex nodal equality constraints are rejected with helpful error."""
1482
+ def test_nonconvex_nodal_equality_accepted():
1483
+ """Non-convex nodal equalities are accepted as soft L1-penalized constraints."""
1491
1484
  n_nodes = 10
1492
1485
  position = State("pos", shape=(3,))
1493
1486
 
1494
- # Create a non-convex nodal equality (without .convex())
1495
1487
  nodal_equality = (position == np.zeros(3)).at([0, 5, 9])
1496
-
1497
- # Verify it's an Equality and not marked convex
1498
1488
  assert isinstance(nodal_equality.constraint, Equality)
1499
1489
  assert not nodal_equality.constraint.is_convex
1500
1490
 
1501
- # Should raise a helpful error
1502
1491
  constraint_set = ConstraintSet(unsorted=[nodal_equality])
1503
- with pytest.raises(ValueError) as exc_info:
1504
- separate_constraints(constraint_set, n_nodes=n_nodes)
1492
+ result = separate_constraints(constraint_set, n_nodes=n_nodes)
1505
1493
 
1506
- # Check error message is helpful
1507
- msg = str(exc_info.value)
1508
- assert "Non-convex equality constraint" in msg
1509
- assert ".convex()" in msg
1510
- assert "nodal" in msg
1494
+ # Routed into the non-convex nodal list (penalized), not the convex list
1495
+ assert len(result.nodal) == 1
1496
+ assert len(result.nodal_convex) == 0
1511
1497
 
1512
1498
 
1513
1499
  def test_ctcs_equality_rejected():
@@ -435,6 +435,31 @@ def test_calculate_nonlinear_penalty_with_nodal_violations(
435
435
  assert nonlinear_penalty >= 0.0
436
436
 
437
437
 
438
+ def test_calculate_nonlinear_penalty_equality_is_two_sided(settings):
439
+ """Equality nodal constraints penalize |g| (two-sided), inequalities use max(0, g)."""
440
+
441
+ def nodal_func(x, u, node, params):
442
+ return x[:, 0] - 1.5 # negative residual at x=0 (satisfied as inequality)
443
+
444
+ x_prop = np.array([[0.0, 0.0], [0.0, 0.0]])
445
+ x_bar = np.zeros((3, 2))
446
+ u_bar = np.zeros((3, 1))
447
+ args = (np.array([1.0, 1.0]), np.full((3, 1), 1.0), np.full(1, 1.0), 1.0)
448
+
449
+ eq = LoweredJaxConstraints(
450
+ nodal=[LoweredNodalConstraint(func=nodal_func, nodes=None, is_equality=True)],
451
+ )
452
+ ineq = LoweredJaxConstraints(
453
+ nodal=[LoweredNodalConstraint(func=nodal_func, nodes=None, is_equality=False)],
454
+ )
455
+
456
+ _, _, eq_pen = calculate_nonlinear_penalty(x_prop, x_bar, u_bar, *args, eq, {}, settings)
457
+ _, _, ineq_pen = calculate_nonlinear_penalty(x_prop, x_bar, u_bar, *args, ineq, {}, settings)
458
+
459
+ assert eq_pen > 0.0 # |−1.5| penalized
460
+ assert ineq_pen == 0.0 # max(0, −1.5) == 0
461
+
462
+
438
463
  def test_calculate_nonlinear_penalty_with_cross_node_violations(settings, cross_node_constraints):
439
464
  """Test penalty calculation with cross-node constraint violations."""
440
465
  x_prop = np.array([[0.5, 0.5], [1.5, 1.5]])
@@ -536,6 +536,77 @@ def test_backend_float32_raises():
536
536
  jax.clear_caches()
537
537
 
538
538
 
539
+ def test_nodal_equality_waypoint():
540
+ """Soft L1-penalized nodal equality drives an off-path waypoint to target."""
541
+ import jax.numpy as jnp
542
+
543
+ import openscvx as ox
544
+ from openscvx import Problem
545
+
546
+ n = 12
547
+ g = 9.81
548
+ mid = n // 2
549
+ # Natural (unconstrained) node-mid position is ~(2.62, 6.69); this is a
550
+ # deliberate off-path deviation the soft equality must pull the iterate to.
551
+ waypoint = np.array([3.0, 6.4])
552
+
553
+ position = ox.State("position", shape=(2,))
554
+ position.max = np.array([10.0, 10.0])
555
+ position.min = np.array([0.0, 0.0])
556
+ position.initial = np.array([0.0, 10.0])
557
+ position.final = [10.0, 5.0]
558
+
559
+ velocity = ox.State("velocity", shape=(1,))
560
+ velocity.max = np.array([15.0])
561
+ velocity.min = np.array([0.0])
562
+ velocity.initial = np.array([0.0])
563
+ velocity.final = [("free", 10.0)]
564
+
565
+ theta = ox.Control("theta", shape=(1,))
566
+ theta.max = np.array([179.0 * jnp.pi / 180])
567
+ theta.min = np.array([0.0])
568
+ theta.guess = np.linspace(5 * jnp.pi / 180, 100.5 * jnp.pi / 180, n).reshape(-1, 1)
569
+
570
+ states = [position, velocity]
571
+ dynamics = {
572
+ "position": ox.Concat(velocity[0] * ox.Sin(theta[0]), -velocity[0] * ox.Cos(theta[0])),
573
+ "velocity": g * ox.Cos(theta[0]),
574
+ }
575
+
576
+ constraint_exprs = []
577
+ for state in states:
578
+ constraint_exprs.extend([ox.ctcs(state <= state.max), ox.ctcs(state.min <= state)])
579
+ constraint_exprs.append((position == waypoint).at([mid]).weight(1e3))
580
+
581
+ time = ox.Time(initial=0.0, final=("minimize", 2.0), min=0.0, max=2.0, uniform_time_grid=True)
582
+
583
+ problem = Problem(
584
+ dynamics=dynamics,
585
+ states=states,
586
+ controls=[theta],
587
+ time=time,
588
+ constraints=constraint_exprs,
589
+ N=n,
590
+ licq_max=1e-8,
591
+ algorithm={"lam_prox": 1e0, "lam_cost": 1e-1, "lam_vc": 1e0, "k_max": 200},
592
+ )
593
+ problem.settings.prp.dt = 0.01
594
+ problem.solver.solver_args = {"abstol": 1e-8, "reltol": 1e-10}
595
+ problem.settings.sim.save_compiled = False
596
+ if hasattr(problem.settings, "dev"):
597
+ problem.settings.dev.printing = False
598
+
599
+ problem.initialize()
600
+ problem.solve()
601
+ result = problem.post_process()
602
+
603
+ assert result["converged"], "Soft-equality problem failed to converge"
604
+ err = np.linalg.norm(result.nodes["position"][mid] - waypoint)
605
+ assert err < 1e-4, f"Waypoint not satisfied at node {mid}: err={err:.4f}"
606
+
607
+ jax.clear_caches()
608
+
609
+
539
610
  @pytest.mark.parametrize("constraint_type", ["ctcs", "nodal", "convex", "over", "at"])
540
611
  def test_constraint_types(constraint_type):
541
612
  """
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.5.2",
3
- "distance": 31,
4
- "node": "gdcb1cb9eb215d338eb5f3392951aaaac30ca12f7",
5
- "dirty": false,
6
- "branch": "main",
7
- "node_date": "2026-06-23"
8
- }
File without changes
File without changes