openscvx 2.dev6__tar.gz → 2.dev8__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 (360) hide show
  1. {openscvx-2.dev6/openscvx.egg-info → openscvx-2.dev8}/PKG-INFO +3 -1
  2. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UnderTheHood/lowering_architecture.md +31 -0
  3. {openscvx-2.dev6 → openscvx-2.dev8}/examples/rocket/6DoF_pdg.py +0 -5
  4. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/__init__.py +16 -1
  5. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/_version.py +3 -3
  6. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/loader.py +2 -2
  7. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/cvxpy_constraints.py +4 -1
  8. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/problem.py +19 -13
  9. openscvx-2.dev8/openscvx/solvers/__init__.py +93 -0
  10. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/solvers/base.py +117 -36
  11. openscvx-2.dev6/openscvx/solvers/ptr_solver.py → openscvx-2.dev8/openscvx/solvers/cvxpy_ptr_solver.py +49 -86
  12. openscvx-2.dev8/openscvx/solvers/ptr_solver.py +196 -0
  13. openscvx-2.dev8/openscvx/solvers/qpax_ptr_solver.py +776 -0
  14. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lower.py +6 -7
  15. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/utils/printing.py +9 -1
  16. {openscvx-2.dev6 → openscvx-2.dev8/openscvx.egg-info}/PKG-INFO +3 -1
  17. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx.egg-info/SOURCES.txt +4 -0
  18. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx.egg-info/requires.txt +3 -0
  19. {openscvx-2.dev6 → openscvx-2.dev8}/pyproject.toml +3 -0
  20. openscvx-2.dev8/tests/solvers/test_qpax_ptr_solver.py +238 -0
  21. openscvx-2.dev8/tests/symbolic/parser/__init__.py +0 -0
  22. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_brachistochrone.py +184 -3
  23. openscvx-2.dev6/openscvx/solvers/__init__.py +0 -76
  24. {openscvx-2.dev6 → openscvx-2.dev8}/.github/assets/logo.svg +0 -0
  25. {openscvx-2.dev6 → openscvx-2.dev8}/.github/release-drafter.yml +0 -0
  26. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/_docs.yml +0 -0
  27. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/branch-name.yml +0 -0
  28. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/docs.yml +0 -0
  29. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/lint.yml +0 -0
  30. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/nightly.yml +0 -0
  31. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/release-drafter.yml +0 -0
  32. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/release.yml +0 -0
  33. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/tests-integration.yml +0 -0
  34. {openscvx-2.dev6 → openscvx-2.dev8}/.github/workflows/tests-unit.yml +0 -0
  35. {openscvx-2.dev6 → openscvx-2.dev8}/.gitignore +0 -0
  36. {openscvx-2.dev6 → openscvx-2.dev8}/.gitmodules +0 -0
  37. {openscvx-2.dev6 → openscvx-2.dev8}/CONTRIBUTING.md +0 -0
  38. {openscvx-2.dev6 → openscvx-2.dev8}/LICENSE +0 -0
  39. {openscvx-2.dev6 → openscvx-2.dev8}/README.md +0 -0
  40. {openscvx-2.dev6 → openscvx-2.dev8}/docs/Foundations/constraint_reformulation.md +0 -0
  41. {openscvx-2.dev6 → openscvx-2.dev8}/docs/Foundations/control_parameterization.md +0 -0
  42. {openscvx-2.dev6 → openscvx-2.dev8}/docs/Foundations/discretization.md +0 -0
  43. {openscvx-2.dev6 → openscvx-2.dev8}/docs/Foundations/ocp.md +0 -0
  44. {openscvx-2.dev6 → openscvx-2.dev8}/docs/Foundations/scvx.md +0 -0
  45. {openscvx-2.dev6 → openscvx-2.dev8}/docs/Foundations/time_dilation.md +0 -0
  46. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  47. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/00_introduction.md +0 -0
  48. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  49. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  50. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  51. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  52. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/05_visualization.md +0 -0
  53. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/06_logic.md +0 -0
  54. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/07_lie.md +0 -0
  55. {openscvx-2.dev6 → openscvx-2.dev8}/docs/UsersGuide/08_mpcc.md +0 -0
  56. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/favicon.png +0 -0
  57. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/images/ct-scvx_dark.png +0 -0
  58. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/images/ct-scvx_light.png +0 -0
  59. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/images/ctcs_dark.png +0 -0
  60. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/images/ctcs_light.png +0 -0
  61. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/images/problem_class_dark.png +0 -0
  62. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/images/problem_class_light.png +0 -0
  63. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/logo.svg +0 -0
  64. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/openscvx_logo_square.png +0 -0
  65. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/viser-client/index.html +0 -0
  66. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  67. {openscvx-2.dev6 → openscvx-2.dev8}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  68. {openscvx-2.dev6 → openscvx-2.dev8}/docs/citation.md +0 -0
  69. {openscvx-2.dev6 → openscvx-2.dev8}/docs/examples.md +0 -0
  70. {openscvx-2.dev6 → openscvx-2.dev8}/docs/index.md +0 -0
  71. {openscvx-2.dev6 → openscvx-2.dev8}/docs/javascripts/mathjax.js +0 -0
  72. {openscvx-2.dev6 → openscvx-2.dev8}/docs/versions.json +0 -0
  73. {openscvx-2.dev6 → openscvx-2.dev8}/examples/_viser_embed_export.py +0 -0
  74. {openscvx-2.dev6 → openscvx-2.dev8}/examples/abstract/brachistochrone.py +0 -0
  75. {openscvx-2.dev6 → openscvx-2.dev8}/examples/abstract/hypersensitive.py +0 -0
  76. {openscvx-2.dev6 → openscvx-2.dev8}/examples/abstract/impulsive.py +0 -0
  77. {openscvx-2.dev6 → openscvx-2.dev8}/examples/abstract/stl_integer_variable.py +0 -0
  78. {openscvx-2.dev6 → openscvx-2.dev8}/examples/abstract/stl_or.py +0 -0
  79. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/7_dof_arm.py +0 -0
  80. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/_camera.py +0 -0
  81. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/_render.py +0 -0
  82. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/_sensor_view.py +0 -0
  83. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/dr_vp_polytope.py +0 -0
  84. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  85. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/logo.py +0 -0
  86. {openscvx-2.dev6 → openscvx-2.dev8}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  87. {openscvx-2.dev6 → openscvx-2.dev8}/examples/arm/3_dof_arm.py +0 -0
  88. {openscvx-2.dev6 → openscvx-2.dev8}/examples/arm/7_dof_arm.py +0 -0
  89. {openscvx-2.dev6 → openscvx-2.dev8}/examples/arm/7_dof_arm_collision.py +0 -0
  90. {openscvx-2.dev6 → openscvx-2.dev8}/examples/arm/7_dof_arm_vp.py +0 -0
  91. {openscvx-2.dev6 → openscvx-2.dev8}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  92. {openscvx-2.dev6 → openscvx-2.dev8}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  93. {openscvx-2.dev6 → openscvx-2.dev8}/examples/car/dubins_car.py +0 -0
  94. {openscvx-2.dev6 → openscvx-2.dev8}/examples/car/dubins_car_disjoint.py +0 -0
  95. {openscvx-2.dev6 → openscvx-2.dev8}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  96. {openscvx-2.dev6 → openscvx-2.dev8}/examples/car/dubins_car_obstacle_stl.py +0 -0
  97. {openscvx-2.dev6 → openscvx-2.dev8}/examples/car/dubins_car_stl_or.py +0 -0
  98. {openscvx-2.dev6 → openscvx-2.dev8}/examples/car/dubins_car_waypoint_stl.py +0 -0
  99. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/cinema_vp.py +0 -0
  100. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/dr_double_integrator.py +0 -0
  101. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/dr_vp.py +0 -0
  102. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/dr_vp_nodal.py +0 -0
  103. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/dr_vp_polytope.py +0 -0
  104. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/drone_racing.py +0 -0
  105. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/logo.py +0 -0
  106. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/logo_utils/acl_logo.svg +0 -0
  107. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  108. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/obstacle_avoidance.py +0 -0
  109. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  110. {openscvx-2.dev6 → openscvx-2.dev8}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  111. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mjx/cartpole_mjx.py +0 -0
  112. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mjx/double_cartpole_mjx.py +0 -0
  113. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mjx/skydio_x2_mjx.py +0 -0
  114. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  115. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mjx/triple_cartpole_game.py +0 -0
  116. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mjx/triple_cartpole_mjx.py +0 -0
  117. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mpc/double_integrator_discrete.py +0 -0
  118. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mpc/double_integrator_drone_racing.py +0 -0
  119. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  120. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  121. {openscvx-2.dev6 → openscvx-2.dev8}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  122. {openscvx-2.dev6 → openscvx-2.dev8}/examples/plotting.py +0 -0
  123. {openscvx-2.dev6 → openscvx-2.dev8}/examples/plotting_viser.py +0 -0
  124. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  125. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  126. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  127. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  128. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  129. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  130. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  131. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  132. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/cinema_vp_realtime.py +0 -0
  133. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/drone_racing_realtime.py +0 -0
  134. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/dubins_car_realtime.py +0 -0
  135. {openscvx-2.dev6 → openscvx-2.dev8}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  136. {openscvx-2.dev6 → openscvx-2.dev8}/examples/rocket/3DoF_pdg.py +0 -0
  137. {openscvx-2.dev6 → openscvx-2.dev8}/examples/spacecraft/halo_orbit.py +0 -0
  138. {openscvx-2.dev6 → openscvx-2.dev8}/examples/spacecraft/hohmann_transfer.py +0 -0
  139. {openscvx-2.dev6 → openscvx-2.dev8}/examples/spacecraft/let_transfer.py +0 -0
  140. {openscvx-2.dev6 → openscvx-2.dev8}/examples/spacecraft/proxops_cw.py +0 -0
  141. {openscvx-2.dev6 → openscvx-2.dev8}/figures/ctlos_cine.gif +0 -0
  142. {openscvx-2.dev6 → openscvx-2.dev8}/figures/ctlos_dr.gif +0 -0
  143. {openscvx-2.dev6 → openscvx-2.dev8}/figures/dtlos_cine.gif +0 -0
  144. {openscvx-2.dev6 → openscvx-2.dev8}/figures/dtlos_dr.gif +0 -0
  145. {openscvx-2.dev6 → openscvx-2.dev8}/figures/openscvx_logo.svg +0 -0
  146. {openscvx-2.dev6 → openscvx-2.dev8}/figures/openscvx_logo_square.png +0 -0
  147. {openscvx-2.dev6 → openscvx-2.dev8}/figures/oscvx_structure_full_dark.svg +0 -0
  148. {openscvx-2.dev6 → openscvx-2.dev8}/figures/video_preview.png +0 -0
  149. {openscvx-2.dev6 → openscvx-2.dev8}/material/__init__.py +0 -0
  150. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/assets/stylesheets/custom.css +0 -0
  151. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  152. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  153. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  154. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/home.html +0 -0
  155. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/main.html +0 -0
  156. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/partials/home-diagram.html +0 -0
  157. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/partials/home-dropin-banner.html +0 -0
  158. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/partials/home-hero.html +0 -0
  159. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/partials/home-pipeline.html +0 -0
  160. {openscvx-2.dev6 → openscvx-2.dev8}/material/overrides/partials/home-viser-strip.html +0 -0
  161. {openscvx-2.dev6 → openscvx-2.dev8}/mkdocs.yml +0 -0
  162. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/__main__.py +0 -0
  163. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/__init__.py +0 -0
  164. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/autotuner/__init__.py +0 -0
  165. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  166. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
  167. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  168. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  169. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/base.py +0 -0
  170. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/optimization_results.py +0 -0
  171. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/scvx/__init__.py +0 -0
  172. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
  173. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/algorithms/weights.py +0 -0
  174. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/config.py +0 -0
  175. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/__init__.py +0 -0
  176. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/base.py +0 -0
  177. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/discretize_linearize.py +0 -0
  178. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/linearize_discretize.py +0 -0
  179. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  180. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  181. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  182. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  183. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/expert/__init__.py +0 -0
  184. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/expert/byof.py +0 -0
  185. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/expert/lowering.py +0 -0
  186. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/expert/validation.py +0 -0
  187. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/init/__init__.py +0 -0
  188. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/init/interpolation.py +0 -0
  189. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/init/inverse_kinematics.py +0 -0
  190. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/integrations/__init__.py +0 -0
  191. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/integrations/base.py +0 -0
  192. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/integrations/menagerie.py +0 -0
  193. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/integrations/mjx.py +0 -0
  194. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/integrators/__init__.py +0 -0
  195. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/integrators/diffrax.py +0 -0
  196. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/integrators/runge_kutta.py +0 -0
  197. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/__init__.py +0 -0
  198. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/cvxpy_variables.py +0 -0
  199. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/dynamics.py +0 -0
  200. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/jax_constraints.py +0 -0
  201. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/parameters.py +0 -0
  202. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/problem.py +0 -0
  203. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/lowered/unified.py +0 -0
  204. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/__init__.py +0 -0
  205. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/plotting.py +0 -0
  206. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/scp_iteration.py +0 -0
  207. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/viser/__init__.py +0 -0
  208. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/viser/animated.py +0 -0
  209. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/viser/orbits.py +0 -0
  210. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/viser/plotly_integration.py +0 -0
  211. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/viser/primitives.py +0 -0
  212. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/viser/scp.py +0 -0
  213. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/plotting/viser/server.py +0 -0
  214. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/propagation/__init__.py +0 -0
  215. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/propagation/post_processing.py +0 -0
  216. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/propagation/propagation.py +0 -0
  217. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/__init__.py +0 -0
  218. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/augmentation.py +0 -0
  219. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/builder.py +0 -0
  220. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/constraint_set.py +0 -0
  221. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/__init__.py +0 -0
  222. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/arithmetic.py +0 -0
  223. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/array.py +0 -0
  224. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/constraint.py +0 -0
  225. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/control.py +0 -0
  226. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/expr.py +0 -0
  227. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  228. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  229. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/lie/se3.py +0 -0
  230. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/lie/so3.py +0 -0
  231. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/linalg.py +0 -0
  232. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/logic.py +0 -0
  233. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/math.py +0 -0
  234. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/parameter.py +0 -0
  235. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/spatial.py +0 -0
  236. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/state.py +0 -0
  237. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/stl.py +0 -0
  238. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/stljax.py +0 -0
  239. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/time.py +0 -0
  240. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/variable.py +0 -0
  241. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/expr/vmap.py +0 -0
  242. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/hashing.py +0 -0
  243. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/__init__.py +0 -0
  244. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  245. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  246. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  247. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  248. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  249. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  250. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  251. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  252. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  253. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  254. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  255. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  256. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  257. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  258. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  259. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  260. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  261. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  262. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  263. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  264. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  265. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  266. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  267. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  268. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  269. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  270. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  271. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  272. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  273. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/__init__.py +0 -0
  274. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/_registry.py +0 -0
  275. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/array.py +0 -0
  276. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/constraint.py +0 -0
  277. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/lie.py +0 -0
  278. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/linalg.py +0 -0
  279. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/logic.py +0 -0
  280. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/math.py +0 -0
  281. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/parser.py +0 -0
  282. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/spatial.py +0 -0
  283. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/stl.py +0 -0
  284. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/stljax.py +0 -0
  285. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/parser/tokenizer.py +0 -0
  286. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/preprocessing.py +0 -0
  287. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/problem.py +0 -0
  288. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/sparsity.py +0 -0
  289. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/symbolic/unified.py +0 -0
  290. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/utils/__init__.py +0 -0
  291. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/utils/cache.py +0 -0
  292. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/utils/caching.py +0 -0
  293. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/utils/profiling.py +0 -0
  294. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx/utils/utils.py +0 -0
  295. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx.egg-info/dependency_links.txt +0 -0
  296. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx.egg-info/entry_points.txt +0 -0
  297. {openscvx-2.dev6 → openscvx-2.dev8}/openscvx.egg-info/top_level.txt +0 -0
  298. {openscvx-2.dev6 → openscvx-2.dev8}/scripts/gen_example_pages.py +0 -0
  299. {openscvx-2.dev6 → openscvx-2.dev8}/scripts/gen_ref_pages.py +0 -0
  300. {openscvx-2.dev6 → openscvx-2.dev8}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  301. {openscvx-2.dev6 → openscvx-2.dev8}/setup.cfg +0 -0
  302. {openscvx-2.dev6 → openscvx-2.dev8}/tests/__init__.py +0 -0
  303. {openscvx-2.dev6 → openscvx-2.dev8}/tests/brachistochrone_analytical.py +0 -0
  304. {openscvx-2.dev6 → openscvx-2.dev8}/tests/expr/__init__.py +0 -0
  305. {openscvx-2.dev6 → openscvx-2.dev8}/tests/expr/test_gmsr.py +0 -0
  306. {openscvx-2.dev6 → openscvx-2.dev8}/tests/fixtures/brachistochrone.json +0 -0
  307. {openscvx-2.dev6 → openscvx-2.dev8}/tests/fixtures/brachistochrone.yaml +0 -0
  308. {openscvx-2.dev6 → openscvx-2.dev8}/tests/hohmann_analytical.py +0 -0
  309. {openscvx-2.dev6 → openscvx-2.dev8}/tests/integrations/__init__.py +0 -0
  310. {openscvx-2.dev6 → openscvx-2.dev8}/tests/integrations/test_mjx.py +0 -0
  311. {openscvx-2.dev6 → openscvx-2.dev8}/tests/integrations/test_mjx_dynamics.py +0 -0
  312. {openscvx-2.dev6/tests/symbolic → openscvx-2.dev8/tests/solvers}/__init__.py +0 -0
  313. {openscvx-2.dev6/tests/symbolic/expr → openscvx-2.dev8/tests/symbolic}/__init__.py +0 -0
  314. {openscvx-2.dev6/tests/symbolic/parser → openscvx-2.dev8/tests/symbolic/expr}/__init__.py +0 -0
  315. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_arithmetic.py +0 -0
  316. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_array.py +0 -0
  317. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_constraint.py +0 -0
  318. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_expr.py +0 -0
  319. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_lie.py +0 -0
  320. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_linalg.py +0 -0
  321. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_logic.py +0 -0
  322. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_math.py +0 -0
  323. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_node_reference.py +0 -0
  324. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_parameters.py +0 -0
  325. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_scaling.py +0 -0
  326. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_spatial.py +0 -0
  327. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_stl.py +0 -0
  328. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_variable.py +0 -0
  329. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/expr/test_vmap.py +0 -0
  330. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_array.py +0 -0
  331. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_constraint.py +0 -0
  332. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_lie.py +0 -0
  333. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_linalg.py +0 -0
  334. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_load.py +0 -0
  335. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_logic.py +0 -0
  336. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_math.py +0 -0
  337. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_parser.py +0 -0
  338. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_spatial.py +0 -0
  339. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_stl.py +0 -0
  340. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_tokenizer.py +0 -0
  341. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/parser/test_vmap.py +0 -0
  342. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/test_augmentation.py +0 -0
  343. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/test_hashing.py +0 -0
  344. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/test_lower_cvxpy.py +0 -0
  345. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/test_lower_jax.py +0 -0
  346. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/test_preprocessing.py +0 -0
  347. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/test_sparsity.py +0 -0
  348. {openscvx-2.dev6 → openscvx-2.dev8}/tests/symbolic/test_unified.py +0 -0
  349. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_autotuning.py +0 -0
  350. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_cvxpygen_optional.py +0 -0
  351. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_discretization.py +0 -0
  352. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_examples.py +0 -0
  353. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_expert.py +0 -0
  354. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_impulsive.py +0 -0
  355. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_init.py +0 -0
  356. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_integrators.py +0 -0
  357. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_loader.py +0 -0
  358. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_optimization_results.py +0 -0
  359. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_plotting.py +0 -0
  360. {openscvx-2.dev6 → openscvx-2.dev8}/tests/test_propagation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 2.dev6
