openscvx 0.5.3.dev50__tar.gz → 0.5.3.dev51__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.dev50/openscvx.egg-info → openscvx-0.5.3.dev51}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/Foundations/discretization.md +38 -1
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/_version.py +3 -3
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/__init__.py +10 -0
- openscvx-0.5.3.dev51/openscvx/symbolic/expr/autodiff.py +159 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/expr.py +41 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/variable.py +6 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/__init__.py +1 -0
- openscvx-0.5.3.dev51/openscvx/symbolic/lowerers/cvxpy/autodiff.py +36 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/__init__.py +1 -0
- openscvx-0.5.3.dev51/openscvx/symbolic/lowerers/jax/autodiff.py +82 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/__init__.py +1 -0
- openscvx-0.5.3.dev51/openscvx/symbolic/lowerers/latex/autodiff.py +17 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx.egg-info/SOURCES.txt +5 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx.egg-info/scm_file_list.json +5 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx.egg-info/scm_version.json +2 -2
- openscvx-0.5.3.dev51/tests/symbolic/expr/test_autodiff.py +450 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/_extra.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/tests-cvxpygen.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/tests-examples.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/tests-lie.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/tests-mjx.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/tests-qpax.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.github/workflows/tests.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.gitignore +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/.gitmodules +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/CITATION.cff +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/LICENSE +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/README.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UnderTheHood/batching_jit_grad.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/changelog.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/citation.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/examples.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/index.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/installation.md +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/llms.txt +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/docs/versions.json +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/abstract/brachistochrone_batched.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/abstract/flappy_bird.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/aircraft/dynamic_soaring.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/aircraft/supersonic_time_to_climb.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/_render.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/logo.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/double_integrator/_plotting.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/double_integrator/moving_safe_zones.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/boresight_trace_mpcc.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/cinema_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/drone_racing_batched_gates.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/logo.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/circle.svg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/multi_agent_circle_swap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/drone/openscvx_logo.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/frax/panda_frax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/frax/panda_frax_pick_place.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/frax/panda_frax_viewplanning.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/frax/panda_frax_waypoint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/frax/ur5e_assets/ur5e.urdf +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/frax/ur5e_pen_trace.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/frax/ur5e_pen_trace_mpcc.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/plotting.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/rocket/ascent_launch_vehicle.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/examples/spacecraft/relative_loitering.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/figures/video_preview.png +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/home.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/main.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/material/overrides/sitemap.xml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/mkdocs.yml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/__main__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/history.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/hyperparams.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/loop.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/penalty.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/scvx/iteration.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/state.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/config.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrations/_utils.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrations/frax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/loader.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/publication.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/coordinates.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/problem.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/solvers/base.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/solvers/cones.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/solvers/moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/solvers/qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/affine.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/canonicalize.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/_lowerer.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/_registry.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/arithmetic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/array.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/constraint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/control.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/expr.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/formulation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/lie.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/linalg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/logic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/math.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/spatial.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/state.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/utils/caching.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/utils/printing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/pyproject.toml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/scripts/mkdocs_seo_hook.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/setup.cfg +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/_iteration_helpers.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/test_iteration_fn_jit.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/test_iteration_fn_parity.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/algorithms/test_make_solve_loop.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/conftest.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_impulsive.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_multishot_propagation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_batched_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_batched_cvxpy_export_errors.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_batched_export_roundtrip.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_bare_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_jit_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_vmap_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_vmap_converged_no_drift.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/_iteration_callback_helpers.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_moreau.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_qpax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/solvers/test_subproblem_pytree.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_guess_expr.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_gmsr.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_latex_formulation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_lower_latex.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_autotuning.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_discretization.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_examples.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_expert.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_init.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_initialize_syncs_guesses.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_integrators.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_loader.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_optimization_results.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_plotting.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_post_process_batched_tau_clamp.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_propagation.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_results_parameters.py +0 -0
- {openscvx-0.5.3.dev50 → openscvx-0.5.3.dev51}/tests/test_solve_batched_inference.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.dev51
|
|
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
|
|
@@ -91,4 +91,41 @@ def dVdt(self, tau: float, V: jnp.ndarray, u_cur: np.ndarray, u_next: np.ndarray
|
|
|
91
91
|
)
|
|
92
92
|
return dVdt.flatten()
|
|
93
93
|
```
|
|
94
|
-
|
|
94
|
+
|
|
95
|
+
## Supplying your own Jacobian
|
|
96
|
+
|
|
97
|
+
The state and control Jacobians above (`dfdx`, `dfdu`) come from automatic
|
|
98
|
+
differentiation of the dynamics you wrote. Occasionally the exact Jacobian is
|
|
99
|
+
not the one you want: a drag law, a contact model, or a lookup table can be
|
|
100
|
+
smooth enough to integrate while its true derivative makes the convex
|
|
101
|
+
subproblem badly conditioned, so the trust region collapses and the SCP loop
|
|
102
|
+
crawls. The standard remedy is to linearize with a deliberately simplified
|
|
103
|
+
(inexact) Jacobian.
|
|
104
|
+
|
|
105
|
+
`Expr.with_jacobian` applies that remedy to a single term:
|
|
106
|
+
|
|
107
|
+
``` py
|
|
108
|
+
drag = -0.5 * rho * ox.Norm(vel) * vel
|
|
109
|
+
J_drag = -0.5 * rho * ox.Norm(vel) * np.eye(3) # drops the d||v||/dv term
|
|
110
|
+
|
|
111
|
+
dynamics = {"pos": vel, "vel": thrust / m + drag.with_jacobian({vel: J_drag})}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The keys are the `State` or `Control` objects the derivative is taken with
|
|
115
|
+
respect to, and each value is an expression (or constant array) of shape
|
|
116
|
+
`(*term.shape, *variable.shape)`. Directions you do not name are still
|
|
117
|
+
differentiated automatically, so the example above hands over `∂/∂vel` while
|
|
118
|
+
`∂/∂thrust` still comes from autodiff.
|
|
119
|
+
|
|
120
|
+
The *value* of the term is untouched — only the search direction changes — so a
|
|
121
|
+
converged trajectory still satisfies the original nonlinear dynamics; the
|
|
122
|
+
defect and the propagated solution are computed with the term as written. An
|
|
123
|
+
inexact Jacobian trades linearization accuracy (and hence convergence rate) for
|
|
124
|
+
conditioning, so reach for it when a term is a known source of stiffness, not
|
|
125
|
+
as a default.
|
|
126
|
+
|
|
127
|
+
The override lives inside the lowered JAX function, so every downstream
|
|
128
|
+
derivative picks it up: the discretizer's `A`/`B`, nonconvex constraint
|
|
129
|
+
linearization, and the sparsity pattern used for coloring. It has no meaning
|
|
130
|
+
inside a constraint that is handed to the convex solver as written, and lowering
|
|
131
|
+
one there raises.
|
|
@@ -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.dev51'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 3, 'dev51')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g21d5581a4'
|
|
@@ -33,6 +33,11 @@ Module Organization:
|
|
|
33
33
|
Array manipulation operations including `Index`, `Concat`, `Stack`, `Hstack`,
|
|
34
34
|
and `Vstack` for indexing, slicing, and combining arrays.
|
|
35
35
|
|
|
36
|
+
User-Supplied Jacobians (autodiff.py):
|
|
37
|
+
`WithJacobian`, built by `Expr.with_jacobian`, replaces a subexpression's
|
|
38
|
+
derivative with respect to chosen variables — the inexact-Jacobian knob for
|
|
39
|
+
SCP conditioning.
|
|
40
|
+
|
|
36
41
|
Constraints (constraint.py):
|
|
37
42
|
Constraint types including `Constraint`, `Equality`, `Inequality`,
|
|
38
43
|
`NodalConstraint`, and `CTCS` (Continuous-Time Constraint Satisfaction).
|
|
@@ -80,6 +85,9 @@ from .arithmetic import Add, Div, MatMul, Mul, Neg, Power, Sub
|
|
|
80
85
|
# Array operations
|
|
81
86
|
from .array import Block, Concat, Hstack, Index, Stack, Vstack
|
|
82
87
|
|
|
88
|
+
# User-supplied Jacobians
|
|
89
|
+
from .autodiff import WithJacobian
|
|
90
|
+
|
|
83
91
|
# Specialized constraints
|
|
84
92
|
from .constraint import (
|
|
85
93
|
CTCS,
|
|
@@ -258,4 +266,6 @@ __all__ = [
|
|
|
258
266
|
"ctcs",
|
|
259
267
|
# Vmap
|
|
260
268
|
"Vmap",
|
|
269
|
+
# User-supplied Jacobians
|
|
270
|
+
"WithJacobian",
|
|
261
271
|
]
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""User-supplied Jacobians for a subexpression.
|
|
2
|
+
|
|
3
|
+
Successive convexification linearizes the dynamics and constraints at every
|
|
4
|
+
iteration, so the *Jacobian* — not the value — is what shapes each convex
|
|
5
|
+
subproblem. Occasionally the exact Jacobian is the wrong one to hand the
|
|
6
|
+
solver: an aerodynamic drag term, a contact model, or a lookup table can be
|
|
7
|
+
smooth enough to integrate but stiff enough that its true derivative wrecks the
|
|
8
|
+
conditioning of the subproblem. The standard remedy is a deliberately
|
|
9
|
+
simplified (inexact) Jacobian — the trajectory still converges to a solution of
|
|
10
|
+
the *nonlinear* problem, because the value used for the defect is untouched;
|
|
11
|
+
only the search direction changes.
|
|
12
|
+
|
|
13
|
+
:class:`WithJacobian` is that remedy, written at sub-expression granularity::
|
|
14
|
+
|
|
15
|
+
drag = -0.5 * rho * ox.Norm(vel) * vel
|
|
16
|
+
accel = thrust / m + drag.with_jacobian({vel: J_drag})
|
|
17
|
+
|
|
18
|
+
The node wraps a subexpression and carries an override Jacobian per variable.
|
|
19
|
+
Lowering to JAX emits a :func:`jax.custom_jvp` rule around the wrapped
|
|
20
|
+
subexpression, so every downstream differentiation — the discretizer's
|
|
21
|
+
``jacfwd``, constraint linearization, sparse coloring — sees the user's
|
|
22
|
+
Jacobian in the overridden directions and autodiff everywhere else, with no
|
|
23
|
+
further special-casing. The primal value is always the wrapped expression
|
|
24
|
+
itself.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import hashlib
|
|
28
|
+
from typing import Dict, List, Tuple
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
|
|
32
|
+
from .expr import Expr, to_expr
|
|
33
|
+
from .variable import Variable
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _without_unit_axes(shape: Tuple[int, ...]) -> Tuple[int, ...]:
|
|
37
|
+
"""Drop length-1 axes, the way :class:`Constant` squeezes a wrapped array."""
|
|
38
|
+
return tuple(d for d in shape if d != 1)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class WithJacobian(Expr):
|
|
42
|
+
"""A subexpression whose derivative w.r.t. chosen variables is user-supplied.
|
|
43
|
+
|
|
44
|
+
Construct this through :meth:`Expr.with_jacobian` rather than directly. The
|
|
45
|
+
node evaluates exactly like the expression it wraps; only differentiation
|
|
46
|
+
differs, and only in the overridden directions (see the module docstring for
|
|
47
|
+
the motivation).
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
expr: The wrapped expression, and the node's value.
|
|
51
|
+
overrides: ``(variable, jacobian)`` pairs in the order given, each
|
|
52
|
+
Jacobian shaped ``(*expr.shape, *variable.shape)``.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, expr: Expr, jacobians: Dict[Variable, Expr]):
|
|
56
|
+
"""Wrap ``expr`` with an override Jacobian per variable.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
expr: Expression whose derivative is being overridden.
|
|
60
|
+
jacobians: Map from a ``State`` or ``Control`` to the Jacobian of
|
|
61
|
+
``expr`` with respect to it. Values are coerced with
|
|
62
|
+
:func:`to_expr`, so constant matrices are accepted.
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
TypeError: If a key is not a decision variable.
|
|
66
|
+
ValueError: If no Jacobian is given.
|
|
67
|
+
"""
|
|
68
|
+
if not jacobians:
|
|
69
|
+
raise ValueError(
|
|
70
|
+
"with_jacobian needs at least one {variable: jacobian} entry; an empty "
|
|
71
|
+
"mapping would wrap the expression without changing anything."
|
|
72
|
+
)
|
|
73
|
+
self.expr = to_expr(expr)
|
|
74
|
+
overrides = []
|
|
75
|
+
for var, jac in jacobians.items():
|
|
76
|
+
if not isinstance(var, Variable):
|
|
77
|
+
raise TypeError(
|
|
78
|
+
f"with_jacobian keys must be the State or Control the derivative is "
|
|
79
|
+
f"taken with respect to, got {type(var).__name__}. Write "
|
|
80
|
+
f"`expr.with_jacobian({{vel: J_vel}})` with `vel` the variable itself."
|
|
81
|
+
)
|
|
82
|
+
overrides.append((var, to_expr(jac)))
|
|
83
|
+
self.overrides: List[Tuple[Variable, Expr]] = overrides
|
|
84
|
+
|
|
85
|
+
def children(self) -> List[Expr]:
|
|
86
|
+
"""Return the wrapped expression followed by each override Jacobian.
|
|
87
|
+
|
|
88
|
+
The overridden variables are not children: they identify *directions*,
|
|
89
|
+
not operands, and appear as leaves inside the Jacobian expressions only
|
|
90
|
+
if the user put them there.
|
|
91
|
+
"""
|
|
92
|
+
return [self.expr, *(jac for _, jac in self.overrides)]
|
|
93
|
+
|
|
94
|
+
def canonicalize(self) -> Expr:
|
|
95
|
+
"""Canonicalize the wrapped expression and every override Jacobian."""
|
|
96
|
+
return WithJacobian(
|
|
97
|
+
self.expr.canonicalize(),
|
|
98
|
+
{var: jac.canonicalize() for var, jac in self.overrides},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def check_shape(self) -> Tuple[int, ...]:
|
|
102
|
+
"""Return the wrapped expression's shape, validating each Jacobian.
|
|
103
|
+
|
|
104
|
+
A Jacobian must be shaped ``(*expr.shape, *var.shape)``. Unit axes are
|
|
105
|
+
ignored in the comparison: a constant is squeezed when it is wrapped, so
|
|
106
|
+
an honest ``(3, 1)`` Jacobian arrives as ``(3,)``. The JAX lowering
|
|
107
|
+
reshapes it back before contracting.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
The shape of the wrapped expression — the wrapper is value-transparent.
|
|
111
|
+
|
|
112
|
+
Raises:
|
|
113
|
+
ValueError: If a Jacobian's shape is not ``(*expr.shape, *var.shape)``.
|
|
114
|
+
"""
|
|
115
|
+
shape = self.expr.check_shape()
|
|
116
|
+
for var, jac in self.overrides:
|
|
117
|
+
expected = (*shape, *var.shape)
|
|
118
|
+
got = jac.check_shape()
|
|
119
|
+
if _without_unit_axes(got) != _without_unit_axes(expected):
|
|
120
|
+
raise ValueError(
|
|
121
|
+
f"Jacobian for {var.__class__.__name__} '{var.name}' has shape {got}, "
|
|
122
|
+
f"expected {expected}: the derivative of an expression of shape "
|
|
123
|
+
f"{shape} with respect to a variable of shape {var.shape}."
|
|
124
|
+
)
|
|
125
|
+
return shape
|
|
126
|
+
|
|
127
|
+
def sparsity(self, n_x: int, n_u: int) -> Tuple[np.ndarray, np.ndarray]:
|
|
128
|
+
"""Conservative pattern: the children's, widened to the overridden columns.
|
|
129
|
+
|
|
130
|
+
The default union over children is not enough here. A user Jacobian may
|
|
131
|
+
be a constant (no dependence of its own) yet still couple outputs to
|
|
132
|
+
every entry of the overridden variable, so those columns are marked
|
|
133
|
+
dense on top of the children's pattern.
|
|
134
|
+
"""
|
|
135
|
+
from .control import Control
|
|
136
|
+
|
|
137
|
+
S_x, S_u = super().sparsity(n_x, n_u)
|
|
138
|
+
for var, _ in self.overrides:
|
|
139
|
+
if var._slice is None:
|
|
140
|
+
continue
|
|
141
|
+
S = S_u if isinstance(var, Control) else S_x
|
|
142
|
+
S[:, var._slice] = True
|
|
143
|
+
return S_x, S_u
|
|
144
|
+
|
|
145
|
+
def _hash_into(self, hasher: "hashlib._Hash") -> None:
|
|
146
|
+
"""Hash the wrapper, the wrapped expression, and each override in order.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
hasher: A hashlib hash object to update
|
|
150
|
+
"""
|
|
151
|
+
hasher.update(b"WithJacobian")
|
|
152
|
+
self.expr._hash_into(hasher)
|
|
153
|
+
for var, jac in self.overrides:
|
|
154
|
+
var._hash_into(hasher)
|
|
155
|
+
jac._hash_into(hasher)
|
|
156
|
+
|
|
157
|
+
def __repr__(self) -> str:
|
|
158
|
+
vars_ = ", ".join(var.name for var, _ in self.overrides)
|
|
159
|
+
return f"{self.expr!r}.with_jacobian({{{vars_}}})"
|
|
@@ -308,6 +308,47 @@ class Expr:
|
|
|
308
308
|
"""
|
|
309
309
|
return NodeReference(self, k)
|
|
310
310
|
|
|
311
|
+
def with_jacobian(self, jacobians: dict) -> "Expr":
|
|
312
|
+
"""Override this expression's derivative w.r.t. chosen variables.
|
|
313
|
+
|
|
314
|
+
Successive convexification linearizes at every iteration, so the Jacobian
|
|
315
|
+
of a term — not its value — is what conditions the convex subproblem. A
|
|
316
|
+
deliberately simplified (inexact) Jacobian is a standard remedy for a term
|
|
317
|
+
that is smooth enough to integrate but whose true derivative makes the
|
|
318
|
+
subproblem badly conditioned. The value of the expression is untouched, so
|
|
319
|
+
the converged trajectory still satisfies the original nonlinear problem;
|
|
320
|
+
only the search direction changes.
|
|
321
|
+
|
|
322
|
+
Directions that are not overridden are still differentiated automatically,
|
|
323
|
+
so a single term can hand-specify its state Jacobian and let the control
|
|
324
|
+
Jacobian fall out of autodiff.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
jacobians: Map from a ``State`` or ``Control`` to the Jacobian of this
|
|
328
|
+
expression with respect to it, shaped ``(*self.shape, *var.shape)``
|
|
329
|
+
(a variable of shape ``(n,)`` and a scalar expression give shape
|
|
330
|
+
``(n,)``). Constant matrices are accepted alongside expressions.
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
Expr: A ``WithJacobian`` node wrapping this expression.
|
|
334
|
+
|
|
335
|
+
Example:
|
|
336
|
+
Damp the drag Jacobian without changing the drag force:
|
|
337
|
+
|
|
338
|
+
drag = -0.5 * rho * ox.Norm(vel) * vel
|
|
339
|
+
J_drag = -0.5 * rho * ox.Norm(vel) * np.eye(3) # drops the d|v|/dv term
|
|
340
|
+
|
|
341
|
+
dynamics = {"vel": thrust / m + drag.with_jacobian({vel: J_drag})}
|
|
342
|
+
|
|
343
|
+
Note:
|
|
344
|
+
The override applies on the JAX path — dynamics linearization and
|
|
345
|
+
constraint linearization. Inside a constraint lowered to CVXPy the
|
|
346
|
+
wrapper has no meaning and raises.
|
|
347
|
+
"""
|
|
348
|
+
from .autodiff import WithJacobian
|
|
349
|
+
|
|
350
|
+
return WithJacobian(self, jacobians)
|
|
351
|
+
|
|
311
352
|
def children(self) -> List["Expr"]:
|
|
312
353
|
"""Return the child expressions of this node.
|
|
313
354
|
|
|
@@ -58,6 +58,12 @@ class Variable(Leaf):
|
|
|
58
58
|
def __repr__(self) -> str:
|
|
59
59
|
return f"Var({self.name!r})"
|
|
60
60
|
|
|
61
|
+
# ``Expr.__eq__`` builds an Equality constraint rather than comparing, which
|
|
62
|
+
# makes Python drop the inherited ``__hash__``. Variables are identities, not
|
|
63
|
+
# values, so restore hashing by identity: it lets a variable key a dict, as in
|
|
64
|
+
# ``expr.with_jacobian({vel: J_vel})``.
|
|
65
|
+
__hash__ = object.__hash__
|
|
66
|
+
|
|
61
67
|
def _hash_into(self, hasher: "hashlib._Hash") -> None:
|
|
62
68
|
"""Hash Variable using its slice (canonical position, name-invariant).
|
|
63
69
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""CVXPy visitors for user-supplied Jacobians.
|
|
2
|
+
|
|
3
|
+
Visitors: WithJacobian
|
|
4
|
+
|
|
5
|
+
A ``WithJacobian`` override reshapes a *linearization*, and linearization happens
|
|
6
|
+
on the JAX path. The convex subproblem sees convex constraints verbatim, with no
|
|
7
|
+
derivative taken, so the wrapper has nothing to act on here and raises
|
|
8
|
+
``NotImplementedError`` — the same treatment ``CTCS`` gets for being a
|
|
9
|
+
JAX-side construct.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import cvxpy as cp
|
|
13
|
+
|
|
14
|
+
from openscvx.symbolic.expr.autodiff import WithJacobian
|
|
15
|
+
from openscvx.symbolic.lowerers.cvxpy._registry import visitor # noqa: F401
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@visitor(WithJacobian)
|
|
19
|
+
def _visit_with_jacobian(lowerer, node: WithJacobian) -> cp.Expression:
|
|
20
|
+
"""Raise NotImplementedError for a Jacobian override inside a convex constraint.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
node: WithJacobian expression node
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
NotImplementedError: Always — see the module docstring.
|
|
27
|
+
"""
|
|
28
|
+
raise NotImplementedError(
|
|
29
|
+
"`.with_jacobian(...)` overrides the derivative used when a nonconvex "
|
|
30
|
+
"expression is linearized, which only happens on the JAX path (dynamics and "
|
|
31
|
+
"nonconvex constraints). This expression was lowered to CVXPy as part of a "
|
|
32
|
+
"convex constraint, which is passed to the solver as written and never "
|
|
33
|
+
"differentiated, so the override has no meaning here. Apply "
|
|
34
|
+
"`.with_jacobian(...)` to the nonconvex term instead, or drop it from this "
|
|
35
|
+
"constraint."
|
|
36
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""JAX visitors for user-supplied Jacobians.
|
|
2
|
+
|
|
3
|
+
Visitors: WithJacobian
|
|
4
|
+
|
|
5
|
+
Lowers a ``WithJacobian`` node to its wrapped subexpression wrapped in a
|
|
6
|
+
:func:`jax.custom_jvp` rule. The rule zeroes the tangent of every overridden
|
|
7
|
+
variable before differentiating the inner function, then adds ``J @ dvar`` for
|
|
8
|
+
each override — so overridden directions come from the user's Jacobian and all
|
|
9
|
+
others from autodiff. Because the override lives inside the lowered function,
|
|
10
|
+
every downstream differentiation (the discretizer's ``jacfwd``, constraint
|
|
11
|
+
linearization, sparse coloring) picks it up with no further plumbing.
|
|
12
|
+
|
|
13
|
+
Unlike the ``Vmap`` and ``Cond`` visitors, this one does not pause the value
|
|
14
|
+
memo: the nested ``jax.jvp`` trace receives its own ``(x, u)`` tracers rather
|
|
15
|
+
than reusing the captured outer ones, and the memo is keyed on all four
|
|
16
|
+
arguments, so a value cached in one trace can never be handed to a caller in
|
|
17
|
+
another.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import jax
|
|
21
|
+
import jax.numpy as jnp
|
|
22
|
+
|
|
23
|
+
from openscvx.symbolic.expr.autodiff import WithJacobian
|
|
24
|
+
from openscvx.symbolic.expr.control import Control
|
|
25
|
+
from openscvx.symbolic.lowerers.jax._registry import visitor # noqa: F401
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@visitor(WithJacobian)
|
|
29
|
+
def _visit_with_jacobian(lowerer, node: WithJacobian):
|
|
30
|
+
"""Lower a user-Jacobian override to a ``jax.custom_jvp``-wrapped function.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
node: WithJacobian expression node
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Function (x, u, node, params) -> value of the wrapped expression, whose
|
|
37
|
+
derivative w.r.t. each overridden variable is the user's Jacobian.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
ValueError: If an overridden variable has no slice assigned (unification
|
|
41
|
+
not run).
|
|
42
|
+
"""
|
|
43
|
+
inner = lowerer.lower(node.expr)
|
|
44
|
+
out_shape = node.expr.check_shape()
|
|
45
|
+
overrides = []
|
|
46
|
+
for var, jac in node.overrides:
|
|
47
|
+
if var._slice is None:
|
|
48
|
+
raise ValueError(f"{var.__class__.__name__} {var.name!r} has no slice assigned")
|
|
49
|
+
# Squeezed constants come back as e.g. () for a (1, 1) Jacobian, so the
|
|
50
|
+
# declared shape is restored before contracting with the tangent.
|
|
51
|
+
jac_shape = (*out_shape, *var.shape)
|
|
52
|
+
overrides.append((var._slice, isinstance(var, Control), lowerer.lower(jac), jac_shape))
|
|
53
|
+
overrides = tuple(overrides)
|
|
54
|
+
|
|
55
|
+
def with_jacobian_fn(x, u, node_idx, params):
|
|
56
|
+
def inner_xu(x_, u_):
|
|
57
|
+
return inner(x_, u_, node_idx, params)
|
|
58
|
+
|
|
59
|
+
f = jax.custom_jvp(inner_xu)
|
|
60
|
+
|
|
61
|
+
@f.defjvp
|
|
62
|
+
def _jvp(primals, tangents):
|
|
63
|
+
x_, u_ = primals
|
|
64
|
+
dx, du = tangents
|
|
65
|
+
# Autodiff supplies the non-overridden directions: blank the
|
|
66
|
+
# overridden slices so their contribution comes only from below.
|
|
67
|
+
dx_free, du_free = dx, du
|
|
68
|
+
for sl, is_control, _, _ in overrides:
|
|
69
|
+
if is_control:
|
|
70
|
+
du_free = du_free.at[sl].set(0.0)
|
|
71
|
+
else:
|
|
72
|
+
dx_free = dx_free.at[sl].set(0.0)
|
|
73
|
+
out, tangent = jax.jvp(inner_xu, (x_, u_), (dx_free, du_free))
|
|
74
|
+
for sl, is_control, jac_fn, jac_shape in overrides:
|
|
75
|
+
J = jnp.reshape(jac_fn(x_, u_, node_idx, params), jac_shape)
|
|
76
|
+
dvar = du[sl] if is_control else dx[sl]
|
|
77
|
+
tangent = tangent + jnp.tensordot(J, dvar, axes=1)
|
|
78
|
+
return out, tangent
|
|
79
|
+
|
|
80
|
+
return f(x, u)
|
|
81
|
+
|
|
82
|
+
return with_jacobian_fn
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""LaTeX visitors for user-supplied Jacobians.
|
|
2
|
+
|
|
3
|
+
Visitors: WithJacobian
|
|
4
|
+
|
|
5
|
+
A Jacobian override changes how a term is differentiated, not what it equals, so
|
|
6
|
+
the rendered formulation shows the wrapped expression alone — the same choice the
|
|
7
|
+
``CTCS`` visitor makes in rendering the constraint it stands for.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from openscvx.symbolic.expr.autodiff import WithJacobian
|
|
11
|
+
from openscvx.symbolic.lowerers.latex._registry import visitor
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@visitor(WithJacobian)
|
|
15
|
+
def _visit_with_jacobian(lowerer, node: WithJacobian):
|
|
16
|
+
"""Render the wrapped expression; the override is invisible in the math."""
|
|
17
|
+
return lowerer.lower(node.expr)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.5.3.
|
|
3
|
+
Version: 0.5.3.dev51
|
|
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
|
|
@@ -281,6 +281,7 @@ openscvx/symbolic/unified.py
|
|
|
281
281
|
openscvx/symbolic/expr/__init__.py
|
|
282
282
|
openscvx/symbolic/expr/arithmetic.py
|
|
283
283
|
openscvx/symbolic/expr/array.py
|
|
284
|
+
openscvx/symbolic/expr/autodiff.py
|
|
284
285
|
openscvx/symbolic/expr/constraint.py
|
|
285
286
|
openscvx/symbolic/expr/control.py
|
|
286
287
|
openscvx/symbolic/expr/expr.py
|
|
@@ -305,6 +306,7 @@ openscvx/symbolic/lowerers/cvxpy/_lowerer.py
|
|
|
305
306
|
openscvx/symbolic/lowerers/cvxpy/_registry.py
|
|
306
307
|
openscvx/symbolic/lowerers/cvxpy/arithmetic.py
|
|
307
308
|
openscvx/symbolic/lowerers/cvxpy/array.py
|
|
309
|
+
openscvx/symbolic/lowerers/cvxpy/autodiff.py
|
|
308
310
|
openscvx/symbolic/lowerers/cvxpy/constraint.py
|
|
309
311
|
openscvx/symbolic/lowerers/cvxpy/control.py
|
|
310
312
|
openscvx/symbolic/lowerers/cvxpy/expr.py
|
|
@@ -317,6 +319,7 @@ openscvx/symbolic/lowerers/jax/_lowerer.py
|
|
|
317
319
|
openscvx/symbolic/lowerers/jax/_registry.py
|
|
318
320
|
openscvx/symbolic/lowerers/jax/arithmetic.py
|
|
319
321
|
openscvx/symbolic/lowerers/jax/array.py
|
|
322
|
+
openscvx/symbolic/lowerers/jax/autodiff.py
|
|
320
323
|
openscvx/symbolic/lowerers/jax/constraint.py
|
|
321
324
|
openscvx/symbolic/lowerers/jax/control.py
|
|
322
325
|
openscvx/symbolic/lowerers/jax/expr.py
|
|
@@ -334,6 +337,7 @@ openscvx/symbolic/lowerers/latex/_lowerer.py
|
|
|
334
337
|
openscvx/symbolic/lowerers/latex/_registry.py
|
|
335
338
|
openscvx/symbolic/lowerers/latex/arithmetic.py
|
|
336
339
|
openscvx/symbolic/lowerers/latex/array.py
|
|
340
|
+
openscvx/symbolic/lowerers/latex/autodiff.py
|
|
337
341
|
openscvx/symbolic/lowerers/latex/constraint.py
|
|
338
342
|
openscvx/symbolic/lowerers/latex/control.py
|
|
339
343
|
openscvx/symbolic/lowerers/latex/expr.py
|
|
@@ -438,6 +442,7 @@ tests/symbolic/test_unified.py
|
|
|
438
442
|
tests/symbolic/expr/__init__.py
|
|
439
443
|
tests/symbolic/expr/test_arithmetic.py
|
|
440
444
|
tests/symbolic/expr/test_array.py
|
|
445
|
+
tests/symbolic/expr/test_autodiff.py
|
|
441
446
|
tests/symbolic/expr/test_constraint.py
|
|
442
447
|
tests/symbolic/expr/test_expr.py
|
|
443
448
|
tests/symbolic/expr/test_guess_expr.py
|
|
@@ -267,6 +267,7 @@
|
|
|
267
267
|
"openscvx/symbolic/expr/__init__.py",
|
|
268
268
|
"openscvx/symbolic/expr/arithmetic.py",
|
|
269
269
|
"openscvx/symbolic/expr/array.py",
|
|
270
|
+
"openscvx/symbolic/expr/autodiff.py",
|
|
270
271
|
"openscvx/symbolic/expr/constraint.py",
|
|
271
272
|
"openscvx/symbolic/expr/control.py",
|
|
272
273
|
"openscvx/symbolic/expr/expr.py",
|
|
@@ -293,6 +294,7 @@
|
|
|
293
294
|
"openscvx/symbolic/lowerers/cvxpy/_registry.py",
|
|
294
295
|
"openscvx/symbolic/lowerers/cvxpy/arithmetic.py",
|
|
295
296
|
"openscvx/symbolic/lowerers/cvxpy/array.py",
|
|
297
|
+
"openscvx/symbolic/lowerers/cvxpy/autodiff.py",
|
|
296
298
|
"openscvx/symbolic/lowerers/cvxpy/constraint.py",
|
|
297
299
|
"openscvx/symbolic/lowerers/cvxpy/control.py",
|
|
298
300
|
"openscvx/symbolic/lowerers/cvxpy/expr.py",
|
|
@@ -305,6 +307,7 @@
|
|
|
305
307
|
"openscvx/symbolic/lowerers/jax/_registry.py",
|
|
306
308
|
"openscvx/symbolic/lowerers/jax/arithmetic.py",
|
|
307
309
|
"openscvx/symbolic/lowerers/jax/array.py",
|
|
310
|
+
"openscvx/symbolic/lowerers/jax/autodiff.py",
|
|
308
311
|
"openscvx/symbolic/lowerers/jax/constraint.py",
|
|
309
312
|
"openscvx/symbolic/lowerers/jax/control.py",
|
|
310
313
|
"openscvx/symbolic/lowerers/jax/expr.py",
|
|
@@ -322,6 +325,7 @@
|
|
|
322
325
|
"openscvx/symbolic/lowerers/latex/_registry.py",
|
|
323
326
|
"openscvx/symbolic/lowerers/latex/arithmetic.py",
|
|
324
327
|
"openscvx/symbolic/lowerers/latex/array.py",
|
|
328
|
+
"openscvx/symbolic/lowerers/latex/autodiff.py",
|
|
325
329
|
"openscvx/symbolic/lowerers/latex/constraint.py",
|
|
326
330
|
"openscvx/symbolic/lowerers/latex/control.py",
|
|
327
331
|
"openscvx/symbolic/lowerers/latex/expr.py",
|
|
@@ -406,6 +410,7 @@
|
|
|
406
410
|
"tests/symbolic/expr/__init__.py",
|
|
407
411
|
"tests/symbolic/expr/test_arithmetic.py",
|
|
408
412
|
"tests/symbolic/expr/test_array.py",
|
|
413
|
+
"tests/symbolic/expr/test_autodiff.py",
|
|
409
414
|
"tests/symbolic/expr/test_constraint.py",
|
|
410
415
|
"tests/symbolic/expr/test_expr.py",
|
|
411
416
|
"tests/symbolic/expr/test_guess_expr.py",
|