openscvx 0.5.2.dev12__tar.gz → 0.5.2.dev14__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-0.5.2.dev12/openscvx.egg-info → openscvx-0.5.2.dev14}/PKG-INFO +1 -1
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UnderTheHood/lowering_architecture.md +2 -2
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/_version.py +3 -3
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/solvers/base.py +97 -6
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/solvers/moreau_ptr_solver.py +198 -51
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/solvers/ptr_solver.py +47 -1
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/solvers/qpax_ptr_solver.py +208 -71
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/solvers/test_moreau_ptr_solver.py +76 -1
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/solvers/test_qpax_ptr_solver.py +72 -1
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_impulsive.py +112 -16
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.gitignore +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/.gitmodules +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/LICENSE +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/README.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/citation.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/examples.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/index.md +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/docs/versions.json +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/_render.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/logo.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/logo.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/plotting.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/figures/video_preview.png +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/home.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/main.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/mkdocs.yml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/__main__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/config.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/loader.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/problem.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/utils/caching.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/utils/printing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx.egg-info/SOURCES.txt +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/pyproject.toml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/setup.cfg +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/_marks.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/conftest.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/expr/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/expr/test_gmsr.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_autotuning.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_discretization.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_examples.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_expert.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_init.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_integrators.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_loader.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_optimization_results.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_plotting.py +0 -0
- {openscvx-0.5.2.dev12 → openscvx-0.5.2.dev14}/tests/test_propagation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.5.2.
|
|
3
|
+
Version: 0.5.2.dev14
|
|
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
|
|
@@ -168,8 +168,8 @@ of the abstract `PTRSolver` base. Three backends ship today:
|
|
|
168
168
|
| Backend | Class | Selector | Notes |
|
|
169
169
|
|---------|-------|----------|-------|
|
|
170
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()
|
|
172
|
-
| Moreau | `MoreauPTRSolver` | `solver={"backend": "moreau"}` | JAX-native conic solver (`moreau.jax.Solver`). Sparse CSR assembly; SOC epigraphs for the L1 / pos PTR penalties (fewer variables and rows than QPAX). Warm-starts between SCP iterations. Same supported subset as QPAX. Paves the way for user `.convex()` SOC support in a follow-up. |
|
|
171
|
+
| QPAX | `QPAXPTRSolver` | `solver={"backend": "qpax"}` | JAX-native QP via `qpax.solve_qp`. Flat `(Q, q, A, b, G, h)` assembly. Supports box / dynamics (continuous and impulsive) / CTCS / boundary-Fix; **rejects** user `.convex()` and cross-node 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
|
+
| Moreau | `MoreauPTRSolver` | `solver={"backend": "moreau"}` | JAX-native conic solver (`moreau.jax.Solver`). Sparse CSR assembly; SOC epigraphs for the L1 / pos PTR penalties (fewer variables and rows than QPAX). Warm-starts between SCP iterations. Same supported subset as QPAX (continuous and impulsive dynamics). Paves the way for user `.convex()` SOC support in a follow-up. |
|
|
173
173
|
|
|
174
174
|
Picking a backend at construction time:
|
|
175
175
|
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.5.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 5, 2, '
|
|
21
|
+
__version__ = version = '0.5.2.dev14'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 2, 'dev14')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g78ea9d746'
|
|
@@ -281,9 +281,24 @@ class PTRSolverSpec(BaseModel):
|
|
|
281
281
|
or ``"moreau"``
|
|
282
282
|
(:class:`openscvx.solvers.moreau_ptr_solver.MoreauPTRSolver`).
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
284
|
+
Backend-specific fields mirror the constructor parameters of each class.
|
|
285
|
+
Fields that don't belong to the active backend are a configuration error
|
|
286
|
+
and raise ``ValidationError``.
|
|
287
|
+
|
|
288
|
+
CVXPy-only:
|
|
289
|
+
``cvx_solver``, ``cvxpygen``, ``cvxpygen_override``.
|
|
290
|
+
|
|
291
|
+
QPAX-only:
|
|
292
|
+
``solver_tol``.
|
|
293
|
+
|
|
294
|
+
Moreau-only:
|
|
295
|
+
``verbose``, ``device``, ``tol_gap_abs``, ``tol_feas``.
|
|
296
|
+
|
|
297
|
+
Shared between QPAX and Moreau:
|
|
298
|
+
``max_iter``.
|
|
299
|
+
|
|
300
|
+
All backends:
|
|
301
|
+
``solver_args`` (escape hatch for settings not covered by named fields).
|
|
287
302
|
|
|
288
303
|
!!! warning
|
|
289
304
|
Enabling ``cvxpygen`` currently disables sparse parameter declarations.
|
|
@@ -294,11 +309,27 @@ class PTRSolverSpec(BaseModel):
|
|
|
294
309
|
|
|
295
310
|
type: Literal["PTRSolver"] = "PTRSolver"
|
|
296
311
|
backend: Literal["cvxpy", "qpax", "moreau"] = "cvxpy"
|
|
312
|
+
|
|
313
|
+
# CVXPy-only
|
|
297
314
|
cvx_solver: Optional[str] = None
|
|
298
|
-
solver_args: Optional[Dict[str, Any]] = None
|
|
299
315
|
cvxpygen: bool = False
|
|
300
316
|
cvxpygen_override: bool = False
|
|
301
317
|
|
|
318
|
+
# QPAX-specific
|
|
319
|
+
solver_tol: Optional[float] = None
|
|
320
|
+
|
|
321
|
+
# Shared between QPAX and Moreau
|
|
322
|
+
max_iter: Optional[int] = None
|
|
323
|
+
|
|
324
|
+
# Moreau-specific
|
|
325
|
+
verbose: Optional[bool] = None
|
|
326
|
+
device: Optional[str] = None
|
|
327
|
+
tol_gap_abs: Optional[float] = None
|
|
328
|
+
tol_feas: Optional[float] = None
|
|
329
|
+
|
|
330
|
+
# Escape hatch for all backends
|
|
331
|
+
solver_args: Optional[Dict[str, Any]] = None
|
|
332
|
+
|
|
302
333
|
model_config = ConfigDict(extra="forbid")
|
|
303
334
|
|
|
304
335
|
@model_validator(mode="after")
|
|
@@ -318,6 +349,45 @@ class PTRSolverSpec(BaseModel):
|
|
|
318
349
|
f"{offenders} only valid for backend='cvxpy'; "
|
|
319
350
|
"remove these fields or set backend='cvxpy'."
|
|
320
351
|
)
|
|
352
|
+
if self.backend == "cvxpy":
|
|
353
|
+
offenders = [
|
|
354
|
+
name
|
|
355
|
+
for name, value in (
|
|
356
|
+
("solver_tol", self.solver_tol),
|
|
357
|
+
("max_iter", self.max_iter),
|
|
358
|
+
("verbose", self.verbose),
|
|
359
|
+
("device", self.device),
|
|
360
|
+
("tol_gap_abs", self.tol_gap_abs),
|
|
361
|
+
("tol_feas", self.tol_feas),
|
|
362
|
+
)
|
|
363
|
+
if value is not None
|
|
364
|
+
]
|
|
365
|
+
if offenders:
|
|
366
|
+
raise ValueError(
|
|
367
|
+
f"{offenders} not valid for backend='cvxpy'; pass these "
|
|
368
|
+
"via solver_args or switch to the qpax / moreau backend."
|
|
369
|
+
)
|
|
370
|
+
if self.backend == "qpax":
|
|
371
|
+
offenders = [
|
|
372
|
+
name
|
|
373
|
+
for name, value in (
|
|
374
|
+
("verbose", self.verbose),
|
|
375
|
+
("device", self.device),
|
|
376
|
+
("tol_gap_abs", self.tol_gap_abs),
|
|
377
|
+
("tol_feas", self.tol_feas),
|
|
378
|
+
)
|
|
379
|
+
if value is not None
|
|
380
|
+
]
|
|
381
|
+
if offenders:
|
|
382
|
+
raise ValueError(
|
|
383
|
+
f"{offenders} only valid for backend='moreau'; "
|
|
384
|
+
"remove these fields or set backend='moreau'."
|
|
385
|
+
)
|
|
386
|
+
if self.backend == "moreau" and self.solver_tol is not None:
|
|
387
|
+
raise ValueError(
|
|
388
|
+
"solver_tol is only valid for backend='qpax'; "
|
|
389
|
+
"remove this field or set backend='qpax'."
|
|
390
|
+
)
|
|
321
391
|
return self
|
|
322
392
|
|
|
323
393
|
def build(self) -> ConvexSolver:
|
|
@@ -335,10 +405,31 @@ class PTRSolverSpec(BaseModel):
|
|
|
335
405
|
if self.backend == "moreau":
|
|
336
406
|
from .moreau_ptr_solver import MoreauPTRSolver
|
|
337
407
|
|
|
338
|
-
|
|
408
|
+
kwargs: Dict[str, Any] = {}
|
|
409
|
+
if self.max_iter is not None:
|
|
410
|
+
kwargs["max_iter"] = self.max_iter
|
|
411
|
+
if self.verbose is not None:
|
|
412
|
+
kwargs["verbose"] = self.verbose
|
|
413
|
+
if self.device is not None:
|
|
414
|
+
kwargs["device"] = self.device
|
|
415
|
+
if self.tol_gap_abs is not None:
|
|
416
|
+
kwargs["tol_gap_abs"] = self.tol_gap_abs
|
|
417
|
+
if self.tol_feas is not None:
|
|
418
|
+
kwargs["tol_feas"] = self.tol_feas
|
|
419
|
+
if self.solver_args is not None:
|
|
420
|
+
kwargs["solver_args"] = self.solver_args
|
|
421
|
+
return MoreauPTRSolver(**kwargs)
|
|
422
|
+
|
|
339
423
|
from .qpax_ptr_solver import QPAXPTRSolver
|
|
340
424
|
|
|
341
|
-
|
|
425
|
+
kwargs = {}
|
|
426
|
+
if self.solver_tol is not None:
|
|
427
|
+
kwargs["solver_tol"] = self.solver_tol
|
|
428
|
+
if self.max_iter is not None:
|
|
429
|
+
kwargs["max_iter"] = self.max_iter
|
|
430
|
+
if self.solver_args is not None:
|
|
431
|
+
kwargs["solver_args"] = self.solver_args
|
|
432
|
+
return QPAXPTRSolver(**kwargs)
|
|
342
433
|
|
|
343
434
|
|
|
344
435
|
def __getattr__(name: str):
|
|
@@ -22,8 +22,15 @@ in ``jit``, ``jax.grad`` / ``jax.vmap`` can reach through a full SCvx solve
|
|
|
22
22
|
Scope:
|
|
23
23
|
* No user ``.convex()`` constraints — rejected upstream by
|
|
24
24
|
:meth:`ConvexSolver.lower_convex_constraints`.
|
|
25
|
-
* No cross-node
|
|
26
|
-
:
|
|
25
|
+
* No cross-node constraints — raises :class:`NotImplementedError` at
|
|
26
|
+
:meth:`MoreauPTRSolver.initialize`.
|
|
27
|
+
* Impulsive controls (``parameterization="impulsive"``) are supported.
|
|
28
|
+
``D_d`` is absorbed numerically into ``A_d / B_d / C_d`` at update
|
|
29
|
+
time and ``E_d`` enters the dynamics row on the impulsive control
|
|
30
|
+
slice; the initial Fix boundary condition picks up the linearized
|
|
31
|
+
impulse at node 0. The static CSR pattern reserves the
|
|
32
|
+
``du[0, slice_imp]`` columns in the initial-Fix rows so warm-start
|
|
33
|
+
structure stays valid across iterations.
|
|
27
34
|
* CTCS constraints are supported; LICQ-style absolute-value inequalities
|
|
28
35
|
are affine and fit in the nonneg cone.
|
|
29
36
|
|
|
@@ -75,6 +82,7 @@ if TYPE_CHECKING:
|
|
|
75
82
|
from openscvx.lowered import LoweredProblem
|
|
76
83
|
from openscvx.lowered.jax_constraints import LoweredJaxConstraints
|
|
77
84
|
from openscvx.lowered.unified import UnifiedControl, UnifiedState
|
|
85
|
+
from openscvx.symbolic.constraint_set import ConstraintSet
|
|
78
86
|
|
|
79
87
|
# Tiny diagonal regularisation added to P on dx/du slots. Moreau's IPM
|
|
80
88
|
# Cholesky factors (P + Gᵀ diag(z/s) G); keeping the diagonal positive avoids
|
|
@@ -218,12 +226,12 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
218
226
|
SOCP support in a follow-up.
|
|
219
227
|
|
|
220
228
|
Scope:
|
|
221
|
-
Supported — state/control box, dynamics linearization
|
|
222
|
-
uniform time grid, linearized nodal
|
|
229
|
+
Supported — state/control box, dynamics linearization (continuous
|
|
230
|
+
and impulsive), boundary Fix, uniform time grid, linearized nodal
|
|
231
|
+
nonconvex, CTCS LICQ rows.
|
|
223
232
|
|
|
224
|
-
Not supported — user ``.convex()`` constraints
|
|
225
|
-
constraints
|
|
226
|
-
:class:`NotImplementedError` with a "use
|
|
233
|
+
Not supported — user ``.convex()`` constraints and cross-node
|
|
234
|
+
constraints. Each raises :class:`NotImplementedError` with a "use
|
|
227
235
|
:class:`openscvx.solvers.cvxpy_ptr_solver.CVXPyPTRSolver`" pointer.
|
|
228
236
|
|
|
229
237
|
Differentiability hook for future work:
|
|
@@ -233,24 +241,75 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
233
241
|
through a full SCvx solve.
|
|
234
242
|
|
|
235
243
|
Args:
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
244
|
+
max_iter: Maximum number of IPM iterations forwarded to
|
|
245
|
+
:class:`moreau.Settings`. Defaults to ``200``.
|
|
246
|
+
verbose: Whether Moreau prints per-iteration diagnostics.
|
|
247
|
+
Forwarded to :class:`moreau.Settings`. Defaults to ``False``.
|
|
248
|
+
device: Compute device for Moreau's JAX kernels. One of
|
|
249
|
+
``"auto"``, ``"cpu"``, or ``"cuda"``. Forwarded to
|
|
250
|
+
:class:`moreau.Settings`. Defaults to ``"auto"``.
|
|
251
|
+
tol_gap_abs: Absolute duality-gap tolerance forwarded to
|
|
252
|
+
:class:`moreau.IPMSettings`. ``None`` uses Moreau's default.
|
|
253
|
+
tol_feas: Primal/dual feasibility tolerance forwarded to
|
|
254
|
+
:class:`moreau.IPMSettings`. ``None`` uses Moreau's default.
|
|
255
|
+
solver_args: Additional keyword arguments forwarded verbatim to
|
|
256
|
+
:class:`moreau.Settings`. Use for settings not covered by the
|
|
257
|
+
named params above. ``solver_args["ipm_settings"]`` may be a
|
|
258
|
+
dict or a :class:`moreau.IPMSettings` object; if it is a dict,
|
|
259
|
+
``tol_gap_abs`` / ``tol_feas`` are merged into it. Raises
|
|
260
|
+
``ValueError`` at construction time if any top-level key or
|
|
261
|
+
IPM tolerance overlaps with a named param.
|
|
241
262
|
|
|
242
263
|
Attributes:
|
|
243
264
|
layout: :class:`_ConicLayout` describing flat decision-vector slot
|
|
244
265
|
ranges. Populated by :meth:`create_variables`.
|
|
245
266
|
"""
|
|
246
267
|
|
|
247
|
-
def __init__(
|
|
268
|
+
def __init__(
|
|
269
|
+
self,
|
|
270
|
+
*,
|
|
271
|
+
max_iter: int = 200,
|
|
272
|
+
verbose: bool = False,
|
|
273
|
+
device: str = "auto",
|
|
274
|
+
tol_gap_abs: Optional[float] = None,
|
|
275
|
+
tol_feas: Optional[float] = None,
|
|
276
|
+
solver_args: Optional[Dict] = None,
|
|
277
|
+
):
|
|
248
278
|
if not _MOREAU_AVAILABLE:
|
|
249
279
|
raise ImportError(
|
|
250
280
|
"MoreauPTRSolver requires the `moreau` package. "
|
|
251
281
|
"Install it with: pip install openscvx[moreau]"
|
|
252
282
|
)
|
|
253
|
-
|
|
283
|
+
|
|
284
|
+
_named = {"max_iter": max_iter, "verbose": verbose, "device": device}
|
|
285
|
+
_extra = dict(solver_args) if solver_args else {}
|
|
286
|
+
_overlap = _named.keys() & _extra.keys()
|
|
287
|
+
if _overlap:
|
|
288
|
+
raise ValueError(
|
|
289
|
+
f"Moreau settings {sorted(_overlap)} appear as both named arguments "
|
|
290
|
+
"and inside solver_args; use one or the other."
|
|
291
|
+
)
|
|
292
|
+
merged = {**_named, **_extra}
|
|
293
|
+
|
|
294
|
+
_ipm = {
|
|
295
|
+
k: v for k, v in [("tol_gap_abs", tol_gap_abs), ("tol_feas", tol_feas)] if v is not None
|
|
296
|
+
}
|
|
297
|
+
if _ipm:
|
|
298
|
+
existing_ipm = merged.get("ipm_settings", {})
|
|
299
|
+
if not isinstance(existing_ipm, dict):
|
|
300
|
+
raise ValueError(
|
|
301
|
+
"Cannot combine tol_gap_abs / tol_feas named arguments with an "
|
|
302
|
+
"ipm_settings object in solver_args; use one form or the other."
|
|
303
|
+
)
|
|
304
|
+
ipm_overlap = _ipm.keys() & existing_ipm.keys()
|
|
305
|
+
if ipm_overlap:
|
|
306
|
+
raise ValueError(
|
|
307
|
+
f"Moreau IPM settings {sorted(ipm_overlap)} appear as both named "
|
|
308
|
+
"arguments and inside solver_args['ipm_settings']; use one or the other."
|
|
309
|
+
)
|
|
310
|
+
merged["ipm_settings"] = {**_ipm, **existing_ipm}
|
|
311
|
+
|
|
312
|
+
self.solver_args = merged
|
|
254
313
|
|
|
255
314
|
self.layout: Optional[_ConicLayout] = None
|
|
256
315
|
self._S_x: Optional[np.ndarray] = None
|
|
@@ -274,6 +333,11 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
274
333
|
self._coo_cols: Optional[np.ndarray] = None
|
|
275
334
|
self._n_con: int = 0
|
|
276
335
|
|
|
336
|
+
# Populated by lower_convex_constraints. Auto-augmented impulsive
|
|
337
|
+
# zero-pin constraints land here; any genuine user .convex() trips
|
|
338
|
+
# the default refusal.
|
|
339
|
+
self._impulsive_pins: List[Tuple[List[int], slice]] = []
|
|
340
|
+
|
|
277
341
|
# Per-iteration data, set by update_* methods.
|
|
278
342
|
self._dyn: dict = {}
|
|
279
343
|
self._cons: dict = {}
|
|
@@ -313,23 +377,12 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
313
377
|
jax_constraints: Lowered JAX constraints (nodal structure only).
|
|
314
378
|
dynamics_sparsity: Ignored.
|
|
315
379
|
constraint_sparsity: Ignored.
|
|
316
|
-
|
|
317
|
-
Raises:
|
|
318
|
-
NotImplementedError: If impulsive controls are present.
|
|
319
380
|
"""
|
|
320
381
|
del dynamics_sparsity, constraint_sparsity
|
|
321
382
|
|
|
322
383
|
n_x = len(x_unified.max)
|
|
323
384
|
n_u = len(u_unified.max)
|
|
324
385
|
|
|
325
|
-
slice_imp = u_unified.slice_impulsive
|
|
326
|
-
if slice_imp.stop > slice_imp.start:
|
|
327
|
-
raise NotImplementedError(
|
|
328
|
-
"MoreauPTRSolver does not support impulsive controls "
|
|
329
|
-
f"(u.slice_impulsive = {slice_imp!r}). "
|
|
330
|
-
"Use CVXPyPTRSolver for problems with impulsive dynamics."
|
|
331
|
-
)
|
|
332
|
-
|
|
333
386
|
S_x, c_x = self._scaling(x_unified)
|
|
334
387
|
S_u, c_u = self._scaling(u_unified)
|
|
335
388
|
|
|
@@ -345,6 +398,28 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
345
398
|
self.layout = _ConicLayout(N=N, n_x=n_x, n_u=n_u, n_nodal=len(jax_constraints.nodal))
|
|
346
399
|
self._jax_constraints = jax_constraints
|
|
347
400
|
|
|
401
|
+
def lower_convex_constraints(
|
|
402
|
+
self,
|
|
403
|
+
constraints: "ConstraintSet",
|
|
404
|
+
parameters: Optional[Dict] = None,
|
|
405
|
+
) -> Tuple[List, Dict]:
|
|
406
|
+
"""Absorb auto-generated impulsive zero-pin constraints; refuse the rest.
|
|
407
|
+
|
|
408
|
+
:func:`openscvx.symbolic.lower._augment_impulsive_constraints` injects
|
|
409
|
+
``Control == 0`` equalities at non-impulse nodes for every impulsive
|
|
410
|
+
control. Those constraints live in ``constraints.nodal_convex`` even
|
|
411
|
+
though no user ``.convex()`` was written; we recognize their fixed
|
|
412
|
+
shape and stash a pin list for the structural pass / assembler to
|
|
413
|
+
emit as plain zero-cone rows. Anything that doesn't match the
|
|
414
|
+
auto-augmentation shape (e.g. a genuine user ``.convex()`` SOC) falls
|
|
415
|
+
through to the default refusal in :class:`ConvexSolver`.
|
|
416
|
+
"""
|
|
417
|
+
pins = self._extract_impulsive_pins(constraints)
|
|
418
|
+
if pins is None:
|
|
419
|
+
return super().lower_convex_constraints(constraints, parameters)
|
|
420
|
+
self._impulsive_pins = pins
|
|
421
|
+
return [], {}
|
|
422
|
+
|
|
348
423
|
def initialize(self, lowered: "LoweredProblem", settings: "Config") -> None:
|
|
349
424
|
"""Build the static conic structure and construct ``moreau.jax.Solver``.
|
|
350
425
|
|
|
@@ -359,7 +434,7 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
359
434
|
|
|
360
435
|
Raises:
|
|
361
436
|
RuntimeError: If :meth:`create_variables` was not called first.
|
|
362
|
-
NotImplementedError: If cross-node
|
|
437
|
+
NotImplementedError: If cross-node constraints are present.
|
|
363
438
|
"""
|
|
364
439
|
if self.layout is None:
|
|
365
440
|
raise RuntimeError(
|
|
@@ -373,11 +448,6 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
373
448
|
f"({len(lowered.jax_constraints.cross_node)} defined). "
|
|
374
449
|
"Use CVXPyPTRSolver."
|
|
375
450
|
)
|
|
376
|
-
slice_imp = settings.sim.u.slice_impulsive
|
|
377
|
-
if slice_imp.stop > slice_imp.start:
|
|
378
|
-
raise NotImplementedError(
|
|
379
|
-
"MoreauPTRSolver does not support impulsive controls. Use CVXPyPTRSolver."
|
|
380
|
-
)
|
|
381
451
|
|
|
382
452
|
self._settings = settings
|
|
383
453
|
# Reset warm-start on new initialization (problem structure may change).
|
|
@@ -456,15 +526,42 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
456
526
|
D_d: Optional[np.ndarray] = None,
|
|
457
527
|
E_d: Optional[np.ndarray] = None,
|
|
458
528
|
) -> None:
|
|
459
|
-
|
|
460
|
-
|
|
529
|
+
A_eff = np.asarray(A_d, dtype=float)
|
|
530
|
+
B_eff = np.asarray(B_d, dtype=float)
|
|
531
|
+
C_eff = np.asarray(C_d, dtype=float)
|
|
532
|
+
|
|
533
|
+
# Absorb the impulsive state Jacobian into the continuous step
|
|
534
|
+
# matrices so the assembly row keeps a single A_d·dx + B_d·du term,
|
|
535
|
+
# matching the recipe in CVXPyPTRSolver.update_dynamics_linearization
|
|
536
|
+
# at openscvx/solvers/cvxpy_ptr_solver.py:636-654.
|
|
537
|
+
if D_d is not None:
|
|
538
|
+
D_arr = np.asarray(D_d, dtype=float)
|
|
539
|
+
if D_arr.ndim == 3 and D_arr.shape[0] == A_eff.shape[0] + 1:
|
|
540
|
+
D_steps = D_arr[1:]
|
|
541
|
+
elif D_arr.ndim == 3 and D_arr.shape[0] == A_eff.shape[0]:
|
|
542
|
+
D_steps = D_arr
|
|
543
|
+
else:
|
|
544
|
+
raise ValueError(
|
|
545
|
+
"Unexpected D_d shape for dynamics update: "
|
|
546
|
+
f"{D_arr.shape}, expected "
|
|
547
|
+
f"{(A_eff.shape[0] + 1, A_eff.shape[1], A_eff.shape[2])} "
|
|
548
|
+
f"or {(A_eff.shape[0], A_eff.shape[1], A_eff.shape[2])}."
|
|
549
|
+
)
|
|
550
|
+
A_eff = np.einsum("kij,kjl->kil", D_steps, A_eff)
|
|
551
|
+
B_eff = np.einsum("kij,kjl->kil", D_steps, B_eff)
|
|
552
|
+
C_eff = np.einsum("kij,kjl->kil", D_steps, C_eff)
|
|
553
|
+
|
|
461
554
|
self._dyn = {
|
|
462
555
|
"x_bar": np.asarray(x_bar, dtype=float),
|
|
463
556
|
"u_bar": np.asarray(u_bar, dtype=float),
|
|
464
|
-
"A_d":
|
|
465
|
-
"B_d":
|
|
466
|
-
"C_d":
|
|
557
|
+
"A_d": A_eff,
|
|
558
|
+
"B_d": B_eff,
|
|
559
|
+
"C_d": C_eff,
|
|
467
560
|
"x_prop": np.asarray(x_prop, dtype=float),
|
|
561
|
+
"x_prop_plus": (
|
|
562
|
+
np.asarray(x_prop_plus, dtype=float) if x_prop_plus is not None else None
|
|
563
|
+
),
|
|
564
|
+
"E_d": np.asarray(E_d, dtype=float) if E_d is not None else None,
|
|
468
565
|
}
|
|
469
566
|
|
|
470
567
|
def update_constraint_linearizations(
|
|
@@ -591,15 +688,32 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
591
688
|
add(row, L.nu_vb_idx(c_idx, node))
|
|
592
689
|
row += 1
|
|
593
690
|
|
|
594
|
-
# Fix boundary conditions (initial / terminal)
|
|
691
|
+
# Fix boundary conditions (initial / terminal). Under impulsive
|
|
692
|
+
# control the initial Fix row couples the post-impulse state at
|
|
693
|
+
# node 0 to du[0, slice_imp]; declare those columns structurally
|
|
694
|
+
# nonzero here so the static CSR pattern accommodates the
|
|
695
|
+
# numerical values emitted in _assemble_conic.
|
|
696
|
+
slice_imp = settings.sim.u.slice_impulsive
|
|
697
|
+
has_impulsive = slice_imp.stop > slice_imp.start
|
|
595
698
|
for i in range(settings.sim.true_state_slice.start, settings.sim.true_state_slice.stop):
|
|
596
699
|
if settings.sim.x.initial_type[i] == "Fix":
|
|
597
700
|
add(row, L.x_idx(0, i))
|
|
701
|
+
if has_impulsive:
|
|
702
|
+
for j in range(slice_imp.start, slice_imp.stop):
|
|
703
|
+
add(row, L.du_idx(0, j))
|
|
598
704
|
row += 1
|
|
599
705
|
if settings.sim.x.final_type[i] == "Fix":
|
|
600
706
|
add(row, L.x_idx(N - 1, i))
|
|
601
707
|
row += 1
|
|
602
708
|
|
|
709
|
+
# Impulsive zero-pin equalities: u[node, j] = const, one row per
|
|
710
|
+
# (node, j) absorbed by lower_convex_constraints.
|
|
711
|
+
for nodes, ctrl_slice in self._impulsive_pins:
|
|
712
|
+
for node in nodes:
|
|
713
|
+
for j in range(ctrl_slice.start, ctrl_slice.stop):
|
|
714
|
+
add(row, L.u_idx(node, j))
|
|
715
|
+
row += 1
|
|
716
|
+
|
|
603
717
|
# Uniform time grid: u[k,j] − u[k-1,j] = 0
|
|
604
718
|
if settings.sim._uniform_time_grid:
|
|
605
719
|
td = settings.sim.time_dilation_slice
|
|
@@ -725,8 +839,11 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
725
839
|
inv_S_x = self._inv_S_x_diag
|
|
726
840
|
inv_S_u = self._inv_S_u_diag
|
|
727
841
|
S_x = self._S_x_diag
|
|
842
|
+
S_u = self._S_u_diag
|
|
728
843
|
c_x = self._c_x
|
|
729
844
|
c_u = self._c_u
|
|
845
|
+
slice_imp = settings.sim.u.slice_impulsive
|
|
846
|
+
has_impulsive = slice_imp.stop > slice_imp.start
|
|
730
847
|
|
|
731
848
|
lam_prox = self._pen["lam_prox"] # (N, n_x + n_u)
|
|
732
849
|
lam_cost = self._pen["lam_cost"] # scalar or (n_x,)
|
|
@@ -739,6 +856,8 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
739
856
|
B_d = self._dyn["B_d"] # (N-1, n_x, n_u)
|
|
740
857
|
C_d = self._dyn["C_d"] # (N-1, n_x, n_u)
|
|
741
858
|
x_prop = self._dyn["x_prop"] # (N-1, n_x)
|
|
859
|
+
E_d_arr = self._dyn["E_d"] # (N, n_x, n_u) or None
|
|
860
|
+
x_prop_plus_arr = self._dyn["x_prop_plus"] # (N, n_x) or None
|
|
742
861
|
|
|
743
862
|
lam_cost_arr = np.broadcast_to(lam_cost, (settings.sim.n_states,))
|
|
744
863
|
|
|
@@ -801,15 +920,23 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
801
920
|
for j in range(n_u):
|
|
802
921
|
emit([1.0, -1.0], inv_S_u[j] * (u_bar[k, j] - c_u[j]))
|
|
803
922
|
|
|
804
|
-
# Dynamics (continuous FOH):
|
|
805
|
-
# x[k] − A_blk·dx[k-1] − B_blk·du[k-1] − C_blk·du[k]
|
|
806
|
-
#
|
|
923
|
+
# Dynamics (continuous FOH, with optional impulsive coupling at node k):
|
|
924
|
+
# x[k] − A_blk·dx[k-1] − B_blk·du[k-1] − C_blk·du[k]
|
|
925
|
+
# − E_blk·du[k][slice_imp] − nu[k-1]
|
|
926
|
+
# = inv_S_x·(x_prop_plus[k] − c_x) if has_impulsive
|
|
927
|
+
# = inv_S_x·(x_prop[k-1] − c_x) otherwise
|
|
928
|
+
# Mirrors CVXPyPTRSolver.constraints at cvxpy_ptr_solver.py:506-530.
|
|
807
929
|
for k in range(1, N):
|
|
808
930
|
kp = k - 1
|
|
809
931
|
A_blk = (inv_S_x[:, None] * A_d[kp]) * S_x[None, :]
|
|
810
|
-
B_blk = (inv_S_x[:, None] * B_d[kp]) *
|
|
811
|
-
C_blk = (inv_S_x[:, None] * C_d[kp]) *
|
|
812
|
-
|
|
932
|
+
B_blk = (inv_S_x[:, None] * B_d[kp]) * S_u[None, :]
|
|
933
|
+
C_blk = (inv_S_x[:, None] * C_d[kp]) * S_u[None, :]
|
|
934
|
+
if has_impulsive:
|
|
935
|
+
E_blk = (inv_S_x[:, None] * E_d_arr[k]) * S_u[None, :]
|
|
936
|
+
rhs_k = inv_S_x * (x_prop_plus_arr[k] - c_x)
|
|
937
|
+
else:
|
|
938
|
+
E_blk = None
|
|
939
|
+
rhs_k = inv_S_x * (x_prop[kp] - c_x)
|
|
813
940
|
for i in range(n_x):
|
|
814
941
|
# Coefficients in the same col order as _structural_pass added them,
|
|
815
942
|
# then sorted by scipy within the row — values line up correctly.
|
|
@@ -818,7 +945,10 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
818
945
|
coeffs.append(-A_blk[i, j]) # dx[kp, j]
|
|
819
946
|
for j in range(n_u):
|
|
820
947
|
coeffs.append(-B_blk[i, j]) # du[kp, j]
|
|
821
|
-
|
|
948
|
+
c_kj = -C_blk[i, j]
|
|
949
|
+
if has_impulsive and slice_imp.start <= j < slice_imp.stop:
|
|
950
|
+
c_kj -= E_blk[i, j]
|
|
951
|
+
coeffs.append(c_kj) # du[k, j]
|
|
822
952
|
coeffs.append(-1.0) # nu[kp, i]
|
|
823
953
|
emit(coeffs, rhs_k[i])
|
|
824
954
|
|
|
@@ -839,15 +969,25 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
839
969
|
coeffs.append(-1.0) # nu_vb[c, node]
|
|
840
970
|
emit(coeffs, -g[node])
|
|
841
971
|
|
|
842
|
-
# Fix boundary conditions
|
|
972
|
+
# Fix boundary conditions. Under impulsive control the initial Fix
|
|
973
|
+
# row couples x[0, i] to du[0, slice_imp] via the linearized impulse
|
|
974
|
+
# Jacobian (CVXPy reference: cvxpy_ptr_solver.py:484-495). Emit
|
|
975
|
+
# coefficients in ascending column-index order so they match the
|
|
976
|
+
# CSR sort applied to the structural pass.
|
|
843
977
|
for i in range(settings.sim.true_state_slice.start, settings.sim.true_state_slice.stop):
|
|
844
978
|
if settings.sim.x.initial_type[i] == "Fix":
|
|
845
|
-
if
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
)
|
|
850
|
-
|
|
979
|
+
if has_impulsive:
|
|
980
|
+
coeffs = [S_x[i]]
|
|
981
|
+
for j in range(slice_imp.start, slice_imp.stop):
|
|
982
|
+
coeffs.append(-E_d_arr[0, i, j] * S_u[j])
|
|
983
|
+
emit(coeffs, x_prop_plus_arr[0, i] - c_x[i])
|
|
984
|
+
else:
|
|
985
|
+
if self._x_init is None:
|
|
986
|
+
raise RuntimeError(
|
|
987
|
+
f"Fix initial condition on state {i} requires x_init; "
|
|
988
|
+
"call update_boundary_conditions() before solve()."
|
|
989
|
+
)
|
|
990
|
+
emit([S_x[i]], self._x_init[i] - c_x[i])
|
|
851
991
|
if settings.sim.x.final_type[i] == "Fix":
|
|
852
992
|
if self._x_term is None:
|
|
853
993
|
raise RuntimeError(
|
|
@@ -856,6 +996,13 @@ class MoreauPTRSolver(PTRSolver):
|
|
|
856
996
|
)
|
|
857
997
|
emit([S_x[i]], self._x_term[i] - c_x[i])
|
|
858
998
|
|
|
999
|
+
# Impulsive zero-pin equalities: u[node, j] = −inv_S_u[j]·c_u[j].
|
|
1000
|
+
# Mirrors CVXPy's lowering of ``u_nonscaled[node][slice_imp] == 0``.
|
|
1001
|
+
for nodes, ctrl_slice in self._impulsive_pins:
|
|
1002
|
+
for node in nodes:
|
|
1003
|
+
for j in range(ctrl_slice.start, ctrl_slice.stop):
|
|
1004
|
+
emit([1.0], -inv_S_u[j] * c_u[j])
|
|
1005
|
+
|
|
859
1006
|
# Uniform time grid: u[k,j] − u[k-1,j] = 0
|
|
860
1007
|
if settings.sim._uniform_time_grid:
|
|
861
1008
|
td = settings.sim.time_dilation_slice
|
|
@@ -22,7 +22,7 @@ Backends:
|
|
|
22
22
|
|
|
23
23
|
from abc import abstractmethod
|
|
24
24
|
from dataclasses import dataclass
|
|
25
|
-
from typing import TYPE_CHECKING, List, Tuple, Union
|
|
25
|
+
from typing import TYPE_CHECKING, List, Optional, Tuple, Union
|
|
26
26
|
|
|
27
27
|
import numpy as np
|
|
28
28
|
|
|
@@ -30,6 +30,7 @@ from .base import ConvexSolver
|
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
32
32
|
from openscvx.lowered.unified import UnifiedControl, UnifiedState
|
|
33
|
+
from openscvx.symbolic.constraint_set import ConstraintSet
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
@dataclass
|
|
@@ -174,6 +175,51 @@ class PTRSolver(ConvexSolver):
|
|
|
174
175
|
"""
|
|
175
176
|
raise NotImplementedError
|
|
176
177
|
|
|
178
|
+
@staticmethod
|
|
179
|
+
def _extract_impulsive_pins(
|
|
180
|
+
constraints: "ConstraintSet",
|
|
181
|
+
) -> Optional[List[Tuple[List[int], slice]]]:
|
|
182
|
+
"""Recognize auto-generated impulsive zero-pin constraints.
|
|
183
|
+
|
|
184
|
+
:func:`openscvx.symbolic.lower._augment_impulsive_constraints` injects
|
|
185
|
+
a ``Control == 0`` equality at every non-impulse node for each
|
|
186
|
+
impulsive control. CVXPy lowers these alongside user ``.convex()``
|
|
187
|
+
constraints, but JAX backends that otherwise refuse user
|
|
188
|
+
``.convex()`` constraints still need to honor them.
|
|
189
|
+
|
|
190
|
+
This helper detects that exact shape — a ``NodalConstraint`` wrapping
|
|
191
|
+
``Equality(Control, Constant(0))`` over a list of nodes — and
|
|
192
|
+
returns the implied ``(nodes, slice)`` pin list. If any
|
|
193
|
+
``nodal_convex`` entry doesn't match the auto-augmentation shape,
|
|
194
|
+
returns ``None`` so the caller can fall back to the default
|
|
195
|
+
refusal.
|
|
196
|
+
|
|
197
|
+
Cross-node convex constraints are never produced by the
|
|
198
|
+
auto-augmentation, so any presence aborts recognition.
|
|
199
|
+
"""
|
|
200
|
+
from openscvx.symbolic.expr.constraint import Equality, NodalConstraint
|
|
201
|
+
from openscvx.symbolic.expr.control import Control
|
|
202
|
+
from openscvx.symbolic.expr.expr import Constant
|
|
203
|
+
|
|
204
|
+
if constraints.cross_node_convex:
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
pins: List[Tuple[List[int], slice]] = []
|
|
208
|
+
for entry in constraints.nodal_convex:
|
|
209
|
+
if not isinstance(entry, NodalConstraint):
|
|
210
|
+
return None
|
|
211
|
+
inner = entry.constraint
|
|
212
|
+
if not isinstance(inner, Equality):
|
|
213
|
+
return None
|
|
214
|
+
rhs = inner.rhs
|
|
215
|
+
if not isinstance(rhs, Constant) or not np.all(np.asarray(rhs.value) == 0):
|
|
216
|
+
return None
|
|
217
|
+
lhs = inner.lhs
|
|
218
|
+
if not isinstance(lhs, Control) or lhs._slice is None:
|
|
219
|
+
return None
|
|
220
|
+
pins.append(([int(k) for k in entry.nodes], lhs._slice))
|
|
221
|
+
return pins
|
|
222
|
+
|
|
177
223
|
@staticmethod
|
|
178
224
|
def _scaling(unified: Union["UnifiedState", "UnifiedControl"]) -> Tuple[np.ndarray, np.ndarray]:
|
|
179
225
|
"""Compute the affine scaling matrices ``(S, c)`` for a unified
|