3
+ Version: 2.dev8
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
@@ -26,6 +26,8 @@ Requires-Dist: pydantic>=2.0
26
26
  Provides-Extra: cvxpygen
27
27
  Requires-Dist: cvxpygen; extra == "cvxpygen"
28
28
  Requires-Dist: qocogen; extra == "cvxpygen"
29
+ Provides-Extra: qpax
30
+ Requires-Dist: qpax>=0.1.1; extra == "qpax"
29
31
  Provides-Extra: stl
30
32
  Requires-Dist: stljax; extra == "stl"
31
33
  Provides-Extra: lie
@@ -160,9 +160,40 @@ JAX lowering has no dependency on:
160
160
 
161
161
  This means JAX-lowered dynamics and constraints could be used with alternative solvers.
162
162
 
163
+ ## Convex Subproblem Backends
164
+
165
+ The convex subproblem at each SCP iteration is solved by a concrete subclass
166
+ of the abstract `PTRSolver` base. Two backends ship today:
167
+
168
+ | Backend | Class | Selector | Notes |
169
+ |---------|-------|----------|-------|
170
+ | CVXPy (default) | `CVXPyPTRSolver` | `solver={"backend": "cvxpy"}` (default) | DCP graph via CVXPy, dispatched to QOCO / CLARABEL / etc. Supports user `.convex()` constraints, cross-node constraints, CTCS, and impulsive controls. Optional cvxpygen code generation. |
171
+ | QPAX | `QPAXPTRSolver` | `solver={"backend": "qpax"}` | JAX-native QP via `qpax.solve_qp`. Flat `(Q, q, A, b, G, h)` assembly. Supports box / dynamics / CTCS / boundary-Fix; **rejects** user `.convex()`, cross-node, and impulsive at `initialize()` with a clear "use `CVXPyPTRSolver`" message. Enables a path toward an end-to-end JAX-differentiable SCP loop in follow-up work. |
172
+
173
+ Picking a backend at construction time:
174
+
175
+ ```python
176
+ import openscvx as ox
177
+
178
+ # Default — same as today's CVXPyPTRSolver.
179
+ problem = ox.Problem(...)
180
+
181
+ # Explicit CVXPy with a different inner solver.
182
+ problem = ox.Problem(..., solver={"backend": "cvxpy", "cvx_solver": "CLARABEL"})
183
+
184
+ # JAX-native QPAX (requires the `qpax` extra: pip install openscvx[qpax]).
185
+ problem = ox.Problem(..., solver={"backend": "qpax"})
186
+ ```
187
+
188
+ QPAX consumes the global JAX dtype — pass `float_dtype="float64"` to `Problem`
189
+ if you need tight inner-solver tolerances; the default `float32` is enough for
190
+ many problems but caps the QP's conditioning.
191
+
163
192
  ## Further Reading
