openscvx 0.5.3.dev23__tar.gz → 0.5.3.dev25__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.dev23/openscvx.egg-info → openscvx-0.5.3.dev25}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UnderTheHood/batching_jit_grad.md +142 -10
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/brachistochrone_batched.py +17 -5
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/6DoF_pdg_batched_ic.py +8 -9
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/_version.py +3 -3
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/__init__.py +8 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/autotuner/__init__.py +3 -0
- openscvx-0.5.3.dev25/openscvx/algorithms/autotuner/acceptance_ratio.py +245 -0
- openscvx-0.5.3.dev25/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +74 -0
- openscvx-0.5.3.dev25/openscvx/algorithms/autotuner/augmented_lagrangian.py +287 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/autotuner/constant_proximal_weight.py +20 -9
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +28 -13
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/base.py +393 -143
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/optimization_results.py +6 -6
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/scvx/iteration.py +15 -20
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/scvx/penalized_trust_region.py +28 -50
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/problem.py +600 -267
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/cvxpy_ptr_solver.py +17 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/caching.py +13 -9
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/printing.py +0 -5
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/SOURCES.txt +3 -0
- openscvx-0.5.3.dev25/tests/algorithms/autotuner/test_hyper_overrides.py +325 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/autotuner/test_update_weights_jit.py +38 -20
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_algorithm_state_pytree.py +16 -2
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_iteration_fn_jit.py +11 -5
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_iteration_fn_parity.py +48 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/test_make_solve_loop.py +4 -2
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/_iteration_callback_helpers.py +4 -1
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_autotuning.py +59 -17
- openscvx-0.5.3.dev25/tests/test_solve_batched_brachistochrone.py +468 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_batched_export_roundtrip.py +27 -9
- openscvx-0.5.3.dev25/tests/test_solve_batched_inference.py +340 -0
- openscvx-0.5.3.dev23/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -192
- openscvx-0.5.3.dev23/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -385
- openscvx-0.5.3.dev23/tests/test_solve_batched_brachistochrone.py +0 -71
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.gitignore +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/.gitmodules +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/LICENSE +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/README.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/citation.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/examples.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/index.md +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/docs/versions.json +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/flappy_bird.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/_render.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/logo.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/cinema_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/drone_racing_batched_gates.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/drone/openscvx_logo.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/plotting.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/rocket/ascent_launch_vehicle.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/examples/spacecraft/relative_loitering.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/figures/video_preview.png +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/home.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/main.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/mkdocs.yml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/__main__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/config.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/loader.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/publication.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/coordinates.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/base.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/cones.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/solvers/qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/affine.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/canonicalize.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/pyproject.toml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/setup.cfg +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/_marks.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/_iteration_helpers.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/conftest.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/expr/test_gmsr.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_moreau.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_qpax.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_iteration_callback_vmap.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/solvers/test_subproblem_pytree.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_discretization.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_examples.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_expert.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_impulsive.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_init.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_integrators.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_loader.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_optimization_results.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_plotting.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_propagation.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev23 → openscvx-0.5.3.dev25}/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.dev25
|
|
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
|
|
@@ -60,7 +60,7 @@ that one difference is the whole point.
|
|
|
60
60
|
no outer `vmap` rule (`call_exported` cannot be batched), so an exported
|
|
61
61
|
artifact can never be re-vmapped, and every fresh process re-traces and
|
|
62
62
|
re-compiles the entire loop.
|
|
63
|
-
* `solve_batched(
|
|
63
|
+
* `solve_batched(x_initial=x0_batch)` — *the library* owns the axis. The vmap
|
|
64
64
|
is applied **inside** the method, before any export, so the whole loop lowers
|
|
65
65
|
to ordinary batched XLA ops and serializes cleanly. Under
|
|
66
66
|
`save_compiled=True` it is written to the solver cache on the first run and
|
|
@@ -74,10 +74,131 @@ problem.initialize()
|
|
|
74
74
|
|
|
75
75
|
# First process: traces, exports, writes <cache>/compiled_solve_batched_<hash>.jax
|
|
76
76
|
# Later processes: deserialize-and-.call, no compile.
|
|
77
|
-
batched = problem.solve_batched(
|
|
77
|
+
batched = problem.solve_batched(x_initial=x0_batch, parameters=params)
|
|
78
78
|
# batched.x.shape == (B, N, n_states) — same pytree jax.vmap(solve_jax) returns.
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
### One rule: add a leading batch axis to whatever varies
|
|
82
|
+
|
|
83
|
+
`solve_batched` takes exactly `solve_jax`'s arguments. Every batchable input
|
|
84
|
+
has a *declared* (unbatched) shape the library knows — `(n_x,)` for the
|
|
85
|
+
boundary pins, `(N, n_x)` / `(N, n_u)` for the trajectory guesses, the
|
|
86
|
+
parameter's stored shape for each parameter, and `()` for the SCP
|
|
87
|
+
hyperparameters. An argument that matches its declared shape is **shared** by
|
|
88
|
+
every batch element; one with exactly one extra leading axis is **batched**
|
|
89
|
+
along it. Rank against the declared shape decides — never the leading-axis
|
|
90
|
+
value — so a shared `(B, n)` matrix parameter is never misread as batched.
|
|
91
|
+
(`B` in these shape patterns is plain notation for the batch size, not
|
|
92
|
+
syntax: it is never passed anywhere — like `jax.vmap`, the library reads it
|
|
93
|
+
off the leading axis of whatever you batched and cross-checks that all
|
|
94
|
+
batched inputs agree.)
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
results = problem.solve_batched(
|
|
98
|
+
x_initial=x0_batch, # (B, n_x): rank = declared+1 -> batched
|
|
99
|
+
parameters={
|
|
100
|
+
"gate_center": centers, # (B, 3) vs declared (3,) -> batched
|
|
101
|
+
"gate_radius": 0.5, # declared shape -> shared
|
|
102
|
+
},
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
For the rare entry the rank rule cannot express — e.g. batching a declared
|
|
107
|
+
rank-1 parameter element-wise — pass an explicit `in_axes` in `jax.vmap`'s
|
|
108
|
+
vocabulary, including its prefix semantics (`0` = batched along the leading
|
|
109
|
+
axis, `None` = shared; a prefix applies to everything below it; partial specs
|
|
110
|
+
fall back to the rank rule):
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
results = problem.solve_batched(
|
|
114
|
+
parameters={"weights": w}, # (B,) is also w's declared shape...
|
|
115
|
+
in_axes={"parameters": {"weights": 0}}, # ...so say "batched" explicitly
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
results = problem.solve_batched(parameters=params, in_axes={"parameters": 0})
|
|
119
|
+
# prefix: every passed parameter is batched, exactly like jax.vmap's
|
|
120
|
+
# pytree-prefix in_axes; a bare in_axes=0 batches every passed input.
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
One deliberate divergence from `jax.vmap`: the *default* is "infer by rank",
|
|
124
|
+
not `0`-everything — an all-shared batched solve has no batch axis to find,
|
|
125
|
+
and inference is what makes mixed shared/batched dicts ergonomic.
|
|
126
|
+
|
|
127
|
+
### Hyperparameter sweeps: the `algorithm` dict
|
|
128
|
+
|
|
129
|
+
Solve-time mirrors construction-time: the `Problem` constructor configures
|
|
130
|
+
the SCP algorithm with a dict (`algorithm={"ep_tr": 1e-5, "lam_prox": 1.0}`),
|
|
131
|
+
and the solve methods take the same box with the same names as per-solve,
|
|
132
|
+
batchable inputs. Every `AlgorithmState` field is a runtime input riding the
|
|
133
|
+
state pytree, and the `algorithm` dict reaches any of them by name —
|
|
134
|
+
convergence thresholds (`ep_tr` / `ep_vb` / `ep_vc`), penalty weights
|
|
135
|
+
(`lam_prox` / `lam_vc` / `lam_cost`), the seed iterate, autotuner
|
|
136
|
+
hyperparameters. There is no whitelist: the field declaration is the
|
|
137
|
+
registration, and the `AlgorithmState` attribute docs are the reference.
|
|
138
|
+
(`max_iters` survives as a named kwarg — sugar for `algorithm={"k_max":
|
|
139
|
+
...}`; passing both raises, as does an entry that shadows any other named
|
|
140
|
+
kwarg's field. Construction-only keys of the constructor dict — `autotuner`,
|
|
141
|
+
`t_max` — raise pointing back at the constructor.)
|
|
142
|
+
|
|
143
|
+
* On `solve_jax`, each value matches the field's shape, or is a scalar
|
|
144
|
+
broadcast to it: `solve_jax(algorithm={"ep_tr": 1e-6, "lam_prox": 2.0})`
|
|
145
|
+
retraces nothing.
|
|
146
|
+
* On `solve_batched`, each value follows the rank rule against the field's
|
|
147
|
+
shape, plus two **fill** forms for array-shaped fields: a scalar (shared)
|
|
148
|
+
or a `(B,)` vector (one scalar per element, broadcast to the field shape).
|
|
149
|
+
Exact shapes win when both parse; `in_axes={"algorithm": {name: 0}}`
|
|
150
|
+
forces the per-element reading. All against one cached artifact:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
B = 8 # batch size. Just an int for building the arrays below — there is no
|
|
154
|
+
# B argument; solve_batched infers it from the leading-axis lengths.
|
|
155
|
+
sweep = problem.solve_batched(algorithm={"ep_tr": jnp.logspace(-6, -3, B)})
|
|
156
|
+
weights = problem.solve_batched(algorithm={"lam_prox": jnp.array([0.5, 1.0, 4.0])})
|
|
157
|
+
budgets = problem.solve_batched(max_iters=jnp.array([5, 10, 20])) # per-element caps
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The batch runs until its slowest element converges or exhausts its own cap;
|
|
161
|
+
finished elements are frozen, not re-iterated, so each element matches the
|
|
162
|
+
corresponding single `solve_jax` run.
|
|
163
|
+
|
|
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:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from openscvx.algorithms import AutotuningBase, HyperParams
|
|
188
|
+
|
|
189
|
+
class MyHyper(HyperParams):
|
|
190
|
+
ramp: float = 2.0
|
|
191
|
+
|
|
192
|
+
class MyAutotuner(AutotuningBase):
|
|
193
|
+
def __init__(self, ramp: float = 2.0):
|
|
194
|
+
self.hyper = MyHyper(ramp=ramp)
|
|
195
|
+
|
|
196
|
+
def update_weights(self, state, ...):
|
|
197
|
+
...state.hyper.ramp...
|
|
198
|
+
|
|
199
|
+
results = problem.solve_batched(algorithm={"ramp": jnp.linspace(1.5, 3.0, B)})
|
|
200
|
+
```
|
|
201
|
+
|
|
81
202
|
Pick `solve_batched` when **cross-process cold-start dominates** — short-lived
|
|
82
203
|
processes (CI sweeps, notebook restarts, deployed workers) that otherwise pay
|
|
83
204
|
the compile every launch. Pick `jax.vmap(solve_jax)` for everything in-program,
|
|
@@ -111,15 +232,21 @@ object contributing through its own `_hash_into` (the same protocol the symbolic
|
|
|
111
232
|
layer uses):
|
|
112
233
|
|
|
113
234
|
* the convex backend class + its `solver_args`,
|
|
114
|
-
* the algorithm + autotuner +
|
|
235
|
+
* the algorithm + autotuner + initial weights,
|
|
115
236
|
* the discretizer scheme (class + hold type + ODE solver),
|
|
116
237
|
* the state/control scaling matrices `inv_S_x` / `inv_S_u`,
|
|
117
|
-
* the fixed batch size `B` (the artifact is exported at one `B`),
|
|
238
|
+
* the fixed batch size `B` (the artifact is exported at one `B`),
|
|
239
|
+
* the per-parameter shared/batched split (baked into the `jax.vmap` program),
|
|
240
|
+
and
|
|
118
241
|
* the JAX version (exported artifacts are not guaranteed to survive an
|
|
119
242
|
incompatible jax bump).
|
|
120
243
|
|
|
121
|
-
Change any of these — backend, a
|
|
122
|
-
a different cache path, so a stale
|
|
244
|
+
Change any of these — backend, a penalty weight, a state bound, which
|
|
245
|
+
parameters are batched — and you get a different cache path, so a stale
|
|
246
|
+
artifact is never reused. Everything the `algorithm` dict can reach — convergence
|
|
247
|
+
thresholds, `max_iters`, weights, autotuner hyperparameters — is deliberately
|
|
248
|
+
*not* in the key: those are runtime inputs on the state pytree, so one
|
|
249
|
+
artifact serves every setting of them.
|
|
123
250
|
|
|
124
251
|
`examples/abstract/brachistochrone_batched.py` shows both paths side by side;
|
|
125
252
|
re-running it is itself the cross-process demo.
|
|
@@ -158,10 +285,15 @@ problem.solve_jax(
|
|
|
158
285
|
parameters=None, # parameters dict for this solve; falls back to
|
|
159
286
|
# ``self._parameters``
|
|
160
287
|
*,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
# the
|
|
288
|
+
x_guess=None, # (N, n_x) state trajectory warm-start
|
|
289
|
+
u_guess=None, # (N, n_u) control trajectory warm-start
|
|
290
|
+
max_iters=None, # SCP iteration cap; sugar for algorithm={"k_max": ...};
|
|
291
|
+
# falls back to the configured k_max
|
|
292
|
+
algorithm=None, # any AlgorithmState field by name (ep_tr, lam_prox,
|
|
293
|
+
# ...) — the constructor's algorithm-dict names;
|
|
294
|
+
# values match the field shape or fill it from a
|
|
295
|
+
# scalar. Runtime inputs on the state pytree — no
|
|
296
|
+
# value forces a retrace
|
|
165
297
|
)
|
|
166
298
|
```
|
|
167
299
|
|
|
@@ -6,7 +6,7 @@ starting x-coordinate — and contrasts the two batching entry points:
|
|
|
6
6
|
* ``jax.vmap(problem.solve_jax)`` — the caller owns the batch axis. Maximally
|
|
7
7
|
idiomatic, composes with ``grad`` / ``scan``, but in-process JIT only: every
|
|
8
8
|
fresh process re-traces and re-compiles the whole SCP loop.
|
|
9
|
-
* ``problem.solve_batched(
|
|
9
|
+
* ``problem.solve_batched(x_initial=...)`` — the library owns the batch
|
|
10
10
|
axis, so the whole vmapped loop is a single function that ``jax.export`` can
|
|
11
11
|
serialize. Under ``save_compiled=True`` it is written to the solver cache on
|
|
12
12
|
the first run and deserialized on later runs, skipping that compile. Reach
|
|
@@ -140,16 +140,28 @@ if __name__ == "__main__":
|
|
|
140
140
|
# The same batched solve, but ``solve_batched`` owns the vmap so the whole
|
|
141
141
|
# loop is one exportable artifact. Under ``save_compiled=True`` it lands in
|
|
142
142
|
# the solver cache on the first run; re-run this script (a fresh process) to
|
|
143
|
-
# see it deserialized instead of recompiled. ``
|
|
144
|
-
#
|
|
143
|
+
# see it deserialized instead of recompiled. One rule: ``x_initial`` is
|
|
144
|
+
# ``(B, n_x)`` — one extra leading axis — so it is batched; the terminal
|
|
145
|
+
# pin is omitted, so every element shares the default.
|
|
145
146
|
export_problem = build_problem()
|
|
146
147
|
export_problem.settings.sim.save_compiled = True
|
|
147
148
|
export_problem.initialize()
|
|
148
149
|
|
|
149
|
-
|
|
150
|
-
batched = export_problem.solve_batched(x_initial_stack, x_term_stack)
|
|
150
|
+
batched = export_problem.solve_batched(x_initial=x_initial_stack)
|
|
151
151
|
|
|
152
152
|
print(f"\nsolve_batched (save_compiled=True) over {x_initial_stack.shape[0]} ICs:")
|
|
153
153
|
print(f" result.x.shape: {batched.x.shape}")
|
|
154
154
|
print(f" result.t_final: {np.asarray(batched.t_final).reshape(-1)}")
|
|
155
155
|
print(f" result.converged: {np.asarray(batched.converged)}")
|
|
156
|
+
|
|
157
|
+
# Algorithm knobs batch by the same rule, through the `algorithm` dict —
|
|
158
|
+
# the same names as the Problem constructor's algorithm config. ep_tr is
|
|
159
|
+
# a scalar field, so a (B,) vector sweeps the convergence tolerance per
|
|
160
|
+
# element — same artifact, no recompile, since the knobs are runtime
|
|
161
|
+
# inputs on the state pytree. The batch size is never passed: it is read
|
|
162
|
+
# off the array's leading axis (4 tolerances -> B = 4).
|
|
163
|
+
sweep = export_problem.solve_batched(
|
|
164
|
+
algorithm={"ep_tr": jnp.logspace(-4, -1, 4), "ep_vc": 1e-7}
|
|
165
|
+
)
|
|
166
|
+
print(f" ep_tr sweep t_final: {np.asarray(sweep.t_final).reshape(-1)}")
|
|
167
|
+
print(f" ep_tr sweep converged: {np.asarray(sweep.converged)}")
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Runs ``N_BATCH`` SCP solves in parallel, each starting from a different random
|
|
4
4
|
initial position drawn uniformly within the position bounds. Per-batch ICs are
|
|
5
|
-
passed through ``
|
|
5
|
+
passed through ``x_initial``: position is declared ``Fix`` at the symbolic level
|
|
6
6
|
(so the solver consumes ``x_init_pin``), then each batch row overwrites the
|
|
7
7
|
position slice with the sampled values. This avoids the per-iteration
|
|
8
8
|
``(position == parameter).convex()`` constraint while still enforcing the full
|
|
@@ -110,7 +110,7 @@ mass.final = [ox.Maximize(1.5)]
|
|
|
110
110
|
position = ox.State("position", shape=(3,))
|
|
111
111
|
position.max = [10.0, 10.0, 10.0]
|
|
112
112
|
position.min = [-10.0, -10.0, -10.0]
|
|
113
|
-
# Fix so
|
|
113
|
+
# Fix so x_initial pins are consumed; per-batch values overwrite these defaults.
|
|
114
114
|
position.initial = [7.5, 4.5, 2.5]
|
|
115
115
|
position.final = [0.0, ox.Free(0.0), ox.Free(0.0)]
|
|
116
116
|
|
|
@@ -193,7 +193,7 @@ constraint_exprs = []
|
|
|
193
193
|
for st in states:
|
|
194
194
|
constraint_exprs.extend([ox.ctcs(st <= st.max), ox.ctcs(st.min <= st)])
|
|
195
195
|
|
|
196
|
-
# Initial position via
|
|
196
|
+
# Initial position via x_initial pins (Fix BC); terminal lateral via convex constraint.
|
|
197
197
|
constraint_exprs.append((position[1:3] == final_position).convex().at([N - 1]))
|
|
198
198
|
|
|
199
199
|
constraint_exprs.append(ox.ctcs(1.0 * (mass - m_dry) >= 0))
|
|
@@ -414,15 +414,14 @@ if __name__ == "__main__":
|
|
|
414
414
|
print(f"Sampled {N_BATCH} initial positions (alt ∈ [3, 9] m, lat ∈ [-7, 7] m)")
|
|
415
415
|
|
|
416
416
|
# ── Compile + solve ───────────────────────────────────────────────────────
|
|
417
|
+
# x_initial is (B, n_x) — one extra leading axis — so it is batched; the
|
|
418
|
+
# terminal pin is omitted, so every element shares the default.
|
|
417
419
|
default_init = np.asarray(problem.state.x_init_pin)
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
x0_stack = jnp.asarray(x0_stack)
|
|
421
|
-
xf_pin = np.asarray(problem.state.x_term_pin)
|
|
422
|
-
xf_stack = jnp.broadcast_to(xf_pin, (N_BATCH, xf_pin.shape[0]))
|
|
420
|
+
x_initial = np.broadcast_to(default_init, (N_BATCH, default_init.shape[0])).copy()
|
|
421
|
+
x_initial[:, POSITION_SLICE] = ic_batch
|
|
423
422
|
|
|
424
423
|
print("Compiling and running solve_batched …")
|
|
425
|
-
results = problem.solve_batched(
|
|
424
|
+
results = problem.solve_batched(x_initial=jnp.asarray(x_initial))
|
|
426
425
|
|
|
427
426
|
# ── Post-process: propagate all B solutions through nonlinear dynamics ────
|
|
428
427
|
print("Post-processing (nonlinear propagation) …")
|
|
@@ -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.dev25'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 3, 'dev25')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'ge4b992a50'
|
|
@@ -37,6 +37,8 @@ from typing import Annotated, Any, Dict, List, Optional, Union
|
|
|
37
37
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
38
38
|
|
|
39
39
|
from .autotuner import (
|
|
40
|
+
AcceptanceRatioAutotuner,
|
|
41
|
+
AcceptanceRatioHyper,
|
|
40
42
|
AdaptiveProximalWeight,
|
|
41
43
|
AdaptiveProximalWeightSpec,
|
|
42
44
|
AugmentedLagrangian,
|
|
@@ -52,7 +54,9 @@ from .base import (
|
|
|
52
54
|
AlgorithmHistory,
|
|
53
55
|
AlgorithmState,
|
|
54
56
|
AutotuningBase,
|
|
57
|
+
CandidateIterate,
|
|
55
58
|
DiscretizationResult,
|
|
59
|
+
HyperParams,
|
|
56
60
|
adaptive_state_code_to_str,
|
|
57
61
|
)
|
|
58
62
|
from .optimization_results import OptimizationResults
|
|
@@ -137,6 +141,7 @@ __all__ = [
|
|
|
137
141
|
"AlgorithmHistory",
|
|
138
142
|
"AlgorithmState",
|
|
139
143
|
"AdaptiveStateCode",
|
|
144
|
+
"CandidateIterate",
|
|
140
145
|
"adaptive_state_code_to_str",
|
|
141
146
|
"DiscretizationResult",
|
|
142
147
|
"Weights",
|
|
@@ -145,6 +150,9 @@ __all__ = [
|
|
|
145
150
|
# PTR algorithm
|
|
146
151
|
"PenalizedTrustRegion",
|
|
147
152
|
"AutotuningBase",
|
|
153
|
+
"HyperParams",
|
|
154
|
+
"AcceptanceRatioAutotuner",
|
|
155
|
+
"AcceptanceRatioHyper",
|
|
148
156
|
"AugmentedLagrangian",
|
|
149
157
|
"AdaptiveProximalWeight",
|
|
150
158
|
"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,245 @@
|
|
|
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 ..base import AdaptiveStateCode, AutotuningBase, HyperParams
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from openscvx.lowered import LoweredJaxConstraints
|
|
36
|
+
|
|
37
|
+
from ..base import AlgorithmState, CandidateIterate
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AcceptanceRatioHyper(HyperParams):
|
|
41
|
+
"""Knobs shared by every acceptance-ratio autotuner.
|
|
42
|
+
|
|
43
|
+
``lam_cost_drop`` is the iteration after which ``lam_cost`` relaxation
|
|
44
|
+
applies (``state.k > lam_cost_drop``): ``-1`` relaxes from the first
|
|
45
|
+
iteration, and the default ``lam_cost_relax=1.0`` makes that a no-op.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
gamma_1: float = 2.0
|
|
49
|
+
gamma_2: float = 0.5
|
|
50
|
+
eta_0: float = 1e-2
|
|
51
|
+
eta_1: float = 1e-1
|
|
52
|
+
eta_2: float = 0.8
|
|
53
|
+
lam_prox_min: float = 1e-3
|
|
54
|
+
lam_prox_max: float = 1e4
|
|
55
|
+
lam_cost_drop: int = -1
|
|
56
|
+
lam_cost_relax: float = 1.0
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class AcceptanceRatioAutotuner(AutotuningBase):
|
|
60
|
+
"""Four-bucket acceptance-ratio update on ``lam_prox``.
|
|
61
|
+
|
|
62
|
+
The acceptance ratio :math:`\\rho` (actual over predicted nonlinear
|
|
63
|
+
reduction) selects one of four buckets — ``REJECT`` / ``ACCEPT_HIGHER`` /
|
|
64
|
+
``ACCEPT_CONSTANT`` / ``ACCEPT_LOWER`` — via a ``jnp.where`` cascade so the
|
|
65
|
+
whole update traces under ``jax.jit``. Subclasses supply the multiplier
|
|
66
|
+
rule (how ``lam_vc`` / ``lam_vb_*`` respond on acceptance) through
|
|
67
|
+
:meth:`_update_multipliers`, and must assign an
|
|
68
|
+
:class:`AcceptanceRatioHyper` (or subclass) instance to ``self.hyper`` in
|
|
69
|
+
``__init__`` — the shared body reads its knobs off ``state.hyper``.
|
|
70
|
+
|
|
71
|
+
``update_weights`` is a pure functional update on the
|
|
72
|
+
:class:`AlgorithmState` pytree; see the base-class contract.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
COLUMNS: List[Column] = [
|
|
76
|
+
Column("J_nonlin", "J_nonlin", 8, "{: .1e}", None, Verbosity.STANDARD),
|
|
77
|
+
Column("J_lin", "J_lin", 8, "{: .1e}", None, Verbosity.STANDARD),
|
|
78
|
+
Column("pred_reduction", "pred_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
|
|
79
|
+
Column("actual_reduction", "act_red", 9, "{: .1e}", min_verbosity=Verbosity.FULL),
|
|
80
|
+
Column(
|
|
81
|
+
"acceptance_ratio",
|
|
82
|
+
"acc_ratio",
|
|
83
|
+
9,
|
|
84
|
+
"{: .2e}",
|
|
85
|
+
color_acceptance_ratio,
|
|
86
|
+
Verbosity.STANDARD,
|
|
87
|
+
),
|
|
88
|
+
Column("lam_prox", "lam_prox", 8, "{: .1e}", min_verbosity=Verbosity.FULL),
|
|
89
|
+
Column("adaptive_state", "Adaptive", 16, "{}", color_adaptive_state, Verbosity.FULL),
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
def _update_multipliers(
|
|
93
|
+
self,
|
|
94
|
+
state: "AlgorithmState",
|
|
95
|
+
candidate: "CandidateIterate",
|
|
96
|
+
nodal_constraints: "LoweredJaxConstraints",
|
|
97
|
+
params: dict,
|
|
98
|
+
settings: Config,
|
|
99
|
+
new_lam_prox: jnp.ndarray,
|
|
100
|
+
) -> dict:
|
|
101
|
+
"""Return the multiplier-weight updates to apply on an accepted iterate.
|
|
102
|
+
|
|
103
|
+
Each returned entry maps an :class:`AlgorithmState` field name
|
|
104
|
+
(``lam_vc`` / ``lam_vb_nodal`` / ``lam_vb_cross``) to its updated
|
|
105
|
+
value, computed against the *candidate* trajectory; the shared body
|
|
106
|
+
gates each by acceptance (a rejected iterate keeps the previous value).
|
|
107
|
+
The default holds every multiplier constant — return ``{}``.
|
|
108
|
+
"""
|
|
109
|
+
return {}
|
|
110
|
+
|
|
111
|
+
def update_weights(
|
|
112
|
+
self,
|
|
113
|
+
state: "AlgorithmState",
|
|
114
|
+
candidate: "CandidateIterate",
|
|
115
|
+
nodal_constraints: "LoweredJaxConstraints",
|
|
116
|
+
settings: Config,
|
|
117
|
+
params: dict,
|
|
118
|
+
) -> "AlgorithmState":
|
|
119
|
+
"""Return the next-iterate state per the acceptance-ratio rules.
|
|
120
|
+
|
|
121
|
+
Pure functional update — see class docstring.
|
|
122
|
+
"""
|
|
123
|
+
candidate_x_prop = candidate.x_prop_plus[1:]
|
|
124
|
+
nonlin_cost, nonlin_pen, nodal_pen = self.calculate_nonlinear_penalty(
|
|
125
|
+
candidate_x_prop,
|
|
126
|
+
candidate.x,
|
|
127
|
+
candidate.u,
|
|
128
|
+
state.lam_vc,
|
|
129
|
+
state.lam_vb_nodal,
|
|
130
|
+
state.lam_vb_cross,
|
|
131
|
+
state.lam_cost,
|
|
132
|
+
nodal_constraints,
|
|
133
|
+
params,
|
|
134
|
+
settings,
|
|
135
|
+
)
|
|
136
|
+
J_nonlin = nonlin_cost + nonlin_pen + nodal_pen
|
|
137
|
+
|
|
138
|
+
# Cost relaxation: when state.k > hyper.lam_cost_drop, scale
|
|
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
|
+
)
|
|
149
|
+
|
|
150
|
+
def first_iter(state):
|
|
151
|
+
# Iter 1: accept unconditionally, leave weights at their init values,
|
|
152
|
+
# only refresh trajectory + propagation fields.
|
|
153
|
+
return state.replace(
|
|
154
|
+
x=candidate.x,
|
|
155
|
+
u=candidate.u,
|
|
156
|
+
x_prop=candidate.x_prop,
|
|
157
|
+
x_prop_plus=candidate.x_prop_plus,
|
|
158
|
+
lam_cost=lam_cost_next,
|
|
159
|
+
J_nonlin=J_nonlin,
|
|
160
|
+
adaptive_state_code=jnp.asarray(int(AdaptiveStateCode.INITIAL), dtype=jnp.int32),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def later_iter(state):
|
|
164
|
+
# Recompute the previous iterate's J_nonlin from the pytree fields
|
|
165
|
+
# (state.x/state.u were the *previous* accepted iterate).
|
|
166
|
+
prev_x_prop = state.x_prop_plus[1:]
|
|
167
|
+
prev_cost, prev_pen, prev_nodal_pen = self.calculate_nonlinear_penalty(
|
|
168
|
+
prev_x_prop,
|
|
169
|
+
state.x,
|
|
170
|
+
state.u,
|
|
171
|
+
state.lam_vc,
|
|
172
|
+
state.lam_vb_nodal,
|
|
173
|
+
state.lam_vb_cross,
|
|
174
|
+
state.lam_cost,
|
|
175
|
+
nodal_constraints,
|
|
176
|
+
params,
|
|
177
|
+
settings,
|
|
178
|
+
)
|
|
179
|
+
prev_J_nonlin = prev_cost + prev_pen + prev_nodal_pen
|
|
180
|
+
|
|
181
|
+
actual = prev_J_nonlin - J_nonlin
|
|
182
|
+
predicted = prev_J_nonlin - candidate.J_lin
|
|
183
|
+
# If predicted reduction is exactly zero, force the reject bucket
|
|
184
|
+
# (rho = -inf) deterministically instead of raising.
|
|
185
|
+
safe_pred = jnp.where(predicted == 0.0, 1.0, predicted)
|
|
186
|
+
rho = jnp.where(predicted == 0.0, -jnp.inf, actual / safe_pred)
|
|
187
|
+
|
|
188
|
+
is_reject = rho < state.hyper.eta_0
|
|
189
|
+
is_accept_higher = (rho >= state.hyper.eta_0) & (rho < state.hyper.eta_1)
|
|
190
|
+
is_accept_constant = (rho >= state.hyper.eta_1) & (rho < state.hyper.eta_2)
|
|
191
|
+
# is_accept_lower implicit (else)
|
|
192
|
+
accepted = ~is_reject
|
|
193
|
+
|
|
194
|
+
# Compute both lam_prox candidates and gate.
|
|
195
|
+
lp_higher = jnp.minimum(state.hyper.lam_prox_max, state.hyper.gamma_1 * state.lam_prox)
|
|
196
|
+
lp_lower = jnp.maximum(state.hyper.lam_prox_min, state.hyper.gamma_2 * state.lam_prox)
|
|
197
|
+
new_lam_prox = jnp.where(
|
|
198
|
+
is_reject | is_accept_higher,
|
|
199
|
+
lp_higher,
|
|
200
|
+
jnp.where(is_accept_constant, state.lam_prox, lp_lower),
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Multiplier (virtual-control / virtual-buffer) updates: computed
|
|
204
|
+
# against the *candidate* trajectory and gated by `accepted`. Reject
|
|
205
|
+
# keeps the previous values (so the next subproblem doesn't see a
|
|
206
|
+
# bumped penalty that wasn't earned). The default hook returns {} —
|
|
207
|
+
# multipliers held constant.
|
|
208
|
+
multiplier_updates = self._update_multipliers(
|
|
209
|
+
state, candidate, nodal_constraints, params, settings, new_lam_prox
|
|
210
|
+
)
|
|
211
|
+
gated_multipliers = {
|
|
212
|
+
name: jnp.where(accepted, value, getattr(state, name))
|
|
213
|
+
for name, value in multiplier_updates.items()
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
code = jnp.where(
|
|
217
|
+
is_reject,
|
|
218
|
+
jnp.int32(AdaptiveStateCode.REJECT),
|
|
219
|
+
jnp.where(
|
|
220
|
+
is_accept_higher,
|
|
221
|
+
jnp.int32(AdaptiveStateCode.ACCEPT_HIGHER),
|
|
222
|
+
jnp.where(
|
|
223
|
+
is_accept_constant,
|
|
224
|
+
jnp.int32(AdaptiveStateCode.ACCEPT_CONSTANT),
|
|
225
|
+
jnp.int32(AdaptiveStateCode.ACCEPT_LOWER),
|
|
226
|
+
),
|
|
227
|
+
),
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
return state.replace(
|
|
231
|
+
x=jnp.where(accepted, candidate.x, state.x),
|
|
232
|
+
u=jnp.where(accepted, candidate.u, state.u),
|
|
233
|
+
x_prop=jnp.where(accepted, candidate.x_prop, state.x_prop),
|
|
234
|
+
x_prop_plus=jnp.where(accepted, candidate.x_prop_plus, state.x_prop_plus),
|
|
235
|
+
lam_prox=new_lam_prox,
|
|
236
|
+
lam_cost=lam_cost_next,
|
|
237
|
+
J_nonlin=jnp.where(accepted, J_nonlin, state.J_nonlin),
|
|
238
|
+
predicted_reduction=predicted,
|
|
239
|
+
actual_reduction=actual,
|
|
240
|
+
acceptance_ratio=rho,
|
|
241
|
+
adaptive_state_code=code,
|
|
242
|
+
**gated_multipliers,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
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))
|