openscvx 0.5.3.dev32__tar.gz → 0.5.3.dev34__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.dev32/openscvx.egg-info → openscvx-0.5.3.dev34}/PKG-INFO +1 -1
- openscvx-0.5.3.dev34/examples/aircraft/dynamic_soaring.py +333 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/_version.py +3 -3
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/optimization_results.py +18 -2
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/problem.py +61 -10
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx.egg-info/SOURCES.txt +2 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx.egg-info/scm_file_list.json +2 -0
- openscvx-0.5.3.dev34/openscvx.egg-info/scm_version.json +8 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_optimization_results.py +27 -0
- openscvx-0.5.3.dev34/tests/test_results_parameters.py +93 -0
- openscvx-0.5.3.dev32/openscvx.egg-info/scm_version.json +0 -8
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.gitignore +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/.gitmodules +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/LICENSE +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/README.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UnderTheHood/batching_jit_grad.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/citation.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/examples.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/index.md +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/docs/versions.json +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/abstract/brachistochrone_batched.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/abstract/flappy_bird.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/aircraft/supersonic_time_to_climb.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/_render.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/logo.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/double_integrator/_plotting.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/double_integrator/moving_safe_zones.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/cinema_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/drone_racing_batched_gates.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/logo.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/multi_agent_circle_swap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/drone/openscvx_logo.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/frax/panda_frax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/frax/panda_frax_pick_place.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/frax/panda_frax_viewplanning.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/frax/panda_frax_waypoint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/plotting.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/rocket/ascent_launch_vehicle.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/examples/spacecraft/relative_loitering.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/figures/video_preview.png +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/home.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/main.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/mkdocs.yml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/__main__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/autotuner/base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/history.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/hyperparams.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/loop.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/penalty.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/scvx/iteration.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/state.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/config.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrations/_utils.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrations/frax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/loader.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/publication.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/coordinates.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/solvers/base.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/solvers/cones.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/solvers/moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/solvers/qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/affine.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/canonicalize.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/utils/caching.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/utils/printing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/pyproject.toml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/setup.cfg +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/_marks.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/_iteration_helpers.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/test_iteration_fn_jit.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/test_iteration_fn_parity.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/algorithms/test_make_solve_loop.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/conftest.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/expr/test_gmsr.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/_iteration_callback_helpers.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_iteration_callback_moreau.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_iteration_callback_qpax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_iteration_callback_vmap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/solvers/test_subproblem_pytree.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_autotuning.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_discretization.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_examples.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_expert.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_impulsive.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_init.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_integrators.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_loader.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_multishot_propagation.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_plotting.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_propagation.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_solve_batched_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_solve_batched_cvxpy_export_errors.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_solve_batched_export_roundtrip.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_solve_batched_inference.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_solve_jax_bare_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_solve_jax_jit_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/tests/test_solve_jax_vmap_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev32 → openscvx-0.5.3.dev34}/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.dev34
|
|
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,333 @@
|
|
|
1
|
+
"""Minimum wind-gradient dynamic soaring of a glider (Zhao 2004).
|
|
2
|
+
|
|
3
|
+
The dynamic soaring benchmark from Zhao, *"Optimal Pattern of Glider Dynamic
|
|
4
|
+
Soaring,"* Optimal Control Applications and Methods, Vol. 25, 2004, pp. 67-89,
|
|
5
|
+
reproduced in the GPOPS-II user's guide. A glider flies one closed loop through
|
|
6
|
+
a linear wind shear, extracting enough energy from the gradient to return to
|
|
7
|
+
its initial airspeed, flight-path angle, and (heading - 2 pi). The objective is
|
|
8
|
+
the *smallest* wind-gradient slope ``beta`` for which such an energy-neutral
|
|
9
|
+
loop exists.
|
|
10
|
+
|
|
11
|
+
Point-mass dynamics over a flat Earth with horizontal wind ``W_x = beta h``
|
|
12
|
+
(state ``[x, y, h, v, gamma, psi]`` = position, airspeed, flight-path angle,
|
|
13
|
+
heading; controls ``C_L`` = lift coefficient and ``phi`` = bank angle):
|
|
14
|
+
|
|
15
|
+
x_dot = v cos(gamma) sin(psi) + beta h
|
|
16
|
+
y_dot = v cos(gamma) cos(psi)
|
|
17
|
+
h_dot = v sin(gamma)
|
|
18
|
+
v_dot = -(rho S / 2 m)(CD0 + K C_L^2) v^2 - g sin(gamma) - W sin(psi) cos(gamma)
|
|
19
|
+
gamma_dot = (rho S / 2 m) C_L v cos(phi) - g cos(gamma) / v + W sin(psi) sin(gamma) / v
|
|
20
|
+
psi_dot = ((rho S / 2 m) C_L v sin(phi) - W cos(psi) / v) / cos(gamma)
|
|
21
|
+
|
|
22
|
+
with wind-shear rate ``W = dW_x/dt = beta v sin(gamma)``. The load factor
|
|
23
|
+
``n = (rho S / 2 m g) C_L v^2`` is limited to ``[-2, 5]`` along the whole loop.
|
|
24
|
+
|
|
25
|
+
Three GPOPS features map onto OpenSCvx as follows:
|
|
26
|
+
|
|
27
|
+
- The free static parameter ``beta`` becomes a state with zero dynamics, so a
|
|
28
|
+
single optimized value is shared by every node. Its final value carries a
|
|
29
|
+
``Minimize`` boundary condition — the Mayer objective.
|
|
30
|
+
- The periodicity events ``v_f = v_0``, ``gamma_f = gamma_0``, and
|
|
31
|
+
``psi_f = psi_0 - 2 pi`` become cross-node equality constraints tying node
|
|
32
|
+
``N-1`` to node 0. They are affine, so they are marked ``.convex()`` and
|
|
33
|
+
enforced exactly by the subproblem solver.
|
|
34
|
+
- The load-factor path constraint becomes a CTCS constraint, satisfied in
|
|
35
|
+
continuous time between nodes — which is why far fewer nodes are needed
|
|
36
|
+
here than GPOPS' collocation mesh.
|
|
37
|
+
|
|
38
|
+
The problem is nonconvex with several locally optimal loops; from the guide's
|
|
39
|
+
initial guess the SCP converges to ``beta ~ 0.069 1/s`` with a ~20 s period, a
|
|
40
|
+
slightly different basin than the IPOPT solution pictured in the guide. The
|
|
41
|
+
solution rides the ``n = 5`` load-factor ceiling through the high-speed bottom
|
|
42
|
+
turn, and forward propagation confirms the loop is periodic in continuous time.
|
|
43
|
+
|
|
44
|
+
Units are English (ft, s, slug), matching the reference.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
import os
|
|
48
|
+
import sys
|
|
49
|
+
|
|
50
|
+
import numpy as np
|
|
51
|
+
import plotly.graph_objects as go
|
|
52
|
+
from plotly.subplots import make_subplots
|
|
53
|
+
|
|
54
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
55
|
+
grandparent_dir = os.path.dirname(os.path.dirname(current_dir))
|
|
56
|
+
if grandparent_dir not in sys.path:
|
|
57
|
+
sys.path.append(grandparent_dir)
|
|
58
|
+
|
|
59
|
+
import openscvx as ox
|
|
60
|
+
from openscvx.plotting import plot_controls, plot_scp_iterations, plot_states
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# Physical constants (English units, Zhao 2004)
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
rho = 0.002378 # air density (slug/ft^3)
|
|
66
|
+
CD0 = 0.00873 # zero-lift drag coefficient
|
|
67
|
+
K = 0.045 # induced drag factor
|
|
68
|
+
g = 32.2 # gravitational acceleration (ft/s^2)
|
|
69
|
+
m = 5.6 # glider mass (slug)
|
|
70
|
+
S = 45.09703 # wing reference area (ft^2)
|
|
71
|
+
|
|
72
|
+
load_min, load_max = -2.0, 5.0 # load factor limits
|
|
73
|
+
beta_min, beta_max = 0.005, 0.15 # wind-gradient slope bounds (1/s)
|
|
74
|
+
|
|
75
|
+
n = 20 # discretization nodes — CTCS keeps the path constraint tight between them
|
|
76
|
+
tf_guess = 24.0 # initial guess for the (free) loop period
|
|
77
|
+
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
# States — the guess is one circular loop through the shear layer: climbing
|
|
80
|
+
# into the wind, diving out of it.
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
_t = np.linspace(0.0, tf_guess, n)
|
|
83
|
+
_th = 2 * np.pi * _t / tf_guess
|
|
84
|
+
|
|
85
|
+
position = ox.State("position", shape=(3,)) # [x, y, h] (ft)
|
|
86
|
+
position.min = [-1000.0, -1000.0, 0.0]
|
|
87
|
+
position.max = [1000.0, 1000.0, 1000.0]
|
|
88
|
+
position.initial = [0.0, 0.0, 0.0]
|
|
89
|
+
position.final = [0.0, 0.0, 0.0]
|
|
90
|
+
position.guess = np.stack(
|
|
91
|
+
[500 * np.cos(_th) - 500, 300 * np.sin(_th), 400 - 400 * np.cos(_th)], axis=1
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
v = ox.State("speed", shape=(1,)) # airspeed (ft/s)
|
|
95
|
+
v.min, v.max = [10.0], [350.0]
|
|
96
|
+
v.initial, v.final = [ox.Free(200.0)], [ox.Free(200.0)]
|
|
97
|
+
v.guess = (80 * (1.5 + np.cos(_th))).reshape(-1, 1)
|
|
98
|
+
|
|
99
|
+
gamma = ox.State("flight_path_angle", shape=(1,))
|
|
100
|
+
gamma.min, gamma.max = [np.deg2rad(-75.0)], [np.deg2rad(75.0)]
|
|
101
|
+
gamma.initial, gamma.final = [ox.Free(0.0)], [ox.Free(0.0)]
|
|
102
|
+
gamma.guess = (np.pi / 6 * np.sin(_th)).reshape(-1, 1)
|
|
103
|
+
|
|
104
|
+
psi = ox.State("heading", shape=(1,))
|
|
105
|
+
psi.min, psi.max = [-3 * np.pi], [np.pi / 2]
|
|
106
|
+
psi.initial, psi.final = [ox.Free(-1.0)], [ox.Free(-1.0 - 2 * np.pi)]
|
|
107
|
+
psi.guess = (-1.0 - _t / 4).reshape(-1, 1)
|
|
108
|
+
|
|
109
|
+
# The wind-gradient slope is a single optimized constant: a state with zero
|
|
110
|
+
# dynamics whose final value is the Mayer objective.
|
|
111
|
+
beta = ox.State("wind_gradient", shape=(1,))
|
|
112
|
+
beta.min, beta.max = [beta_min], [beta_max]
|
|
113
|
+
beta.initial, beta.final = [ox.Free(0.08)], [ox.Minimize(0.08)]
|
|
114
|
+
beta.guess = np.full((n, 1), 0.08)
|
|
115
|
+
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
# Controls
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
CL = ox.Control("lift_coefficient", shape=(1,))
|
|
120
|
+
CL.min, CL.max = [-0.5], [1.5]
|
|
121
|
+
CL.guess = np.full((n, 1), 0.5)
|
|
122
|
+
|
|
123
|
+
phi = ox.Control("bank_angle", shape=(1,))
|
|
124
|
+
phi.min, phi.max = [np.deg2rad(-75.0)], [np.deg2rad(75.0)]
|
|
125
|
+
phi.guess = np.full((n, 1), -1.0)
|
|
126
|
+
|
|
127
|
+
states = [position, v, gamma, psi, beta]
|
|
128
|
+
controls = [CL, phi]
|
|
129
|
+
|
|
130
|
+
# ---------------------------------------------------------------------------
|
|
131
|
+
# Dynamics
|
|
132
|
+
# ---------------------------------------------------------------------------
|
|
133
|
+
hs = position[2]
|
|
134
|
+
vs, fpa, head, b = v[0], gamma[0], psi[0], beta[0]
|
|
135
|
+
cl, bank = CL[0], phi[0]
|
|
136
|
+
|
|
137
|
+
aero = rho * S / (2 * m) # (rho S / 2 m), the common aerodynamic factor
|
|
138
|
+
shear = b * vs * ox.Sin(fpa) # W = dW_x/dt, the wind-shear rate
|
|
139
|
+
|
|
140
|
+
dynamics = {
|
|
141
|
+
"position": ox.Concat(
|
|
142
|
+
vs * ox.Cos(fpa) * ox.Sin(head) + b * hs,
|
|
143
|
+
vs * ox.Cos(fpa) * ox.Cos(head),
|
|
144
|
+
vs * ox.Sin(fpa),
|
|
145
|
+
),
|
|
146
|
+
"speed": -aero * (CD0 + K * cl**2) * vs**2
|
|
147
|
+
- g * ox.Sin(fpa)
|
|
148
|
+
- shear * ox.Sin(head) * ox.Cos(fpa),
|
|
149
|
+
"flight_path_angle": aero * cl * vs * ox.Cos(bank)
|
|
150
|
+
- g * ox.Cos(fpa) / vs
|
|
151
|
+
+ shear * ox.Sin(head) * ox.Sin(fpa) / vs,
|
|
152
|
+
"heading": (aero * cl * vs * ox.Sin(bank) - shear * ox.Cos(head) / vs) / ox.Cos(fpa),
|
|
153
|
+
"wind_gradient": 0.0 * b,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# ---------------------------------------------------------------------------
|
|
157
|
+
# Constraints: state boxes and the load-factor limit hold in continuous time;
|
|
158
|
+
# the periodicity events tie the last node back to the first.
|
|
159
|
+
# ---------------------------------------------------------------------------
|
|
160
|
+
constraints = []
|
|
161
|
+
for state in states:
|
|
162
|
+
constraints.extend([ox.ctcs(state <= state.max), ox.ctcs(state.min <= state)])
|
|
163
|
+
|
|
164
|
+
load_factor = (aero / g) * cl * vs**2
|
|
165
|
+
constraints.extend([ox.ctcs(load_factor <= load_max), ox.ctcs(load_min <= load_factor)])
|
|
166
|
+
|
|
167
|
+
constraints.extend(
|
|
168
|
+
[
|
|
169
|
+
(v.at(n - 1) - v.at(0) == 0.0).convex(),
|
|
170
|
+
(gamma.at(n - 1) - gamma.at(0) == 0.0).convex(),
|
|
171
|
+
(psi.at(n - 1) - psi.at(0) == -2 * np.pi).convex(),
|
|
172
|
+
]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# ---------------------------------------------------------------------------
|
|
176
|
+
# Free final time — the loop period is optimized but carries no cost.
|
|
177
|
+
# ---------------------------------------------------------------------------
|
|
178
|
+
time = ox.Time(
|
|
179
|
+
initial=0.0,
|
|
180
|
+
final=ox.Free(tf_guess),
|
|
181
|
+
min=0.0,
|
|
182
|
+
max=30.0,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# A fixed proximal weight converges in ~25 iterations here, where the adaptive
|
|
186
|
+
# default stalls just short of the dynamics-feasibility tolerance.
|
|
187
|
+
problem = ox.Problem(
|
|
188
|
+
dynamics=dynamics,
|
|
189
|
+
states=states,
|
|
190
|
+
controls=controls,
|
|
191
|
+
time=time,
|
|
192
|
+
constraints=constraints,
|
|
193
|
+
N=n,
|
|
194
|
+
licq_max=1e-8,
|
|
195
|
+
algorithm={"lam_prox": 2e-2, "autotuner": ox.ConstantProximalWeight()},
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def plot_gpops_comparison(results):
|
|
200
|
+
"""Reproduce the six GPOPS-II diagnostic plots for this benchmark.
|
|
201
|
+
|
|
202
|
+
Lays out the 3-D soaring loop (x, y, h) followed by airspeed, flight-path
|
|
203
|
+
angle, heading, lift coefficient, and bank angle versus time. The
|
|
204
|
+
high-resolution propagated trajectory is drawn as a line with the
|
|
205
|
+
discretization nodes overlaid.
|
|
206
|
+
"""
|
|
207
|
+
nodes, traj = results.nodes, results.trajectory
|
|
208
|
+
|
|
209
|
+
def col(source, key, idx=0):
|
|
210
|
+
arr = np.asarray(source[key])
|
|
211
|
+
return arr[:, idx] if arr.ndim > 1 else arr
|
|
212
|
+
|
|
213
|
+
fig = make_subplots(
|
|
214
|
+
rows=2,
|
|
215
|
+
cols=3,
|
|
216
|
+
specs=[
|
|
217
|
+
[{"type": "scene"}, {"type": "xy"}, {"type": "xy"}],
|
|
218
|
+
[{"type": "xy"}, {"type": "xy"}, {"type": "xy"}],
|
|
219
|
+
],
|
|
220
|
+
subplot_titles=(
|
|
221
|
+
"Soaring Loop",
|
|
222
|
+
"Airspeed vs. Time",
|
|
223
|
+
"Flight-Path Angle vs. Time",
|
|
224
|
+
"Heading vs. Time",
|
|
225
|
+
"Lift Coefficient vs. Time",
|
|
226
|
+
"Bank Angle vs. Time",
|
|
227
|
+
),
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
line_style = {"color": "#19d3f3", "width": 3}
|
|
231
|
+
marker_style = {"color": "#ffa600", "size": 5}
|
|
232
|
+
|
|
233
|
+
fig.add_trace(
|
|
234
|
+
go.Scatter3d(
|
|
235
|
+
x=col(traj, "position", 0),
|
|
236
|
+
y=col(traj, "position", 1),
|
|
237
|
+
z=col(traj, "position", 2),
|
|
238
|
+
mode="lines",
|
|
239
|
+
name="Propagated",
|
|
240
|
+
line=line_style,
|
|
241
|
+
legendgroup="traj",
|
|
242
|
+
),
|
|
243
|
+
row=1,
|
|
244
|
+
col=1,
|
|
245
|
+
)
|
|
246
|
+
fig.add_trace(
|
|
247
|
+
go.Scatter3d(
|
|
248
|
+
x=col(nodes, "position", 0),
|
|
249
|
+
y=col(nodes, "position", 1),
|
|
250
|
+
z=col(nodes, "position", 2),
|
|
251
|
+
mode="markers",
|
|
252
|
+
name="Nodes",
|
|
253
|
+
marker=marker_style,
|
|
254
|
+
legendgroup="nodes",
|
|
255
|
+
),
|
|
256
|
+
row=1,
|
|
257
|
+
col=1,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# (row, col, y-trajectory, y-nodes) for the five time-series panels.
|
|
261
|
+
t_traj, t_nodes = col(traj, "time"), col(nodes, "time")
|
|
262
|
+
panels = [
|
|
263
|
+
(1, 2, col(traj, "speed"), col(nodes, "speed")),
|
|
264
|
+
(
|
|
265
|
+
1,
|
|
266
|
+
3,
|
|
267
|
+
np.rad2deg(col(traj, "flight_path_angle")),
|
|
268
|
+
np.rad2deg(col(nodes, "flight_path_angle")),
|
|
269
|
+
),
|
|
270
|
+
(2, 1, np.rad2deg(col(traj, "heading")), np.rad2deg(col(nodes, "heading"))),
|
|
271
|
+
(2, 2, col(traj, "lift_coefficient"), col(nodes, "lift_coefficient")),
|
|
272
|
+
(2, 3, np.rad2deg(col(traj, "bank_angle")), np.rad2deg(col(nodes, "bank_angle"))),
|
|
273
|
+
]
|
|
274
|
+
for r, c, yt, yn in panels:
|
|
275
|
+
fig.add_trace(
|
|
276
|
+
go.Scatter(
|
|
277
|
+
x=t_traj,
|
|
278
|
+
y=yt,
|
|
279
|
+
mode="lines",
|
|
280
|
+
name="Propagated",
|
|
281
|
+
line={"color": line_style["color"], "width": 2},
|
|
282
|
+
legendgroup="traj",
|
|
283
|
+
showlegend=False,
|
|
284
|
+
),
|
|
285
|
+
row=r,
|
|
286
|
+
col=c,
|
|
287
|
+
)
|
|
288
|
+
fig.add_trace(
|
|
289
|
+
go.Scatter(
|
|
290
|
+
x=t_nodes,
|
|
291
|
+
y=yn,
|
|
292
|
+
mode="markers",
|
|
293
|
+
name="Nodes",
|
|
294
|
+
marker=marker_style,
|
|
295
|
+
legendgroup="nodes",
|
|
296
|
+
showlegend=False,
|
|
297
|
+
),
|
|
298
|
+
row=r,
|
|
299
|
+
col=c,
|
|
300
|
+
)
|
|
301
|
+
fig.update_xaxes(title_text="Time [s]", row=r, col=c)
|
|
302
|
+
|
|
303
|
+
fig.update_yaxes(title_text="Airspeed [ft/s]", row=1, col=2)
|
|
304
|
+
fig.update_yaxes(title_text="Flight-path angle [deg]", row=1, col=3)
|
|
305
|
+
fig.update_yaxes(title_text="Heading [deg]", row=2, col=1)
|
|
306
|
+
fig.update_yaxes(title_text="Lift coefficient", row=2, col=2)
|
|
307
|
+
fig.update_yaxes(title_text="Bank angle [deg]", row=2, col=3)
|
|
308
|
+
fig.update_layout(
|
|
309
|
+
title="Dynamic Soaring",
|
|
310
|
+
template="plotly_dark",
|
|
311
|
+
scene={
|
|
312
|
+
"xaxis_title": "x [ft]",
|
|
313
|
+
"yaxis_title": "y [ft]",
|
|
314
|
+
"zaxis_title": "h [ft]",
|
|
315
|
+
"aspectmode": "data",
|
|
316
|
+
},
|
|
317
|
+
)
|
|
318
|
+
return fig
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
if __name__ == "__main__":
|
|
322
|
+
problem.initialize()
|
|
323
|
+
results = problem.solve()
|
|
324
|
+
results = problem.post_process()
|
|
325
|
+
|
|
326
|
+
beta_opt = float(np.asarray(results.nodes["wind_gradient"]).flatten()[-1])
|
|
327
|
+
final_time = float(np.asarray(results.nodes["time"]).flatten()[-1])
|
|
328
|
+
print(f"Minimum wind-gradient slope: {beta_opt:.4f} 1/s (loop period {final_time:.2f} s)")
|
|
329
|
+
|
|
330
|
+
plot_gpops_comparison(results).show()
|
|
331
|
+
plot_states(results).show()
|
|
332
|
+
plot_controls(results).show()
|
|
333
|
+
plot_scp_iterations(results).show()
|
|
@@ -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.dev34'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 3, 'dev34')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g264808b5c'
|
|
@@ -50,6 +50,14 @@ class OptimizationResults:
|
|
|
50
50
|
Added by propagate_trajectory_results.
|
|
51
51
|
ctcs_violation (Optional[np.ndarray]): Continuous-time constraint violations.
|
|
52
52
|
Added by propagate_trajectory_results.
|
|
53
|
+
parameters (dict[str, np.ndarray]): Parameter values the solve used, recorded
|
|
54
|
+
by :meth:`~openscvx.problem.Problem.solve` and
|
|
55
|
+
:meth:`~openscvx.problem.Problem.solve_batched` (batched solves store every
|
|
56
|
+
value with a leading ``(B,)`` axis, shared values replicated). Results
|
|
57
|
+
record what happened: post-processing propagates with these values, and
|
|
58
|
+
the Problem's parameter dict only seeds the next solve. Empty when no
|
|
59
|
+
snapshot was recorded (e.g. ``solve_jax``, whose callers manage
|
|
60
|
+
parameters themselves).
|
|
53
61
|
plotting_data (dict[str, Any]): Flexible storage for plotting and application data.
|
|
54
62
|
|
|
55
63
|
!!! note "JAX pytree registration"
|
|
@@ -59,8 +67,9 @@ class OptimizationResults:
|
|
|
59
67
|
``converged``, ``t_final``, ``nodes``, ``trajectory``, ``X``, ``U``,
|
|
60
68
|
and every ``*_history`` field — the data the user actually consumes.
|
|
61
69
|
Post-process fields (``t_full``, ``x_full``, ``u_full``, ``cost``,
|
|
62
|
-
``ctcs_violation``), ``plotting_data``, and the
|
|
63
|
-
``_controls`` metadata are stashed in the
|
|
70
|
+
``ctcs_violation``), ``parameters``, ``plotting_data``, and the
|
|
71
|
+
internal ``_states`` / ``_controls`` metadata are stashed in the
|
|
72
|
+
treedef's *aux* instead, so
|
|
64
73
|
a batched ``solve_jax`` doesn't force callers to handle ``None``
|
|
65
74
|
leaves and ``post_process()`` outputs stay outside the vmap surface
|
|
66
75
|
(post-process per element after the batched solve).
|
|
@@ -217,6 +226,10 @@ class OptimizationResults:
|
|
|
217
226
|
cost: Optional[float] = field(default=None, metadata={"npz": "optional_scalar"})
|
|
218
227
|
ctcs_violation: Optional[np.ndarray] = field(default=None, metadata={"npz": "optional_array"})
|
|
219
228
|
|
|
229
|
+
# Parameter values the solve used (recorded by Problem.solve() /
|
|
230
|
+
# Problem.solve_batched(); empty when nothing was recorded)
|
|
231
|
+
parameters: dict[str, np.ndarray] = field(default_factory=dict, metadata={"npz": "dict"})
|
|
232
|
+
|
|
220
233
|
# Additional plotting/application data (added by user)
|
|
221
234
|
plotting_data: dict[str, Any] = field(default_factory=dict, metadata={"npz": "dict"})
|
|
222
235
|
|
|
@@ -245,6 +258,7 @@ class OptimizationResults:
|
|
|
245
258
|
self.u_full,
|
|
246
259
|
self.cost,
|
|
247
260
|
self.ctcs_violation,
|
|
261
|
+
self.parameters,
|
|
248
262
|
self.plotting_data,
|
|
249
263
|
)
|
|
250
264
|
return children, aux
|
|
@@ -260,6 +274,7 @@ class OptimizationResults:
|
|
|
260
274
|
u_full,
|
|
261
275
|
cost,
|
|
262
276
|
ctcs_violation,
|
|
277
|
+
parameters,
|
|
263
278
|
plotting_data,
|
|
264
279
|
) = aux
|
|
265
280
|
return cls(
|
|
@@ -271,6 +286,7 @@ class OptimizationResults:
|
|
|
271
286
|
u_full=u_full,
|
|
272
287
|
cost=cost,
|
|
273
288
|
ctcs_violation=ctcs_violation,
|
|
289
|
+
parameters=parameters,
|
|
274
290
|
plotting_data=plotting_data,
|
|
275
291
|
)
|
|
276
292
|
|
|
@@ -23,6 +23,7 @@ import os
|
|
|
23
23
|
import queue
|
|
24
24
|
import threading
|
|
25
25
|
import time
|
|
26
|
+
import warnings
|
|
26
27
|
from dataclasses import fields as dc_fields
|
|
27
28
|
from dataclasses import replace as dc_replace
|
|
28
29
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
@@ -672,6 +673,7 @@ class Problem:
|
|
|
672
673
|
# Final solution state (saved after successful solve)
|
|
673
674
|
self._solution: Optional[AlgorithmState] = None
|
|
674
675
|
self._solution_history: Optional[AlgorithmHistory] = None
|
|
676
|
+
self._solution_parameters: Optional[Dict[str, np.ndarray]] = None
|
|
675
677
|
|
|
676
678
|
# SCP algorithm (resolved from `algorithm` parameter above)
|
|
677
679
|
|
|
@@ -1287,6 +1289,7 @@ class Problem:
|
|
|
1287
1289
|
# Reset solution
|
|
1288
1290
|
self._solution = None
|
|
1289
1291
|
self._solution_history = None
|
|
1292
|
+
self._solution_parameters = None
|
|
1290
1293
|
|
|
1291
1294
|
# Reset timing
|
|
1292
1295
|
self.timing_solve = None
|
|
@@ -1355,7 +1358,10 @@ class Problem:
|
|
|
1355
1358
|
|
|
1356
1359
|
Returns:
|
|
1357
1360
|
OptimizationResults with trajectory and convergence info
|
|
1358
|
-
(call post_process() for full propagation)
|
|
1361
|
+
(call post_process() for full propagation). The parameter
|
|
1362
|
+
values used for the solve are recorded on
|
|
1363
|
+
``results.parameters``; :meth:`post_process` propagates
|
|
1364
|
+
with them.
|
|
1359
1365
|
"""
|
|
1360
1366
|
# Sync parameters, boundary conditions, and SCP constants before solving
|
|
1361
1367
|
self._sync_parameters()
|
|
@@ -1408,16 +1414,22 @@ class Problem:
|
|
|
1408
1414
|
|
|
1409
1415
|
profiling.profiling_end(pr, "solve")
|
|
1410
1416
|
|
|
1411
|
-
# Snapshot state
|
|
1417
|
+
# Snapshot state, history, and parameters for post_process() / plotting
|
|
1418
|
+
# reuse.
|
|
1412
1419
|
self._solution = self._state
|
|
1413
1420
|
self._solution_history = copy.deepcopy(self._history)
|
|
1421
|
+
self._solution_parameters = {
|
|
1422
|
+
name: np.array(value) for name, value in self._parameters.items()
|
|
1423
|
+
}
|
|
1414
1424
|
|
|
1415
1425
|
timed_out = t_max is not None and self.timing_solve >= t_max
|
|
1416
|
-
|
|
1426
|
+
result = self._format_result(
|
|
1417
1427
|
self._state,
|
|
1418
1428
|
self._history,
|
|
1419
1429
|
int(self._state.k) <= k_max and not timed_out,
|
|
1420
1430
|
)
|
|
1431
|
+
result.parameters = self._solution_parameters
|
|
1432
|
+
return result
|
|
1421
1433
|
|
|
1422
1434
|
def _default_state(self) -> AlgorithmState:
|
|
1423
1435
|
"""Fresh :class:`AlgorithmState` from settings and the algorithm's SCP constants.
|
|
@@ -1665,6 +1677,11 @@ class Problem:
|
|
|
1665
1677
|
parameters: Problem parameters dict for the current solve. Use
|
|
1666
1678
|
this rather than mutating ``self.parameters`` if the
|
|
1667
1679
|
parameters are traced. ``None`` reuses ``self._parameters``.
|
|
1680
|
+
Unlike :meth:`solve` / :meth:`solve_batched`, the merged
|
|
1681
|
+
values are *not* recorded on the returned results — under a
|
|
1682
|
+
caller's ``jit`` / ``vmap`` they are tracers, which must not
|
|
1683
|
+
leak into the pytree's aux — so callers that post-process
|
|
1684
|
+
manage parameter bookkeeping themselves.
|
|
1668
1685
|
x_guess: Initial state trajectory guess, shape ``(N, n_states)``.
|
|
1669
1686
|
Replaces ``state.x``; ``None`` uses the default from
|
|
1670
1687
|
settings (``State.guess`` at ``initialize()``).
|
|
@@ -1846,7 +1863,12 @@ class Problem:
|
|
|
1846
1863
|
|
|
1847
1864
|
Returns:
|
|
1848
1865
|
:class:`OptimizationResults` pytree with a leading ``B`` axis on
|
|
1849
|
-
every leaf and empty per-iteration histories.
|
|
1866
|
+
every leaf and empty per-iteration histories. The merged
|
|
1867
|
+
parameter values used for the solve are recorded on
|
|
1868
|
+
``results.parameters``, post-broadcast — every value carries the
|
|
1869
|
+
leading ``(B,)`` axis, shared values replicated — and
|
|
1870
|
+
:meth:`post_process_batched` propagates each element with its
|
|
1871
|
+
own values.
|
|
1850
1872
|
"""
|
|
1851
1873
|
if self._iteration_fn_jit_inner is None:
|
|
1852
1874
|
raise ValueError(
|
|
@@ -1953,7 +1975,16 @@ class Problem:
|
|
|
1953
1975
|
final_states = batched_solve(states, params_for_solve)
|
|
1954
1976
|
jax.block_until_ready(final_states)
|
|
1955
1977
|
self.timing_solve = time.time() - t_0_solve
|
|
1956
|
-
|
|
1978
|
+
results = OptimizationResults.from_final_state(final_states, problem=self)
|
|
1979
|
+
# Record the as-used parameter values with a leading (B,) axis on
|
|
1980
|
+
# every leaf, so post_process_batched() can index element b directly.
|
|
1981
|
+
results.parameters = {
|
|
1982
|
+
name: np.array(np.moveaxis(np.asarray(value), param_axes[name], 0))
|
|
1983
|
+
if param_axes[name] is not None
|
|
1984
|
+
else np.broadcast_to(np.asarray(value), (B,) + np.shape(value)).copy()
|
|
1985
|
+
for name, value in params_for_solve.items()
|
|
1986
|
+
}
|
|
1987
|
+
return results
|
|
1957
1988
|
|
|
1958
1989
|
def post_process(self) -> OptimizationResults:
|
|
1959
1990
|
"""Propagate solution through full nonlinear dynamics for high-fidelity trajectory.
|
|
@@ -1961,6 +1992,10 @@ class Problem:
|
|
|
1961
1992
|
Integrates the converged SCP solution through the nonlinear dynamics to
|
|
1962
1993
|
produce x_full, u_full, and t_full. Call after solve() for final results.
|
|
1963
1994
|
|
|
1995
|
+
Propagation uses the parameter values recorded at solve time
|
|
1996
|
+
(``results.parameters``), so mutating ``self.parameters`` between
|
|
1997
|
+
:meth:`solve` and here only seeds the next solve.
|
|
1998
|
+
|
|
1964
1999
|
Returns:
|
|
1965
2000
|
OptimizationResults with propagated trajectory fields
|
|
1966
2001
|
|
|
@@ -1980,9 +2015,11 @@ class Problem:
|
|
|
1980
2015
|
int(self._solution.k) <= self._algorithm.k_max,
|
|
1981
2016
|
)
|
|
1982
2017
|
|
|
2018
|
+
result.parameters = self._solution_parameters
|
|
2019
|
+
|
|
1983
2020
|
t_0_post = time.time()
|
|
1984
2021
|
result = propagate_trajectory_results(
|
|
1985
|
-
self.
|
|
2022
|
+
self._solution_parameters,
|
|
1986
2023
|
self.settings,
|
|
1987
2024
|
result,
|
|
1988
2025
|
self._propagation_solver,
|
|
@@ -2022,9 +2059,11 @@ class Problem:
|
|
|
2022
2059
|
- ``results.cost`` — ``(B,)``
|
|
2023
2060
|
- ``results.ctcs_violation`` — ``(B, ...)`` or ``None``
|
|
2024
2061
|
|
|
2025
|
-
Propagation runs sequentially over the batch in a Python loop;
|
|
2026
|
-
|
|
2027
|
-
|
|
2062
|
+
Propagation runs sequentially over the batch in a Python loop; each
|
|
2063
|
+
element propagates with its own parameter values from the snapshot
|
|
2064
|
+
:meth:`solve_batched` recorded on ``results.parameters``. Results
|
|
2065
|
+
without a snapshot (e.g. loaded from an older save) fall back to
|
|
2066
|
+
``self.parameters`` with a warning.
|
|
2028
2067
|
|
|
2029
2068
|
Args:
|
|
2030
2069
|
results: Batched :class:`~openscvx.algorithms.OptimizationResults`
|
|
@@ -2068,11 +2107,23 @@ class Problem:
|
|
|
2068
2107
|
costs: List[float] = []
|
|
2069
2108
|
ctcs_violations = []
|
|
2070
2109
|
|
|
2110
|
+
# Empty for results saved before the snapshot existed — those fall
|
|
2111
|
+
# back to the Problem's current values, the pre-snapshot behaviour.
|
|
2112
|
+
snapshot = getattr(results, "parameters", None) or {}
|
|
2113
|
+
if not snapshot and self._parameters:
|
|
2114
|
+
warnings.warn(
|
|
2115
|
+
"results carry no record of the parameter values they were solved "
|
|
2116
|
+
"with; propagating every element with the Problem's current "
|
|
2117
|
+
"parameters, which may differ from the solved values.",
|
|
2118
|
+
UserWarning,
|
|
2119
|
+
stacklevel=2,
|
|
2120
|
+
)
|
|
2121
|
+
|
|
2071
2122
|
t_0_post = time.time()
|
|
2072
2123
|
for b in range(B):
|
|
2073
2124
|
single = _make_single_result(results, b)
|
|
2074
2125
|
prop = propagate_trajectory_results(
|
|
2075
|
-
self._parameters,
|
|
2126
|
+
dict(self._parameters, **{k: np.asarray(v)[b] for k, v in snapshot.items()}),
|
|
2076
2127
|
self.settings,
|
|
2077
2128
|
single,
|
|
2078
2129
|
self._propagation_solver,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.5.3.
|
|
3
|
+
Version: 0.5.3.dev34
|
|
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
|
|
@@ -63,6 +63,7 @@ examples/abstract/hypersensitive.py
|
|
|
63
63
|
examples/abstract/impulsive.py
|
|
64
64
|
examples/abstract/stl_integer_variable.py
|
|
65
65
|
examples/abstract/stl_or.py
|
|
66
|
+
examples/aircraft/dynamic_soaring.py
|
|
66
67
|
examples/aircraft/supersonic_time_to_climb.py
|
|
67
68
|
examples/animations/7_dof_arm.py
|
|
68
69
|
examples/animations/_camera.py
|
|
@@ -354,6 +355,7 @@ tests/test_multishot_propagation.py
|
|
|
354
355
|
tests/test_optimization_results.py
|
|
355
356
|
tests/test_plotting.py
|
|
356
357
|
tests/test_propagation.py
|
|
358
|
+
tests/test_results_parameters.py
|
|
357
359
|
tests/test_solve_batched_brachistochrone.py
|
|
358
360
|
tests/test_solve_batched_cvxpy_export_errors.py
|
|
359
361
|
tests/test_solve_batched_export_roundtrip.py
|
|
@@ -220,6 +220,7 @@
|
|
|
220
220
|
"tests/test_propagation.py",
|
|
221
221
|
"tests/hohmann_analytical.py",
|
|
222
222
|
"tests/test_expert.py",
|
|
223
|
+
"tests/test_results_parameters.py",
|
|
223
224
|
"tests/test_solve_batched_inference.py",
|
|
224
225
|
"tests/test_solve_jax_bare_brachistochrone.py",
|
|
225
226
|
"tests/test_cvxpygen_optional.py",
|
|
@@ -333,6 +334,7 @@
|
|
|
333
334
|
"examples/abstract/stl_or.py",
|
|
334
335
|
"examples/abstract/stl_integer_variable.py",
|
|
335
336
|
"examples/abstract/brachistochrone.py",
|
|
337
|
+
"examples/aircraft/dynamic_soaring.py",
|
|
336
338
|
"examples/aircraft/supersonic_time_to_climb.py",
|
|
337
339
|
"examples/drone/dr_vp.py",
|
|
338
340
|
"examples/drone/openscvx_logo.py",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Tests for OptimizationResults save/load round-trip."""
|
|
2
2
|
|
|
3
|
+
import jax
|
|
3
4
|
import numpy as np
|
|
4
5
|
import pytest
|
|
5
6
|
|
|
@@ -184,3 +185,29 @@ def test_plotting_data_skips_non_array(tmp_path):
|
|
|
184
185
|
loaded = OptimizationResults.load(path)
|
|
185
186
|
np.testing.assert_array_equal(loaded.plotting_data["good"], np.array([1, 2, 3]))
|
|
186
187
|
assert "bad_func" not in loaded.plotting_data
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_save_load_roundtrip_parameters(tmp_path):
|
|
191
|
+
"""The recorded parameter snapshot survives a save/load round-trip."""
|
|
192
|
+
original = _make_result()
|
|
193
|
+
original.parameters = {"gain": np.array([2.0]), "center": np.array([1.0, 2.0, 3.0])}
|
|
194
|
+
path = tmp_path / "with_parameters.npz"
|
|
195
|
+
original.save(path)
|
|
196
|
+
|
|
197
|
+
loaded = OptimizationResults.load(path)
|
|
198
|
+
assert set(loaded.parameters) == set(original.parameters)
|
|
199
|
+
for key, value in original.parameters.items():
|
|
200
|
+
np.testing.assert_array_equal(loaded.parameters[key], value)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_parameters_snapshot_is_pytree_aux_not_child():
|
|
204
|
+
"""The parameter snapshot rides the treedef's aux, leaving the children unchanged."""
|
|
205
|
+
result = _make_result()
|
|
206
|
+
n_leaves = len(jax.tree_util.tree_leaves(result))
|
|
207
|
+
|
|
208
|
+
result.parameters = {"gain": np.array([2.0])}
|
|
209
|
+
leaves, treedef = jax.tree_util.tree_flatten(result)
|
|
210
|
+
assert len(leaves) == n_leaves # no new pytree children
|
|
211
|
+
|
|
212
|
+
restored = jax.tree_util.tree_unflatten(treedef, leaves)
|
|
213
|
+
np.testing.assert_array_equal(restored.parameters["gain"], np.array([2.0]))
|