openscvx 0.3.2.dev328__tar.gz → 0.3.2.dev339__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.dev339}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/_version.py +3 -3
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/problem.py +1 -2
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/builder.py +13 -7
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/__init__.py +35 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +111 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/_registry.py +75 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +149 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/array.py +152 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/constraint.py +122 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/control.py +38 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/expr.py +135 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/linalg.py +91 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/logic.py +75 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/math.py +372 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/cvxpy/state.py +40 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/__init__.py +40 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/_lowerer.py +56 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/_registry.py +74 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/arithmetic.py +87 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/array.py +132 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/constraint.py +159 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/control.py +30 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/expr.py +108 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/lie.py +291 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/linalg.py +76 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/logic.py +161 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/math.py +268 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/spatial.py +120 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/state.py +32 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/stl.py +82 -0
- openscvx-0.3.2.dev339/openscvx/symbolic/lowerers/jax/vmap.py +152 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/preprocessing.py +136 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx.egg-info/SOURCES.txt +28 -2
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_arithmetic.py +6 -6
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_constraint.py +2 -2
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_parameters.py +3 -3
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_variable.py +4 -4
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/test_lower_jax.py +6 -6
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/test_preprocessing.py +175 -0
- 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.dev339}/.github/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/docs.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/lint.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/release.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/.gitignore +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/CONTRIBUTING.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/LICENSE +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/README.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/UsersGuide/07_lie.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/favicon.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/citation.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/examples.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/getting-started.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/index.md +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/arm/three_link_arm.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/car/dubins_car.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/car/dubins_car_conditional.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/car/dubins_car_stljax.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/plotting.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/plotting_viser.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/figures/video_preview.png +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/home.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/main.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/mkdocs.yml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/algorithms/autotuning.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/config.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/discretization/discretization.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/expert/byof.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/expert/validation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/init/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/solvers/base.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/time.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/utils/cache.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/utils/caching.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/utils/printing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx/utils/utils.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/pyproject.toml +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/setup.cfg +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_discretization.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_examples.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_expert.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_init.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_integrators.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/tests/test_plotting.py +0 -0
- {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev339}/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.dev339
|
|
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.dev339'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 2, 'dev339')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g0ad465892'
|
|
@@ -50,7 +50,6 @@ from openscvx.lowered.jax_constraints import (
|
|
|
50
50
|
from openscvx.propagation import get_propagation_solver, propagate_trajectory_results
|
|
51
51
|
from openscvx.solvers import PTRSolver
|
|
52
52
|
from openscvx.symbolic.builder import preprocess_symbolic_problem
|
|
53
|
-
from openscvx.symbolic.constraint_set import ConstraintSet
|
|
54
53
|
from openscvx.symbolic.expr import CTCS, Constraint
|
|
55
54
|
from openscvx.symbolic.expr.control import Control
|
|
56
55
|
from openscvx.symbolic.expr.state import State
|
|
@@ -128,7 +127,7 @@ class Problem:
|
|
|
128
127
|
# Symbolic Preprocessing & Augmentation
|
|
129
128
|
self.symbolic: SymbolicProblem = preprocess_symbolic_problem(
|
|
130
129
|
dynamics=dynamics,
|
|
131
|
-
constraints=
|
|
130
|
+
constraints=constraints,
|
|
132
131
|
states=states,
|
|
133
132
|
controls=controls,
|
|
134
133
|
N=N,
|
|
@@ -55,6 +55,8 @@ from openscvx.symbolic.preprocessing import (
|
|
|
55
55
|
validate_dynamics_dict_dimensions,
|
|
56
56
|
validate_dynamics_dimension,
|
|
57
57
|
validate_guesses,
|
|
58
|
+
validate_input_types,
|
|
59
|
+
validate_propagation_input_types,
|
|
58
60
|
validate_shapes,
|
|
59
61
|
validate_variable_names,
|
|
60
62
|
)
|
|
@@ -64,7 +66,7 @@ from openscvx.symbolic.time import Time
|
|
|
64
66
|
|
|
65
67
|
def preprocess_symbolic_problem(
|
|
66
68
|
dynamics: dict,
|
|
67
|
-
constraints:
|
|
69
|
+
constraints: list,
|
|
68
70
|
states: List[State],
|
|
69
71
|
controls: List[Control],
|
|
70
72
|
N: int,
|
|
@@ -99,8 +101,8 @@ def preprocess_symbolic_problem(
|
|
|
99
101
|
Args:
|
|
100
102
|
dynamics: Dictionary mapping state names to dynamics expressions.
|
|
101
103
|
Example: {"x": v, "v": u}
|
|
102
|
-
constraints:
|
|
103
|
-
|
|
104
|
+
constraints: List of constraint objects (Constraint, NodalConstraint,
|
|
105
|
+
CrossNodeConstraint, or CTCS).
|
|
104
106
|
states: List of user-defined State objects (should NOT include time or CTCS states)
|
|
105
107
|
controls: List of user-defined Control objects (should NOT include time dilation)
|
|
106
108
|
N: Number of discretization nodes in the trajectory
|
|
@@ -140,16 +142,13 @@ def preprocess_symbolic_problem(
|
|
|
140
142
|
Basic usage with CTCS constraint::
|
|
141
143
|
|
|
142
144
|
import openscvx as ox
|
|
143
|
-
from openscvx.symbolic.constraint_set import ConstraintSet
|
|
144
145
|
|
|
145
146
|
x = ox.State("x", shape=(2,))
|
|
146
147
|
v = ox.State("v", shape=(2,))
|
|
147
148
|
u = ox.Control("u", shape=(2,))
|
|
148
149
|
|
|
149
150
|
dynamics = {"x": v, "v": u}
|
|
150
|
-
constraints =
|
|
151
|
-
(ox.Norm(x) <= 5.0).over((0, 50))
|
|
152
|
-
])
|
|
151
|
+
constraints = [(ox.Norm(x) <= 5.0).over((0, 50))]
|
|
153
152
|
|
|
154
153
|
problem = preprocess_symbolic_problem(
|
|
155
154
|
dynamics=dynamics,
|
|
@@ -187,6 +186,13 @@ def preprocess_symbolic_problem(
|
|
|
187
186
|
print([s.name for s in problem.states_prop])
|
|
188
187
|
"""
|
|
189
188
|
|
|
189
|
+
# Validate input types before anything else
|
|
190
|
+
validate_input_types(dynamics, states, controls, constraints, N, time)
|
|
191
|
+
validate_propagation_input_types(dynamics_prop_extra, states_prop_extra)
|
|
192
|
+
|
|
193
|
+
# Wrap validated constraints into a ConstraintSet
|
|
194
|
+
constraints = ConstraintSet(unsorted=list(constraints))
|
|
195
|
+
|
|
190
196
|
# Validate user-provided variables have required attributes
|
|
191
197
|
validate_boundary_conditions(states)
|
|
192
198
|
validate_bounds(states + controls)
|
|
@@ -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)
|