openscvx 0.5.3.dev24__tar.gz → 0.5.3.dev26__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.dev24/openscvx.egg-info → openscvx-0.5.3.dev26}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UnderTheHood/batching_jit_grad.md +21 -9
- openscvx-0.5.3.dev26/docs/UnderTheHood/custom_algorithms_autotuners.md +223 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/mkdocs.yml +2 -1
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/_version.py +3 -3
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/__init__.py +18 -11
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/__init__.py +3 -0
- openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/acceptance_ratio.py +234 -0
- openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +74 -0
- openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/augmented_lagrangian.py +287 -0
- openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/base.py +259 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/constant_proximal_weight.py +14 -16
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +23 -20
- openscvx-0.5.3.dev26/openscvx/algorithms/base.py +254 -0
- openscvx-0.5.3.dev26/openscvx/algorithms/history.py +303 -0
- openscvx-0.5.3.dev26/openscvx/algorithms/hyperparams.py +96 -0
- openscvx-0.5.3.dev26/openscvx/algorithms/loop.py +81 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/optimization_results.py +8 -8
- openscvx-0.5.3.dev26/openscvx/algorithms/penalty.py +109 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/iteration.py +31 -75
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/penalized_trust_region.py +54 -94
- openscvx-0.5.3.dev26/openscvx/algorithms/state.py +345 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/problem.py +8 -13
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/cvxpy_ptr_solver.py +17 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/caching.py +9 -1
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/printing.py +0 -5
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/SOURCES.txt +10 -0
- openscvx-0.5.3.dev26/tests/algorithms/autotuner/test_defaults_agreement.py +137 -0
- openscvx-0.5.3.dev26/tests/algorithms/autotuner/test_hyper_overrides.py +324 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/test_update_weights_jit.py +36 -40
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_parity.py +48 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_make_solve_loop.py +25 -3
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_autotuning.py +149 -114
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_discretization.py +1 -1
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_brachistochrone.py +31 -2
- openscvx-0.5.3.dev24/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -198
- openscvx-0.5.3.dev24/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -402
- openscvx-0.5.3.dev24/openscvx/algorithms/base.py +0 -1079
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.gitignore +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/.gitmodules +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/LICENSE +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/README.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/citation.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/examples.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/index.md +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/docs/versions.json +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone_batched.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/flappy_bird.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/_render.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/logo.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/drone_racing_batched_gates.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/drone/openscvx_logo.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/plotting.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/rocket/ascent_launch_vehicle.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/examples/spacecraft/relative_loitering.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/figures/video_preview.png +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/home.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/main.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/__main__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/config.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/loader.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/publication.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/coordinates.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/base.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/cones.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/solvers/qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/affine.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/canonicalize.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/pyproject.toml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/setup.cfg +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/_marks.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/_iteration_helpers.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_jit.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/conftest.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/expr/test_gmsr.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/_iteration_callback_helpers.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_moreau.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_qpax.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_vmap.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/solvers/test_subproblem_pytree.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_examples.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_expert.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_impulsive.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_init.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_integrators.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_loader.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_optimization_results.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_plotting.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_propagation.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_export_roundtrip.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_batched_inference.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev24 → openscvx-0.5.3.dev26}/tests/test_solve_jax_vmap_converged_no_drift.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.5.3.
|
|
3
|
+
Version: 0.5.3.dev26
|
|
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
|
|
@@ -161,15 +161,27 @@ The batch runs until its slowest element converges or exhausts its own cap;
|
|
|
161
161
|
finished elements are frozen, not re-iterated, so each element matches the
|
|
162
162
|
corresponding single `solve_jax` run.
|
|
163
163
|
|
|
164
|
-
**
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
**Every built-in autotuner knob batches for free.** All numeric knobs of the
|
|
165
|
+
built-in autotuners are declared hyperparameters — the trust-region factors
|
|
166
|
+
(`gamma_1` / `gamma_2`), the acceptance thresholds (`eta_0` / `eta_1` /
|
|
167
|
+
`eta_2`), the weight clips, the cost-relaxation schedule — so any of them is a
|
|
168
|
+
`solve_jax` override and a `solve_batched` sweep target by name:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
# sweep the trust-region growth factor across a batch, one cached artifact
|
|
172
|
+
results = problem.solve_batched(algorithm={"gamma_1": jnp.linspace(1.5, 3.0, B)})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**New autotuners batch the same way.** A custom autotuner's tunable knobs
|
|
176
|
+
follow the same derivation: declare them as fields on a `HyperParams` subclass
|
|
177
|
+
— bare annotations, no decorator; subclassing applies the frozen-dataclass
|
|
178
|
+
transform and the JAX pytree registration, and the annotation picks the dtype
|
|
179
|
+
(`int` gets the iteration counter's, `float` the problem's) — assign an
|
|
180
|
+
instance to `self.hyper`, and read `state.hyper.<field>` inside
|
|
181
|
+
`update_weights` (see the `AutotuningBase` docstring). The declaration is the
|
|
182
|
+
registration — each field immediately works as a `solve_jax` override, a
|
|
183
|
+
`solve_batched` sweep target, and a runtime input of the exported artifact,
|
|
184
|
+
with zero edits anywhere else:
|
|
173
185
|
|
|
174
186
|
```python
|
|
175
187
|
from openscvx.algorithms import AutotuningBase, HyperParams
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Custom Algorithms and Autotuners
|
|
2
|
+
|
|
3
|
+
OpenSCvx solves through a pluggable SCP loop: an **algorithm** owns the
|
|
4
|
+
iteration (how a subproblem is built, when the loop is converged) and an
|
|
5
|
+
**autotuner** owns the penalty-weight update applied each step. Both are
|
|
6
|
+
ordinary Python classes behind small abstract bases — `Algorithm` and
|
|
7
|
+
`AutotuningBase`, importable from `openscvx.algorithms` — so swapping either
|
|
8
|
+
out is a subclass, not a fork.
|
|
9
|
+
|
|
10
|
+
Most users never touch these: the default
|
|
11
|
+
`PenalizedTrustRegion` + `AugmentedLagrangian` pair covers the common case.
|
|
12
|
+
Reach for this page when you want a different penalty schedule, a different
|
|
13
|
+
convergence rule, or a whole new SCP variant — and you want it to keep
|
|
14
|
+
working under `solve()`, `solve_jax()`, and `solve_batched()` alike.
|
|
15
|
+
|
|
16
|
+
Both bases live under `openscvx.algorithms`:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from openscvx.algorithms import Algorithm, AutotuningBase, HyperParams
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## A custom autotuner
|
|
23
|
+
|
|
24
|
+
An autotuner is a **pure functional update on the iterate**. Its one required
|
|
25
|
+
method, `update_weights`, takes the current `AlgorithmState`, the just-solved
|
|
26
|
+
subproblem `candidate`, the constraints, settings, and parameters, and returns
|
|
27
|
+
the *next* `AlgorithmState`:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import jax.numpy as jnp
|
|
31
|
+
from openscvx.algorithms import AdaptiveStateCode, AutotuningBase, HyperParams
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class MyHyper(HyperParams):
|
|
35
|
+
ramp: float = 2.0
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MyAutotuner(AutotuningBase):
|
|
39
|
+
COMPUTES_ACCEPTANCE_METRICS = False # this tuner never rejects an iterate
|
|
40
|
+
|
|
41
|
+
def __init__(self, ramp: float = 2.0):
|
|
42
|
+
self.hyper = MyHyper(ramp=ramp) # assign self.hyper FIRST
|
|
43
|
+
|
|
44
|
+
def update_weights(self, state, candidate, nodal_constraints, settings, params):
|
|
45
|
+
return state.replace(
|
|
46
|
+
# accept the candidate: its trajectory becomes the next iterate
|
|
47
|
+
x=candidate.x,
|
|
48
|
+
u=candidate.u,
|
|
49
|
+
x_prop=candidate.x_prop,
|
|
50
|
+
x_prop_plus=candidate.x_prop_plus,
|
|
51
|
+
# ramp the proximal weight every iteration
|
|
52
|
+
lam_prox=state.lam_prox * state.hyper.ramp,
|
|
53
|
+
# jnp.int32, not bare asarray: the code must keep the state field's
|
|
54
|
+
# strong int32 dtype or the lax.while_loop carry check fails.
|
|
55
|
+
adaptive_state_code=jnp.int32(AdaptiveStateCode.ACCEPT_HIGHER),
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Three rules carry the whole contract.
|
|
60
|
+
|
|
61
|
+
### The returned state *is* the next iterate
|
|
62
|
+
|
|
63
|
+
The SCP loop discards everything except what `update_weights` returns.
|
|
64
|
+
Accepting the subproblem's candidate therefore means **carrying its
|
|
65
|
+
trajectory onto the returned state** — `x` / `u` / `x_prop` / `x_prop_plus`
|
|
66
|
+
from `candidate` — while rejecting means keeping the previous fields and
|
|
67
|
+
adjusting only the weights.
|
|
68
|
+
|
|
69
|
+
!!! warning "The silent no-op"
|
|
70
|
+
An update that never copies the candidate produces a solver that runs to
|
|
71
|
+
`k_max` without the iterate ever moving — no error, just a flat history.
|
|
72
|
+
If a custom tuner seems to "not converge," check that the accept branch
|
|
73
|
+
copies all four trajectory fields.
|
|
74
|
+
|
|
75
|
+
Express any accept/reject branching with `jax.lax.cond` or `jnp.where`, not a
|
|
76
|
+
Python `if` on iterate values: `update_weights` is traced (it runs inside the
|
|
77
|
+
`lax.while_loop` of `solve_jax` / `solve_batched`, vmapped per batch element),
|
|
78
|
+
so it must not mutate `state` or `candidate`, raise on data-dependent
|
|
79
|
+
conditions, or return strings.
|
|
80
|
+
|
|
81
|
+
### Declare tunable knobs as `HyperParams`, not `self` attributes
|
|
82
|
+
|
|
83
|
+
A numeric knob a user might sweep (a ramp factor, a relaxation iteration) must
|
|
84
|
+
**not** be read off `self` inside `update_weights` — a plain Python attribute
|
|
85
|
+
is baked into the trace and invisible to every override channel. Declare it on
|
|
86
|
+
a `HyperParams` subclass, assign an instance to `self.hyper`, and read it from
|
|
87
|
+
`state.hyper`.
|
|
88
|
+
|
|
89
|
+
The declaration *is* the registration. With nothing else, the field becomes:
|
|
90
|
+
|
|
91
|
+
* a **per-solve override** — `problem.solve_jax(algorithm={"ramp": 1.5})`;
|
|
92
|
+
* a **batchable sweep target** —
|
|
93
|
+
`problem.solve_batched(algorithm={"ramp": jnp.linspace(1.1, 2.0, 8)})`;
|
|
94
|
+
* a **runtime input** of the exported `solve_batched` artifact, so changing it
|
|
95
|
+
needs no recompile.
|
|
96
|
+
|
|
97
|
+
!!! danger "Assign `self.hyper` first"
|
|
98
|
+
Declared knobs are also readable and writable as bare attributes
|
|
99
|
+
(`autotuner.ramp = 3.0`) for ergonomics — a proxy on `AutotuningBase`
|
|
100
|
+
routes the access into `hyper`. That proxy only works once `self.hyper`
|
|
101
|
+
exists, so assign it as the **first** line of `__init__`. A knob assigned
|
|
102
|
+
before `hyper` exists lands as a plain instance attribute the proxy cannot
|
|
103
|
+
see, and your override channels silently break.
|
|
104
|
+
|
|
105
|
+
### Acceptance metrics are opt-in
|
|
106
|
+
|
|
107
|
+
`COMPUTES_ACCEPTANCE_METRICS` (default `True`) tells the loop whether
|
|
108
|
+
`update_weights` produces a predicted/actual reduction and an acceptance
|
|
109
|
+
ratio. The loop records and prints those diagnostics only when it is `True`.
|
|
110
|
+
A tuner that never rejects an iterate — like the built-in
|
|
111
|
+
`ConstantProximalWeight` and `RampProximalWeight` — sets it `False`.
|
|
112
|
+
|
|
113
|
+
To add columns to the iteration table, set the class attribute `COLUMNS` to a
|
|
114
|
+
list of `openscvx.utils.printing.Column` specs; the algorithm concatenates
|
|
115
|
+
them into its own table via `get_columns`.
|
|
116
|
+
|
|
117
|
+
## A custom algorithm
|
|
118
|
+
|
|
119
|
+
An `Algorithm` owns the SCP iteration end to end: it *builds* the JAX-pure
|
|
120
|
+
iteration body, *stores* it, and *drives* it one step at a time. All iteration
|
|
121
|
+
state lives on `AlgorithmState` (JAX-traceable) and `AlgorithmHistory`
|
|
122
|
+
(Python-side) threaded explicitly through `step()` — avoid storing mutable
|
|
123
|
+
iteration state on `self`.
|
|
124
|
+
|
|
125
|
+
The surface is six methods. `converged` has a working default; the other five
|
|
126
|
+
are abstract.
|
|
127
|
+
|
|
128
|
+
### `__init__` — end with `super().__init__`
|
|
129
|
+
|
|
130
|
+
The base records the weights, autotuner, and convergence parameters. Every
|
|
131
|
+
parameter is required, so the ABC is not yet another place defaults are
|
|
132
|
+
declared — your subclass owns the user-facing defaults and forwards them:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from openscvx.algorithms import Algorithm
|
|
136
|
+
from openscvx.algorithms.weights import Weights
|
|
137
|
+
from openscvx.algorithms import AugmentedLagrangian
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class MyAlgorithm(Algorithm):
|
|
141
|
+
def __init__(self, autotuner=None, k_max=200, **weight_kwargs):
|
|
142
|
+
super().__init__(
|
|
143
|
+
weights=Weights.build(**weight_kwargs),
|
|
144
|
+
autotuner=autotuner if autotuner is not None else AugmentedLagrangian(),
|
|
145
|
+
k_max=k_max,
|
|
146
|
+
t_max=None,
|
|
147
|
+
ep_tr=1e-4,
|
|
148
|
+
ep_vb=1e-4,
|
|
149
|
+
ep_vc=1e-8,
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `build_iteration` — fuse the step
|
|
154
|
+
|
|
155
|
+
`Problem` assembles the discretization solvers, lowered constraints, and
|
|
156
|
+
convex-solver callback, then asks the algorithm to fuse them into one JAX-pure
|
|
157
|
+
`(state, params) -> (next_state, diagnostics)` body. The algorithm owns this
|
|
158
|
+
because the fusion is algorithm-specific (which autotuner runs, which penalty
|
|
159
|
+
terms are assembled). PTR's implementation is a thin wrapper around
|
|
160
|
+
`make_scp_iteration` (`openscvx/algorithms/scvx/iteration.py`) that threads its
|
|
161
|
+
`autotuner` into the fused body. The returned body must advance `state.k` by
|
|
162
|
+
one per call — every solve path terminates on `k` reaching `k_max`.
|
|
163
|
+
|
|
164
|
+
### `initialize` and `step` — store, then drive
|
|
165
|
+
|
|
166
|
+
`Problem.initialize()` builds and JIT-warms the body, then hands it back via
|
|
167
|
+
`initialize(iteration_fn, emitter)` for the algorithm to store. `step()` is the
|
|
168
|
+
Python-loop driver: it calls the stored body, records the per-iteration
|
|
169
|
+
diagnostics into `history`, emits progress, and returns
|
|
170
|
+
`(next_state, converged)`.
|
|
171
|
+
|
|
172
|
+
### `converged` — the one-method convergence hook
|
|
173
|
+
|
|
174
|
+
`converged(state)` is the only piece of convergence policy that is
|
|
175
|
+
algorithm-specific; it has a concrete default, so override it only to change
|
|
176
|
+
the rule:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
def converged(self, state):
|
|
180
|
+
return state.J_vc < state.ep_vc # custom: virtual control alone
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The default — every metric below its threshold — is algorithm-agnostic, since
|
|
184
|
+
`AlgorithmState` carries `J_tr` / `J_vb` / `J_vc` and the `ep_*` tolerances
|
|
185
|
+
generically.
|
|
186
|
+
|
|
187
|
+
!!! note "Honored on every solve path"
|
|
188
|
+
The override is honored on **all three** solve paths. `step()` routes
|
|
189
|
+
through it on the Python `solve()` path, and the `lax.while_loop` harness
|
|
190
|
+
(`openscvx/algorithms/loop.py`) takes it as the loop predicate for
|
|
191
|
+
`solve_jax` / `solve_batched`, where it is vmapped per batch element. It
|
|
192
|
+
must therefore be JAX-traceable. An override implies a subclass, hence a
|
|
193
|
+
distinct class name that the export cache key already folds in — so a
|
|
194
|
+
changed predicate invalidates stale batched artifacts on its own.
|
|
195
|
+
|
|
196
|
+
By contrast, `t_max` (the wall-clock time limit) is honored **only** on the
|
|
197
|
+
Python `solve()` path; the JAX loop terminates on `k_max` and `converged`
|
|
198
|
+
alone, since there is no wall-clock probe inside a trace.
|
|
199
|
+
|
|
200
|
+
### `get_columns` and `citation`
|
|
201
|
+
|
|
202
|
+
`get_columns(verbosity)` returns the iteration-table columns to print —
|
|
203
|
+
implementations typically concatenate the algorithm's own columns with the
|
|
204
|
+
autotuner's `COLUMNS` and filter by each column's `min_verbosity`.
|
|
205
|
+
`citation()` returns a list of BibTeX strings for the algorithm.
|
|
206
|
+
|
|
207
|
+
## Using a custom class
|
|
208
|
+
|
|
209
|
+
Pass either to the `Problem` constructor — the algorithm directly, an
|
|
210
|
+
autotuner through the algorithm:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
import openscvx as ox
|
|
214
|
+
|
|
215
|
+
problem = ox.Problem(
|
|
216
|
+
...,
|
|
217
|
+
algorithm=MyAlgorithm(autotuner=MyAutotuner(ramp=1.5)),
|
|
218
|
+
)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The default `PenalizedTrustRegion` lives at
|
|
222
|
+
`openscvx/algorithms/scvx/penalized_trust_region.py` and is the reference
|
|
223
|
+
implementation to read alongside this guide.
|
|
@@ -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.dev26'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 3, 'dev26')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g053a32537'
|
|
@@ -5,9 +5,11 @@ for solving non-convex trajectory optimization problems through iterative convex
|
|
|
5
5
|
approximation.
|
|
6
6
|
|
|
7
7
|
All algorithms inherit from :class:`Algorithm`, enabling pluggable algorithm
|
|
8
|
-
implementations and custom SCvx variants.
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
implementations and custom SCvx variants. An algorithm builds its fused,
|
|
9
|
+
JAX-pure iteration body (``build_iteration``), stores it along with the
|
|
10
|
+
diagnostics emitter (``initialize``), drives it one step at a time on the
|
|
11
|
+
Python path (``step``), and owns its convergence policy (``converged``) —
|
|
12
|
+
honored identically by ``solve()``, ``solve_jax()``, and ``solve_batched()``.
|
|
11
13
|
|
|
12
14
|
The iterate carry is split into two objects:
|
|
13
15
|
|
|
@@ -37,6 +39,8 @@ from typing import Annotated, Any, Dict, List, Optional, Union
|
|
|
37
39
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
38
40
|
|
|
39
41
|
from .autotuner import (
|
|
42
|
+
AcceptanceRatioAutotuner,
|
|
43
|
+
AcceptanceRatioHyper,
|
|
40
44
|
AdaptiveProximalWeight,
|
|
41
45
|
AdaptiveProximalWeightSpec,
|
|
42
46
|
AugmentedLagrangian,
|
|
@@ -46,18 +50,18 @@ from .autotuner import (
|
|
|
46
50
|
RampProximalWeight,
|
|
47
51
|
RampProximalWeightSpec,
|
|
48
52
|
)
|
|
49
|
-
from .base import
|
|
53
|
+
from .autotuner.base import AutotuningBase
|
|
54
|
+
from .base import Algorithm
|
|
55
|
+
from .history import AlgorithmHistory, DiscretizationResult
|
|
56
|
+
from .hyperparams import HyperParams
|
|
57
|
+
from .optimization_results import OptimizationResults
|
|
58
|
+
from .scvx import PenalizedTrustRegion
|
|
59
|
+
from .state import (
|
|
50
60
|
AdaptiveStateCode,
|
|
51
|
-
Algorithm,
|
|
52
|
-
AlgorithmHistory,
|
|
53
61
|
AlgorithmState,
|
|
54
|
-
|
|
55
|
-
DiscretizationResult,
|
|
56
|
-
HyperParams,
|
|
62
|
+
CandidateIterate,
|
|
57
63
|
adaptive_state_code_to_str,
|
|
58
64
|
)
|
|
59
|
-
from .optimization_results import OptimizationResults
|
|
60
|
-
from .scvx import PenalizedTrustRegion
|
|
61
65
|
from .weights import Weights
|
|
62
66
|
|
|
63
67
|
# ---------------------------------------------------------------------------
|
|
@@ -138,6 +142,7 @@ __all__ = [
|
|
|
138
142
|
"AlgorithmHistory",
|
|
139
143
|
"AlgorithmState",
|
|
140
144
|
"AdaptiveStateCode",
|
|
145
|
+
"CandidateIterate",
|
|
141
146
|
"adaptive_state_code_to_str",
|
|
142
147
|
"DiscretizationResult",
|
|
143
148
|
"Weights",
|
|
@@ -147,6 +152,8 @@ __all__ = [
|
|
|
147
152
|
"PenalizedTrustRegion",
|
|
148
153
|
"AutotuningBase",
|
|
149
154
|
"HyperParams",
|
|
155
|
+
"AcceptanceRatioAutotuner",
|
|
156
|
+
"AcceptanceRatioHyper",
|
|
150
157
|
"AugmentedLagrangian",
|
|
151
158
|
"AdaptiveProximalWeight",
|
|
152
159
|
"ConstantProximalWeight",
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
"""SCP weight autotuning strategies."""
|
|
2
2
|
|
|
3
|
+
from .acceptance_ratio import AcceptanceRatioAutotuner, AcceptanceRatioHyper
|
|
3
4
|
from .adaptive_proximal_weight import AdaptiveProximalWeight, AdaptiveProximalWeightSpec
|
|
4
5
|
from .augmented_lagrangian import AugmentedLagrangian, AugmentedLagrangianSpec
|
|
5
6
|
from .constant_proximal_weight import ConstantProximalWeight, ConstantProximalWeightSpec
|
|
6
7
|
from .ramp_proximal_weight import RampProximalWeight, RampProximalWeightSpec
|
|
7
8
|
|
|
8
9
|
__all__ = [
|
|
10
|
+
"AcceptanceRatioAutotuner",
|
|
11
|
+
"AcceptanceRatioHyper",
|
|
9
12
|
"AdaptiveProximalWeight",
|
|
10
13
|
"AdaptiveProximalWeightSpec",
|
|
11
14
|
"AugmentedLagrangian",
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""Acceptance-ratio autotuner family.
|
|
2
|
+
|
|
3
|
+
The acceptance-ratio autotuners share one decision rule: an acceptance ratio
|
|
4
|
+
:math:`\\rho` between the predicted and actual reduction of the nonlinear
|
|
5
|
+
objective drives a four-bucket update of the trust-region weight ``lam_prox``
|
|
6
|
+
(``REJECT`` / ``ACCEPT_HIGHER`` / ``ACCEPT_CONSTANT`` / ``ACCEPT_LOWER``). What
|
|
7
|
+
differs between members is the *multiplier* rule — how the virtual-control and
|
|
8
|
+
virtual-buffer weights (``lam_vc`` / ``lam_vb_*``) respond once an iterate is
|
|
9
|
+
accepted.
|
|
10
|
+
|
|
11
|
+
:class:`AcceptanceRatioAutotuner` owns the shared decision body and exposes a
|
|
12
|
+
single :meth:`AcceptanceRatioAutotuner._update_multipliers` hook for the
|
|
13
|
+
multiplier rule; subclasses supply only that hook.
|
|
14
|
+
:class:`AdaptiveProximalWeight` is the hook-default (multipliers held
|
|
15
|
+
constant); :class:`AugmentedLagrangian` overrides it with the
|
|
16
|
+
constraint-violation update.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from typing import TYPE_CHECKING, List
|
|
20
|
+
|
|
21
|
+
import jax
|
|
22
|
+
import jax.numpy as jnp
|
|
23
|
+
|
|
24
|
+
from openscvx.config import Config
|
|
25
|
+
from openscvx.utils.printing import (
|
|
26
|
+
Column,
|
|
27
|
+
Verbosity,
|
|
28
|
+
color_acceptance_ratio,
|
|
29
|
+
color_adaptive_state,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
from ..penalty import calculate_nonlinear_penalty
|
|
33
|
+
from ..state import AdaptiveStateCode
|
|
34
|
+
from .base import AutotuningBase, LamCostRelaxHyper
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from openscvx.lowered import LoweredJaxConstraints
|
|
38
|
+
|
|
39
|
+
from ..state import AlgorithmState, CandidateIterate
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AcceptanceRatioHyper(LamCostRelaxHyper):
|
|
43
|
+
"""Knobs shared by every acceptance-ratio autotuner.
|
|
44
|
+
|
|
45
|
+
Extends the shared :class:`LamCostRelaxHyper` ``lam_cost`` relaxation knobs
|
|
46
|
+
with the acceptance-ratio decision thresholds and the ``lam_prox`` clips.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
gamma_1: float = 2.0
|
|
50
|
+
gamma_2: float = 0.5
|
|
51
|
+
eta_0: float = 1e-2
|
|
52
|
+
eta_1: float = 1e-1
|
|
53
|
+
eta_2: float = 0.8
|
|
54
|
+
lam_prox_min: float = 1e-3
|
|
55
|
+
lam_prox_max: float = 1e4
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class AcceptanceRatioAutotuner(AutotuningBase):
|
|
59
|
+
"""Four-bucket acceptance-ratio update on ``lam_prox``.
|
|
60
|
+
|
|
61
|
+
The acceptance ratio :math:`\\rho` (actual over predicted nonlinear
|
|
62
|
+
reduction) selects one of four buckets — ``REJECT`` / ``ACCEPT_HIGHER`` /
|
|
63
|
+
``ACCEPT_CONSTANT`` / ``ACCEPT_LOWER`` — via a ``jnp.where`` cascade so the
|
|
64
|
+
whole update traces under ``jax.jit``. Subclasses supply the multiplier
|
|
65
|
+
rule (how ``lam_vc`` / ``lam_vb_*`` respond on acceptance) through
|
|
66
|
+
:meth:`_update_multipliers`, and must assign an
|
|
67
|
+
:class:`AcceptanceRatioHyper` (or subclass) instance to ``self.hyper`` in
|
|
68
|
+
``__init__`` — the shared body reads its knobs off ``state.hyper``.
|
|
69
|
+
|
|
70
|
+
``update_weights`` is a pure functional update on the
|
|
71
|
+
:class:`AlgorithmState` pytree; see the base-class contract.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
COLUMNS: List[Column] = [
|
|
75
|
+
Column("J_nonlin", "J_nonlin", 8, "{: .1e}", None, Verbosity.STANDARD),
|
|
76
|
+
Column("J_lin", "J_lin", 8, "{: .1e}", None, Verbosity.STANDARD),
|
|
77
|
+
Column("pred_reduction", "pred_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
|
|
78
|
+
Column("actual_reduction", "act_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
|
|
79
|
+
Column(
|
|
80
|
+
"acceptance_ratio",
|
|
81
|
+
"acc_ratio",
|
|
82
|
+
9,
|
|
83
|
+
"{: .2e}",
|
|
84
|
+
color_acceptance_ratio,
|
|
85
|
+
Verbosity.STANDARD,
|
|
86
|
+
),
|
|
87
|
+
Column("lam_prox", "lam_prox", 8, "{: .1e}", min_verbosity=Verbosity.FULL),
|
|
88
|
+
Column("adaptive_state", "Adaptive", 16, "{}", color_adaptive_state, Verbosity.FULL),
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
def _update_multipliers(
|
|
92
|
+
self,
|
|
93
|
+
state: "AlgorithmState",
|
|
94
|
+
candidate: "CandidateIterate",
|
|
95
|
+
nodal_constraints: "LoweredJaxConstraints",
|
|
96
|
+
params: dict,
|
|
97
|
+
settings: Config,
|
|
98
|
+
new_lam_prox: jnp.ndarray,
|
|
99
|
+
) -> dict:
|
|
100
|
+
"""Return the multiplier-weight updates to apply on an accepted iterate.
|
|
101
|
+
|
|
102
|
+
Each returned entry maps an :class:`AlgorithmState` field name
|
|
103
|
+
(``lam_vc`` / ``lam_vb_nodal`` / ``lam_vb_cross``) to its updated
|
|
104
|
+
value, computed against the *candidate* trajectory; the shared body
|
|
105
|
+
gates each by acceptance (a rejected iterate keeps the previous value).
|
|
106
|
+
The default holds every multiplier constant — return ``{}``.
|
|
107
|
+
"""
|
|
108
|
+
return {}
|
|
109
|
+
|
|
110
|
+
def update_weights(
|
|
111
|
+
self,
|
|
112
|
+
state: "AlgorithmState",
|
|
113
|
+
candidate: "CandidateIterate",
|
|
114
|
+
nodal_constraints: "LoweredJaxConstraints",
|
|
115
|
+
settings: Config,
|
|
116
|
+
params: dict,
|
|
117
|
+
) -> "AlgorithmState":
|
|
118
|
+
"""Return the next-iterate state per the acceptance-ratio rules.
|
|
119
|
+
|
|
120
|
+
Pure functional update — see class docstring.
|
|
121
|
+
"""
|
|
122
|
+
candidate_x_prop = candidate.x_prop_plus[1:]
|
|
123
|
+
nonlin_cost, nonlin_pen, nodal_pen = calculate_nonlinear_penalty(
|
|
124
|
+
candidate_x_prop,
|
|
125
|
+
candidate.x,
|
|
126
|
+
candidate.u,
|
|
127
|
+
state.lam_vc,
|
|
128
|
+
state.lam_vb_nodal,
|
|
129
|
+
state.lam_vb_cross,
|
|
130
|
+
state.lam_cost,
|
|
131
|
+
nodal_constraints,
|
|
132
|
+
params,
|
|
133
|
+
settings,
|
|
134
|
+
)
|
|
135
|
+
J_nonlin = nonlin_cost + nonlin_pen + nodal_pen
|
|
136
|
+
|
|
137
|
+
lam_cost_next = self._relaxed_lam_cost(state)
|
|
138
|
+
|
|
139
|
+
def first_iter(state):
|
|
140
|
+
# Iter 1: accept unconditionally, leave weights at their init values,
|
|
141
|
+
# only refresh trajectory + propagation fields.
|
|
142
|
+
return state.replace(
|
|
143
|
+
x=candidate.x,
|
|
144
|
+
u=candidate.u,
|
|
145
|
+
x_prop=candidate.x_prop,
|
|
146
|
+
x_prop_plus=candidate.x_prop_plus,
|
|
147
|
+
lam_cost=lam_cost_next,
|
|
148
|
+
J_nonlin=J_nonlin,
|
|
149
|
+
adaptive_state_code=jnp.asarray(int(AdaptiveStateCode.INITIAL), dtype=jnp.int32),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def later_iter(state):
|
|
153
|
+
# Recompute the previous iterate's J_nonlin from the pytree fields
|
|
154
|
+
# (state.x/state.u were the *previous* accepted iterate).
|
|
155
|
+
prev_x_prop = state.x_prop_plus[1:]
|
|
156
|
+
prev_cost, prev_pen, prev_nodal_pen = calculate_nonlinear_penalty(
|
|
157
|
+
prev_x_prop,
|
|
158
|
+
state.x,
|
|
159
|
+
state.u,
|
|
160
|
+
state.lam_vc,
|
|
161
|
+
state.lam_vb_nodal,
|
|
162
|
+
state.lam_vb_cross,
|
|
163
|
+
state.lam_cost,
|
|
164
|
+
nodal_constraints,
|
|
165
|
+
params,
|
|
166
|
+
settings,
|
|
167
|
+
)
|
|
168
|
+
prev_J_nonlin = prev_cost + prev_pen + prev_nodal_pen
|
|
169
|
+
|
|
170
|
+
actual = prev_J_nonlin - J_nonlin
|
|
171
|
+
predicted = prev_J_nonlin - candidate.J_lin
|
|
172
|
+
# If predicted reduction is exactly zero, force the reject bucket
|
|
173
|
+
# (rho = -inf) deterministically instead of raising.
|
|
174
|
+
safe_pred = jnp.where(predicted == 0.0, 1.0, predicted)
|
|
175
|
+
rho = jnp.where(predicted == 0.0, -jnp.inf, actual / safe_pred)
|
|
176
|
+
|
|
177
|
+
is_reject = rho < state.hyper.eta_0
|
|
178
|
+
is_accept_higher = (rho >= state.hyper.eta_0) & (rho < state.hyper.eta_1)
|
|
179
|
+
is_accept_constant = (rho >= state.hyper.eta_1) & (rho < state.hyper.eta_2)
|
|
180
|
+
# is_accept_lower implicit (else)
|
|
181
|
+
accepted = ~is_reject
|
|
182
|
+
|
|
183
|
+
# Compute both lam_prox candidates and gate.
|
|
184
|
+
lp_higher = jnp.minimum(state.hyper.lam_prox_max, state.hyper.gamma_1 * state.lam_prox)
|
|
185
|
+
lp_lower = jnp.maximum(state.hyper.lam_prox_min, state.hyper.gamma_2 * state.lam_prox)
|
|
186
|
+
new_lam_prox = jnp.where(
|
|
187
|
+
is_reject | is_accept_higher,
|
|
188
|
+
lp_higher,
|
|
189
|
+
jnp.where(is_accept_constant, state.lam_prox, lp_lower),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Multiplier (virtual-control / virtual-buffer) updates: computed
|
|
193
|
+
# against the *candidate* trajectory and gated by `accepted`. Reject
|
|
194
|
+
# keeps the previous values (so the next subproblem doesn't see a
|
|
195
|
+
# bumped penalty that wasn't earned). The default hook returns {} —
|
|
196
|
+
# multipliers held constant.
|
|
197
|
+
multiplier_updates = self._update_multipliers(
|
|
198
|
+
state, candidate, nodal_constraints, params, settings, new_lam_prox
|
|
199
|
+
)
|
|
200
|
+
gated_multipliers = {
|
|
201
|
+
name: jnp.where(accepted, value, getattr(state, name))
|
|
202
|
+
for name, value in multiplier_updates.items()
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
code = jnp.where(
|
|
206
|
+
is_reject,
|
|
207
|
+
jnp.int32(AdaptiveStateCode.REJECT),
|
|
208
|
+
jnp.where(
|
|
209
|
+
is_accept_higher,
|
|
210
|
+
jnp.int32(AdaptiveStateCode.ACCEPT_HIGHER),
|
|
211
|
+
jnp.where(
|
|
212
|
+
is_accept_constant,
|
|
213
|
+
jnp.int32(AdaptiveStateCode.ACCEPT_CONSTANT),
|
|
214
|
+
jnp.int32(AdaptiveStateCode.ACCEPT_LOWER),
|
|
215
|
+
),
|
|
216
|
+
),
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
return state.replace(
|
|
220
|
+
x=jnp.where(accepted, candidate.x, state.x),
|
|
221
|
+
u=jnp.where(accepted, candidate.u, state.u),
|
|
222
|
+
x_prop=jnp.where(accepted, candidate.x_prop, state.x_prop),
|
|
223
|
+
x_prop_plus=jnp.where(accepted, candidate.x_prop_plus, state.x_prop_plus),
|
|
224
|
+
lam_prox=new_lam_prox,
|
|
225
|
+
lam_cost=lam_cost_next,
|
|
226
|
+
J_nonlin=jnp.where(accepted, J_nonlin, state.J_nonlin),
|
|
227
|
+
predicted_reduction=predicted,
|
|
228
|
+
actual_reduction=actual,
|
|
229
|
+
acceptance_ratio=rho,
|
|
230
|
+
adaptive_state_code=code,
|
|
231
|
+
**gated_multipliers,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
return jax.lax.cond(state.k == 1, first_iter, later_iter, state)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Adaptive proximal-weight autotuner.
|
|
2
|
+
|
|
3
|
+
Same acceptance-ratio decision logic as the rest of the family for
|
|
4
|
+
``lam_prox``, but ``lam_vc`` and ``lam_vb_*`` are held constant at their
|
|
5
|
+
current values — the default multiplier hook.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, ConfigDict
|
|
11
|
+
|
|
12
|
+
from .acceptance_ratio import AcceptanceRatioAutotuner, AcceptanceRatioHyper
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AdaptiveProximalWeight(AcceptanceRatioAutotuner):
|
|
16
|
+
"""PTR-style proximal adaptation with fixed virtual-penalty weights.
|
|
17
|
+
|
|
18
|
+
Inherits the four-bucket acceptance-ratio update on ``lam_prox`` from
|
|
19
|
+
:class:`~openscvx.algorithms.autotuner.acceptance_ratio.AcceptanceRatioAutotuner`
|
|
20
|
+
and keeps the default multiplier hook, so the virtual-control and
|
|
21
|
+
virtual-buffer weights are carried unchanged.
|
|
22
|
+
|
|
23
|
+
``update_weights`` is a pure functional update on the
|
|
24
|
+
:class:`AlgorithmState` pytree; see the base-class contract.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
gamma_1: float = 2.0,
|
|
30
|
+
gamma_2: float = 0.5,
|
|
31
|
+
eta_0: float = 1e-2,
|
|
32
|
+
eta_1: float = 1e-1,
|
|
33
|
+
eta_2: float = 0.8,
|
|
34
|
+
lam_prox_min: float = 1e-3,
|
|
35
|
+
lam_prox_max: float = 1e4,
|
|
36
|
+
lam_cost_drop: int = -1,
|
|
37
|
+
lam_cost_relax: float = 1.0,
|
|
38
|
+
):
|
|
39
|
+
self.hyper = AcceptanceRatioHyper(
|
|
40
|
+
gamma_1=gamma_1,
|
|
41
|
+
gamma_2=gamma_2,
|
|
42
|
+
eta_0=eta_0,
|
|
43
|
+
eta_1=eta_1,
|
|
44
|
+
eta_2=eta_2,
|
|
45
|
+
lam_prox_min=lam_prox_min,
|
|
46
|
+
lam_prox_max=lam_prox_max,
|
|
47
|
+
lam_cost_drop=lam_cost_drop,
|
|
48
|
+
lam_cost_relax=lam_cost_relax,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# =============================================================================
|
|
53
|
+
# Pydantic spec for dict / YAML validation
|
|
54
|
+
# =============================================================================
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class AdaptiveProximalWeightSpec(BaseModel):
|
|
58
|
+
"""Validates AdaptiveProximalWeight configuration from dict/YAML input."""
|
|
59
|
+
|
|
60
|
+
type: Literal["AdaptiveProximalWeight"] = "AdaptiveProximalWeight"
|
|
61
|
+
gamma_1: float = 2.0
|
|
62
|
+
gamma_2: float = 0.5
|
|
63
|
+
eta_0: float = 1e-2
|
|
64
|
+
eta_1: float = 1e-1
|
|
65
|
+
eta_2: float = 0.8
|
|
66
|
+
lam_prox_min: float = 1e-3
|
|
67
|
+
lam_prox_max: float = 1e4
|
|
68
|
+
lam_cost_drop: int = -1
|
|
69
|
+
lam_cost_relax: float = 1.0
|
|
70
|
+
|
|
71
|
+
model_config = ConfigDict(extra="forbid")
|
|
72
|
+
|
|
73
|
+
def build(self) -> AdaptiveProximalWeight:
|
|
74
|
+
return AdaptiveProximalWeight(**self.model_dump(exclude={"type"}, exclude_unset=True))
|