openscvx 0.5.3.dev15__tar.gz → 0.5.3.dev16__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.3.dev15/openscvx.egg-info → openscvx-0.5.3.dev16}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UnderTheHood/lowering_architecture.md +18 -8
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/_version.py +3 -3
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/base.py +39 -7
- openscvx-0.5.3.dev16/openscvx/algorithms/scvx/iteration.py +369 -0
- openscvx-0.5.3.dev16/openscvx/algorithms/scvx/penalized_trust_region.py +330 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/problem.py +51 -51
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/cvxpy_ptr_solver.py +33 -2
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/qpax_ptr_solver.py +37 -26
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/caching.py +25 -17
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/SOURCES.txt +5 -0
- openscvx-0.5.3.dev16/tests/algorithms/_iteration_helpers.py +27 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/autotuner/test_update_weights_jit.py +1 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/test_algorithm_state_pytree.py +1 -0
- openscvx-0.5.3.dev16/tests/algorithms/test_iteration_fn_jit.py +47 -0
- openscvx-0.5.3.dev16/tests/algorithms/test_iteration_fn_parity.py +64 -0
- openscvx-0.5.3.dev16/tests/algorithms/test_make_solve_loop.py +41 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/_iteration_callback_helpers.py +86 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_moreau.py +5 -4
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_qpax.py +12 -11
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_vmap.py +3 -2
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_moreau_ptr_solver.py +3 -1
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_qpax_ptr_solver.py +9 -3
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_autotuning.py +1 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_brachistochrone.py +10 -21
- openscvx-0.5.3.dev15/openscvx/algorithms/scvx/penalized_trust_region.py +0 -794
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.gitignore +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/.gitmodules +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/LICENSE +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/README.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/citation.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/examples.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/index.md +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/docs/versions.json +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/_render.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/logo.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/logo.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/plotting.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/examples/spacecraft/relative_loitering.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/figures/video_preview.png +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/home.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/main.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/mkdocs.yml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/__main__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/config.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/loader.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/base.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/printing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/pyproject.toml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/setup.cfg +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/_marks.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/conftest.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/expr/test_gmsr.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/solvers/test_subproblem_pytree.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_discretization.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_examples.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_expert.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_impulsive.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_init.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_integrators.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_loader.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_optimization_results.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_plotting.py +0 -0
- {openscvx-0.5.3.dev15 → openscvx-0.5.3.dev16}/tests/test_propagation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.5.3.
|
|
3
|
+
Version: 0.5.3.dev16
|
|
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,18 +168,28 @@ 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 (continuous and impulsive) / CTCS / boundary-Fix; **rejects** user `.convex()` and cross-node at `initialize()` with a clear "use `CVXPyPTRSolver`" message.
|
|
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. The `iteration_callback` uses `qpax.solve_qp`, whose convergence flag maps to a `status_code` so a diverged solve fails loudly (chosen over the differentiable `solve_qp_primal`, which exposes no such flag). |
|
|
172
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
|
Each backend exposes two per-iteration entry points: the historical NumPy
|
|
175
|
-
`update_*` + `solve()` stages
|
|
175
|
+
`update_*` + `solve()` stages (kept for direct / interactive solver use), and a
|
|
176
176
|
JAX-pure `iteration_callback()` built once at `initialize()`. The callback
|
|
177
|
-
returns a `(state, SubproblemData) -> SubproblemSolution` callable; all
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
returns a `(state, SubproblemData) -> SubproblemSolution` callable; all three
|
|
178
|
+
backends emit the same input/output pytree shape (CVXPy host-calls via
|
|
179
|
+
`jax.pure_callback`).
|
|
180
|
+
|
|
181
|
+
`Problem.initialize()` fuses that callback with discretization, constraint
|
|
182
|
+
linearization, the SCP metrics, and the autotuner into one JAX function —
|
|
183
|
+
`iteration_fn`, built by `make_scp_iteration`
|
|
184
|
+
(`openscvx/algorithms/scvx/iteration.py`). A single JIT'd `iteration_fn` call
|
|
185
|
+
per iteration replaces the former per-step NumPy↔JAX stitching, and the Python
|
|
186
|
+
SCP loop now drives that one fused body. Forward propagation stays a separate
|
|
187
|
+
JAX export, used only by `post_process()` — so a compiled problem holds **one
|
|
188
|
+
`iteration_fn` plus one propagation export**, not three discretization /
|
|
189
|
+
propagation exports stitched together in Python. Because `iteration_fn` is a
|
|
190
|
+
registered pytree in and out, it also composes with `jax.jit`; `make_solve_loop`
|
|
191
|
+
wraps it in `lax.while_loop` as the primitive for a future fully-JAX-driven
|
|
192
|
+
solve.
|
|
183
193
|
|
|
184
194
|
Picking a backend at construction time:
|
|
185
195
|
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.5.3.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 5, 3, '
|
|
21
|
+
__version__ = version = '0.5.3.dev16'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 3, 'dev16')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'gb2479bf05'
|
|
@@ -29,7 +29,6 @@ from openscvx.utils.printing import Column
|
|
|
29
29
|
if TYPE_CHECKING:
|
|
30
30
|
from openscvx.config import Config
|
|
31
31
|
from openscvx.lowered.jax_constraints import LoweredJaxConstraints
|
|
32
|
-
from openscvx.solvers import ConvexSolver
|
|
33
32
|
|
|
34
33
|
from .weights import Weights
|
|
35
34
|
|
|
@@ -373,6 +372,16 @@ class AlgorithmState:
|
|
|
373
372
|
actual_reduction: Actual reduction in ``J_nonlin`` for this iter.
|
|
374
373
|
acceptance_ratio: ``actual_reduction / predicted_reduction``.
|
|
375
374
|
adaptive_state_code: :class:`AdaptiveStateCode` value as ``int32``.
|
|
375
|
+
x_init_pin: Initial-state boundary condition, shape ``(n_states,)``.
|
|
376
|
+
``jnp.nan`` where the state is not pinned at t0 (``initial_type``
|
|
377
|
+
is not ``"Fix"``). Carried on the pytree — rather than read from
|
|
378
|
+
``settings`` — so the fused SCP iteration body assembles the
|
|
379
|
+
subproblem's initial boundary rows as a pure function of state,
|
|
380
|
+
and a future ``jax.vmap`` over problems can batch boundary
|
|
381
|
+
conditions per element.
|
|
382
|
+
x_term_pin: Terminal-state boundary condition, shape ``(n_states,)``.
|
|
383
|
+
``jnp.nan`` where the state is not pinned at tf (``final_type`` is
|
|
384
|
+
not ``"Fix"``).
|
|
376
385
|
"""
|
|
377
386
|
|
|
378
387
|
x: jnp.ndarray
|
|
@@ -394,6 +403,8 @@ class AlgorithmState:
|
|
|
394
403
|
actual_reduction: jnp.ndarray
|
|
395
404
|
acceptance_ratio: jnp.ndarray
|
|
396
405
|
adaptive_state_code: jnp.ndarray
|
|
406
|
+
x_init_pin: jnp.ndarray
|
|
407
|
+
x_term_pin: jnp.ndarray
|
|
397
408
|
|
|
398
409
|
# Field order is the source of truth for tree_flatten / tree_unflatten;
|
|
399
410
|
# keep _FIELDS in sync with the dataclass field declarations above.
|
|
@@ -417,6 +428,8 @@ class AlgorithmState:
|
|
|
417
428
|
"actual_reduction",
|
|
418
429
|
"acceptance_ratio",
|
|
419
430
|
"adaptive_state_code",
|
|
431
|
+
"x_init_pin",
|
|
432
|
+
"x_term_pin",
|
|
420
433
|
)
|
|
421
434
|
|
|
422
435
|
def replace(self, **changes) -> "AlgorithmState":
|
|
@@ -475,6 +488,17 @@ class AlgorithmState:
|
|
|
475
488
|
else:
|
|
476
489
|
lam_cost_init = np.full(n_states, weights.lam_cost)
|
|
477
490
|
|
|
491
|
+
# Boundary-condition pins: the physical value where the state is fixed
|
|
492
|
+
# at t0 / tf, ``nan`` elsewhere. The subproblem only reads these at
|
|
493
|
+
# ``"Fix"`` entries, so the sentinel marks "unpinned" without poisoning
|
|
494
|
+
# any value the solver consumes.
|
|
495
|
+
x_initial = np.asarray(settings.sim.x.initial, dtype=float).reshape(-1)
|
|
496
|
+
x_final = np.asarray(settings.sim.x.final, dtype=float).reshape(-1)
|
|
497
|
+
init_fixed = np.asarray(settings.sim.x.initial_type) == "Fix"
|
|
498
|
+
final_fixed = np.asarray(settings.sim.x.final_type) == "Fix"
|
|
499
|
+
x_init_pin = np.where(init_fixed, x_initial, np.nan)
|
|
500
|
+
x_term_pin = np.where(final_fixed, x_final, np.nan)
|
|
501
|
+
|
|
478
502
|
return cls(
|
|
479
503
|
x=put(jnp.asarray(settings.sim.x.guess, dtype=f)),
|
|
480
504
|
u=put(jnp.asarray(settings.sim.u.guess, dtype=f)),
|
|
@@ -495,6 +519,8 @@ class AlgorithmState:
|
|
|
495
519
|
actual_reduction=put(jnp.asarray(0.0, dtype=f)),
|
|
496
520
|
acceptance_ratio=put(jnp.asarray(0.0, dtype=f)),
|
|
497
521
|
adaptive_state_code=put(jnp.asarray(int(AdaptiveStateCode.INITIAL), dtype=i)),
|
|
522
|
+
x_init_pin=put(jnp.asarray(x_init_pin, dtype=f)),
|
|
523
|
+
x_term_pin=put(jnp.asarray(x_term_pin, dtype=f)),
|
|
498
524
|
)
|
|
499
525
|
|
|
500
526
|
|
|
@@ -798,15 +824,21 @@ class Algorithm(ABC):
|
|
|
798
824
|
@abstractmethod
|
|
799
825
|
def initialize(
|
|
800
826
|
self,
|
|
801
|
-
|
|
802
|
-
discretization_solver: callable,
|
|
803
|
-
jax_constraints: "LoweredJaxConstraints",
|
|
827
|
+
iteration_fn: Callable,
|
|
804
828
|
emitter: callable,
|
|
805
|
-
|
|
829
|
+
jax_constraints: "LoweredJaxConstraints",
|
|
806
830
|
settings: "Config",
|
|
807
|
-
discretization_solver_impulsive: Optional[Callable] = None,
|
|
808
831
|
) -> None:
|
|
809
|
-
"""
|
|
832
|
+
"""Store the fused SCP iteration body and per-iteration infrastructure.
|
|
833
|
+
|
|
834
|
+
Args:
|
|
835
|
+
iteration_fn: The JAX-pure ``(state, params) -> (next_state,
|
|
836
|
+
diagnostics)`` body built by
|
|
837
|
+
:func:`~openscvx.algorithms.scvx.iteration.make_scp_iteration`.
|
|
838
|
+
emitter: Per-iteration diagnostics sink (printing queue / no-op).
|
|
839
|
+
jax_constraints: Lowered JAX constraints the body operates over.
|
|
840
|
+
settings: Problem configuration.
|
|
841
|
+
"""
|
|
810
842
|
raise NotImplementedError
|
|
811
843
|
|
|
812
844
|
@abstractmethod
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"""One fused, JAX-pure SCP iteration body.
|
|
2
|
+
|
|
3
|
+
Historically a single SCP step was stitched together in Python: ``Problem``
|
|
4
|
+
exported three separate JAX callables (continuous discretization, impulsive
|
|
5
|
+
discretization, propagation) and :meth:`PenalizedTrustRegion._subproblem`
|
|
6
|
+
invoked each one, copied NumPy out of every result, pushed the data through
|
|
7
|
+
the solver's ``update_*`` methods, and finally called ``solver.solve()``. Every
|
|
8
|
+
step crossed the NumPy↔JAX boundary several times, and there was no batch axis
|
|
9
|
+
anywhere.
|
|
10
|
+
|
|
11
|
+
This module collapses that stitching into one function. :func:`make_scp_iteration`
|
|
12
|
+
returns a ``(state, params) -> (state, IterationDiagnostics)`` callable that, on
|
|
13
|
+
the JAX side end to end, discretizes the current iterate, linearizes the
|
|
14
|
+
constraints, packs a :class:`~openscvx.solvers.ptr_solver.SubproblemData`, hands
|
|
15
|
+
it to the backend's :meth:`~openscvx.solvers.ptr_solver.PTRSolver.iteration_callback`,
|
|
16
|
+
and folds the returned :class:`~openscvx.solvers.ptr_solver.SubproblemSolution`
|
|
17
|
+
through the autotuner — producing the next :class:`AlgorithmState`. The
|
|
18
|
+
:class:`IterationDiagnostics` riding alongside carry the host-side bookkeeping
|
|
19
|
+
(raw discretization matrices, trust-region / virtual-control matrices, cost,
|
|
20
|
+
status) that the Python-loop ``step()`` records into ``AlgorithmHistory`` and
|
|
21
|
+
emits, exactly as the legacy path did. Because state is a registered pytree, the
|
|
22
|
+
body composes with ``jax.jit`` and ``jax.vmap``.
|
|
23
|
+
|
|
24
|
+
:func:`make_solve_loop` wraps that body in a ``lax.while_loop`` keyed on the SCP
|
|
25
|
+
convergence metrics, projecting the diagnostics away so the loop carry stays
|
|
26
|
+
``state -> state``. It exists as a primitive for tests and for the JAX-pure
|
|
27
|
+
``.solve()`` path in follow-up work; today's ``Problem.solve()`` still drives the
|
|
28
|
+
body from a Python ``while`` loop, so behavior is unchanged.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from dataclasses import dataclass, fields
|
|
32
|
+
from typing import TYPE_CHECKING, Callable, Tuple
|
|
33
|
+
|
|
34
|
+
import jax
|
|
35
|
+
import jax.numpy as jnp
|
|
36
|
+
import numpy as np
|
|
37
|
+
|
|
38
|
+
from openscvx.solvers.ptr_solver import SubproblemData, SubproblemSolution
|
|
39
|
+
|
|
40
|
+
from ..base import AlgorithmState, CandidateIterate
|
|
41
|
+
|
|
42
|
+
if TYPE_CHECKING:
|
|
43
|
+
from openscvx.config import Config
|
|
44
|
+
from openscvx.lowered import LoweredJaxConstraints
|
|
45
|
+
|
|
46
|
+
from ..base import AutotuningBase
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@jax.tree_util.register_pytree_node_class
|
|
50
|
+
@dataclass(frozen=True)
|
|
51
|
+
class IterationDiagnostics:
|
|
52
|
+
"""Host-side bookkeeping produced alongside the next :class:`AlgorithmState`.
|
|
53
|
+
|
|
54
|
+
These ride beside the state out of :func:`make_scp_iteration` so the
|
|
55
|
+
Python-loop ``step()`` can populate :class:`AlgorithmHistory` and the
|
|
56
|
+
emitter exactly as the legacy ``_subproblem`` did — the data they carry is
|
|
57
|
+
not on the JAX-traceable state pytree (raw discretization matrices are
|
|
58
|
+
large and host-only; cost / status / ``J_lin`` come from the subproblem
|
|
59
|
+
solve). :func:`make_solve_loop` projects them away.
|
|
60
|
+
|
|
61
|
+
Attributes:
|
|
62
|
+
cost: Boundary-weighted objective at the candidate (scalar) — the
|
|
63
|
+
``cost[-1]`` the emitter prints.
|
|
64
|
+
status: Subproblem :class:`StatusCode` as ``int32``.
|
|
65
|
+
J_lin: Subproblem optimal (linearized) cost (scalar).
|
|
66
|
+
V: Raw continuous discretization matrix of the candidate.
|
|
67
|
+
W: Raw impulsive discretization matrix of the candidate.
|
|
68
|
+
TR: Scaled trust-region step matrix, shape ``(n_x + n_u, N)``.
|
|
69
|
+
VC: Scaled virtual-control matrix, shape ``(N-1, n_x)``.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
cost: jnp.ndarray
|
|
73
|
+
status: jnp.ndarray
|
|
74
|
+
J_lin: jnp.ndarray
|
|
75
|
+
V: jnp.ndarray
|
|
76
|
+
W: jnp.ndarray
|
|
77
|
+
TR: jnp.ndarray
|
|
78
|
+
VC: jnp.ndarray
|
|
79
|
+
|
|
80
|
+
def tree_flatten(self):
|
|
81
|
+
children = tuple(getattr(self, f.name) for f in fields(self))
|
|
82
|
+
return children, None
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def tree_unflatten(cls, aux, children):
|
|
86
|
+
return cls(*children)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def make_scp_iteration(
|
|
90
|
+
dis_continuous: Callable,
|
|
91
|
+
dis_impulsive: Callable,
|
|
92
|
+
jax_constraints: "LoweredJaxConstraints",
|
|
93
|
+
solver_callback: Callable[[AlgorithmState, SubproblemData], SubproblemSolution],
|
|
94
|
+
autotuner: "AutotuningBase",
|
|
95
|
+
settings: "Config",
|
|
96
|
+
) -> Callable[[AlgorithmState, dict], Tuple[AlgorithmState, IterationDiagnostics]]:
|
|
97
|
+
"""Build one JAX-pure SCP iteration body.
|
|
98
|
+
|
|
99
|
+
The returned ``iteration_fn(state, params)`` performs a single SCP step and
|
|
100
|
+
returns ``(next_state, diagnostics)``. It is the fused mirror of the legacy
|
|
101
|
+
discretize → linearize → solve → autotune pipeline:
|
|
102
|
+
|
|
103
|
+
1. Discretize the continuous dynamics about the current iterate
|
|
104
|
+
(``state.x`` / ``state.u``) → ``A_d, B_d, C_d, x_prop``.
|
|
105
|
+
2. Discretize the impulsive/discrete dynamics about the propagated nodes →
|
|
106
|
+
``x_prop_plus, D_d, E_d``.
|
|
107
|
+
3. Evaluate every nodal / cross-node constraint and its gradients.
|
|
108
|
+
4. Pack the linearization, penalty weights, and boundary pins into a
|
|
109
|
+
:class:`SubproblemData`.
|
|
110
|
+
5. Hand it to ``solver_callback`` (the backend's ``iteration_callback``),
|
|
111
|
+
which returns a :class:`SubproblemSolution`.
|
|
112
|
+
6. Compute the ``J_tr / J_vb / J_vc`` metrics and fold the candidate through
|
|
113
|
+
the autotuner to produce the next state, alongside an
|
|
114
|
+
:class:`IterationDiagnostics`.
|
|
115
|
+
|
|
116
|
+
The current-iterate discretization (steps 1–2) is recomputed every call
|
|
117
|
+
rather than read from a carried ``state.x_prop``; see the plan's decision
|
|
118
|
+
log. The discretization solvers are built by the caller (``Problem``) and
|
|
119
|
+
captured here so the caching policy stays in its own layer; the constraint
|
|
120
|
+
linearizers, per-backend solver callback, autotuner, and settings are
|
|
121
|
+
likewise closure constants.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
dis_continuous: Continuous discretization solver,
|
|
125
|
+
``(x, u, params) -> (A_d, B_d, C_d, x_prop, V)``. A ``jax.jit``
|
|
126
|
+
callable (vmappable) or a ``jax.export`` wrapper (``.call``).
|
|
127
|
+
dis_impulsive: Impulsive discretization solver,
|
|
128
|
+
``(x_nodes, u, params) -> (x_prop_plus, D_d, E_d, W)``.
|
|
129
|
+
jax_constraints: Lowered nodal / cross-node JAX constraints.
|
|
130
|
+
solver_callback: ``(state, SubproblemData) -> SubproblemSolution`` from
|
|
131
|
+
the convex backend's :meth:`iteration_callback`.
|
|
132
|
+
autotuner: Weight-update strategy applied to the candidate.
|
|
133
|
+
settings: Problem configuration (scaling matrices, boundary types).
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
``iteration_fn(state, params) -> (next_state, diagnostics)``.
|
|
137
|
+
"""
|
|
138
|
+
N = settings.sim.n
|
|
139
|
+
n_x = settings.sim.n_states
|
|
140
|
+
n_u = settings.sim.n_controls
|
|
141
|
+
n_nodal = len(jax_constraints.nodal)
|
|
142
|
+
|
|
143
|
+
# Accept either a bare ``jax.jit`` callable or a ``jax.export`` wrapper.
|
|
144
|
+
dis_continuous = dis_continuous.call if hasattr(dis_continuous, "call") else dis_continuous
|
|
145
|
+
dis_impulsive = dis_impulsive.call if hasattr(dis_impulsive, "call") else dis_impulsive
|
|
146
|
+
|
|
147
|
+
# Scaling matrices for the SCP convergence / diagnostic metrics (static).
|
|
148
|
+
inv_S_x = jnp.asarray(settings.sim.inv_S_x)
|
|
149
|
+
inv_S_u = jnp.asarray(settings.sim.inv_S_u)
|
|
150
|
+
|
|
151
|
+
# Boundary types drive the candidate cost reduction (static, host-side).
|
|
152
|
+
final_type = list(settings.sim.x.final_type)
|
|
153
|
+
|
|
154
|
+
# Node-0 prior recovery: fixed initial entries come from the boundary
|
|
155
|
+
# condition, free entries from the iterate. The impulsive discretization
|
|
156
|
+
# linearizes about the propagated nodes prefixed with this prior.
|
|
157
|
+
init_fixed = jnp.asarray(np.asarray(settings.sim.x.initial_type) == "Fix")
|
|
158
|
+
x_initial = jnp.asarray(np.asarray(settings.sim.x.initial, dtype=float))
|
|
159
|
+
|
|
160
|
+
def _discretize(x: jnp.ndarray, u: jnp.ndarray, params: dict):
|
|
161
|
+
"""Discretize ``(x, u)`` through both dynamics; return propagation pieces.
|
|
162
|
+
|
|
163
|
+
Returns ``(A_d, B_d, C_d, x_prop, x_prop_plus, D_d, E_d, V, W)`` — ``V``
|
|
164
|
+
/ ``W`` are the raw multi-shot matrices the history recorder unpacks.
|
|
165
|
+
"""
|
|
166
|
+
A_d, B_d, C_d, x_prop, V = dis_continuous(x, u, params)
|
|
167
|
+
x0_prior = jnp.where(init_fixed, x_initial, x[0])
|
|
168
|
+
x_nodes_prior = jnp.concatenate([x0_prior[None, :], x_prop], axis=0)
|
|
169
|
+
x_prop_plus, D_d, E_d, W = dis_impulsive(x_nodes_prior, u, params)
|
|
170
|
+
return A_d, B_d, C_d, x_prop, x_prop_plus, D_d, E_d, V, W
|
|
171
|
+
|
|
172
|
+
def _linearize_constraints(x: jnp.ndarray, u: jnp.ndarray, params: dict):
|
|
173
|
+
"""Stack nodal / cross-node constraint values and gradients.
|
|
174
|
+
|
|
175
|
+
Nodal data is laid out ``(N, n_nodal[, ·])`` with zero-fill at nodes
|
|
176
|
+
outside each constraint's static ``nodes`` set — the backend assembly
|
|
177
|
+
closes over those node sets and skips the zeros.
|
|
178
|
+
"""
|
|
179
|
+
nodal_g = jnp.zeros((N, n_nodal))
|
|
180
|
+
nodal_grad_x = jnp.zeros((N, n_nodal, n_x))
|
|
181
|
+
nodal_grad_u = jnp.zeros((N, n_nodal, n_u))
|
|
182
|
+
for c_idx, constraint in enumerate(jax_constraints.nodal):
|
|
183
|
+
g = jnp.squeeze(jnp.asarray(constraint.func(x, u, 0, params)))
|
|
184
|
+
if g.ndim == 0:
|
|
185
|
+
g = jnp.broadcast_to(g, (N,))
|
|
186
|
+
elif g.ndim > 1:
|
|
187
|
+
g = g.reshape(g.shape[0], -1).sum(axis=1)
|
|
188
|
+
|
|
189
|
+
grad_x = jnp.asarray(constraint.grad_g_x(x, u, 0, params))
|
|
190
|
+
if grad_x.ndim == 1:
|
|
191
|
+
grad_x = jnp.broadcast_to(grad_x, (N, grad_x.shape[0]))
|
|
192
|
+
elif grad_x.ndim > 2:
|
|
193
|
+
grad_x = grad_x.reshape(grad_x.shape[0], -1)[:, :n_x]
|
|
194
|
+
|
|
195
|
+
grad_u = jnp.asarray(constraint.grad_g_u(x, u, 0, params))
|
|
196
|
+
if grad_u.ndim == 1:
|
|
197
|
+
grad_u = jnp.broadcast_to(grad_u, (N, grad_u.shape[0]))
|
|
198
|
+
elif grad_u.ndim > 2:
|
|
199
|
+
grad_u = grad_u.reshape(grad_u.shape[0], -1)[:, :n_u]
|
|
200
|
+
|
|
201
|
+
nodes = jnp.asarray(constraint.nodes) if constraint.nodes is not None else jnp.arange(N)
|
|
202
|
+
nodal_g = nodal_g.at[nodes, c_idx].set(g[nodes])
|
|
203
|
+
nodal_grad_x = nodal_grad_x.at[nodes, c_idx].set(grad_x[nodes])
|
|
204
|
+
nodal_grad_u = nodal_grad_u.at[nodes, c_idx].set(grad_u[nodes])
|
|
205
|
+
|
|
206
|
+
if jax_constraints.cross_node:
|
|
207
|
+
cross_g = jnp.stack(
|
|
208
|
+
[jnp.asarray(c.func(x, u, params)) for c in jax_constraints.cross_node]
|
|
209
|
+
)
|
|
210
|
+
cross_grad_X = jnp.stack(
|
|
211
|
+
[jnp.asarray(c.grad_g_X(x, u, params)) for c in jax_constraints.cross_node]
|
|
212
|
+
)
|
|
213
|
+
cross_grad_U = jnp.stack(
|
|
214
|
+
[jnp.asarray(c.grad_g_U(x, u, params)) for c in jax_constraints.cross_node]
|
|
215
|
+
)
|
|
216
|
+
else:
|
|
217
|
+
cross_g = jnp.zeros((0,))
|
|
218
|
+
cross_grad_X = jnp.zeros((0, N, n_x))
|
|
219
|
+
cross_grad_U = jnp.zeros((0, N, n_u))
|
|
220
|
+
|
|
221
|
+
return nodal_g, nodal_grad_x, nodal_grad_u, cross_g, cross_grad_X, cross_grad_U
|
|
222
|
+
|
|
223
|
+
def _candidate_cost(x: jnp.ndarray) -> jnp.ndarray:
|
|
224
|
+
"""Boundary-weighted reduction objective at the candidate's terminal node."""
|
|
225
|
+
cost = jnp.asarray(0.0)
|
|
226
|
+
for i, bc_type in enumerate(final_type):
|
|
227
|
+
if bc_type == "Minimize":
|
|
228
|
+
cost = cost + x[-1, i]
|
|
229
|
+
elif bc_type == "Maximize":
|
|
230
|
+
cost = cost - x[-1, i]
|
|
231
|
+
return cost
|
|
232
|
+
|
|
233
|
+
def iteration_fn(
|
|
234
|
+
state: AlgorithmState, params: dict
|
|
235
|
+
) -> Tuple[AlgorithmState, IterationDiagnostics]:
|
|
236
|
+
# 1–2. Discretize the current iterate for the subproblem linearization.
|
|
237
|
+
A_d, B_d, C_d, x_prop, x_prop_plus, D_d, E_d, _, _ = _discretize(state.x, state.u, params)
|
|
238
|
+
|
|
239
|
+
# 3. Linearize the constraints about the current iterate.
|
|
240
|
+
(
|
|
241
|
+
nodal_g,
|
|
242
|
+
nodal_grad_x,
|
|
243
|
+
nodal_grad_u,
|
|
244
|
+
cross_g,
|
|
245
|
+
cross_grad_X,
|
|
246
|
+
cross_grad_U,
|
|
247
|
+
) = _linearize_constraints(state.x, state.u, params)
|
|
248
|
+
|
|
249
|
+
# 4. Pack the subproblem inputs.
|
|
250
|
+
data = SubproblemData(
|
|
251
|
+
x_bar=state.x,
|
|
252
|
+
u_bar=state.u,
|
|
253
|
+
A_d=A_d,
|
|
254
|
+
B_d=B_d,
|
|
255
|
+
C_d=C_d,
|
|
256
|
+
x_prop=x_prop,
|
|
257
|
+
x_prop_plus=x_prop_plus,
|
|
258
|
+
D_d=D_d,
|
|
259
|
+
E_d=E_d,
|
|
260
|
+
nodal_g=nodal_g,
|
|
261
|
+
nodal_grad_x=nodal_grad_x,
|
|
262
|
+
nodal_grad_u=nodal_grad_u,
|
|
263
|
+
cross_g=cross_g,
|
|
264
|
+
cross_grad_X=cross_grad_X,
|
|
265
|
+
cross_grad_U=cross_grad_U,
|
|
266
|
+
lam_prox=state.lam_prox,
|
|
267
|
+
lam_cost=state.lam_cost,
|
|
268
|
+
lam_vc=state.lam_vc,
|
|
269
|
+
lam_vb_nodal=state.lam_vb_nodal,
|
|
270
|
+
lam_vb_cross=state.lam_vb_cross,
|
|
271
|
+
x_init=state.x_init_pin,
|
|
272
|
+
x_term=state.x_term_pin,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
# 5. Solve the convex subproblem.
|
|
276
|
+
solution = solver_callback(state, data)
|
|
277
|
+
|
|
278
|
+
# 6a. Discretize the candidate for the autotuner's propagation fields
|
|
279
|
+
# and the history's raw discretization matrices.
|
|
280
|
+
_, _, _, cand_x_prop, cand_x_prop_plus, _, _, V_cand, W_cand = _discretize(
|
|
281
|
+
solution.x, solution.u, params
|
|
282
|
+
)
|
|
283
|
+
candidate = CandidateIterate()
|
|
284
|
+
candidate.x = solution.x
|
|
285
|
+
candidate.u = solution.u
|
|
286
|
+
candidate.x_prop = cand_x_prop
|
|
287
|
+
candidate.x_prop_plus = cand_x_prop_plus
|
|
288
|
+
candidate.J_lin = solution.cost
|
|
289
|
+
|
|
290
|
+
# 6b. SCP convergence metrics (scaled trust region / virtual control /
|
|
291
|
+
# virtual buffer), matching the legacy ``_subproblem`` reductions.
|
|
292
|
+
tr_x = inv_S_x @ (solution.x - state.x).T
|
|
293
|
+
tr_u = inv_S_u @ (solution.u - state.u).T
|
|
294
|
+
TR = jnp.concatenate([tr_x, tr_u], axis=0)
|
|
295
|
+
VC = jnp.abs(inv_S_x @ solution.nu.T).T
|
|
296
|
+
J_tr = jnp.sum(TR**2)
|
|
297
|
+
J_vc = jnp.sum(VC)
|
|
298
|
+
J_vb = jnp.sum(jnp.maximum(0.0, solution.nu_vb)) + jnp.sum(
|
|
299
|
+
jnp.maximum(0.0, solution.nu_vb_cross)
|
|
300
|
+
)
|
|
301
|
+
state = state.replace(
|
|
302
|
+
J_tr=jnp.asarray(J_tr, dtype=state.J_tr.dtype),
|
|
303
|
+
J_vb=jnp.asarray(J_vb, dtype=state.J_vb.dtype),
|
|
304
|
+
J_vc=jnp.asarray(J_vc, dtype=state.J_vc.dtype),
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
# 6c. Autotuner: pure functional update producing the next iterate.
|
|
308
|
+
next_state = autotuner.update_weights(state, candidate, jax_constraints, settings, params)
|
|
309
|
+
next_state = next_state.replace(k=state.k + 1)
|
|
310
|
+
|
|
311
|
+
diagnostics = IterationDiagnostics(
|
|
312
|
+
cost=_candidate_cost(solution.x),
|
|
313
|
+
status=solution.status_code,
|
|
314
|
+
J_lin=solution.cost,
|
|
315
|
+
V=V_cand,
|
|
316
|
+
W=W_cand,
|
|
317
|
+
TR=TR,
|
|
318
|
+
VC=VC,
|
|
319
|
+
)
|
|
320
|
+
return next_state, diagnostics
|
|
321
|
+
|
|
322
|
+
return iteration_fn
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _converged(state: AlgorithmState, ep_tr: float, ep_vb: float, ep_vc: float) -> jnp.ndarray:
|
|
326
|
+
"""Boolean SCP convergence test from the metrics on ``state``."""
|
|
327
|
+
return (state.J_tr < ep_tr) & (state.J_vb < ep_vb) & (state.J_vc < ep_vc)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def make_solve_loop(
|
|
331
|
+
iteration_fn: Callable[[AlgorithmState, dict], Tuple[AlgorithmState, IterationDiagnostics]],
|
|
332
|
+
ep_tr: float,
|
|
333
|
+
ep_vb: float,
|
|
334
|
+
ep_vc: float,
|
|
335
|
+
k_max: int,
|
|
336
|
+
) -> Callable[[AlgorithmState, dict], AlgorithmState]:
|
|
337
|
+
"""Wrap ``iteration_fn`` in a ``lax.while_loop`` keyed on convergence.
|
|
338
|
+
|
|
339
|
+
The loop runs ``iteration_fn`` until either the SCP metrics fall below the
|
|
340
|
+
``ep_*`` thresholds or the iteration counter ``state.k`` exceeds ``k_max`` —
|
|
341
|
+
matching the Python ``while`` loop in ``Problem.solve()``. The per-iteration
|
|
342
|
+
:class:`IterationDiagnostics` are projected away so the loop carry stays
|
|
343
|
+
``state -> state`` (XLA dead-code-eliminates their host-only pieces). It
|
|
344
|
+
exists as a primitive for tests and the future JAX-pure ``.solve()`` path;
|
|
345
|
+
the public ``Problem.solve()`` continues to drive ``iteration_fn`` from
|
|
346
|
+
Python.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
iteration_fn: A body built by :func:`make_scp_iteration`.
|
|
350
|
+
ep_tr: Convergence threshold on ``J_tr`` (trust-region step).
|
|
351
|
+
ep_vb: Convergence threshold on ``J_vb`` (virtual buffer).
|
|
352
|
+
ep_vc: Convergence threshold on ``J_vc`` (virtual control).
|
|
353
|
+
k_max: Maximum number of SCP iterations.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
``solve_loop(state, params) -> final_state``.
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
def solve_loop(state: AlgorithmState, params: dict) -> AlgorithmState:
|
|
360
|
+
def cond(state: AlgorithmState) -> jnp.ndarray:
|
|
361
|
+
return (state.k <= k_max) & jnp.logical_not(_converged(state, ep_tr, ep_vb, ep_vc))
|
|
362
|
+
|
|
363
|
+
def body(state: AlgorithmState) -> AlgorithmState:
|
|
364
|
+
next_state, _ = iteration_fn(state, params)
|
|
365
|
+
return next_state
|
|
366
|
+
|
|
367
|
+
return jax.lax.while_loop(cond, body, state)
|
|
368
|
+
|
|
369
|
+
return solve_loop
|