openscvx 0.3.2.dev328__tar.gz → 0.3.2.dev333__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.3.2.dev328/openscvx.egg-info → openscvx-0.3.2.dev333}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/_version.py +3 -3
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/__init__.py +35 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +111 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/_registry.py +75 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +149 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/array.py +152 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/constraint.py +122 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/control.py +38 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/expr.py +135 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/linalg.py +91 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/logic.py +75 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/math.py +372 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/state.py +40 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/__init__.py +40 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/_lowerer.py +56 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/_registry.py +74 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/arithmetic.py +87 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/array.py +132 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/constraint.py +159 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/control.py +30 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/expr.py +108 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/lie.py +291 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/linalg.py +76 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/logic.py +161 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/math.py +268 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/spatial.py +120 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/state.py +32 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/stl.py +82 -0
- openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/vmap.py +152 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/SOURCES.txt +28 -2
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_arithmetic.py +6 -6
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_constraint.py +2 -2
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_parameters.py +3 -3
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_variable.py +4 -4
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_lower_jax.py +6 -6
- openscvx-0.3.2.dev328/openscvx/symbolic/lowerers/cvxpy.py +0 -1431
- openscvx-0.3.2.dev328/openscvx/symbolic/lowerers/jax.py +0 -1789
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/docs.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/lint.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/release.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.gitignore +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/CONTRIBUTING.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/LICENSE +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/README.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/favicon.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/citation.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/examples.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/getting-started.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/index.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/arm/three_link_arm.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car_conditional.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car_stljax.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/plotting.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/plotting_viser.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/video_preview.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/home.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/main.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/mkdocs.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/autotuning.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/config.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/discretization/discretization.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/byof.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/validation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/init/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/problem.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/solvers/base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/time.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/cache.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/caching.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/printing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/utils.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/pyproject.toml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/setup.cfg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_discretization.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_examples.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_expert.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_init.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_integrators.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_plotting.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_propagation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.3.2.
|
|
3
|
+
Version: 0.3.2.dev333
|
|
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
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.3.2.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 3, 2, '
|
|
31
|
+
__version__ = version = '0.3.2.dev333'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 2, 'dev333')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g298f4bc4f'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""CVXPy backend for lowering symbolic expressions to disciplined convex programs.
|
|
2
|
+
|
|
3
|
+
This package implements the CVXPy lowering backend that converts symbolic
|
|
4
|
+
expression AST nodes into CVXPy expressions and constraints for convex
|
|
5
|
+
optimization. The lowering uses a visitor pattern where each expression
|
|
6
|
+
type has a corresponding visitor function registered via ``@visitor``.
|
|
7
|
+
|
|
8
|
+
The visitor functions are split across submodules that mirror the
|
|
9
|
+
``openscvx.symbolic.expr`` package structure. Importing this package
|
|
10
|
+
triggers registration of all visitors.
|
|
11
|
+
|
|
12
|
+
Example::
|
|
13
|
+
|
|
14
|
+
from openscvx.symbolic.lowerers.cvxpy import CvxpyLowerer
|
|
15
|
+
|
|
16
|
+
lowerer = CvxpyLowerer(variable_map={"x": cvx_x, "u": cvx_u})
|
|
17
|
+
cvx_expr = lowerer.lower(expr)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# Import visitor modules to trigger @visitor registration.
|
|
21
|
+
# Each module populates _CVXPY_VISITORS as a side effect of import.
|
|
22
|
+
from openscvx.symbolic.lowerers.cvxpy import (
|
|
23
|
+
arithmetic, # noqa: F401
|
|
24
|
+
array, # noqa: F401
|
|
25
|
+
constraint, # noqa: F401
|
|
26
|
+
control, # noqa: F401
|
|
27
|
+
expr, # noqa: F401
|
|
28
|
+
linalg, # noqa: F401
|
|
29
|
+
logic, # noqa: F401
|
|
30
|
+
math, # noqa: F401
|
|
31
|
+
state, # noqa: F401
|
|
32
|
+
)
|
|
33
|
+
from openscvx.symbolic.lowerers.cvxpy._lowerer import CvxpyLowerer, lower_to_cvxpy
|
|
34
|
+
|
|
35
|
+
__all__ = ["CvxpyLowerer", "lower_to_cvxpy"]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""CvxpyLowerer 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 Dict
|
|
9
|
+
|
|
10
|
+
import cvxpy as cp
|
|
11
|
+
|
|
12
|
+
from openscvx.symbolic.expr import Expr
|
|
13
|
+
from openscvx.symbolic.lowerers.cvxpy._registry import dispatch
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CvxpyLowerer:
|
|
17
|
+
"""CVXPy backend for lowering symbolic expressions to disciplined convex programs.
|
|
18
|
+
|
|
19
|
+
This class implements the visitor pattern for converting symbolic expression
|
|
20
|
+
AST nodes to CVXPy expressions and constraints. Each expression type has a
|
|
21
|
+
corresponding visitor function decorated with @visitor that handles the
|
|
22
|
+
lowering logic.
|
|
23
|
+
|
|
24
|
+
The lowering process is recursive: each visitor lowers its child expressions
|
|
25
|
+
first, then composes them into a CVXPy operation. CVXPy will validate DCP
|
|
26
|
+
(Disciplined Convex Programming) compliance when the problem is constructed.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
variable_map (dict): Dictionary mapping variable names to CVXPy expressions.
|
|
30
|
+
Must include "x" for states and "u" for controls. May include parameter
|
|
31
|
+
names mapped to CVXPy Parameter objects or constants.
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
Lower an expression to CVXPy::
|
|
35
|
+
|
|
36
|
+
import cvxpy as cp
|
|
37
|
+
lowerer = CvxpyLowerer(variable_map={
|
|
38
|
+
"x": cp.Variable(3),
|
|
39
|
+
"u": cp.Variable(2),
|
|
40
|
+
})
|
|
41
|
+
expr = ox.Norm(x)**2 + 0.1 * ox.Norm(u)**2
|
|
42
|
+
cvx_expr = lowerer.lower(expr)
|
|
43
|
+
|
|
44
|
+
Note:
|
|
45
|
+
The lowerer is stateful (stores variable_map) unlike JaxLowerer which
|
|
46
|
+
is stateless. Variables must be registered before lowering expressions
|
|
47
|
+
that reference them.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, variable_map: Dict[str, cp.Expression] = None):
|
|
51
|
+
"""Initialize the CVXPy lowerer.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
variable_map: Dictionary mapping variable names to CVXPy expressions.
|
|
55
|
+
For State/Control objects, keys should be "x" and "u" respectively.
|
|
56
|
+
For Parameter objects, keys should match their names. If None, an
|
|
57
|
+
empty dictionary is created.
|
|
58
|
+
"""
|
|
59
|
+
self.variable_map = variable_map or {}
|
|
60
|
+
|
|
61
|
+
def register_variable(self, name: str, value: cp.Expression):
|
|
62
|
+
"""Register a variable in the variable map.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
name: Variable name (e.g., "x", "u", or parameter name)
|
|
66
|
+
value: CVXPy expression to associate with the name
|
|
67
|
+
"""
|
|
68
|
+
self.variable_map[name] = value
|
|
69
|
+
|
|
70
|
+
def lower(self, expr: Expr) -> cp.Expression:
|
|
71
|
+
"""Lower a symbolic expression to a CVXPy expression.
|
|
72
|
+
|
|
73
|
+
Main entry point for lowering. Delegates to dispatch() which looks up
|
|
74
|
+
the appropriate visitor method based on the expression type.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
expr: Symbolic expression to lower (any Expr subclass)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
CVXPy expression or constraint
|
|
81
|
+
|
|
82
|
+
Raises:
|
|
83
|
+
NotImplementedError: If no visitor exists for the expression type
|
|
84
|
+
ValueError: If required variables are missing from variable_map
|
|
85
|
+
"""
|
|
86
|
+
return dispatch(self, expr)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def lower_to_cvxpy(expr: Expr, variable_map: Dict[str, cp.Expression] = None) -> cp.Expression:
|
|
90
|
+
"""Lower symbolic expression to CVXPy expression or constraint.
|
|
91
|
+
|
|
92
|
+
Convenience wrapper that creates a CvxpyLowerer and lowers a single
|
|
93
|
+
symbolic expression to a CVXPy expression. The result can be used in
|
|
94
|
+
CVXPy optimization problems.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
expr: Symbolic expression to lower (any Expr subclass)
|
|
98
|
+
variable_map: Dictionary mapping variable names to CVXPy expressions.
|
|
99
|
+
Must include "x" for states and "u" for controls. May include
|
|
100
|
+
parameter names mapped to CVXPy Parameters or constants.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
CVXPy expression for arithmetic expressions (Add, Mul, Norm, etc.)
|
|
104
|
+
or CVXPy constraint for constraint expressions (Equality, Inequality)
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
NotImplementedError: If the expression type is not supported
|
|
108
|
+
ValueError: If required variables are missing from variable_map
|
|
109
|
+
"""
|
|
110
|
+
lowerer = CvxpyLowerer(variable_map)
|
|
111
|
+
return lowerer.lower(expr)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Visitor registry for the CVXPy lowerer.
|
|
2
|
+
|
|
3
|
+
This module holds the shared visitor dictionary, the ``@visitor`` decorator,
|
|
4
|
+
and the ``dispatch`` function. It is deliberately kept free of heavyweight
|
|
5
|
+
imports (no CVXPy, no expression subclasses beyond the base ``Expr``) so that
|
|
6
|
+
the visitor modules can import from it without circular-dependency issues.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Callable, Dict, Type
|
|
10
|
+
|
|
11
|
+
from openscvx.symbolic.expr import Expr
|
|
12
|
+
|
|
13
|
+
_CVXPY_VISITORS: Dict[Type[Expr], Callable] = {}
|
|
14
|
+
"""Registry mapping expression types to their visitor functions."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def visitor(expr_cls: Type[Expr]) -> Callable[[Callable], Callable]:
|
|
18
|
+
"""Decorator to register a visitor function for an expression type.
|
|
19
|
+
|
|
20
|
+
This decorator registers a visitor method to handle a specific expression
|
|
21
|
+
type during CVXPy lowering. The decorated function is stored in
|
|
22
|
+
_CVXPY_VISITORS and will be called by dispatch() when lowering that
|
|
23
|
+
expression type.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
expr_cls: The Expr subclass this visitor handles (e.g., Add, Mul, Norm)
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Decorator function that registers the visitor and returns it unchanged
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
Register a visitor function for the Add expression::
|
|
33
|
+
|
|
34
|
+
@visitor(Add)
|
|
35
|
+
def _visit_add(lowerer, node: Add):
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
Note:
|
|
39
|
+
Multiple expression types can share a visitor by stacking decorators::
|
|
40
|
+
|
|
41
|
+
@visitor(Equality)
|
|
42
|
+
@visitor(Inequality)
|
|
43
|
+
def _visit_constraint(lowerer, node: Constraint):
|
|
44
|
+
...
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def register(fn: Callable[[Any, Expr], Any]):
|
|
48
|
+
_CVXPY_VISITORS[expr_cls] = fn
|
|
49
|
+
return fn
|
|
50
|
+
|
|
51
|
+
return register
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def dispatch(lowerer: Any, expr: Expr) -> Any:
|
|
55
|
+
"""Dispatch an expression to its registered visitor function.
|
|
56
|
+
|
|
57
|
+
Looks up the visitor function for the expression's type and calls it.
|
|
58
|
+
This is the core of the visitor pattern implementation.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
lowerer: The CvxpyLowerer instance (provides context for visitor methods)
|
|
62
|
+
expr: The expression node to lower
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
The result of calling the visitor function (CVXPy expression or constraint)
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
NotImplementedError: If no visitor is registered for the expression type
|
|
69
|
+
"""
|
|
70
|
+
fn = _CVXPY_VISITORS.get(type(expr))
|
|
71
|
+
if fn is None:
|
|
72
|
+
raise NotImplementedError(
|
|
73
|
+
f"{lowerer.__class__.__name__!r} has no visitor for {type(expr).__name__}"
|
|
74
|
+
)
|
|
75
|
+
return fn(lowerer, expr)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""CVXPy visitors for arithmetic expressions.
|
|
2
|
+
|
|
3
|
+
Visitors: Add, Sub, Mul, Div, MatMul, Neg, Power
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import cvxpy as cp
|
|
7
|
+
|
|
8
|
+
# Expression types to handle — uncomment as you paste visitors:
|
|
9
|
+
from openscvx.symbolic.expr.arithmetic import Add, Div, MatMul, Mul, Neg, Power, Sub
|
|
10
|
+
from openscvx.symbolic.lowerers.cvxpy._registry import visitor # noqa: F401
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@visitor(Add)
|
|
14
|
+
def _visit_add(lowerer, node: Add) -> cp.Expression:
|
|
15
|
+
"""Lower addition to CVXPy expression.
|
|
16
|
+
|
|
17
|
+
Recursively lowers all terms and composes them with element-wise addition.
|
|
18
|
+
Addition is affine and always DCP-compliant.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
node: Add expression node with multiple terms
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
CVXPy expression representing the sum of all terms
|
|
25
|
+
"""
|
|
26
|
+
terms = [lowerer.lower(term) for term in node.terms]
|
|
27
|
+
result = terms[0]
|
|
28
|
+
for term in terms[1:]:
|
|
29
|
+
result = result + term
|
|
30
|
+
return result
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@visitor(Sub)
|
|
34
|
+
def _visit_sub(lowerer, node: Sub) -> cp.Expression:
|
|
35
|
+
"""Lower subtraction to CVXPy expression (element-wise left - right).
|
|
36
|
+
|
|
37
|
+
Subtraction is affine and always DCP-compliant.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
node: Sub expression node
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
CVXPy expression representing left - right
|
|
44
|
+
"""
|
|
45
|
+
left = lowerer.lower(node.left)
|
|
46
|
+
right = lowerer.lower(node.right)
|
|
47
|
+
return left - right
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@visitor(Mul)
|
|
51
|
+
def _visit_mul(lowerer, node: Mul) -> cp.Expression:
|
|
52
|
+
"""Lower element-wise multiplication to CVXPy expression.
|
|
53
|
+
|
|
54
|
+
Element-wise multiplication is DCP-compliant when at least one operand
|
|
55
|
+
is constant. For quadratic forms, use MatMul instead.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
node: Mul expression node with multiple factors
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
CVXPy expression representing element-wise product
|
|
62
|
+
|
|
63
|
+
Note:
|
|
64
|
+
For convex optimization, typically one factor should be constant.
|
|
65
|
+
CVXPy will raise a DCP error if the composition violates DCP rules.
|
|
66
|
+
"""
|
|
67
|
+
factors = [lowerer.lower(factor) for factor in node.factors]
|
|
68
|
+
result = factors[0]
|
|
69
|
+
for factor in factors[1:]:
|
|
70
|
+
result = result * factor
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@visitor(Div)
|
|
75
|
+
def _visit_div(lowerer, node: Div) -> cp.Expression:
|
|
76
|
+
"""Lower element-wise division to CVXPy expression.
|
|
77
|
+
|
|
78
|
+
Division is DCP-compliant when the denominator is constant or when
|
|
79
|
+
the numerator is constant and the denominator is concave.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
node: Div expression node
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
CVXPy expression representing left / right
|
|
86
|
+
|
|
87
|
+
Note:
|
|
88
|
+
CVXPy will raise a DCP error if the division violates DCP rules.
|
|
89
|
+
"""
|
|
90
|
+
left = lowerer.lower(node.left)
|
|
91
|
+
right = lowerer.lower(node.right)
|
|
92
|
+
return left / right
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@visitor(MatMul)
|
|
96
|
+
def _visit_matmul(lowerer, node: MatMul) -> cp.Expression:
|
|
97
|
+
"""Lower matrix multiplication to CVXPy expression using @ operator.
|
|
98
|
+
|
|
99
|
+
Matrix multiplication is DCP-compliant when at least one operand is
|
|
100
|
+
constant. Used for quadratic forms like x.T @ Q @ x.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
node: MatMul expression node
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
CVXPy expression representing left @ right
|
|
107
|
+
"""
|
|
108
|
+
left = lowerer.lower(node.left)
|
|
109
|
+
right = lowerer.lower(node.right)
|
|
110
|
+
return left @ right
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@visitor(Neg)
|
|
114
|
+
def _visit_neg(lowerer, node: Neg) -> cp.Expression:
|
|
115
|
+
"""Lower negation (unary minus) to CVXPy expression.
|
|
116
|
+
|
|
117
|
+
Negation preserves DCP properties (negating convex gives concave).
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
node: Neg expression node
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
CVXPy expression representing -operand
|
|
124
|
+
"""
|
|
125
|
+
operand = lowerer.lower(node.operand)
|
|
126
|
+
return -operand
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@visitor(Power)
|
|
130
|
+
def _visit_power(lowerer, node: Power) -> cp.Expression:
|
|
131
|
+
"""Lower element-wise power (base**exponent) to CVXPy expression.
|
|
132
|
+
|
|
133
|
+
Power is DCP-compliant for specific exponent values:
|
|
134
|
+
- exponent >= 1: convex (when base >= 0)
|
|
135
|
+
- 0 <= exponent <= 1: concave (when base >= 0)
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
node: Power expression node
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
CVXPy expression representing base**exponent
|
|
142
|
+
|
|
143
|
+
Note:
|
|
144
|
+
CVXPy will verify DCP compliance at problem construction time.
|
|
145
|
+
Common convex cases: x^2, x^3, x^4 (even powers)
|
|
146
|
+
"""
|
|
147
|
+
base = lowerer.lower(node.base)
|
|
148
|
+
exponent = lowerer.lower(node.exponent)
|
|
149
|
+
return cp.power(base, exponent)
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""CVXPy visitors for array expressions.
|
|
2
|
+
|
|
3
|
+
Visitors: Index, Concat, Stack, Hstack, Vstack, Block
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import cvxpy as cp
|
|
7
|
+
|
|
8
|
+
# Expression types to handle — uncomment as you paste visitors:
|
|
9
|
+
from openscvx.symbolic.expr.array import Block, Concat, Hstack, Index, Stack, Vstack
|
|
10
|
+
from openscvx.symbolic.lowerers.cvxpy._registry import visitor # noqa: F401
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@visitor(Index)
|
|
14
|
+
def _visit_index(lowerer, node: Index) -> cp.Expression:
|
|
15
|
+
"""Lower indexing/slicing operation to CVXPy expression.
|
|
16
|
+
|
|
17
|
+
Indexing preserves DCP properties (indexing into convex is convex).
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
node: Index expression node
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
CVXPy expression representing base[index]
|
|
24
|
+
"""
|
|
25
|
+
base = lowerer.lower(node.base)
|
|
26
|
+
return base[node.index]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@visitor(Concat)
|
|
30
|
+
def _visit_concat(lowerer, node: Concat) -> cp.Expression:
|
|
31
|
+
"""Lower concatenation to CVXPy expression.
|
|
32
|
+
|
|
33
|
+
Concatenates expressions horizontally along axis 0. Scalars are
|
|
34
|
+
promoted to 1D arrays before concatenation. Preserves DCP properties.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
node: Concat expression node
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
CVXPy expression representing horizontal concatenation
|
|
41
|
+
|
|
42
|
+
Note:
|
|
43
|
+
Uses cp.hstack for concatenation. Scalars are reshaped to (1,).
|
|
44
|
+
"""
|
|
45
|
+
exprs = [lowerer.lower(child) for child in node.exprs]
|
|
46
|
+
# Ensure all expressions are at least 1D for concatenation
|
|
47
|
+
exprs_1d = []
|
|
48
|
+
for expr in exprs:
|
|
49
|
+
if expr.ndim == 0: # scalar
|
|
50
|
+
exprs_1d.append(cp.reshape(expr, (1,), order="C"))
|
|
51
|
+
else:
|
|
52
|
+
exprs_1d.append(expr)
|
|
53
|
+
return cp.hstack(exprs_1d)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@visitor(Stack)
|
|
57
|
+
def _visit_stack(lowerer, node: Stack) -> cp.Expression:
|
|
58
|
+
"""Lower vertical stacking to CVXPy expression.
|
|
59
|
+
|
|
60
|
+
Stacks expressions vertically using cp.vstack. Preserves DCP properties.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
node: Stack expression node with multiple rows
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
CVXPy expression representing vertical stack of rows
|
|
67
|
+
|
|
68
|
+
Note:
|
|
69
|
+
Each row is stacked along axis 0 to create a 2D array.
|
|
70
|
+
"""
|
|
71
|
+
rows = [lowerer.lower(row) for row in node.rows]
|
|
72
|
+
# Stack rows vertically
|
|
73
|
+
return cp.vstack(rows)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@visitor(Hstack)
|
|
77
|
+
def _visit_hstack(lowerer, node: Hstack) -> cp.Expression:
|
|
78
|
+
"""Lower horizontal stacking to CVXPy expression.
|
|
79
|
+
|
|
80
|
+
For 1D arrays, uses cp.hstack (concatenation). For 2D+ arrays, uses
|
|
81
|
+
cp.bmat with a single row to achieve proper horizontal stacking along
|
|
82
|
+
axis 1, matching numpy.hstack semantics.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
node: Hstack expression node with multiple arrays
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
CVXPy expression representing horizontal stack of arrays
|
|
89
|
+
"""
|
|
90
|
+
arrays = [lowerer.lower(arr) for arr in node.arrays]
|
|
91
|
+
|
|
92
|
+
# Check dimensionality from the symbolic node's shape
|
|
93
|
+
shape = node.check_shape()
|
|
94
|
+
if len(shape) == 1:
|
|
95
|
+
# 1D: simple concatenation
|
|
96
|
+
return cp.hstack(arrays)
|
|
97
|
+
else:
|
|
98
|
+
# 2D+: use bmat with single row for proper horizontal stacking
|
|
99
|
+
return cp.bmat([arrays])
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@visitor(Vstack)
|
|
103
|
+
def _visit_vstack(lowerer, node: Vstack) -> cp.Expression:
|
|
104
|
+
"""Lower vertical stacking to CVXPy expression.
|
|
105
|
+
|
|
106
|
+
Stacks expressions vertically using cp.vstack. Preserves DCP properties.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
node: Vstack expression node with multiple arrays
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
CVXPy expression representing vertical stack of arrays
|
|
113
|
+
"""
|
|
114
|
+
arrays = [lowerer.lower(arr) for arr in node.arrays]
|
|
115
|
+
return cp.vstack(arrays)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@visitor(Block)
|
|
119
|
+
def _visit_block(lowerer, node: Block) -> cp.Expression:
|
|
120
|
+
"""Lower block matrix construction to CVXPy expression.
|
|
121
|
+
|
|
122
|
+
Assembles a block matrix from nested lists of expressions using cp.bmat.
|
|
123
|
+
This is the CVXPy equivalent of numpy.block() for block matrix construction.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
node: Block expression node with 2D nested structure of expressions
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
CVXPy expression representing the assembled block matrix
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
NotImplementedError: If any block has more than 2 dimensions
|
|
133
|
+
|
|
134
|
+
Note:
|
|
135
|
+
cp.bmat preserves DCP properties when all blocks are DCP-compliant.
|
|
136
|
+
Block matrices are commonly used for constraint aggregation.
|
|
137
|
+
For 3D+ tensors, use JAX lowering instead.
|
|
138
|
+
"""
|
|
139
|
+
# Check for 3D+ blocks - CVXPy's bmat only supports 2D
|
|
140
|
+
for i, row in enumerate(node.blocks):
|
|
141
|
+
for j, block in enumerate(row):
|
|
142
|
+
block_shape = block.check_shape()
|
|
143
|
+
if len(block_shape) > 2:
|
|
144
|
+
raise NotImplementedError(
|
|
145
|
+
f"CVXPy does not support Block with tensors of dimension > 2. "
|
|
146
|
+
f"Block[{i}][{j}] has shape {block_shape} ({len(block_shape)}D). "
|
|
147
|
+
f"For N-D tensor block assembly, use JAX lowering instead."
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Lower each block expression
|
|
151
|
+
block_exprs = [[lowerer.lower(block) for block in row] for row in node.blocks]
|
|
152
|
+
return cp.bmat(block_exprs)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""CVXPy visitors for constraint expressions.
|
|
2
|
+
|
|
3
|
+
Visitors: Equality, Inequality, CrossNodeConstraint, CTCS
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import cvxpy as cp
|
|
7
|
+
|
|
8
|
+
# Expression types to handle — uncomment as you paste visitors:
|
|
9
|
+
from openscvx.symbolic.expr.constraint import (
|
|
10
|
+
CTCS,
|
|
11
|
+
CrossNodeConstraint,
|
|
12
|
+
Equality,
|
|
13
|
+
Inequality,
|
|
14
|
+
)
|
|
15
|
+
from openscvx.symbolic.lowerers.cvxpy._registry import visitor # noqa: F401
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@visitor(Equality)
|
|
19
|
+
def _visit_equality(lowerer, node: Equality) -> cp.Constraint:
|
|
20
|
+
"""Lower equality constraint to CVXPy constraint (lhs == rhs).
|
|
21
|
+
|
|
22
|
+
Equality constraints require affine expressions on both sides for
|
|
23
|
+
DCP compliance.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
node: Equality constraint node
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
CVXPy equality constraint object
|
|
30
|
+
|
|
31
|
+
Note:
|
|
32
|
+
For DCP compliance, both lhs and rhs must be affine. CVXPy will
|
|
33
|
+
raise a DCP error if either side is non-affine.
|
|
34
|
+
"""
|
|
35
|
+
left = lowerer.lower(node.lhs)
|
|
36
|
+
right = lowerer.lower(node.rhs)
|
|
37
|
+
return left == right
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@visitor(Inequality)
|
|
41
|
+
def _visit_inequality(lowerer, node: Inequality) -> cp.Constraint:
|
|
42
|
+
"""Lower inequality constraint to CVXPy constraint (lhs <= rhs).
|
|
43
|
+
|
|
44
|
+
Inequality constraints must satisfy DCP rules: convex <= concave.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
node: Inequality constraint node
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
CVXPy inequality constraint object
|
|
51
|
+
|
|
52
|
+
Note:
|
|
53
|
+
For DCP compliance: lhs must be convex and rhs must be concave.
|
|
54
|
+
Common form: convex_expr(x) <= constant
|
|
55
|
+
"""
|
|
56
|
+
left = lowerer.lower(node.lhs)
|
|
57
|
+
right = lowerer.lower(node.rhs)
|
|
58
|
+
return left <= right
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@visitor(CrossNodeConstraint)
|
|
62
|
+
def _visit_cross_node_constraint(lowerer, node: CrossNodeConstraint) -> cp.Constraint:
|
|
63
|
+
"""Lower CrossNodeConstraint to CVXPy constraint.
|
|
64
|
+
|
|
65
|
+
CrossNodeConstraint wraps constraints that reference multiple trajectory
|
|
66
|
+
nodes via NodeReference (e.g., rate limits like x.at(k) - x.at(k-1) <= r).
|
|
67
|
+
|
|
68
|
+
For CVXPy lowering, this simply lowers the inner constraint. The NodeReference
|
|
69
|
+
nodes within the constraint will handle extracting values from the full
|
|
70
|
+
trajectory arrays (which must be provided in variable_map as "x" and "u").
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
node: CrossNodeConstraint expression wrapping the inner constraint
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
CVXPy constraint object
|
|
77
|
+
|
|
78
|
+
Note:
|
|
79
|
+
The variable_map must contain full trajectory arrays:
|
|
80
|
+
- "x": (N, n_x) CVXPy expression (e.g., cp.vstack(x_nonscaled))
|
|
81
|
+
- "u": (N, n_u) CVXPy expression (e.g., cp.vstack(u_nonscaled))
|
|
82
|
+
|
|
83
|
+
NodeReference visitors will index into these arrays using the fixed
|
|
84
|
+
node indices baked into the expression.
|
|
85
|
+
|
|
86
|
+
Example:
|
|
87
|
+
For constraint: position.at(5) - position.at(4) <= max_step
|
|
88
|
+
|
|
89
|
+
With variable_map = {"x": cp.vstack([x[k] for k in range(N)])}
|
|
90
|
+
|
|
91
|
+
The lowered constraint evaluates:
|
|
92
|
+
x[5, pos_slice] - x[4, pos_slice] <= max_step
|
|
93
|
+
"""
|
|
94
|
+
# Simply lower the inner constraint - NodeReference handles indexing
|
|
95
|
+
return lowerer.lower(node.constraint)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@visitor(CTCS)
|
|
99
|
+
def _visit_ctcs(lowerer, node: CTCS) -> cp.Expression:
|
|
100
|
+
"""Raise NotImplementedError for CTCS constraints.
|
|
101
|
+
|
|
102
|
+
CTCS (Continuous-Time Constraint Satisfaction) constraints are handled
|
|
103
|
+
through dynamics augmentation using JAX, not CVXPy. They represent
|
|
104
|
+
non-convex continuous-time constraints.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
node: CTCS constraint node
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
NotImplementedError: Always raised since CTCS uses JAX, not CVXPy
|
|
111
|
+
|
|
112
|
+
Note:
|
|
113
|
+
CTCS constraints are lowered to JAX during dynamics augmentation.
|
|
114
|
+
They add virtual states and controls to enforce constraints over
|
|
115
|
+
continuous time intervals. See JaxLowerer.visit_ctcs() instead.
|
|
116
|
+
"""
|
|
117
|
+
raise NotImplementedError(
|
|
118
|
+
"CTCS constraints are for continuous-time constraint satisfaction and "
|
|
119
|
+
"should be handled through dynamics augmentation with JAX lowering, "
|
|
120
|
+
"not CVXPy lowering. CTCS constraints represent non-convex dynamics "
|
|
121
|
+
"augmentation."
|
|
122
|
+
)
|