openscvx 0.5.3.dev25__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.dev25/openscvx.egg-info → openscvx-0.5.3.dev26}/PKG-INFO +1 -1
- openscvx-0.5.3.dev26/docs/UnderTheHood/custom_algorithms_autotuners.md +223 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/mkdocs.yml +2 -1
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/_version.py +3 -3
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/__init__.py +12 -11
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/acceptance_ratio.py +10 -21
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/augmented_lagrangian.py +1 -1
- openscvx-0.5.3.dev26/openscvx/algorithms/autotuner/base.py +259 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/constant_proximal_weight.py +7 -14
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +7 -13
- 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.dev25 → 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.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/iteration.py +31 -75
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/penalized_trust_region.py +31 -52
- openscvx-0.5.3.dev26/openscvx/algorithms/state.py +345 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/problem.py +6 -9
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/caching.py +9 -1
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/SOURCES.txt +8 -0
- openscvx-0.5.3.dev26/tests/algorithms/autotuner/test_defaults_agreement.py +137 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/test_hyper_overrides.py +16 -17
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/test_update_weights_jit.py +9 -12
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_make_solve_loop.py +25 -3
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_autotuning.py +118 -104
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_discretization.py +1 -1
- openscvx-0.5.3.dev25/openscvx/algorithms/base.py +0 -1162
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.gitignore +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/.gitmodules +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/LICENSE +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/README.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UnderTheHood/batching_jit_grad.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/citation.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/examples.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/index.md +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/docs/versions.json +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/brachistochrone_batched.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/flappy_bird.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/_render.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/logo.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/cinema_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/drone_racing_batched_gates.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/drone/openscvx_logo.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/plotting.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/rocket/ascent_launch_vehicle.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/examples/spacecraft/relative_loitering.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/figures/video_preview.png +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/home.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/main.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/__main__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/config.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/loader.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/publication.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/coordinates.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/base.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/cones.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/solvers/qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/affine.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/canonicalize.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/printing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/pyproject.toml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/setup.cfg +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/_marks.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/_iteration_helpers.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_jit.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/algorithms/test_iteration_fn_parity.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/conftest.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/expr/test_gmsr.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/_iteration_callback_helpers.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_moreau.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_qpax.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_iteration_callback_vmap.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/solvers/test_subproblem_pytree.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_examples.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_expert.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_impulsive.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_init.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_integrators.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_loader.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_optimization_results.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_plotting.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_propagation.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_export_roundtrip.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_batched_inference.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev25 → 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
|
|
@@ -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
|
|
|
@@ -48,19 +50,18 @@ from .autotuner import (
|
|
|
48
50
|
RampProximalWeight,
|
|
49
51
|
RampProximalWeightSpec,
|
|
50
52
|
)
|
|
51
|
-
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 (
|
|
52
60
|
AdaptiveStateCode,
|
|
53
|
-
Algorithm,
|
|
54
|
-
AlgorithmHistory,
|
|
55
61
|
AlgorithmState,
|
|
56
|
-
AutotuningBase,
|
|
57
62
|
CandidateIterate,
|
|
58
|
-
DiscretizationResult,
|
|
59
|
-
HyperParams,
|
|
60
63
|
adaptive_state_code_to_str,
|
|
61
64
|
)
|
|
62
|
-
from .optimization_results import OptimizationResults
|
|
63
|
-
from .scvx import PenalizedTrustRegion
|
|
64
65
|
from .weights import Weights
|
|
65
66
|
|
|
66
67
|
# ---------------------------------------------------------------------------
|
{openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/acceptance_ratio.py
RENAMED
|
@@ -29,20 +29,21 @@ from openscvx.utils.printing import (
|
|
|
29
29
|
color_adaptive_state,
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
from ..
|
|
32
|
+
from ..penalty import calculate_nonlinear_penalty
|
|
33
|
+
from ..state import AdaptiveStateCode
|
|
34
|
+
from .base import AutotuningBase, LamCostRelaxHyper
|
|
33
35
|
|
|
34
36
|
if TYPE_CHECKING:
|
|
35
37
|
from openscvx.lowered import LoweredJaxConstraints
|
|
36
38
|
|
|
37
|
-
from ..
|
|
39
|
+
from ..state import AlgorithmState, CandidateIterate
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
class AcceptanceRatioHyper(
|
|
42
|
+
class AcceptanceRatioHyper(LamCostRelaxHyper):
|
|
41
43
|
"""Knobs shared by every acceptance-ratio autotuner.
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
iteration, and the default ``lam_cost_relax=1.0`` makes that a no-op.
|
|
45
|
+
Extends the shared :class:`LamCostRelaxHyper` ``lam_cost`` relaxation knobs
|
|
46
|
+
with the acceptance-ratio decision thresholds and the ``lam_prox`` clips.
|
|
46
47
|
"""
|
|
47
48
|
|
|
48
49
|
gamma_1: float = 2.0
|
|
@@ -52,8 +53,6 @@ class AcceptanceRatioHyper(HyperParams):
|
|
|
52
53
|
eta_2: float = 0.8
|
|
53
54
|
lam_prox_min: float = 1e-3
|
|
54
55
|
lam_prox_max: float = 1e4
|
|
55
|
-
lam_cost_drop: int = -1
|
|
56
|
-
lam_cost_relax: float = 1.0
|
|
57
56
|
|
|
58
57
|
|
|
59
58
|
class AcceptanceRatioAutotuner(AutotuningBase):
|
|
@@ -121,7 +120,7 @@ class AcceptanceRatioAutotuner(AutotuningBase):
|
|
|
121
120
|
Pure functional update — see class docstring.
|
|
122
121
|
"""
|
|
123
122
|
candidate_x_prop = candidate.x_prop_plus[1:]
|
|
124
|
-
nonlin_cost, nonlin_pen, nodal_pen =
|
|
123
|
+
nonlin_cost, nonlin_pen, nodal_pen = calculate_nonlinear_penalty(
|
|
125
124
|
candidate_x_prop,
|
|
126
125
|
candidate.x,
|
|
127
126
|
candidate.u,
|
|
@@ -135,17 +134,7 @@ class AcceptanceRatioAutotuner(AutotuningBase):
|
|
|
135
134
|
)
|
|
136
135
|
J_nonlin = nonlin_cost + nonlin_pen + nodal_pen
|
|
137
136
|
|
|
138
|
-
|
|
139
|
-
# state.lam_cost; otherwise reset to the algorithm's initial weight
|
|
140
|
-
# (carried on the pytree as state.lam_cost_init, broadcast at
|
|
141
|
-
# from_settings()). Both constants ride the pytree so per-solve
|
|
142
|
-
# overrides and vmap sweeps reach the traced body. Scalar
|
|
143
|
-
# lam_cost_relax preserves the user-specified per-state weight ratios.
|
|
144
|
-
lam_cost_next = jnp.where(
|
|
145
|
-
state.k > state.hyper.lam_cost_drop,
|
|
146
|
-
state.lam_cost * state.hyper.lam_cost_relax,
|
|
147
|
-
state.lam_cost_init,
|
|
148
|
-
)
|
|
137
|
+
lam_cost_next = self._relaxed_lam_cost(state)
|
|
149
138
|
|
|
150
139
|
def first_iter(state):
|
|
151
140
|
# Iter 1: accept unconditionally, leave weights at their init values,
|
|
@@ -164,7 +153,7 @@ class AcceptanceRatioAutotuner(AutotuningBase):
|
|
|
164
153
|
# Recompute the previous iterate's J_nonlin from the pytree fields
|
|
165
154
|
# (state.x/state.u were the *previous* accepted iterate).
|
|
166
155
|
prev_x_prop = state.x_prop_plus[1:]
|
|
167
|
-
prev_cost, prev_pen, prev_nodal_pen =
|
|
156
|
+
prev_cost, prev_pen, prev_nodal_pen = calculate_nonlinear_penalty(
|
|
168
157
|
prev_x_prop,
|
|
169
158
|
state.x,
|
|
170
159
|
state.u,
|
{openscvx-0.5.3.dev25 → openscvx-0.5.3.dev26}/openscvx/algorithms/autotuner/augmented_lagrangian.py
RENAMED
|
@@ -18,7 +18,7 @@ from .acceptance_ratio import AcceptanceRatioAutotuner, AcceptanceRatioHyper
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from openscvx.lowered import LoweredJaxConstraints
|
|
20
20
|
|
|
21
|
-
from ..
|
|
21
|
+
from ..state import AlgorithmState, CandidateIterate
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class AugmentedLagrangianHyper(AcceptanceRatioHyper):
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""Abstract base for autotuning strategies.
|
|
2
|
+
|
|
3
|
+
:class:`AutotuningBase` is the contract every penalty-weight update rule
|
|
4
|
+
implements: :py:meth:`~AutotuningBase.update_weights` is a pure functional
|
|
5
|
+
update on an :class:`~openscvx.algorithms.state.AlgorithmState` pytree, so the
|
|
6
|
+
SCP body composes with ``jax.jit`` / ``jax.vmap`` / ``jax.grad``. The base also
|
|
7
|
+
houses :class:`LamCostRelaxHyper`, the ``lam_cost`` relaxation knobs every
|
|
8
|
+
built-in autotuner shares, and :meth:`AutotuningBase._relaxed_lam_cost`, the
|
|
9
|
+
single implementation of that rule.
|
|
10
|
+
|
|
11
|
+
This module mirrors the package's ``base.py``-is-the-ABC idiom inside the
|
|
12
|
+
``autotuner`` subpackage; the concrete autotuners live alongside it.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from abc import ABC, abstractmethod
|
|
16
|
+
from dataclasses import fields as dc_fields
|
|
17
|
+
from dataclasses import replace as dc_replace
|
|
18
|
+
from typing import TYPE_CHECKING, List
|
|
19
|
+
|
|
20
|
+
import jax.numpy as jnp
|
|
21
|
+
|
|
22
|
+
from openscvx.utils.printing import Column
|
|
23
|
+
|
|
24
|
+
from ..hyperparams import HyperParams
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
import hashlib
|
|
28
|
+
|
|
29
|
+
from openscvx.config import Config
|
|
30
|
+
from openscvx.lowered.jax_constraints import LoweredJaxConstraints
|
|
31
|
+
|
|
32
|
+
from ..state import AlgorithmState, CandidateIterate
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class LamCostRelaxHyper(HyperParams):
|
|
36
|
+
"""``lam_cost`` relaxation knobs shared by every built-in autotuner.
|
|
37
|
+
|
|
38
|
+
Every autotuner relaxes ``lam_cost`` by the same rule (see
|
|
39
|
+
:meth:`AutotuningBase._relaxed_lam_cost`), so the two knobs that steer it
|
|
40
|
+
live here once instead of being re-declared per class. ``lam_cost_drop`` is
|
|
41
|
+
the iteration after which relaxation applies (``state.k > lam_cost_drop``):
|
|
42
|
+
``-1`` relaxes from the first iteration, and the default
|
|
43
|
+
``lam_cost_relax=1.0`` makes that a no-op.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
lam_cost_drop: int = -1
|
|
47
|
+
lam_cost_relax: float = 1.0
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class AutotuningBase(ABC):
|
|
51
|
+
"""Base class for autotuning strategies in SCP algorithms.
|
|
52
|
+
|
|
53
|
+
Subclasses implement :py:meth:`update_weights` as a **pure functional
|
|
54
|
+
update** on an :class:`AlgorithmState` pytree. Concretely, an autotuner
|
|
55
|
+
must:
|
|
56
|
+
|
|
57
|
+
* Not mutate ``state`` or ``candidate``.
|
|
58
|
+
* Not return strings, raise on data-dependent conditions, or append to
|
|
59
|
+
Python lists at trace time.
|
|
60
|
+
* Express all branching on iterate values via ``jax.lax.cond`` /
|
|
61
|
+
``jnp.where``.
|
|
62
|
+
|
|
63
|
+
The autotuner's per-iteration outcome is encoded as an
|
|
64
|
+
:class:`AdaptiveStateCode` int32 on the returned state; the SCP loop
|
|
65
|
+
converts that back to a human-readable label only on the Python-loop
|
|
66
|
+
printing path.
|
|
67
|
+
|
|
68
|
+
**The returned state IS the next iterate.** The SCP loop discards
|
|
69
|
+
everything except what ``update_weights`` returns, so accepting the
|
|
70
|
+
subproblem's candidate means carrying its trajectory onto the returned
|
|
71
|
+
state — ``x`` / ``u`` / ``x_prop`` / ``x_prop_plus`` from ``candidate`` —
|
|
72
|
+
while rejecting means keeping the previous fields and adjusting only the
|
|
73
|
+
weights. An update that never copies the candidate produces a solver that
|
|
74
|
+
runs to ``k_max`` without the iterate ever moving, silently.
|
|
75
|
+
|
|
76
|
+
**Declaring tunable hyperparameters.** A numeric knob a user might sweep
|
|
77
|
+
(a penalty ramp, a relaxation iteration) must not be read off ``self``
|
|
78
|
+
inside ``update_weights`` — a Python attribute is baked into the trace
|
|
79
|
+
and invisible to every override channel. Instead, declare it on a
|
|
80
|
+
:class:`HyperParams` subclass, assign an instance to ``self.hyper``, and
|
|
81
|
+
read it from ``state.hyper``::
|
|
82
|
+
|
|
83
|
+
class MyHyper(HyperParams):
|
|
84
|
+
ramp: float = 2.0
|
|
85
|
+
|
|
86
|
+
class MyAutotuner(AutotuningBase):
|
|
87
|
+
def __init__(self, ramp: float = 2.0):
|
|
88
|
+
self.hyper = MyHyper(ramp=ramp)
|
|
89
|
+
|
|
90
|
+
def update_weights(self, state, candidate, nodal_constraints, settings, params):
|
|
91
|
+
return state.replace(
|
|
92
|
+
# accept the candidate: it becomes the next iterate
|
|
93
|
+
x=candidate.x,
|
|
94
|
+
u=candidate.u,
|
|
95
|
+
x_prop=candidate.x_prop,
|
|
96
|
+
x_prop_plus=candidate.x_prop_plus,
|
|
97
|
+
lam_prox=state.lam_prox * state.hyper.ramp,
|
|
98
|
+
adaptive_state_code=...,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
The declaration is the registration: the field becomes a per-solve
|
|
102
|
+
override (``solve_jax(algorithm={"ramp": ...})``), a batchable sweep
|
|
103
|
+
target (``solve_batched(algorithm={"ramp": jnp.linspace(...)})``), and a
|
|
104
|
+
runtime input of the exported batched artifact — with zero core edits.
|
|
105
|
+
Every numeric knob of the built-in autotuners is declared this way, so the
|
|
106
|
+
only configuration left outside ``hyper`` is structural choices that select
|
|
107
|
+
code paths (class attributes like ``COMPUTES_ACCEPTANCE_METRICS``); they
|
|
108
|
+
are part of the traced program, not data. For ergonomics, declared knobs
|
|
109
|
+
are still readable and writable as bare attributes
|
|
110
|
+
(``autotuner.ramp = 3.0``): the proxy below routes the access into
|
|
111
|
+
``hyper`` so a constructor — or a test — may keep assigning knobs by name.
|
|
112
|
+
Assign ``self.hyper`` *first* in ``__init__``; a knob assigned before
|
|
113
|
+
``hyper`` exists lands as a plain instance attribute the proxy cannot see.
|
|
114
|
+
|
|
115
|
+
Class Attributes:
|
|
116
|
+
COLUMNS: List of Column specs for autotuner-specific metrics to display.
|
|
117
|
+
Subclasses override this to add their own columns.
|
|
118
|
+
COMPUTES_ACCEPTANCE_METRICS: Whether ``update_weights`` computes a
|
|
119
|
+
predicted/actual reduction and the resulting acceptance ratio. The
|
|
120
|
+
SCP loop records and prints those diagnostics only when this is
|
|
121
|
+
``True`` (the default); tuners that never reject an iterate — e.g.
|
|
122
|
+
:class:`~openscvx.algorithms.autotuner.constant_proximal_weight.ConstantProximalWeight`
|
|
123
|
+
and :class:`~openscvx.algorithms.autotuner.ramp_proximal_weight.RampProximalWeight`
|
|
124
|
+
— set it ``False``.
|
|
125
|
+
hyper: The autotuner's declared hyperparameters — a
|
|
126
|
+
:class:`HyperParams` instance carrying plain-Python defaults
|
|
127
|
+
(the empty base when it declares none). Snapshotted onto
|
|
128
|
+
``AlgorithmState.hyper`` with array leaves (see
|
|
129
|
+
:meth:`AlgorithmState.from_settings`; ``int`` fields get ``k``'s
|
|
130
|
+
integer dtype, ``float`` fields the float dtype), which is what
|
|
131
|
+
``update_weights`` reads at trace time.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
COLUMNS: List[Column] = []
|
|
135
|
+
COMPUTES_ACCEPTANCE_METRICS: bool = True
|
|
136
|
+
hyper: HyperParams = HyperParams()
|
|
137
|
+
|
|
138
|
+
def __getattr__(self, name: str):
|
|
139
|
+
"""Read a declared hyperparameter as a bare attribute.
|
|
140
|
+
|
|
141
|
+
Promoted knobs live on the frozen ``hyper`` container, but the
|
|
142
|
+
documented API and constructors still touch them by name
|
|
143
|
+
(``autotuner.lam_prox_max``). ``__getattr__`` fires only on failed
|
|
144
|
+
normal lookups, so real attributes (``COLUMNS``, ``hyper`` itself) are
|
|
145
|
+
unaffected; a name matching a ``hyper`` field resolves there.
|
|
146
|
+
"""
|
|
147
|
+
hyper = self.__dict__.get("hyper")
|
|
148
|
+
if hyper is not None and name in {f.name for f in dc_fields(hyper)}:
|
|
149
|
+
return getattr(hyper, name)
|
|
150
|
+
raise AttributeError(f"{type(self).__name__!r} has no attribute {name!r}")
|
|
151
|
+
|
|
152
|
+
def __setattr__(self, name: str, value) -> None:
|
|
153
|
+
"""Route a write to a declared hyperparameter into the frozen ``hyper``.
|
|
154
|
+
|
|
155
|
+
Without this, assigning a promoted knob as a bare attribute
|
|
156
|
+
(``autotuner.lam_prox_max = 1e6``) would silently shadow the ``hyper``
|
|
157
|
+
field and never reach the solve. A name matching a ``hyper`` field is
|
|
158
|
+
applied via :func:`dataclasses.replace`; every other attribute
|
|
159
|
+
(including ``hyper`` itself) is set normally, so constructors may keep
|
|
160
|
+
assigning knobs by name — they route into ``hyper``, provided
|
|
161
|
+
``self.hyper`` was assigned first (see the class docstring).
|
|
162
|
+
"""
|
|
163
|
+
hyper = self.__dict__.get("hyper")
|
|
164
|
+
if hyper is not None and name != "hyper" and name in {f.name for f in dc_fields(hyper)}:
|
|
165
|
+
# Clear any instance attribute shadowing the knob (left by an
|
|
166
|
+
# assignment made before ``hyper`` existed) so reads resolve
|
|
167
|
+
# through ``__getattr__`` to the value just written.
|
|
168
|
+
self.__dict__.pop(name, None)
|
|
169
|
+
super().__setattr__("hyper", dc_replace(hyper, **{name: value}))
|
|
170
|
+
else:
|
|
171
|
+
super().__setattr__(name, value)
|
|
172
|
+
|
|
173
|
+
def _hash_into(self, hasher: "hashlib._Hash") -> None:
|
|
174
|
+
"""Contribute the autotuner's update rule to the ``solve_batched`` cache key.
|
|
175
|
+
|
|
176
|
+
The exported batched loop bakes in ``update_weights`` and every numeric
|
|
177
|
+
parameter that steers it (penalty ramps, acceptance thresholds, weight
|
|
178
|
+
clips). The default hashes the concrete class plus all instance
|
|
179
|
+
attributes — sufficient because autotuner parameters are plain
|
|
180
|
+
scalars. The ``hyper`` *values* are excluded: declared hyperparameters
|
|
181
|
+
ride ``AlgorithmState.hyper`` as runtime inputs, so one artifact serves
|
|
182
|
+
every setting of them (the same reasoning that keeps the ``ep_*``
|
|
183
|
+
thresholds out of the algorithm's hash). The ``hyper`` *schema* is
|
|
184
|
+
folded in, though: the ``hyper`` leaves map positionally onto the
|
|
185
|
+
exported artifact's avals, so a field reorder or addition silently
|
|
186
|
+
permutes runtime values against the wrong leaves. Hashing the field
|
|
187
|
+
names in declaration order turns such a change into a clean cache miss
|
|
188
|
+
and rebuild — this matters because :class:`LamCostRelaxHyper` moves
|
|
189
|
+
``lam_cost_drop`` / ``lam_cost_relax`` to the *front* of the field
|
|
190
|
+
order. Folded in by :meth:`Algorithm._hash_into`; mirrors the symbolic
|
|
191
|
+
``_hash_into`` protocol.
|
|
192
|
+
"""
|
|
193
|
+
from openscvx.utils.caching import hash_value_into
|
|
194
|
+
|
|
195
|
+
hasher.update(type(self).__name__.encode())
|
|
196
|
+
for name in sorted(vars(self)):
|
|
197
|
+
if name == "hyper":
|
|
198
|
+
continue
|
|
199
|
+
hasher.update(name.encode())
|
|
200
|
+
hash_value_into(hasher, getattr(self, name))
|
|
201
|
+
# Schema, not values: the hyper field order/names fix the exported
|
|
202
|
+
# artifact's leaf layout, so a reorder must invalidate cached artifacts
|
|
203
|
+
# rather than silently permute runtime values onto the wrong avals.
|
|
204
|
+
for fld in dc_fields(self.hyper):
|
|
205
|
+
hasher.update(fld.name.encode())
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def _relaxed_lam_cost(state: "AlgorithmState") -> jnp.ndarray:
|
|
209
|
+
"""``lam_cost`` for the next iterate per the shared relaxation rule.
|
|
210
|
+
|
|
211
|
+
When ``state.k > state.hyper.lam_cost_drop``, scale ``state.lam_cost``
|
|
212
|
+
by ``state.hyper.lam_cost_relax``; otherwise reset to the algorithm's
|
|
213
|
+
initial weight (carried on the pytree as ``state.lam_cost_init``,
|
|
214
|
+
broadcast at :meth:`AlgorithmState.from_settings`). Both constants ride
|
|
215
|
+
the pytree so per-solve overrides and ``vmap`` sweeps reach the traced
|
|
216
|
+
body; the scalar ``lam_cost_relax`` preserves the user-specified
|
|
217
|
+
per-state weight ratios. Shared verbatim by every built-in autotuner
|
|
218
|
+
via the :class:`LamCostRelaxHyper` knobs.
|
|
219
|
+
"""
|
|
220
|
+
return jnp.where(
|
|
221
|
+
state.k > state.hyper.lam_cost_drop,
|
|
222
|
+
state.lam_cost * state.hyper.lam_cost_relax,
|
|
223
|
+
state.lam_cost_init,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
@abstractmethod
|
|
227
|
+
def update_weights(
|
|
228
|
+
self,
|
|
229
|
+
state: "AlgorithmState",
|
|
230
|
+
candidate: "CandidateIterate",
|
|
231
|
+
nodal_constraints: "LoweredJaxConstraints",
|
|
232
|
+
settings: "Config",
|
|
233
|
+
params: dict,
|
|
234
|
+
) -> "AlgorithmState":
|
|
235
|
+
"""Return the next-iterate :class:`AlgorithmState`.
|
|
236
|
+
|
|
237
|
+
Must be JAX-traceable. See the class docstring for the contract.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
state: Current-iterate pytree. Initial weights live on
|
|
241
|
+
``state.lam_cost_init``; autotuners read from there rather than
|
|
242
|
+
from the algorithm's ``Weights`` object so the JIT'd closure
|
|
243
|
+
stays cache-stable across weight mutations.
|
|
244
|
+
candidate: Subproblem result (read-only here). On acceptance its
|
|
245
|
+
trajectory fields must be carried onto the returned state —
|
|
246
|
+
see the class docstring.
|
|
247
|
+
nodal_constraints: Lowered JAX constraints.
|
|
248
|
+
settings: Configuration object.
|
|
249
|
+
params: Problem parameter dictionary.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
The next-iterate :class:`AlgorithmState` — the SCP loop uses
|
|
253
|
+
nothing else, so an accepting update carries
|
|
254
|
+
``candidate.x / u / x_prop / x_prop_plus`` onto it, while a
|
|
255
|
+
rejecting update keeps the previous fields and adjusts only the
|
|
256
|
+
weights. Its :py:attr:`AlgorithmState.adaptive_state_code` encodes
|
|
257
|
+
the autotuner's decision; the SCP loop records that into history
|
|
258
|
+
and maps it to a printable label.
|
|
259
|
+
"""
|