openscvx 0.5.3.dev36__tar.gz → 0.5.3.dev38__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.dev36/openscvx.egg-info → openscvx-0.5.3.dev38}/PKG-INFO +1 -1
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/relative_loitering.py +0 -1
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/_version.py +3 -3
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/problem.py +6 -9
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/augmentation.py +31 -35
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/builder.py +5 -10
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/constraint.py +46 -2
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/expr.py +43 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/stl.py +13 -1
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/stljax.py +11 -1
- openscvx-0.5.3.dev38/openscvx/symbolic/lowerers/jax/_lowerer.py +122 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/logic.py +16 -6
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/vmap.py +14 -4
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38/openscvx.egg-info}/PKG-INFO +1 -1
- openscvx-0.5.3.dev38/openscvx.egg-info/scm_version.json +8 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_augmentation.py +74 -34
- openscvx-0.5.3.dev36/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -56
- openscvx-0.5.3.dev36/openscvx.egg-info/scm_version.json +0 -8
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/_extra.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/docs.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/lint.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/release.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-cvxpygen.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-examples.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-lie.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-mjx.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests-qpax.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.github/workflows/tests.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.gitignore +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/.gitmodules +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/CONTRIBUTING.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/LICENSE +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/README.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/batching_jit_grad.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/favicon.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/logo.svg +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/viser-client/index.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/viser-recordings/drone_racing.viser +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/citation.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/examples.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/index.md +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/docs/versions.json +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/_viser_embed_export.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/brachistochrone_batched.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/flappy_bird.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/hypersensitive.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/aircraft/dynamic_soaring.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/aircraft/supersonic_time_to_climb.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/_camera.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/_render.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/_sensor_view.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/logo.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/animations/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/7_dof_arm_collision.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/franka_fr3v2_pick_place.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/double_integrator/_plotting.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/double_integrator/moving_safe_zones.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/cinema_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/drone_racing_batched_gates.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/multi_agent_circle_swap.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/drone/openscvx_logo.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax_pick_place.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax_viewplanning.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/frax/panda_frax_waypoint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/double_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/skydio_x2_mjx.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/triple_cartpole_game.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mjx/triple_cartpole_mjx.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/plotting.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/plotting_viser.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/rocket/ascent_launch_vehicle.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/let_transfer.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/figures/video_preview.png +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/home-hero.css +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/assets/stylesheets/home-viser.css +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/home.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/main.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-diagram.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-dropin-banner.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-hero.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-pipeline.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/material/overrides/partials/home-viser-strip.html +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/mkdocs.yml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/__main__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/history.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/hyperparams.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/loop.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/penalty.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/scvx/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/scvx/iteration.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/state.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/config.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/byof.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/expert/validation.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/init/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/_utils.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/frax.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/menagerie.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrations/mjx.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/loader.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/publication.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/coordinates.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/base.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/cones.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/solvers/qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/affine.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/canonicalize.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/cache.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/caching.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/printing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx/utils/utils.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/SOURCES.txt +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/scm_file_list.json +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/pyproject.toml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/setup.cfg +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/_iteration_helpers.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_iteration_fn_jit.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_iteration_fn_parity.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/algorithms/test_make_solve_loop.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/conftest.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_impulsive.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_multishot_propagation.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_batched_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_batched_cvxpy_export_errors.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_batched_export_roundtrip.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_bare_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_jit_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_vmap_brachistochrone.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/e2e/test_solve_jax_vmap_converged_no_drift.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/integrations/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/integrations/test_mjx.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/integrations/test_mjx_dynamics.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/_iteration_callback_helpers.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_moreau.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_qpax.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_iteration_callback_vmap.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_moreau_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_qpax_ptr_solver.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/solvers/test_subproblem_pytree.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_gmsr.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_autotuning.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_discretization.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_examples.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_expert.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_init.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_integrators.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_loader.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_optimization_results.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_plotting.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_post_process_batched_tau_clamp.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_propagation.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/tests/test_results_parameters.py +0 -0
- {openscvx-0.5.3.dev36 → openscvx-0.5.3.dev38}/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.dev38
|
|
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
|
|
@@ -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.dev38'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 3, 'dev38')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g235acbb25'
|
|
@@ -340,8 +340,7 @@ class Problem:
|
|
|
340
340
|
dynamics_prop: Optional[dict] = None,
|
|
341
341
|
states_prop: Optional[List[State]] = None,
|
|
342
342
|
algebraic_prop: Optional[dict] = None,
|
|
343
|
-
|
|
344
|
-
licq_max: Union[float, Dict[int, float]] = 1e-4,
|
|
343
|
+
licq_max: float = 1e-4,
|
|
345
344
|
algorithm: Optional[Union[Algorithm, dict]] = None,
|
|
346
345
|
discretizer: Optional[Union[Discretizer, dict]] = None,
|
|
347
346
|
solver: Optional[Union[ConvexSolver, dict]] = None,
|
|
@@ -373,12 +372,11 @@ class Problem:
|
|
|
373
372
|
Only specify additional states beyond optimization states. Used with dynamics_prop.
|
|
374
373
|
algebraic_prop (dict, optional): Dictionary mapping names to symbolic expressions
|
|
375
374
|
for outputs evaluated (not integrated) during propagation.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
mapping CTCS group ``idx`` to per-group bounds.
|
|
375
|
+
licq_max: Problem-wide upper bound for CTCS augmented states
|
|
376
|
+
(default: 1e-4). Serves as the default for all constraint
|
|
377
|
+
groups; a ``licq_max`` set on an individual constraint (via
|
|
378
|
+
``ctcs(...)`` or ``.over(...)``) overrides it for that
|
|
379
|
+
constraint's augmented state.
|
|
382
380
|
algorithm: SCP algorithm configuration. Accepts:
|
|
383
381
|
|
|
384
382
|
- ``None`` — uses ``PenalizedTrustRegion()`` with defaults.
|
|
@@ -539,7 +537,6 @@ class Problem:
|
|
|
539
537
|
controls=controls,
|
|
540
538
|
N=N,
|
|
541
539
|
time=time,
|
|
542
|
-
licq_min=licq_min,
|
|
543
540
|
licq_max=licq_max,
|
|
544
541
|
dynamics_prop_extra=dynamics_prop,
|
|
545
542
|
states_prop_extra=states_prop,
|
|
@@ -54,7 +54,7 @@ Example:
|
|
|
54
54
|
# controls_aug includes original controls + time dilation
|
|
55
55
|
"""
|
|
56
56
|
|
|
57
|
-
from typing import Dict, List, Optional, Tuple
|
|
57
|
+
from typing import Dict, List, Optional, Tuple
|
|
58
58
|
|
|
59
59
|
import numpy as np
|
|
60
60
|
|
|
@@ -448,8 +448,7 @@ def augment_dynamics_with_ctcs(
|
|
|
448
448
|
N: int,
|
|
449
449
|
xdelta: Optional[Expr] = None,
|
|
450
450
|
*,
|
|
451
|
-
|
|
452
|
-
licq_max: Union[float, Dict[int, float]] = 1e-4,
|
|
451
|
+
licq_max: float = 1e-4,
|
|
453
452
|
) -> Tuple[Expr, Optional[Expr], List[State], List[Control]]:
|
|
454
453
|
"""Augment dynamics with continuous-time constraint satisfaction states.
|
|
455
454
|
|
|
@@ -467,18 +466,20 @@ def augment_dynamics_with_ctcs(
|
|
|
467
466
|
aug_dot = penalty(g(x, u)) # For each constraint group
|
|
468
467
|
time_dot = 1.0
|
|
469
468
|
|
|
469
|
+
Each augmented state is bounded to [0, licq_max], where the group's bound
|
|
470
|
+
is taken from its member constraints' ``licq_max`` attribute (constraints in
|
|
471
|
+
a group must agree) and falls back to the problem-wide ``licq_max`` when no
|
|
472
|
+
member specifies one.
|
|
473
|
+
|
|
470
474
|
Args:
|
|
471
475
|
xdot: Original dynamics expression for states
|
|
472
476
|
states: List of state variables (must include a state named "time")
|
|
473
477
|
controls: List of control variables
|
|
474
478
|
constraints_ctcs: List of CTCS constraints (should be sorted and grouped)
|
|
475
479
|
N: Number of discretization nodes
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
licq_max: Maximum bound for augmented states (default: 1e-4).
|
|
480
|
-
Either a scalar (applied to all groups) or a dict mapping
|
|
481
|
-
CTCS group ``idx`` to per-group bounds.
|
|
480
|
+
licq_max: Problem-wide default upper bound for augmented states
|
|
481
|
+
(default: 1e-4). Per-constraint ``licq_max`` values override it
|
|
482
|
+
for their group.
|
|
482
483
|
|
|
483
484
|
Returns:
|
|
484
485
|
Tuple of:
|
|
@@ -489,6 +490,8 @@ def augment_dynamics_with_ctcs(
|
|
|
489
490
|
|
|
490
491
|
Raises:
|
|
491
492
|
ValueError: If no state named "time" is found in the states list
|
|
493
|
+
ValueError: If constraints sharing an augmented state specify
|
|
494
|
+
conflicting ``licq_max`` values
|
|
492
495
|
|
|
493
496
|
Example:
|
|
494
497
|
Augment dynamics with CTCS penalty states:
|
|
@@ -509,6 +512,9 @@ def augment_dynamics_with_ctcs(
|
|
|
509
512
|
states_aug includes x, time, and _ctcs_aug_0,
|
|
510
513
|
controls_aug includes u and _time_dilation
|
|
511
514
|
"""
|
|
515
|
+
if licq_max <= 0:
|
|
516
|
+
raise ValueError(f"licq_max must be a positive number, got {licq_max!r}")
|
|
517
|
+
|
|
512
518
|
# Save if discrete dynamics is null
|
|
513
519
|
discrete_dynamics_set = xdelta is not None
|
|
514
520
|
|
|
@@ -535,24 +541,6 @@ def augment_dynamics_with_ctcs(
|
|
|
535
541
|
penalty_groups[ctcs.idx] = []
|
|
536
542
|
penalty_groups[ctcs.idx].append(ctcs)
|
|
537
543
|
|
|
538
|
-
# Validate dict-valued licq_min / licq_max keys against actual groups.
|
|
539
|
-
valid_ids = set(penalty_groups.keys())
|
|
540
|
-
for name, val in [("licq_min", licq_min), ("licq_max", licq_max)]:
|
|
541
|
-
if isinstance(val, dict):
|
|
542
|
-
unknown = set(val.keys()) - valid_ids
|
|
543
|
-
if unknown:
|
|
544
|
-
raise ValueError(
|
|
545
|
-
f"{name} dict contains unknown CTCS group idx: {unknown}. "
|
|
546
|
-
f"Valid idx values: {sorted(valid_ids)}"
|
|
547
|
-
)
|
|
548
|
-
missing = valid_ids - set(val.keys())
|
|
549
|
-
if missing:
|
|
550
|
-
raise ValueError(
|
|
551
|
-
f"{name} dict is missing entries for CTCS group idx: "
|
|
552
|
-
f"{sorted(missing)}. When using a dict, all groups must "
|
|
553
|
-
f"have an entry. Valid idx values: {sorted(valid_ids)}"
|
|
554
|
-
)
|
|
555
|
-
|
|
556
544
|
# Create augmented state expressions for each group and corresponding
|
|
557
545
|
# augmented state variables. For discrete dynamics, preserve these states
|
|
558
546
|
# by identity mapping across impulsive updates.
|
|
@@ -566,17 +554,25 @@ def augment_dynamics_with_ctcs(
|
|
|
566
554
|
augmented_state_expr = Add(*penalty_terms)
|
|
567
555
|
augmented_state_exprs.append(augmented_state_expr)
|
|
568
556
|
|
|
569
|
-
# Resolve
|
|
570
|
-
|
|
571
|
-
|
|
557
|
+
# Resolve the group's LICQ bound from its member constraints:
|
|
558
|
+
# explicit values must agree; otherwise fall back to the
|
|
559
|
+
# problem-wide default.
|
|
560
|
+
explicit = {c.licq_max for c in penalty_terms if c.licq_max is not None}
|
|
561
|
+
if len(explicit) > 1:
|
|
562
|
+
raise ValueError(
|
|
563
|
+
f"CTCS constraints sharing augmented state idx={idx} specify "
|
|
564
|
+
f"conflicting licq_max values: {sorted(explicit)}. Constraints "
|
|
565
|
+
f"in the same group must agree on licq_max; set the same value "
|
|
566
|
+
f"on each, or separate them into different groups via idx."
|
|
567
|
+
)
|
|
568
|
+
group_licq_max = explicit.pop() if explicit else licq_max
|
|
572
569
|
|
|
573
570
|
aug_var = State(f"_ctcs_aug_{idx}", shape=(1,))
|
|
574
|
-
aug_var.initial = np.array([
|
|
571
|
+
aug_var.initial = np.array([0.0])
|
|
575
572
|
aug_var.final = [("free", 0)]
|
|
576
|
-
aug_var.min = np.array([
|
|
577
|
-
aug_var.max = np.array([
|
|
578
|
-
#
|
|
579
|
-
aug_var.guess = np.full([N, 1], idx_min) # N x num augmented states
|
|
573
|
+
aug_var.min = np.array([0.0])
|
|
574
|
+
aug_var.max = np.array([group_licq_max])
|
|
575
|
+
aug_var.guess = np.zeros([N, 1]) # N x num augmented states
|
|
580
576
|
states_augmented.append(aug_var)
|
|
581
577
|
augmented_state_exprs_discrete.append(aug_var)
|
|
582
578
|
|
|
@@ -29,7 +29,7 @@ Pipeline stages:
|
|
|
29
29
|
See `preprocess_symbolic_problem()` for the main entry point.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
from typing import Dict, List, Optional, Tuple
|
|
32
|
+
from typing import Dict, List, Optional, Tuple
|
|
33
33
|
|
|
34
34
|
import numpy as np
|
|
35
35
|
|
|
@@ -71,8 +71,7 @@ def preprocess_symbolic_problem(
|
|
|
71
71
|
controls: List[Control],
|
|
72
72
|
N: int,
|
|
73
73
|
time: Time,
|
|
74
|
-
|
|
75
|
-
licq_max: Union[float, Dict[int, float]] = 1e-4,
|
|
74
|
+
licq_max: float = 1e-4,
|
|
76
75
|
dynamics_prop_extra: dict = None,
|
|
77
76
|
dynamics_discrete: dict = None,
|
|
78
77
|
states_prop_extra: List[State] = None,
|
|
@@ -106,12 +105,9 @@ def preprocess_symbolic_problem(
|
|
|
106
105
|
controls: List of user-defined Control objects (should NOT include time dilation)
|
|
107
106
|
N: Number of discretization nodes in the trajectory
|
|
108
107
|
time: Time configuration object specifying time bounds and constraints
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
licq_max: Maximum bound for CTCS augmented states (default: 1e-4).
|
|
113
|
-
Either a scalar (applied to all groups) or a dict mapping
|
|
114
|
-
CTCS group ``idx`` to per-group bounds.
|
|
108
|
+
licq_max: Problem-wide default upper bound for CTCS augmented states
|
|
109
|
+
(default: 1e-4). Per-constraint ``licq_max`` values override it
|
|
110
|
+
for their group.
|
|
115
111
|
dynamics_prop_extra: Optional dictionary of additional dynamics for propagation-only
|
|
116
112
|
states (default: None)
|
|
117
113
|
states_prop_extra: Optional list of additional State objects for propagation only
|
|
@@ -350,7 +346,6 @@ def preprocess_symbolic_problem(
|
|
|
350
346
|
constraints.ctcs,
|
|
351
347
|
N,
|
|
352
348
|
xdelta=dynamics_discrete_concat,
|
|
353
|
-
licq_min=licq_min,
|
|
354
349
|
licq_max=licq_max,
|
|
355
350
|
)
|
|
356
351
|
|
|
@@ -127,6 +127,7 @@ class Constraint(Expr):
|
|
|
127
127
|
penalty: str = "squared_relu",
|
|
128
128
|
idx: Optional[int] = None,
|
|
129
129
|
check_nodally: bool = False,
|
|
130
|
+
licq_max: Optional[float] = None,
|
|
130
131
|
) -> "CTCS":
|
|
131
132
|
"""Apply this constraint over a continuous interval using CTCS.
|
|
132
133
|
|
|
@@ -135,11 +136,22 @@ class Constraint(Expr):
|
|
|
135
136
|
penalty: Penalty function type ("squared_relu", "huber", "smooth_relu")
|
|
136
137
|
idx: Optional grouping index for multiple augmented states
|
|
137
138
|
check_nodally: Whether to also enforce this constraint nodally
|
|
139
|
+
licq_max: Optional upper bound on the augmented state that accumulates
|
|
140
|
+
this constraint's violation penalty. Constraints sharing an
|
|
141
|
+
augmented state must agree on the value; groups without one use
|
|
142
|
+
the problem-wide ``licq_max`` (a ``Problem`` argument).
|
|
138
143
|
|
|
139
144
|
Returns:
|
|
140
145
|
CTCS constraint wrapping this constraint with interval specification
|
|
141
146
|
"""
|
|
142
|
-
return CTCS(
|
|
147
|
+
return CTCS(
|
|
148
|
+
self,
|
|
149
|
+
penalty=penalty,
|
|
150
|
+
nodes=interval,
|
|
151
|
+
idx=idx,
|
|
152
|
+
check_nodally=check_nodally,
|
|
153
|
+
licq_max=licq_max,
|
|
154
|
+
)
|
|
143
155
|
|
|
144
156
|
def convex(self) -> "Constraint":
|
|
145
157
|
"""Mark this constraint as convex for CVXPy lowering.
|
|
@@ -609,6 +621,11 @@ class CTCS(Expr):
|
|
|
609
621
|
an augmented state. If None, auto-assigned based on node intervals.
|
|
610
622
|
check_nodally: Whether to also enforce the constraint at discrete nodes for
|
|
611
623
|
additional numerical robustness (creates both continuous and nodal constraints)
|
|
624
|
+
licq_max: Optional upper bound on the augmented state accumulating this
|
|
625
|
+
constraint's violation penalty. Smaller values enforce the constraint
|
|
626
|
+
more strictly between nodes. Constraints sharing an augmented state
|
|
627
|
+
must agree on the value; groups without one use the problem-wide
|
|
628
|
+
``licq_max`` (a ``Problem`` argument).
|
|
612
629
|
|
|
613
630
|
Example:
|
|
614
631
|
Single augmented state (default behavior - same node interval):
|
|
@@ -642,6 +659,7 @@ class CTCS(Expr):
|
|
|
642
659
|
nodes: Optional[Tuple[int, int]] = None,
|
|
643
660
|
idx: Optional[int] = None,
|
|
644
661
|
check_nodally: bool = False,
|
|
662
|
+
licq_max: Optional[float] = None,
|
|
645
663
|
):
|
|
646
664
|
"""Initialize a CTCS constraint.
|
|
647
665
|
|
|
@@ -662,11 +680,16 @@ class CTCS(Expr):
|
|
|
662
680
|
check_nodally: If True, also enforce the constraint at discrete nodes for
|
|
663
681
|
numerical stability (creates both continuous and nodal constraints).
|
|
664
682
|
Defaults to False.
|
|
683
|
+
licq_max: Optional upper bound on the augmented state accumulating this
|
|
684
|
+
constraint's violation penalty. Constraints sharing an augmented
|
|
685
|
+
state must agree on the value; groups without one use the
|
|
686
|
+
problem-wide ``licq_max`` (a ``Problem`` argument).
|
|
665
687
|
|
|
666
688
|
Raises:
|
|
667
689
|
TypeError: If constraint is not a Constraint instance
|
|
668
690
|
ValueError: If nodes is not None or a 2-tuple of integers
|
|
669
691
|
ValueError: If nodes[0] >= nodes[1] (invalid interval)
|
|
692
|
+
ValueError: If licq_max is not a positive number
|
|
670
693
|
"""
|
|
671
694
|
if not isinstance(constraint, Constraint):
|
|
672
695
|
raise TypeError("CTCS must wrap a Constraint")
|
|
@@ -683,12 +706,19 @@ class CTCS(Expr):
|
|
|
683
706
|
if nodes[0] >= nodes[1]:
|
|
684
707
|
raise ValueError("CTCS node range must have start < end")
|
|
685
708
|
|
|
709
|
+
if licq_max is not None:
|
|
710
|
+
if not isinstance(licq_max, (int, float)) or licq_max <= 0:
|
|
711
|
+
raise ValueError(f"licq_max must be a positive number, got {licq_max!r}")
|
|
712
|
+
licq_max = float(licq_max)
|
|
713
|
+
|
|
686
714
|
self.constraint = constraint
|
|
687
715
|
self.penalty = penalty
|
|
688
716
|
self.nodes = nodes # (start, end) node range or None for all nodes
|
|
689
717
|
self.idx = idx # Optional grouping index for multiple augmented states
|
|
690
718
|
# Whether to also enforce this constraint nodally for numerical stability
|
|
691
719
|
self.check_nodally = check_nodally
|
|
720
|
+
# Upper bound on the augmented state; None defers to the group default
|
|
721
|
+
self.licq_max = licq_max
|
|
692
722
|
|
|
693
723
|
def children(self) -> List[Expr]:
|
|
694
724
|
"""Return the wrapped constraint as the only child.
|
|
@@ -711,6 +741,7 @@ class CTCS(Expr):
|
|
|
711
741
|
nodes=self.nodes,
|
|
712
742
|
idx=self.idx,
|
|
713
743
|
check_nodally=self.check_nodally,
|
|
744
|
+
licq_max=self.licq_max,
|
|
714
745
|
)
|
|
715
746
|
|
|
716
747
|
def check_shape(self) -> Tuple[int, ...]:
|
|
@@ -767,6 +798,11 @@ class CTCS(Expr):
|
|
|
767
798
|
hasher.update(b"None")
|
|
768
799
|
# Hash check_nodally
|
|
769
800
|
hasher.update(b"1" if self.check_nodally else b"0")
|
|
801
|
+
# Hash licq_max
|
|
802
|
+
if self.licq_max is not None:
|
|
803
|
+
hasher.update(struct.pack(">d", self.licq_max))
|
|
804
|
+
else:
|
|
805
|
+
hasher.update(b"None")
|
|
770
806
|
# Hash the wrapped constraint
|
|
771
807
|
self.constraint._hash_into(hasher)
|
|
772
808
|
|
|
@@ -794,6 +830,7 @@ class CTCS(Expr):
|
|
|
794
830
|
nodes=interval,
|
|
795
831
|
idx=self.idx,
|
|
796
832
|
check_nodally=self.check_nodally,
|
|
833
|
+
licq_max=self.licq_max,
|
|
797
834
|
)
|
|
798
835
|
|
|
799
836
|
def __repr__(self) -> str:
|
|
@@ -809,6 +846,8 @@ class CTCS(Expr):
|
|
|
809
846
|
parts.append(f"idx={self.idx}")
|
|
810
847
|
if self.check_nodally:
|
|
811
848
|
parts.append(f"check_nodally={self.check_nodally}")
|
|
849
|
+
if self.licq_max is not None:
|
|
850
|
+
parts.append(f"licq_max={self.licq_max}")
|
|
812
851
|
return f"CTCS({', '.join(parts)})"
|
|
813
852
|
|
|
814
853
|
def penalty_expr(self) -> Expr:
|
|
@@ -861,6 +900,7 @@ def ctcs(
|
|
|
861
900
|
nodes: Optional[Tuple[int, int]] = None,
|
|
862
901
|
idx: Optional[int] = None,
|
|
863
902
|
check_nodally: bool = False,
|
|
903
|
+
licq_max: Optional[float] = None,
|
|
864
904
|
) -> CTCS:
|
|
865
905
|
"""Helper function to create CTCS (Continuous-Time Constraint Satisfaction) constraints.
|
|
866
906
|
|
|
@@ -876,6 +916,10 @@ def ctcs(
|
|
|
876
916
|
idx: Optional grouping index for multiple augmented states
|
|
877
917
|
check_nodally: Whether to also enforce constraint at discrete nodes.
|
|
878
918
|
Defaults to False.
|
|
919
|
+
licq_max: Optional upper bound on the augmented state accumulating this
|
|
920
|
+
constraint's violation penalty. Constraints sharing an augmented
|
|
921
|
+
state must agree on the value; groups without one use the
|
|
922
|
+
problem-wide ``licq_max`` (a ``Problem`` argument).
|
|
879
923
|
|
|
880
924
|
Returns:
|
|
881
925
|
CTCS: A CTCS constraint wrapping the input constraint
|
|
@@ -899,4 +943,4 @@ def ctcs(
|
|
|
899
943
|
|
|
900
944
|
altitude_constraint = (altitude >= 10).over((0, 100), penalty="huber")
|
|
901
945
|
"""
|
|
902
|
-
return CTCS(constraint, penalty, nodes, idx, check_nodally)
|
|
946
|
+
return CTCS(constraint, penalty, nodes, idx, check_nodally, licq_max)
|
|
@@ -63,8 +63,10 @@ Example:
|
|
|
63
63
|
canonical = expr.canonicalize() # Simplifies to: x + x
|
|
64
64
|
"""
|
|
65
65
|
|
|
66
|
+
import functools
|
|
66
67
|
import hashlib
|
|
67
68
|
import struct
|
|
69
|
+
import threading
|
|
68
70
|
from typing import TYPE_CHECKING, Callable, List, Tuple, Union
|
|
69
71
|
|
|
70
72
|
if TYPE_CHECKING:
|
|
@@ -72,6 +74,40 @@ if TYPE_CHECKING:
|
|
|
72
74
|
|
|
73
75
|
import numpy as np
|
|
74
76
|
|
|
77
|
+
# Per-thread memo for canonicalize(). The memo canonicalizes each node once and
|
|
78
|
+
# returns the same object to every parent, preserving sharing.
|
|
79
|
+
_canon_state = threading.local()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _memoized_canonicalize(fn: Callable) -> Callable:
|
|
83
|
+
"""Wrap a subclass ``canonicalize`` so shared subexpressions are reused.
|
|
84
|
+
|
|
85
|
+
Keyed by ``id(self)``; the node is held alive in the memo for the duration of
|
|
86
|
+
the pass so its id cannot be recycled, with an identity guard on lookup. The
|
|
87
|
+
top-level call owns the memo and clears it on exit, so each independent
|
|
88
|
+
canonicalize pass starts fresh.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
@functools.wraps(fn)
|
|
92
|
+
def wrapper(self):
|
|
93
|
+
memo = getattr(_canon_state, "memo", None)
|
|
94
|
+
owns = memo is None
|
|
95
|
+
if owns:
|
|
96
|
+
memo = {}
|
|
97
|
+
_canon_state.memo = memo
|
|
98
|
+
try:
|
|
99
|
+
entry = memo.get(id(self))
|
|
100
|
+
if entry is not None and entry[0] is self:
|
|
101
|
+
return entry[1]
|
|
102
|
+
result = fn(self)
|
|
103
|
+
memo[id(self)] = (self, result)
|
|
104
|
+
return result
|
|
105
|
+
finally:
|
|
106
|
+
if owns:
|
|
107
|
+
_canon_state.memo = None
|
|
108
|
+
|
|
109
|
+
return wrapper
|
|
110
|
+
|
|
75
111
|
|
|
76
112
|
class Expr:
|
|
77
113
|
"""Base class for symbolic expressions in optimization problems.
|
|
@@ -101,6 +137,13 @@ class Expr:
|
|
|
101
137
|
# Give Expr objects higher priority than numpy arrays in operations
|
|
102
138
|
__array_priority__ = 1000
|
|
103
139
|
|
|
140
|
+
def __init_subclass__(cls, **kwargs):
|
|
141
|
+
# Wrap each subclass's own canonicalize() with identity memoization so a
|
|
142
|
+
# shared DAG node is canonicalized once rather than re-expanded per parent.
|
|
143
|
+
super().__init_subclass__(**kwargs)
|
|
144
|
+
if "canonicalize" in cls.__dict__:
|
|
145
|
+
cls.canonicalize = _memoized_canonicalize(cls.__dict__["canonicalize"])
|
|
146
|
+
|
|
104
147
|
def __le__(self, other):
|
|
105
148
|
from .constraint import Inequality
|
|
106
149
|
|
|
@@ -310,6 +310,7 @@ class STLExpr(Expr):
|
|
|
310
310
|
penalty: str = "smooth_relu",
|
|
311
311
|
idx: Optional[int] = None,
|
|
312
312
|
check_nodally: bool = False,
|
|
313
|
+
licq_max: Optional[float] = None,
|
|
313
314
|
interval_type: IntervalKind = "nodes",
|
|
314
315
|
) -> "CTCS":
|
|
315
316
|
"""Apply this STL expression over an enforcement interval using CTCS.
|
|
@@ -323,6 +324,10 @@ class STLExpr(Expr):
|
|
|
323
324
|
penalty: Penalty function type for CTCS
|
|
324
325
|
idx: Optional grouping index for multiple augmented states
|
|
325
326
|
check_nodally: Whether to also enforce at discrete nodes
|
|
327
|
+
licq_max: Optional upper bound on the augmented state accumulating
|
|
328
|
+
this constraint's violation penalty. Constraints sharing an
|
|
329
|
+
augmented state must agree on the value; groups without one use
|
|
330
|
+
the problem-wide ``licq_max`` (a ``Problem`` argument).
|
|
326
331
|
|
|
327
332
|
Returns:
|
|
328
333
|
Continuous-time constraint satisfaction wrapper
|
|
@@ -359,6 +364,7 @@ class STLExpr(Expr):
|
|
|
359
364
|
nodes=(coerced.start, coerced.end),
|
|
360
365
|
idx=idx,
|
|
361
366
|
check_nodally=check_nodally,
|
|
367
|
+
licq_max=licq_max,
|
|
362
368
|
)
|
|
363
369
|
|
|
364
370
|
def at(self, nodes: Union[list, tuple]) -> "NodalConstraint":
|
|
@@ -863,6 +869,7 @@ class Always(_TemporalSTLExpr):
|
|
|
863
869
|
penalty: str = "smooth_relu",
|
|
864
870
|
idx: Optional[int] = None,
|
|
865
871
|
check_nodally: bool = False,
|
|
872
|
+
licq_max: Optional[float] = None,
|
|
866
873
|
interval_type: IntervalKind = "nodes",
|
|
867
874
|
) -> "CTCS":
|
|
868
875
|
"""Convert this ``Always`` to a ``CTCS`` constraint.
|
|
@@ -876,6 +883,10 @@ class Always(_TemporalSTLExpr):
|
|
|
876
883
|
penalty: CTCS penalty function name.
|
|
877
884
|
idx: Optional grouping index for multiple augmented states.
|
|
878
885
|
check_nodally: Whether to additionally enforce at discrete nodes.
|
|
886
|
+
licq_max: Optional upper bound on the augmented state accumulating
|
|
887
|
+
this constraint's violation penalty. Constraints sharing an
|
|
888
|
+
augmented state must agree on the value; groups without one use
|
|
889
|
+
the problem-wide ``licq_max`` (a ``Problem`` argument).
|
|
879
890
|
|
|
880
891
|
Returns:
|
|
881
892
|
A ``CTCS`` constraint enforcing the inner predicate over the
|
|
@@ -903,7 +914,7 @@ class Always(_TemporalSTLExpr):
|
|
|
903
914
|
|
|
904
915
|
if isinstance(self.predicate, STLExpr):
|
|
905
916
|
return self.predicate.over(
|
|
906
|
-
chosen, penalty=penalty, idx=idx, check_nodally=check_nodally
|
|
917
|
+
chosen, penalty=penalty, idx=idx, check_nodally=check_nodally, licq_max=licq_max
|
|
907
918
|
)
|
|
908
919
|
|
|
909
920
|
from .constraint import CTCS
|
|
@@ -914,6 +925,7 @@ class Always(_TemporalSTLExpr):
|
|
|
914
925
|
nodes=(chosen.start, chosen.end),
|
|
915
926
|
idx=idx,
|
|
916
927
|
check_nodally=check_nodally,
|
|
928
|
+
licq_max=licq_max,
|
|
917
929
|
)
|
|
918
930
|
|
|
919
931
|
def __repr__(self) -> str:
|
|
@@ -59,6 +59,7 @@ class STLJaxExpr(Expr):
|
|
|
59
59
|
penalty: str = "squared_relu",
|
|
60
60
|
idx: Optional[int] = None,
|
|
61
61
|
check_nodally: bool = False,
|
|
62
|
+
licq_max: Optional[float] = None,
|
|
62
63
|
) -> "CTCS":
|
|
63
64
|
"""Apply this STL expression over a continuous interval using CTCS.
|
|
64
65
|
|
|
@@ -70,6 +71,10 @@ class STLJaxExpr(Expr):
|
|
|
70
71
|
penalty: Penalty function type for CTCS
|
|
71
72
|
idx: Optional grouping index for multiple augmented states
|
|
72
73
|
check_nodally: Whether to also enforce at discrete nodes
|
|
74
|
+
licq_max: Optional upper bound on the augmented state accumulating
|
|
75
|
+
this constraint's violation penalty. Constraints sharing an
|
|
76
|
+
augmented state must agree on the value; groups without one use
|
|
77
|
+
the problem-wide ``licq_max`` (a ``Problem`` argument).
|
|
73
78
|
|
|
74
79
|
Returns:
|
|
75
80
|
Continuous-time constraint satisfaction wrapper
|
|
@@ -89,7 +94,12 @@ class STLJaxExpr(Expr):
|
|
|
89
94
|
constraint = Inequality(Neg(self), Constant(np.array(0.0)))
|
|
90
95
|
|
|
91
96
|
return CTCS(
|
|
92
|
-
constraint,
|
|
97
|
+
constraint,
|
|
98
|
+
penalty=penalty,
|
|
99
|
+
nodes=interval,
|
|
100
|
+
idx=idx,
|
|
101
|
+
check_nodally=check_nodally,
|
|
102
|
+
licq_max=licq_max,
|
|
93
103
|
)
|
|
94
104
|
|
|
95
105
|
def at(self, nodes: Union[list, tuple]) -> "NodalConstraint":
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""JaxLowerer class definition.
|
|
2
|
+
|
|
3
|
+
The visitor methods that populate the registry live in sibling modules
|
|
4
|
+
(``arithmetic``, ``math``, ``linalg``, etc.) and are registered via
|
|
5
|
+
``@visitor`` at import time.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Callable
|
|
9
|
+
|
|
10
|
+
import jax
|
|
11
|
+
|
|
12
|
+
from openscvx.symbolic.expr import Expr
|
|
13
|
+
from openscvx.symbolic.lowerers.jax._registry import dispatch
|
|
14
|
+
|
|
15
|
+
_MISSING = object()
|
|
16
|
+
|
|
17
|
+
# Value-memoization is only valid within a single JAX trace. Visitors bracket
|
|
18
|
+
# their nested trace with :func:`pause_memo` / :func:`resume_memo` so the wrapped
|
|
19
|
+
# closures recompute instead of returning a cross-trace value.
|
|
20
|
+
_memo_paused = [0]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def pause_memo() -> None:
|
|
24
|
+
"""Disable value-memoization for the duration of a nested sub-trace."""
|
|
25
|
+
_memo_paused[0] += 1
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def resume_memo() -> None:
|
|
29
|
+
"""Re-enable value-memoization after a nested sub-trace finishes tracing."""
|
|
30
|
+
_memo_paused[0] -= 1
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _memoize_call(fn: Callable) -> Callable:
|
|
34
|
+
"""Cache a lowered closure's result so it emits its subgraph once per trace.
|
|
35
|
+
|
|
36
|
+
Within a trace every node receives the same argument objects, so caching on
|
|
37
|
+
argument identity (``is``) lets a shared subexpression emit its subgraph once
|
|
38
|
+
instead of once per consumer. The cache only applies while tracing (at least
|
|
39
|
+
one positional argument is a JAX tracer); eager calls, keyword-argument
|
|
40
|
+
calls, and paused sections (nested sub-traces, see module note) bypass it.
|
|
41
|
+
"""
|
|
42
|
+
last_args = None
|
|
43
|
+
last_val = _MISSING
|
|
44
|
+
|
|
45
|
+
def wrapped(*args, **kwargs):
|
|
46
|
+
nonlocal last_args, last_val
|
|
47
|
+
if kwargs or _memo_paused[0] or not any(isinstance(a, jax.core.Tracer) for a in args):
|
|
48
|
+
return fn(*args, **kwargs)
|
|
49
|
+
if (
|
|
50
|
+
last_val is not _MISSING
|
|
51
|
+
and last_args is not None
|
|
52
|
+
and len(last_args) == len(args)
|
|
53
|
+
and all(a is b for a, b in zip(last_args, args))
|
|
54
|
+
):
|
|
55
|
+
return last_val
|
|
56
|
+
last_val = fn(*args)
|
|
57
|
+
last_args = args
|
|
58
|
+
return last_val
|
|
59
|
+
|
|
60
|
+
return wrapped
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class JaxLowerer:
|
|
64
|
+
"""JAX backend for lowering symbolic expressions to executable functions.
|
|
65
|
+
|
|
66
|
+
This class implements the visitor pattern for converting symbolic expression
|
|
67
|
+
AST nodes to JAX functions. Each expression type has a corresponding visitor
|
|
68
|
+
function decorated with @visitor that handles the lowering logic.
|
|
69
|
+
|
|
70
|
+
The lowering process is recursive: each visitor lowers its child expressions
|
|
71
|
+
first, then composes them into a JAX operation. All lowered functions have
|
|
72
|
+
a standardized signature (x, u, node, params) -> result.
|
|
73
|
+
|
|
74
|
+
Shared subexpressions are lowered once: :meth:`lower` caches the closure for
|
|
75
|
+
each AST node by object identity, and each closure is wrapped so it emits its
|
|
76
|
+
subgraph only once per trace (see :func:`_memoize_call`).
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
Set up the JaxLowerer and lower an expression to a JAX function::
|
|
80
|
+
|
|
81
|
+
lowerer = JaxLowerer()
|
|
82
|
+
expr = ox.Norm(x)**2 + 0.1 * ox.Norm(u)**2
|
|
83
|
+
f = lowerer.lower(expr)
|
|
84
|
+
result = f(x_val, u_val, node=0, params={})
|
|
85
|
+
|
|
86
|
+
Note:
|
|
87
|
+
A fresh lowerer is created per lowering pass; its node cache is keyed by
|
|
88
|
+
``id(expr)`` and is valid only while the expression tree is alive.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self) -> None:
|
|
92
|
+
# Maps id(expr) -> (expr, lowered closure) so each node is lowered once,
|
|
93
|
+
# no matter how many parents share it. Storing the expr itself keeps it
|
|
94
|
+
# alive: if it were garbage-collected, Python could reuse its id for a
|
|
95
|
+
# new node and the cache would return the wrong closure. The identity
|
|
96
|
+
# check on lookup guards against exactly that.
|
|
97
|
+
self._node_cache: dict[int, tuple[Expr, Callable]] = {}
|
|
98
|
+
|
|
99
|
+
def lower(self, expr: Expr) -> Callable:
|
|
100
|
+
"""Lower a symbolic expression to a JAX function.
|
|
101
|
+
|
|
102
|
+
Main entry point for lowering. Delegates to dispatch() which looks up
|
|
103
|
+
the appropriate visitor method based on the expression type. Results are
|
|
104
|
+
memoized by node identity so shared subexpressions are lowered once.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
expr: Symbolic expression to lower (any Expr subclass)
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
JAX function with signature (x, u, node, params) -> result
|
|
111
|
+
|
|
112
|
+
Raises:
|
|
113
|
+
NotImplementedError: If no visitor exists for the expression type
|
|
114
|
+
ValueError: If the expression is malformed (e.g., State without slice)
|
|
115
|
+
"""
|
|
116
|
+
eid = id(expr)
|
|
117
|
+
cached = self._node_cache.get(eid)
|
|
118
|
+
if cached is not None and cached[0] is expr:
|
|
119
|
+
return cached[1]
|
|
120
|
+
fn = _memoize_call(dispatch(self, expr))
|
|
121
|
+
self._node_cache[eid] = (expr, fn)
|
|
122
|
+
return fn
|