164
193
 
165
194
  - `openscvx/symbolic/lower.py` — Main lowering implementation
166
195
  - `openscvx/lowered/` — Dataclass definitions
167
196
  - `openscvx/symbolic/lowerers/jax.py` — JAX visitor implementation
168
197
  - `openscvx/symbolic/lowerers/cvxpy.py` — CVXPy visitor implementation
198
+ - `openscvx/solvers/ptr_solver.py` — Abstract `PTRSolver` contract
199
+ - `openscvx/solvers/cvxpy_ptr_solver.py` / `qpax_ptr_solver.py` — Concrete backends
@@ -218,11 +218,6 @@ problem = Problem(
218
218
  discretizer={
219
219
  "diffrax_kwargs": {"stepsize_controller": dfx.StepTo(np.linspace(0.0, 1 / (n - 1), 3))}
220
220
  },
221
- solver={
222
- "cvxpygen": True,
223
- "cvx_solver": "qocogen",
224
- "solver_args": {},
225
- },
226
221
  )
227
222
 
228
223
  problem.settings.dev.printing = False
@@ -29,7 +29,10 @@ from openscvx.expert import ByofSpec
29
29
  from openscvx.integrations import DynamicsAdapter, MjxDynamics
30
30
  from openscvx.loader import load_dict, load_json, load_yaml
