openscvx 2.dev5__tar.gz → 2.dev7__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.
- {openscvx-2.dev5/openscvx.egg-info → openscvx-2.dev7}/PKG-INFO +3 -1
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UnderTheHood/lowering_architecture.md +31 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/__init__.py +18 -1
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/_version.py +3 -3
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/algorithms/__init__.py +13 -4
- openscvx-2.dev7/openscvx/algorithms/autotuner/__init__.py +17 -0
- openscvx-2.dev7/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +190 -0
- {openscvx-2.dev5/openscvx/algorithms → openscvx-2.dev7/openscvx/algorithms/autotuner}/augmented_lagrangian.py +9 -5
- {openscvx-2.dev5/openscvx/algorithms → openscvx-2.dev7/openscvx/algorithms/autotuner}/constant_proximal_weight.py +3 -3
- {openscvx-2.dev5/openscvx/algorithms → openscvx-2.dev7/openscvx/algorithms/autotuner}/ramp_proximal_weight.py +3 -3
- openscvx-2.dev7/openscvx/algorithms/scvx/__init__.py +5 -0
- {openscvx-2.dev5/openscvx/algorithms → openscvx-2.dev7/openscvx/algorithms/scvx}/penalized_trust_region.py +6 -6
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/loader.py +2 -2
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/cvxpy_constraints.py +4 -1
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/problem.py +19 -13
- openscvx-2.dev7/openscvx/solvers/__init__.py +93 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/solvers/base.py +117 -36
- openscvx-2.dev5/openscvx/solvers/ptr_solver.py → openscvx-2.dev7/openscvx/solvers/cvxpy_ptr_solver.py +49 -86
- openscvx-2.dev7/openscvx/solvers/ptr_solver.py +196 -0
- openscvx-2.dev7/openscvx/solvers/qpax_ptr_solver.py +776 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lower.py +6 -7
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/utils/printing.py +9 -1
- {openscvx-2.dev5 → openscvx-2.dev7/openscvx.egg-info}/PKG-INFO +3 -1
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx.egg-info/SOURCES.txt +11 -4
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx.egg-info/requires.txt +3 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/pyproject.toml +3 -0
- openscvx-2.dev7/tests/solvers/test_qpax_ptr_solver.py +238 -0
- openscvx-2.dev7/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_autotuning.py +196 -4
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_brachistochrone.py +111 -3
- openscvx-2.dev5/openscvx/solvers/__init__.py +0 -76
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/assets/logo.svg +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/release-drafter.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/_docs.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/branch-name.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/docs.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/lint.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/nightly.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/release.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.gitignore +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/.gitmodules +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/CONTRIBUTING.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/LICENSE +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/README.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/Foundations/discretization.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/Foundations/ocp.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/Foundations/scvx.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/favicon.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/logo.svg +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/viser-client/index.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/citation.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/examples.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/index.md +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/javascripts/mathjax.js +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/docs/versions.json +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/_viser_embed_export.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/abstract/impulsive.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/abstract/stl_or.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/_camera.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/_render.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/_sensor_view.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/logo.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/car/dubins_car.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/cinema_vp.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/dr_vp.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/drone_racing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/logo.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/plotting.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/plotting_viser.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/ctlos_cine.gif +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/ctlos_dr.gif +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/dtlos_cine.gif +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/dtlos_dr.gif +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/openscvx_logo.svg +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/openscvx_logo_square.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/figures/video_preview.png +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/home.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/main.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/mkdocs.yml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/__main__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/algorithms/base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/algorithms/weights.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/config.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/expert/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/expert/byof.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/expert/lowering.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/expert/validation.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/init/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/init/interpolation.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/integrations/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/integrations/base.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/integrations/mjx.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/integrators/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/parameters.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/problem.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/lowered/unified.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/plotting.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/propagation/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/propagation/propagation.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/builder.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/problem.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/symbolic/unified.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/utils/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/utils/cache.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/utils/caching.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/utils/profiling.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx/utils/utils.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/scripts/gen_example_pages.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/scripts/gen_ref_pages.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/setup.cfg +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/expr/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/expr/test_gmsr.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/hohmann_analytical.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/integrations/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/integrations/test_mjx.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-2.dev5/tests/symbolic → openscvx-2.dev7/tests/solvers}/__init__.py +0 -0
- {openscvx-2.dev5/tests/symbolic/expr → openscvx-2.dev7/tests/symbolic}/__init__.py +0 -0
- {openscvx-2.dev5/tests/symbolic/parser → openscvx-2.dev7/tests/symbolic/expr}/__init__.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/symbolic/test_unified.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_discretization.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_examples.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_expert.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_impulsive.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_init.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_integrators.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_loader.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_optimization_results.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_plotting.py +0 -0
- {openscvx-2.dev5 → openscvx-2.dev7}/tests/test_propagation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.dev7
|
|
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
|
|
@@ -12,6 +12,7 @@ import openscvx.symbolic.expr.spatial as spatial
|
|
|
12
12
|
import openscvx.symbolic.expr.stl as stl
|
|
13
13
|
import openscvx.symbolic.expr.stljax as stljax
|
|
14
14
|
from openscvx.algorithms import (
|
|
15
|
+
AdaptiveProximalWeight,
|
|
15
16
|
AugmentedLagrangian,
|
|
16
17
|
ConstantProximalWeight,
|
|
17
18
|
PenalizedTrustRegion,
|
|
@@ -28,7 +29,10 @@ from openscvx.expert import ByofSpec
|
|
|
28
29
|
from openscvx.integrations import DynamicsAdapter, MjxDynamics
|
|
29
30
|
from openscvx.loader import load_dict, load_json, load_yaml
|
|
30
31
|
from openscvx.problem import Problem
|
|
31
|
-
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.
|
|
32
36
|
from openscvx.symbolic.expr import (
|
|
33
37
|
CTCS,
|
|
34
38
|
Abs,
|
|
@@ -90,6 +94,16 @@ from openscvx.utils.cache import clear_cache, get_cache_dir, get_cache_size
|
|
|
90
94
|
|
|
91
95
|
load_results = OptimizationResults.load
|
|
92
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
|
+
|
|
93
107
|
__all__ = [
|
|
94
108
|
# Main Trajectory Optimization Entrypoint
|
|
95
109
|
"Problem",
|
|
@@ -187,9 +201,12 @@ __all__ = [
|
|
|
187
201
|
"VectorizeDiscretizeLinearize",
|
|
188
202
|
# Convex Solver
|
|
189
203
|
"PTRSolver",
|
|
204
|
+
"CVXPyPTRSolver",
|
|
205
|
+
"QPAXPTRSolver",
|
|
190
206
|
# Algorithm & Autotuning
|
|
191
207
|
"PenalizedTrustRegion",
|
|
192
208
|
"AugmentedLagrangian",
|
|
209
|
+
"AdaptiveProximalWeight",
|
|
193
210
|
"ConstantProximalWeight",
|
|
194
211
|
"RampProximalWeight",
|
|
195
212
|
]
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, '
|
|
21
|
+
__version__ = version = '2.dev7'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 'dev7')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g3a34d4fce'
|
|
@@ -82,12 +82,19 @@ from typing import Annotated, Any, Dict, List, Optional, Union
|
|
|
82
82
|
|
|
83
83
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
84
84
|
|
|
85
|
-
from .
|
|
85
|
+
from .autotuner import (
|
|
86
|
+
AdaptiveProximalWeight,
|
|
87
|
+
AdaptiveProximalWeightSpec,
|
|
88
|
+
AugmentedLagrangian,
|
|
89
|
+
AugmentedLagrangianSpec,
|
|
90
|
+
ConstantProximalWeight,
|
|
91
|
+
ConstantProximalWeightSpec,
|
|
92
|
+
RampProximalWeight,
|
|
93
|
+
RampProximalWeightSpec,
|
|
94
|
+
)
|
|
86
95
|
from .base import Algorithm, AlgorithmState, AutotuningBase, DiscretizationResult
|
|
87
|
-
from .constant_proximal_weight import ConstantProximalWeight, ConstantProximalWeightSpec
|
|
88
96
|
from .optimization_results import OptimizationResults
|
|
89
|
-
from .
|
|
90
|
-
from .ramp_proximal_weight import RampProximalWeight, RampProximalWeightSpec
|
|
97
|
+
from .scvx import PenalizedTrustRegion
|
|
91
98
|
from .weights import Weights
|
|
92
99
|
|
|
93
100
|
# ---------------------------------------------------------------------------
|
|
@@ -97,6 +104,7 @@ from .weights import Weights
|
|
|
97
104
|
AutotunerConfig = Annotated[
|
|
98
105
|
Union[
|
|
99
106
|
AugmentedLagrangianSpec,
|
|
107
|
+
AdaptiveProximalWeightSpec,
|
|
100
108
|
RampProximalWeightSpec,
|
|
101
109
|
ConstantProximalWeightSpec,
|
|
102
110
|
],
|
|
@@ -173,6 +181,7 @@ __all__ = [
|
|
|
173
181
|
"PenalizedTrustRegion",
|
|
174
182
|
"AutotuningBase",
|
|
175
183
|
"AugmentedLagrangian",
|
|
184
|
+
"AdaptiveProximalWeight",
|
|
176
185
|
"ConstantProximalWeight",
|
|
177
186
|
"RampProximalWeight",
|
|
178
187
|
# Config models
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""SCP weight autotuning strategies."""
|
|
2
|
+
|
|
3
|
+
from .adaptive_proximal_weight import AdaptiveProximalWeight, AdaptiveProximalWeightSpec
|
|
4
|
+
from .augmented_lagrangian import AugmentedLagrangian, AugmentedLagrangianSpec
|
|
5
|
+
from .constant_proximal_weight import ConstantProximalWeight, ConstantProximalWeightSpec
|
|
6
|
+
from .ramp_proximal_weight import RampProximalWeight, RampProximalWeightSpec
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"AdaptiveProximalWeight",
|
|
10
|
+
"AdaptiveProximalWeightSpec",
|
|
11
|
+
"AugmentedLagrangian",
|
|
12
|
+
"AugmentedLagrangianSpec",
|
|
13
|
+
"ConstantProximalWeight",
|
|
14
|
+
"ConstantProximalWeightSpec",
|
|
15
|
+
"RampProximalWeight",
|
|
16
|
+
"RampProximalWeightSpec",
|
|
17
|
+
]
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Autotuning functions for SCP (Successive Convex Programming) parameters."""
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from typing import TYPE_CHECKING, Literal
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from pydantic import BaseModel, ConfigDict
|
|
8
|
+
|
|
9
|
+
from openscvx.config import Config
|
|
10
|
+
|
|
11
|
+
from ..base import AutotuningBase
|
|
12
|
+
from .augmented_lagrangian import AugmentedLagrangian
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from openscvx.lowered import LoweredJaxConstraints
|
|
16
|
+
|
|
17
|
+
from ..base import AlgorithmState, CandidateIterate
|
|
18
|
+
from ..weights import Weights
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AdaptiveProximalWeight(AutotuningBase):
|
|
22
|
+
"""PTR-style proximal adaptation with fixed virtual penalty weights.
|
|
23
|
+
|
|
24
|
+
Same acceptance-ratio logic as :class:`AugmentedLagrangian` for ``lam_prox``,
|
|
25
|
+
but ``lam_vc`` and ``lam_vb_*`` are held constant at their current state values.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
COLUMNS = AugmentedLagrangian.COLUMNS
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
gamma_1: float = 2.0,
|
|
33
|
+
gamma_2: float = 0.5,
|
|
34
|
+
eta_0: float = 1e-2,
|
|
35
|
+
eta_1: float = 1e-1,
|
|
36
|
+
eta_2: float = 0.8,
|
|
37
|
+
lam_prox_min: float = 1e-3,
|
|
38
|
+
lam_prox_max: float = 1e4,
|
|
39
|
+
lam_cost_drop: int = -1,
|
|
40
|
+
lam_cost_relax: float = 1.0,
|
|
41
|
+
):
|
|
42
|
+
self.gamma_1 = gamma_1
|
|
43
|
+
self.gamma_2 = gamma_2
|
|
44
|
+
self.eta_0 = eta_0
|
|
45
|
+
self.eta_1 = eta_1
|
|
46
|
+
self.eta_2 = eta_2
|
|
47
|
+
self.lam_prox_min = lam_prox_min
|
|
48
|
+
self.lam_prox_max = lam_prox_max
|
|
49
|
+
self.lam_cost_drop = lam_cost_drop
|
|
50
|
+
self.lam_cost_relax = lam_cost_relax
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def _copy_virtual_weights(
|
|
54
|
+
candidate: "CandidateIterate",
|
|
55
|
+
state: "AlgorithmState",
|
|
56
|
+
) -> None:
|
|
57
|
+
candidate.lam_vc = state.lam_vc
|
|
58
|
+
candidate.lam_vb_nodal = state.lam_vb_nodal
|
|
59
|
+
candidate.lam_vb_cross = state.lam_vb_cross
|
|
60
|
+
|
|
61
|
+
def update_weights(
|
|
62
|
+
self,
|
|
63
|
+
state: "AlgorithmState",
|
|
64
|
+
candidate: "CandidateIterate",
|
|
65
|
+
nodal_constraints: "LoweredJaxConstraints",
|
|
66
|
+
settings: Config,
|
|
67
|
+
params: dict,
|
|
68
|
+
weights: "Weights",
|
|
69
|
+
) -> str:
|
|
70
|
+
"""Update SCP proximal weight based on acceptance ratio; keep VC/VB fixed."""
|
|
71
|
+
candidate_x_prop = (
|
|
72
|
+
candidate.x_prop_plus[1:] if candidate.x_prop_plus is not None else candidate.x_prop
|
|
73
|
+
)
|
|
74
|
+
(
|
|
75
|
+
nonlinear_cost,
|
|
76
|
+
nonlinear_penalty,
|
|
77
|
+
nodal_penalty,
|
|
78
|
+
) = self.calculate_nonlinear_penalty(
|
|
79
|
+
candidate_x_prop,
|
|
80
|
+
candidate.x,
|
|
81
|
+
candidate.u,
|
|
82
|
+
state.lam_vc,
|
|
83
|
+
state.lam_vb_nodal,
|
|
84
|
+
state.lam_vb_cross,
|
|
85
|
+
state.lam_cost,
|
|
86
|
+
nodal_constraints,
|
|
87
|
+
params,
|
|
88
|
+
settings,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
candidate.J_nonlin = nonlinear_cost + nonlinear_penalty + nodal_penalty
|
|
92
|
+
|
|
93
|
+
if state.k > self.lam_cost_drop:
|
|
94
|
+
candidate.lam_cost = state.lam_cost * self.lam_cost_relax
|
|
95
|
+
else:
|
|
96
|
+
candidate.lam_cost = weights.lam_cost
|
|
97
|
+
|
|
98
|
+
lam_prox_k = deepcopy(state.lam_prox)
|
|
99
|
+
|
|
100
|
+
if state.k > 1:
|
|
101
|
+
state_x_prop_plus = state.x_prop_plus()
|
|
102
|
+
state_x_prop = (
|
|
103
|
+
state_x_prop_plus[1:] if state_x_prop_plus is not None else state.x_prop()
|
|
104
|
+
)
|
|
105
|
+
(
|
|
106
|
+
prev_nonlinear_cost,
|
|
107
|
+
prev_nonlinear_penalty,
|
|
108
|
+
prev_nodal_penalty,
|
|
109
|
+
) = self.calculate_nonlinear_penalty(
|
|
110
|
+
state_x_prop,
|
|
111
|
+
state.x,
|
|
112
|
+
state.u,
|
|
113
|
+
state.lam_vc,
|
|
114
|
+
state.lam_vb_nodal,
|
|
115
|
+
state.lam_vb_cross,
|
|
116
|
+
state.lam_cost,
|
|
117
|
+
nodal_constraints,
|
|
118
|
+
params,
|
|
119
|
+
settings,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
J_nonlin_prev = prev_nonlinear_cost + prev_nonlinear_penalty + prev_nodal_penalty
|
|
123
|
+
|
|
124
|
+
actual_reduction = J_nonlin_prev - candidate.J_nonlin
|
|
125
|
+
predicted_reduction = J_nonlin_prev - candidate.J_lin
|
|
126
|
+
|
|
127
|
+
if predicted_reduction == 0:
|
|
128
|
+
raise ValueError("Predicted reduction is 0.")
|
|
129
|
+
|
|
130
|
+
rho = actual_reduction / predicted_reduction
|
|
131
|
+
|
|
132
|
+
state.pred_reduction_history.append(predicted_reduction)
|
|
133
|
+
state.actual_reduction_history.append(actual_reduction)
|
|
134
|
+
state.acceptance_ratio_history.append(rho)
|
|
135
|
+
|
|
136
|
+
if rho < self.eta_0:
|
|
137
|
+
lam_prox_k1 = np.minimum(self.lam_prox_max, self.gamma_1 * lam_prox_k)
|
|
138
|
+
candidate.lam_prox = lam_prox_k1
|
|
139
|
+
state.reject_solution(candidate)
|
|
140
|
+
adaptive_state = "Reject Higher"
|
|
141
|
+
elif rho >= self.eta_0 and rho < self.eta_1:
|
|
142
|
+
lam_prox_k1 = np.minimum(self.lam_prox_max, self.gamma_1 * lam_prox_k)
|
|
143
|
+
candidate.lam_prox = lam_prox_k1
|
|
144
|
+
self._copy_virtual_weights(candidate, state)
|
|
145
|
+
state.accept_solution(candidate)
|
|
146
|
+
adaptive_state = "Accept Higher"
|
|
147
|
+
elif rho >= self.eta_1 and rho < self.eta_2:
|
|
148
|
+
candidate.lam_prox = lam_prox_k
|
|
149
|
+
self._copy_virtual_weights(candidate, state)
|
|
150
|
+
state.accept_solution(candidate)
|
|
151
|
+
adaptive_state = "Accept Constant"
|
|
152
|
+
else:
|
|
153
|
+
lam_prox_k1 = np.maximum(self.lam_prox_min, self.gamma_2 * lam_prox_k)
|
|
154
|
+
candidate.lam_prox = lam_prox_k1
|
|
155
|
+
self._copy_virtual_weights(candidate, state)
|
|
156
|
+
state.accept_solution(candidate)
|
|
157
|
+
adaptive_state = "Accept Lower"
|
|
158
|
+
|
|
159
|
+
else:
|
|
160
|
+
candidate.lam_prox = lam_prox_k
|
|
161
|
+
self._copy_virtual_weights(candidate, state)
|
|
162
|
+
state.accept_solution(candidate)
|
|
163
|
+
adaptive_state = "Initial"
|
|
164
|
+
|
|
165
|
+
return adaptive_state
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# =============================================================================
|
|
169
|
+
# Pydantic spec for dict / YAML validation
|
|
170
|
+
# =============================================================================
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class AdaptiveProximalWeightSpec(BaseModel):
|
|
174
|
+
"""Validates AdaptiveProximalWeight configuration from dict/YAML input."""
|
|
175
|
+
|
|
176
|
+
type: Literal["AdaptiveProximalWeight"] = "AdaptiveProximalWeight"
|
|
177
|
+
gamma_1: float = 2.0
|
|
178
|
+
gamma_2: float = 0.5
|
|
179
|
+
eta_0: float = 1e-2
|
|
180
|
+
eta_1: float = 1e-1
|
|
181
|
+
eta_2: float = 0.8
|
|
182
|
+
lam_prox_min: float = 1e-3
|
|
183
|
+
lam_prox_max: float = 1e4
|
|
184
|
+
lam_cost_drop: int = -1
|
|
185
|
+
lam_cost_relax: float = 1.0
|
|
186
|
+
|
|
187
|
+
model_config = ConfigDict(extra="forbid")
|
|
188
|
+
|
|
189
|
+
def build(self) -> AdaptiveProximalWeight:
|
|
190
|
+
return AdaptiveProximalWeight(**self.model_dump(exclude={"type"}, exclude_unset=True))
|
|
@@ -14,13 +14,13 @@ from openscvx.utils.printing import (
|
|
|
14
14
|
color_adaptive_state,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from ..base import AutotuningBase
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
20
|
from openscvx.lowered import LoweredJaxConstraints
|
|
21
21
|
|
|
22
|
-
from
|
|
23
|
-
from
|
|
22
|
+
from ..base import AlgorithmState, CandidateIterate
|
|
23
|
+
from ..weights import Weights
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class AugmentedLagrangian(AutotuningBase):
|
|
@@ -86,8 +86,12 @@ class AugmentedLagrangian(AutotuningBase):
|
|
|
86
86
|
eta_2: Threshold above which solution is accepted with lower weight.
|
|
87
87
|
Defaults to 0.8.
|
|
88
88
|
ep: Threshold for virtual control weight update (nu > ep vs nu <= ep).
|
|
89
|
-
Defaults to 0.
|
|
90
|
-
|
|
89
|
+
Must lie in (0, 1). Defaults to 0.99; when tuning, try 1e-1 if needed.
|
|
90
|
+
Typically tuned together with ``eta_lambda`` (often the first
|
|
91
|
+
parameters adjusted).
|
|
92
|
+
eta_lambda: Step size for virtual control weight update. Defaults to 1e1.
|
|
93
|
+
Typically tuned together with ``ep`` (often the first parameters
|
|
94
|
+
adjusted).
|
|
91
95
|
lam_vc_max: Maximum virtual control penalty weight. Defaults to 1e5.
|
|
92
96
|
lam_prox_min: Minimum trust region (proximal) weight. Defaults to 1e-3.
|
|
93
97
|
lam_prox_max: Maximum trust region (proximal) weight. Defaults to 2e5.
|
|
@@ -6,13 +6,13 @@ from pydantic import BaseModel, ConfigDict
|
|
|
6
6
|
|
|
7
7
|
from openscvx.config import Config
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from ..base import AutotuningBase
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
from openscvx.lowered import LoweredJaxConstraints
|
|
13
13
|
|
|
14
|
-
from
|
|
15
|
-
from
|
|
14
|
+
from ..base import AlgorithmState, CandidateIterate
|
|
15
|
+
from ..weights import Weights
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class ConstantProximalWeight(AutotuningBase):
|
|
@@ -7,13 +7,13 @@ from pydantic import BaseModel, ConfigDict
|
|
|
7
7
|
|
|
8
8
|
from openscvx.config import Config
|
|
9
9
|
|
|
10
|
-
from
|
|
10
|
+
from ..base import AutotuningBase
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
13
|
from openscvx.lowered import LoweredJaxConstraints
|
|
14
14
|
|
|
15
|
-
from
|
|
16
|
-
from
|
|
15
|
+
from ..base import AlgorithmState, CandidateIterate
|
|
16
|
+
from ..weights import Weights
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class RampProximalWeight(AutotuningBase):
|
|
@@ -22,11 +22,11 @@ from openscvx.utils.printing import (
|
|
|
22
22
|
color_prob_stat,
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
from .augmented_lagrangian import AugmentedLagrangian
|
|
26
|
-
from .
|
|
27
|
-
from .
|
|
28
|
-
from
|
|
29
|
-
from
|
|
25
|
+
from ..autotuner.augmented_lagrangian import AugmentedLagrangian
|
|
26
|
+
from ..autotuner.constant_proximal_weight import ConstantProximalWeight
|
|
27
|
+
from ..autotuner.ramp_proximal_weight import RampProximalWeight
|
|
28
|
+
from ..base import Algorithm, AlgorithmState, CandidateIterate
|
|
29
|
+
from ..weights import Weights
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
32
32
|
from openscvx.lowered import LoweredJaxConstraints
|
|
@@ -34,7 +34,7 @@ if TYPE_CHECKING:
|
|
|
34
34
|
from openscvx.symbolic.expr.control import Control
|
|
35
35
|
from openscvx.symbolic.expr.state import State
|
|
36
36
|
|
|
37
|
-
from
|
|
37
|
+
from ..base import AutotuningBase
|
|
38
38
|
|
|
39
39
|
warnings.filterwarnings("ignore")
|
|
40
40
|
|
|
@@ -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
|
|
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[
|
|
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 ``
|
|
204
|
+
- ``None`` — uses ``CVXPyPTRSolver()`` with defaults (QOCO backend).
|
|
205
205
|
- A ``ConvexSolver`` instance — used directly.
|
|
206
|
-
- A ``dict`` —
|
|
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.
|
|
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
|
-
|
|
397
|
-
``cvxpygen_override``
|
|
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
|
|
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
|
-
#
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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
|
+
]
|