31
31
  from openscvx.problem import Problem
32
- from openscvx.solvers import PTRSolver
32
+ from openscvx.solvers import CVXPyPTRSolver, PTRSolver
33
+
34
+ # QPAXPTRSolver is exposed lazily via __getattr__ below to keep `import qpax`
35
+ # off the hot import path for users who don't install the optional extra.
33
36
  from openscvx.symbolic.expr import (
34
37
  CTCS,
35
38
  Abs,
@@ -91,6 +94,16 @@ from openscvx.utils.cache import clear_cache, get_cache_dir, get_cache_size
91
94
 
92
95
  load_results = OptimizationResults.load
93
96
 
97
+
98
+ def __getattr__(name: str):
99
+ """Lazy export for backends that depend on optional packages."""
100
+ if name == "QPAXPTRSolver":
101
+ from openscvx.solvers.qpax_ptr_solver import QPAXPTRSolver
102
+
103
+ return QPAXPTRSolver
104
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
105
+
106
+
94
107
  __all__ = [
95
108
  # Main Trajectory Optimization Entrypoint
96
109
  "Problem",
@@ -188,6 +201,8 @@ __all__ = [
188
201
  "VectorizeDiscretizeLinearize",
189
202
  # Convex Solver
190
203
  "PTRSolver",
204
+ "CVXPyPTRSolver",
205
+ "QPAXPTRSolver",
191
206
  # Algorithm & Autotuning
192
207
  "PenalizedTrustRegion",
193
208
  "AugmentedLagrangian",
@@ -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 = '2.dev6'
22
- __version_tuple__ = version_tuple = (2, 'dev6')
21
+ __version__ = version = '2.dev8'
22
+ __version_tuple__ = version_tuple = (2, 'dev8')
23
23
 
24
- __commit_id__ = commit_id = 'gcabefce07'
24
+ __commit_id__ = commit_id = 'g69d91aabb'
@@ -40,7 +40,7 @@ from pydantic import BaseModel, ConfigDict
40
40
  from openscvx.algorithms import PenalizedTrustRegionConfig
41
41
  from openscvx.config import SettingsSpec
42
42
  from openscvx.discretization import DiscretizerSpec
43
- from openscvx.solvers import SolverSpec
43
+ from openscvx.solvers import PTRSolverSpec
44
44
  from openscvx.symbolic.expr.control import ControlSpec
45
45
  from openscvx.symbolic.expr.expr import Expr
46
46
  from openscvx.symbolic.expr.parameter import ParameterSpec
@@ -66,7 +66,7 @@ class ProblemSpec(BaseModel):
66
66
  constraints: List[str] = []
67
67
  algorithm: Optional[PenalizedTrustRegionConfig] = None
68
68
  discretizer: Optional[DiscretizerSpec] = None
69
- solver: Optional[SolverSpec] = None
69
+ solver: Optional[PTRSolverSpec] = None
70
70
  settings: Optional[SettingsSpec] = None
71
71
  states_prop: Optional[List[StateSpec]] = None
72
72
  dynamics_prop: Optional[Dict[str, Any]] = None
@@ -17,7 +17,10 @@ class LoweredCvxpyConstraints:
17
17
 
18
18
  Attributes:
19
19
  constraints: List of CVXPy constraint objects (cp.Constraint).
20
- Includes both nodal and cross-node convex constraints.
20
+ Includes both nodal and cross-node convex constraints. Empty
21
+ for backends that don't accept ``.convex()`` constraints — the
22
+ refusal happens earlier, in
23
+ :meth:`openscvx.solvers.base.ConvexSolver.lower_convex_constraints`.
21
24
  """
22
25
 
23
26
  constraints: list["cp.Constraint"] = field(default_factory=list)
@@ -201,9 +201,11 @@ class Problem:
201
201
  discretizer=ox.LinearizeDiscretize(dis_type="ZOH", ode_solver="Dopri8")
202
202
  solver: Convex subproblem solver configuration. Accepts:
203
203
 
204
- - ``None`` — uses ``PTRSolver()`` with defaults (QOCO backend).
204
+ - ``None`` — uses ``CVXPyPTRSolver()`` with defaults (QOCO backend).
205
205
  - A ``ConvexSolver`` instance — used directly.
206
- - A ``dict`` — passed as kwargs to ``PTRSolver()``.
206
+ - A ``dict`` — validated as ``PTRSolverSpec``; the ``backend``
207
+ field (``"cvxpy"`` or ``"qpax"``) selects the concrete
208
+ backend.
207
209
 
208
210
  Examples::
209
211
 
@@ -216,8 +218,12 @@ class Problem:
216
218
  # Enable cvxpygen code generation
217
219
  solver={"cvxpygen": True}
218
220
 
221
+ # JAX-native QPAX backend (no cvx_solver / cvxpygen fields)
222
+ solver={"backend": "qpax"}
223
+
219
224
  # Instance
220
- solver=ox.PTRSolver(cvx_solver="CLARABEL")
225
+ solver=ox.CVXPyPTRSolver(cvx_solver="CLARABEL")
226
+ solver=ox.QPAXPTRSolver()
221
227
  byof (ByofSpec, optional): Expert mode only. Raw JAX functions to
222
228
  bypass symbolic layer. See :class:`openscvx.expert.ByofSpec` for
223
229
  detailed documentation.
@@ -393,9 +399,9 @@ class Problem:
393
399
  def solver(self) -> ConvexSolver:
394
400
  """Access the convex subproblem solver instance.
395
401
 
396
- Attributes such as ``cvx_solver``, ``solver_args``, ``cvxpygen``, and
397
- ``cvxpygen_override`` can be modified freely before ``initialize``
398
- is called::
402
+ Backend-specific attributes (e.g. ``cvx_solver``, ``solver_args``,
403
+ ``cvxpygen``, ``cvxpygen_override`` on :class:`CVXPyPTRSolver`) can
404
+ be modified freely before ``initialize`` is called::
399
405
 
400
406
  problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
401
407
  problem.solver.cvxpygen = True
@@ -407,7 +413,7 @@ class Problem:
407
413
  will have no effect on subsequent solves.
408
414
 
409
415
  Returns:
410
- The solver instance (e.g., PTRSolver).
416
+ The solver instance a concrete :class:`PTRSolver` subclass.
411
417
  """
412
418
  return self._solver
413
419
 
@@ -510,12 +516,12 @@ class Problem:
510
516
  self._lowered.x_prop_unified.final[state._slice] = state.final
511
517
  self._lowered.x_prop_unified.final_type[state._slice] = state.final_type
512
518
 
513
- # Update CVXPy solver parameters (only if solver is initialized)
514
- if self._solver._problem is not None:
515
- self._solver.update_boundary_conditions(
516
- x_init=self._lowered.x_unified.initial,
517
- x_term=self._lowered.x_unified.final,
518
- )
519
+ # Push to the solver both backends short-circuit on a pre-initialize
520
+ # call, so this is safe to invoke from any lifecycle point.
521
+ self._solver.update_boundary_conditions(
522
+ x_init=self._lowered.x_unified.initial,
523
+ x_term=self._lowered.x_unified.final,
524
+ )
519
525
 
520
526
  def _sync_guesses(self):
521
527
  """Sync trajectory guesses from State/Control objects to lowered representation.
@@ -0,0 +1,93 @@
1
+ """Convex subproblem solvers for trajectory optimization.
2
+
3
+ This module provides implementations of convex subproblem solvers used within
4
+ SCvx algorithms. At each iteration of a successive convexification algorithm,
5
+ the non-convex problem is approximated by a convex subproblem, which is then
6
+ solved using one of these solver backends.
7
+
8
+ All solvers inherit from :class:`ConvexSolver`, enabling pluggable solver
9
+ implementations and custom backends:
10
+
11
+ ```python
12
+ class ConvexSolver(ABC):
13
+ @abstractmethod
14
+ def create_variables(self, N, x_unified, u_unified, jax_constraints) -> None:
15
+ '''Create backend-specific optimization variables (called once).'''
16
+ ...
17
+
18
+ @abstractmethod
19
+ def initialize(self, lowered, settings) -> None:
20
+ '''Build the convex subproblem structure (called once).'''
21
+ ...
22
+
23
+ @abstractmethod
24
+ def solve(self, state, params, settings) -> Any:
25
+ '''Update parameters and solve (called each iteration).'''
26
+ ...
27
+ ```
28
+
29
+ The Penalized Trust-Region (PTR) subproblem ships with two concrete backends:
30
+
31
+ - :class:`CVXPyPTRSolver` — DCP graph via CVXPy, dispatched to any of its
32
+ supported conic solvers (QOCO, CLARABEL, ...). Optional code generation
33
+ via cvxpygen for improved per-iteration performance.
34
+ - :class:`QPAXPTRSolver` — flat ``(Q, q, A, b, G, h)`` assembled as JAX
35
+ arrays and solved with ``qpax.solve_qp``. Aimed at end-to-end JAX
36
+ differentiability of the SCP loop (follow-up work).
37
+
38
+ Both share the abstract :class:`PTRSolver` contract.
39
+
40
+ Note:
41
+ Solvers own their optimization variables (e.g., ``CVXPySolver.ocp_vars``).
42
+ The lowering process calls ``solver.create_variables()`` before constraint
43
+ lowering, then ``solver.initialize()`` after. See :mod:`openscvx.solvers.base`
44
+ for the interface details.
45
+ """
46
+
47
+ import warnings
48
+ from typing import Any
49
+
50
+ from .base import ConvexSolver, PTRSolverSpec
51
+ from .cvxpy_ptr_solver import CVXPyPTRSolver
52
+ from .ptr_solver import PTRSolver, PTRSolveResult
53
+
54
+
55
+ def resolve_solver_config(val: Any) -> PTRSolverSpec:
56
+ """Validate a dict / Spec into a :class:`PTRSolverSpec` instance."""
57
+ if isinstance(val, PTRSolverSpec):
58
+ return val
59
+ return PTRSolverSpec.model_validate(val)
60
+
61
+
62
+ def __getattr__(name: str):
63
+ """Deprecated alias: ``SolverSpec`` → :class:`PTRSolverSpec`."""
64
+ if name == "SolverSpec":
65
+ warnings.warn(
66
+ "openscvx.solvers.SolverSpec is deprecated; use PTRSolverSpec.",
67
+ DeprecationWarning,
68
+ stacklevel=2,
69
+ )
70
+ return PTRSolverSpec
71
+ if name == "QPAXPTRSolver":
72
+ # Lazy import so users without the qpax extra don't pay a hard
73
+ # ImportError just for `from openscvx.solvers import QPAXPTRSolver`
74
+ # — the import error gets deferred to instantiation time, where the
75
+ # error message points at the install command.
76
+ from .qpax_ptr_solver import QPAXPTRSolver
77
+
78
+ return QPAXPTRSolver
79
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
80
+
81
+
82
+ __all__ = [
83
+ # Base classes
84
+ "ConvexSolver",
85
+ "PTRSolver",
86
+ "PTRSolveResult",
87
+ # PTR backends
88
+ "CVXPyPTRSolver",
89
+ "QPAXPTRSolver",
90
+ # Config
91
+ "PTRSolverSpec",
92
+ "resolve_solver_config",
93
+ ]
@@ -5,40 +5,29 @@ must follow for use within successive convexification algorithms.
5
5
 
6
6
  !!! note
7
7
 
8
- Solvers own their optimization variables via ``create_variables()``.
9
- Convex constraint lowering remains in ``lower.py`` but uses the solver's
10
- variables.
11
-
12
- When adding non-CVXPy backends, there are two approaches:
13
-
14
- 1. **Solver owns the lowerer**: The solver implements a
15
- ``lower_convex_constraints()`` method containing the lowering logic.
16
-
17
- 2. **Solver determines the lowerer**: The solver references which lowerer
18
- to use, but the lowering logic stays in ``lower.py``. Example:
19
-
20
- ```python
21
- # In solver
22
- @property
23
- def lowerer(self):
24
- from openscvx.symbolic.lower import lower_cvxpy_constraints
25
- return lower_cvxpy_constraints
26
-
27
- # In lower_symbolic_problem()
28
- lowered_constraints = solver.lowerer(constraints, solver.variables, parameters)
29
- ```
8
+ Solvers own both their optimization variables (``create_variables()``) and
9
+ the lowering of any user ``.convex()`` constraints
10
+ (``lower_convex_constraints()``). The default ``lower_convex_constraints``
11
+ refuses user ``.convex()`` constraints with a clear error — backends that
12
+ accept them override it. This keeps ``openscvx.symbolic.lower``
13
+ backend-agnostic: it never branches on solver type, it just delegates.
14
+
15
+ See :class:`openscvx.solvers.ptr_solver.PTRSolver` for the PTR-specific
16
+ interface every PTR backend implements.
30
17
  """
31
18
 
19
+ import warnings
32
20
  from abc import ABC, abstractmethod
33
- from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional
21
+ from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Tuple
34
22
 
35
- from pydantic import BaseModel, ConfigDict
23
+ from pydantic import BaseModel, ConfigDict, model_validator
36
24
 
37
25
  if TYPE_CHECKING:
38
26
  from openscvx.config import Config
39
27
  from openscvx.lowered import LoweredProblem
40
28
  from openscvx.lowered.jax_constraints import LoweredJaxConstraints
41
29
  from openscvx.lowered.unified import UnifiedControl, UnifiedState
30
+ from openscvx.symbolic.constraint_set import ConstraintSet
42
31
 
43
32
 
44
33
  class ConvexSolver(ABC):
@@ -91,10 +80,6 @@ class ConvexSolver(ABC):
91
80
  return MyResult(...)
92
81
  """
93
82
 
94
- #: Backend solver name (e.g., ``"QOCO"``, ``"CLARABEL"``). Subclasses
95
- #: must set this in ``__init__``.
96
- cvx_solver: str
97
-
98
83
  @abstractmethod
99
84
  def create_variables(
100
85
  self,
@@ -128,6 +113,50 @@ class ConvexSolver(ABC):
128
113
  """
129
114
  raise NotImplementedError
130
115
 
116
+ def lower_convex_constraints(
117
+ self,
118
+ constraints: "ConstraintSet",
119
+ parameters: Optional[Dict[str, Any]] = None,
120
+ ) -> Tuple[List[Any], Dict[str, Any]]:
121
+ """Lower user ``.convex()`` constraints into this backend's form.
122
+
123
+ Called once by :func:`openscvx.symbolic.lower.lower_symbolic_problem`
124
+ after ``create_variables()`` and before ``initialize()``.
125
+
126
+ The default implementation refuses any user ``.convex()``
127
+ constraints — appropriate for backends like
128
+ :class:`openscvx.solvers.qpax_ptr_solver.QPAXPTRSolver` that don't
129
+ accept second-order-cone constraints. Backends that do accept them
130
+ (e.g. :class:`openscvx.solvers.cvxpy_ptr_solver.CVXPyPTRSolver`)
131
+ override this to invoke their backend-specific lowerer.
132
+
133
+ Args:
134
+ constraints: Categorized symbolic constraints. Only the
135
+ ``nodal_convex`` / ``cross_node_convex`` lists matter here;
136
+ non-convex constraints go through the JAX lowering pipeline.
137
+ parameters: Optional dict of symbolic ``Parameter`` objects
138
+ referenced by the constraints. May be ``None``.
139
+
140
+ Returns:
141
+ ``(lowered_list, parameter_map)``. The first is a list of
142
+ backend-specific constraint objects (e.g. ``cp.Constraint``);
143
+ the second maps parameter names to backend-specific parameter
144
+ objects. Both are empty for the default refusal path.
145
+
146
+ Raises:
147
+ NotImplementedError: if the user defined any ``.convex()``
148
+ constraints and this backend doesn't override.
149
+ """
150
+ n = len(constraints.nodal_convex) + len(constraints.cross_node_convex)
151
+ if n:
152
+ raise NotImplementedError(
153
+ f"{type(self).__name__} does not support user-defined "
154
+ f".convex() constraints ({n} defined). Drop the .convex() "
155
+ "constraint or switch to a backend that supports them "
156
+ "(e.g. openscvx.CVXPyPTRSolver)."
157
+ )
158
+ return [], {}
159
+
131
160
  @abstractmethod
132
161
  def initialize(
133
162
  self,
@@ -241,11 +270,17 @@ class ConvexSolver(ABC):
241
270
  # Pydantic spec for dict / YAML validation
242
271
  # =============================================================================
243
272
 
244
- _SOLVER_MAP: Dict[str, type] = {} # populated by __init__.py after all classes are imported
245
273
 
274
+ class PTRSolverSpec(BaseModel):
275
+ """Validates PTR solver configuration from dict/YAML input.
246
276
 
247
- class SolverSpec(BaseModel):
248
- """Validates solver configuration from dict/YAML input.
277
+ The ``backend`` discriminator selects which concrete PTR backend to build:
278
+ ``"cvxpy"`` (the default,
279
+ :class:`openscvx.solvers.cvxpy_ptr_solver.CVXPyPTRSolver`) or ``"qpax"``
280
+ (:class:`openscvx.solvers.qpax_ptr_solver.QPAXPTRSolver`).
281
+
282
+ ``cvx_solver``, ``cvxpygen``, and ``cvxpygen_override`` are CVXPy-only;
283
+ setting them under ``backend="qpax"`` is a configuration error.
249
284
 
250
285
  !!! warning
251
286
  Enabling ``cvxpygen`` currently disables sparse parameter declarations.
@@ -255,15 +290,61 @@ class SolverSpec(BaseModel):
255
290
  """
256
291
 
257
292
  type: Literal["PTRSolver"] = "PTRSolver"
258
- cvx_solver: str = "QOCO"
293
+ backend: Literal["cvxpy", "qpax"] = "cvxpy"
294
+ cvx_solver: Optional[str] = None
259
295
  solver_args: Optional[Dict[str, Any]] = None
260
296
  cvxpygen: bool = False
261
297
  cvxpygen_override: bool = False
262
298
 
263
299
  model_config = ConfigDict(extra="forbid")
264
300
 
301
+ @model_validator(mode="after")
302
+ def _check_backend_fields(self):
303
+ if self.backend == "qpax":
304
+ offenders = [
305
+ name
306
+ for name, value in (
307
+ ("cvx_solver", self.cvx_solver),
308
+ ("cvxpygen", self.cvxpygen),
309
+ ("cvxpygen_override", self.cvxpygen_override),
310
+ )
311
+ if value
312
+ ]
313
+ if offenders:
314
+ raise ValueError(
315
+ f"{offenders} only valid for backend='cvxpy'; "
316
+ "remove these fields or set backend='cvxpy'."
317
+ )
318
+ return self
319
+
265
320
  def build(self) -> ConvexSolver:
266
- cls = _SOLVER_MAP.get(self.type)
267
- if cls is None:
268
- raise ValueError(f"Unknown solver {self.type!r}; expected one of {sorted(_SOLVER_MAP)}")
269
- return cls(**self.model_dump(exclude={"type"}, exclude_unset=True))
321
+ # Local imports keep CVXPy / qpax out of the import path until the
322
+ # corresponding backend is actually requested.
323
+ if self.backend == "cvxpy":
324
+ from .cvxpy_ptr_solver import CVXPyPTRSolver
325
+
326
+ return CVXPyPTRSolver(
327
+ cvx_solver=self.cvx_solver or "QOCO",
328
+ solver_args=self.solver_args,
329
+ cvxpygen=self.cvxpygen,
330
+ cvxpygen_override=self.cvxpygen_override,
331
+ )
332
+ from .qpax_ptr_solver import QPAXPTRSolver
333
+
334
+ return QPAXPTRSolver(solver_args=self.solver_args)
335
+
336
+
337
+ def __getattr__(name: str):
338
+ """Deprecated alias: ``SolverSpec`` → :class:`PTRSolverSpec`.
339
+
340
+ Kept for one release so existing dict/YAML configs and tests that import
341
+ ``SolverSpec`` continue to work. Emit a ``DeprecationWarning`` on access.
342
+ """
343
+ if name == "SolverSpec":
344
+ warnings.warn(
345
+ "openscvx.solvers.base.SolverSpec is deprecated; use PTRSolverSpec.",
346
+ DeprecationWarning,
347
+ stacklevel=2,
348
+ )
349
+ return PTRSolverSpec
350
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")