openscvx 0.3.2.dev195__tar.gz → 0.3.2.dev210__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.dev195/openscvx.egg-info → openscvx-0.3.2.dev210}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/__init__.py +6 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/_version.py +3 -3
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/__init__.py +6 -1
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/linalg.py +83 -1
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/math.py +202 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/lowerers/cvxpy.py +62 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/lowerers/jax.py +93 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_linalg.py +186 -1
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_math.py +676 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/docs.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/lint.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/release.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/.gitignore +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/CONTRIBUTING.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/LICENSE +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/README.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Overview/constraint_reformulation.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Overview/control_parameterization.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Overview/discretization.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Overview/ocp.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Overview/scvx.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Overview/time_dilation.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/advanced_problem_setup.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/api.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/api_constraints.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/api_control.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/api_integrators.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/api_state.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/api_trajoptproblem.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/api_variable.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/basic_problem_setup.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/tutorial_6dof_los_guidance.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/tutorial_6dof_obstacle_avoidance.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/Usage/tutorials.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/favicon.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/citation.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/examples.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/getting-started.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/index.md +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/abstract/3DoF_pdg.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/arm/three_link_arm.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/car/dubins_car.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/car/dubins_car_stljax.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/plotting.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/plotting_viser.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/figures/video_preview.png +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/home.html +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/main.html +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/mkdocs.yml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/algorithms/autotuning.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/config.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/discretization/discretization.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/expert/byof.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/expert/validation.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/problem.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/solvers/cvxpy.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/time.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/utils/cache.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/utils/caching.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/utils/printing.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx/utils/utils.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx.egg-info/SOURCES.txt +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/pyproject.toml +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/setup.cfg +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/test_discretization.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/test_examples.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/test_expert.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/test_integrators.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/tests/test_plotting.py +0 -0
- {openscvx-0.3.2.dev195 → openscvx-0.3.2.dev210}/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.dev210
|
|
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
|
|
@@ -15,6 +15,7 @@ from openscvx.symbolic.expr import (
|
|
|
15
15
|
CTCS,
|
|
16
16
|
Abs,
|
|
17
17
|
Add,
|
|
18
|
+
Bilerp,
|
|
18
19
|
Block,
|
|
19
20
|
Concat,
|
|
20
21
|
Constant,
|
|
@@ -31,7 +32,9 @@ from openscvx.symbolic.expr import (
|
|
|
31
32
|
Hstack,
|
|
32
33
|
Index,
|
|
33
34
|
Inequality,
|
|
35
|
+
Inv,
|
|
34
36
|
Leaf,
|
|
37
|
+
Linterp,
|
|
35
38
|
Log,
|
|
36
39
|
LogSumExp,
|
|
37
40
|
MatMul,
|
|
@@ -96,6 +99,7 @@ __all__ = [
|
|
|
96
99
|
"Vstack",
|
|
97
100
|
"Block",
|
|
98
101
|
"Diag",
|
|
102
|
+
"Inv",
|
|
99
103
|
"Constant",
|
|
100
104
|
# Mathematical functions
|
|
101
105
|
"Sin",
|
|
@@ -107,6 +111,8 @@ __all__ = [
|
|
|
107
111
|
"Log",
|
|
108
112
|
"LogSumExp",
|
|
109
113
|
"Max",
|
|
114
|
+
"Linterp",
|
|
115
|
+
"Bilerp",
|
|
110
116
|
# Constraints
|
|
111
117
|
"Constraint",
|
|
112
118
|
"Equality",
|
|
@@ -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.dev210'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 2, 'dev210')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g28ab57c34'
|
|
@@ -113,14 +113,16 @@ from .lie import (
|
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
# Linear algebra operations
|
|
116
|
-
from .linalg import Diag, Norm, Sum, Transpose
|
|
116
|
+
from .linalg import Diag, Inv, Norm, Sum, Transpose
|
|
117
117
|
|
|
118
118
|
# Mathematical functions
|
|
119
119
|
from .math import (
|
|
120
120
|
Abs,
|
|
121
|
+
Bilerp,
|
|
121
122
|
Cos,
|
|
122
123
|
Exp,
|
|
123
124
|
Huber,
|
|
125
|
+
Linterp,
|
|
124
126
|
Log,
|
|
125
127
|
LogSumExp,
|
|
126
128
|
Max,
|
|
@@ -194,6 +196,8 @@ __all__ = [
|
|
|
194
196
|
"Log",
|
|
195
197
|
"LogSumExp",
|
|
196
198
|
"Max",
|
|
199
|
+
"Linterp",
|
|
200
|
+
"Bilerp",
|
|
197
201
|
# Linear algebra operations
|
|
198
202
|
"Transpose",
|
|
199
203
|
"Stack",
|
|
@@ -202,6 +206,7 @@ __all__ = [
|
|
|
202
206
|
"Block",
|
|
203
207
|
"Norm",
|
|
204
208
|
"Diag",
|
|
209
|
+
"Inv",
|
|
205
210
|
# Spatial/3D operations
|
|
206
211
|
"QDCM",
|
|
207
212
|
"SSMP",
|
|
@@ -8,6 +8,7 @@ Key Operations:
|
|
|
8
8
|
- **Matrix Operations:**
|
|
9
9
|
- `Transpose` - Matrix/tensor transposition (swaps last two dimensions)
|
|
10
10
|
- `Diag` - Construct diagonal matrix from vector
|
|
11
|
+
- `Inv` - Matrix inverse (square matrices only, JAX lowering only)
|
|
11
12
|
- **Reductions:**
|
|
12
13
|
- `Sum` - Sum all elements of an array (reduces to scalar)
|
|
13
14
|
- `Norm` - Euclidean (L2) norm and other norms of vectors/matrices
|
|
@@ -50,7 +51,9 @@ Example:
|
|
|
50
51
|
import hashlib
|
|
51
52
|
from typing import Tuple
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
import numpy as np
|
|
55
|
+
|
|
56
|
+
from .expr import Constant, Expr, to_expr
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
class Transpose(Expr):
|
|
@@ -213,6 +216,85 @@ class Sum(Expr):
|
|
|
213
216
|
return f"sum({self.operand!r})"
|
|
214
217
|
|
|
215
218
|
|
|
219
|
+
class Inv(Expr):
|
|
220
|
+
"""Matrix inverse operation for symbolic expressions.
|
|
221
|
+
|
|
222
|
+
Computes the inverse of a square matrix. For batched inputs with shape
|
|
223
|
+
(..., M, M), inverts the last two dimensions following jax.numpy.linalg.inv
|
|
224
|
+
conventions.
|
|
225
|
+
|
|
226
|
+
The canonicalization includes an optimization that eliminates double inverses:
|
|
227
|
+
Inv(Inv(A)) simplifies to A.
|
|
228
|
+
|
|
229
|
+
Attributes:
|
|
230
|
+
operand: Square matrix expression to invert
|
|
231
|
+
|
|
232
|
+
Example:
|
|
233
|
+
Define matrix inverse expressions::
|
|
234
|
+
|
|
235
|
+
M = Variable("M", shape=(3, 3))
|
|
236
|
+
M_inv = Inv(M) # Result shape (3, 3)
|
|
237
|
+
|
|
238
|
+
# Batched case
|
|
239
|
+
M_batch = Variable("M_batch", shape=(5, 3, 3))
|
|
240
|
+
M_batch_inv = Inv(M_batch) # Result shape (5, 3, 3)
|
|
241
|
+
|
|
242
|
+
Note:
|
|
243
|
+
Matrix inverse is non-convex and only supported in JAX lowering.
|
|
244
|
+
CVXPy lowering will raise NotImplementedError since inv(X) is neither
|
|
245
|
+
convex nor concave for variable matrices.
|
|
246
|
+
|
|
247
|
+
!!! warning
|
|
248
|
+
Solving a matrix inverse inside an optimization loop can be somewhat
|
|
249
|
+
of an oxymoron and performance may be severly impacted.
|
|
250
|
+
Consider whether your problem can be reformulated to avoid the inverse.
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
def __init__(self, operand):
|
|
254
|
+
"""Initialize a matrix inverse operation.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
operand: Square matrix expression to invert. Must have shape
|
|
258
|
+
(..., M, M) where the last two dimensions are equal.
|
|
259
|
+
"""
|
|
260
|
+
self.operand = to_expr(operand)
|
|
261
|
+
|
|
262
|
+
def children(self):
|
|
263
|
+
return [self.operand]
|
|
264
|
+
|
|
265
|
+
def canonicalize(self) -> "Expr":
|
|
266
|
+
"""Canonicalize the operand with double inverse optimization and constant folding."""
|
|
267
|
+
operand = self.operand.canonicalize()
|
|
268
|
+
|
|
269
|
+
# Double inverse optimization: Inv(Inv(A)) = A
|
|
270
|
+
if isinstance(operand, Inv):
|
|
271
|
+
return operand.operand
|
|
272
|
+
|
|
273
|
+
# Constant folding: compute inverse at canonicalization time
|
|
274
|
+
if isinstance(operand, Constant):
|
|
275
|
+
return Constant(np.linalg.inv(operand.value))
|
|
276
|
+
|
|
277
|
+
return Inv(operand)
|
|
278
|
+
|
|
279
|
+
def check_shape(self) -> Tuple[int, ...]:
|
|
280
|
+
"""Matrix inverse preserves shape; validates square matrix."""
|
|
281
|
+
operand_shape = self.operand.check_shape()
|
|
282
|
+
|
|
283
|
+
if len(operand_shape) < 2:
|
|
284
|
+
raise ValueError(f"Inv requires at least a 2D matrix, got shape {operand_shape}")
|
|
285
|
+
|
|
286
|
+
if operand_shape[-1] != operand_shape[-2]:
|
|
287
|
+
raise ValueError(
|
|
288
|
+
f"Inv requires a square matrix (last two dims must be equal), "
|
|
289
|
+
f"got shape {operand_shape}"
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
return operand_shape
|
|
293
|
+
|
|
294
|
+
def __repr__(self):
|
|
295
|
+
return f"inv({self.operand!r})"
|
|
296
|
+
|
|
297
|
+
|
|
216
298
|
class Norm(Expr):
|
|
217
299
|
"""Norm operation for symbolic expressions (reduction to scalar).
|
|
218
300
|
|
|
@@ -697,3 +697,205 @@ class LogSumExp(Expr):
|
|
|
697
697
|
def __repr__(self):
|
|
698
698
|
inner = ", ".join(repr(op) for op in self.operands)
|
|
699
699
|
return f"logsumexp({inner})"
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
class Linterp(Expr):
|
|
703
|
+
"""1D linear interpolation for symbolic expressions.
|
|
704
|
+
|
|
705
|
+
Computes the linear interpolant of data points (xp, fp) evaluated at x,
|
|
706
|
+
equivalent to jax.numpy.interp(x, xp, fp). For values outside the data range,
|
|
707
|
+
the boundary values are returned (no extrapolation).
|
|
708
|
+
|
|
709
|
+
This is useful for incorporating tabulated data (e.g., atmospheric properties,
|
|
710
|
+
engine thrust curves, aerodynamic coefficients) into trajectory optimization
|
|
711
|
+
dynamics and constraints.
|
|
712
|
+
|
|
713
|
+
Attributes:
|
|
714
|
+
x: Query point(s) at which to evaluate the interpolant (symbolic expression)
|
|
715
|
+
xp: 1D array of x-coordinates of data points (must be increasing)
|
|
716
|
+
fp: 1D array of y-coordinates of data points (same length as xp)
|
|
717
|
+
|
|
718
|
+
Example:
|
|
719
|
+
Interpolate atmospheric density from altitude table::
|
|
720
|
+
|
|
721
|
+
import openscvx as ox
|
|
722
|
+
import numpy as np
|
|
723
|
+
|
|
724
|
+
# US 1976 Standard Atmosphere data
|
|
725
|
+
alt_data = np.array([0, 5000, 10000, 15000, 20000]) # meters
|
|
726
|
+
rho_data = np.array([1.225, 0.736, 0.414, 0.195, 0.089]) # kg/m^3
|
|
727
|
+
|
|
728
|
+
altitude = ox.State("altitude", shape=(1,))
|
|
729
|
+
rho = ox.Linterp(altitude[0], alt_data, rho_data)
|
|
730
|
+
|
|
731
|
+
# rho can now be used in dynamics expressions
|
|
732
|
+
drag = 0.5 * rho * v**2 * Cd * S
|
|
733
|
+
|
|
734
|
+
Note:
|
|
735
|
+
- xp must be strictly increasing
|
|
736
|
+
- For query points outside [xp[0], xp[-1]], boundary values are returned
|
|
737
|
+
"""
|
|
738
|
+
|
|
739
|
+
def __init__(self, x, xp, fp):
|
|
740
|
+
"""Initialize a 1D linear interpolation node.
|
|
741
|
+
|
|
742
|
+
Args:
|
|
743
|
+
x: Query point(s) at which to evaluate the interpolant.
|
|
744
|
+
Can be a scalar or array symbolic expression.
|
|
745
|
+
xp: 1D array of x-coordinates of data points. Must be increasing.
|
|
746
|
+
Can be a numpy array or Constant expression.
|
|
747
|
+
fp: 1D array of y-coordinates of data points. Must have same length as xp.
|
|
748
|
+
Can be a numpy array or Constant expression.
|
|
749
|
+
"""
|
|
750
|
+
self.x = to_expr(x)
|
|
751
|
+
self.xp = to_expr(xp)
|
|
752
|
+
self.fp = to_expr(fp)
|
|
753
|
+
|
|
754
|
+
def children(self):
|
|
755
|
+
return [self.x, self.xp, self.fp]
|
|
756
|
+
|
|
757
|
+
def canonicalize(self) -> "Expr":
|
|
758
|
+
"""Canonicalize by canonicalizing all operands."""
|
|
759
|
+
x = self.x.canonicalize()
|
|
760
|
+
xp = self.xp.canonicalize()
|
|
761
|
+
fp = self.fp.canonicalize()
|
|
762
|
+
return Linterp(x, xp, fp)
|
|
763
|
+
|
|
764
|
+
def check_shape(self) -> Tuple[int, ...]:
|
|
765
|
+
"""Output shape matches the query point shape.
|
|
766
|
+
|
|
767
|
+
The interpolation is element-wise over x, so the output has
|
|
768
|
+
the same shape as the query points.
|
|
769
|
+
|
|
770
|
+
Returns:
|
|
771
|
+
tuple: Shape of the query point x
|
|
772
|
+
|
|
773
|
+
Raises:
|
|
774
|
+
ValueError: If xp and fp have different lengths or are not 1D
|
|
775
|
+
"""
|
|
776
|
+
xp_shape = self.xp.check_shape()
|
|
777
|
+
fp_shape = self.fp.check_shape()
|
|
778
|
+
|
|
779
|
+
if len(xp_shape) != 1:
|
|
780
|
+
raise ValueError(f"Linterp xp must be 1D, got shape {xp_shape}")
|
|
781
|
+
if len(fp_shape) != 1:
|
|
782
|
+
raise ValueError(f"Linterp fp must be 1D, got shape {fp_shape}")
|
|
783
|
+
if xp_shape != fp_shape:
|
|
784
|
+
raise ValueError(
|
|
785
|
+
f"Linterp xp and fp must have same length, got {xp_shape} vs {fp_shape}"
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
return self.x.check_shape()
|
|
789
|
+
|
|
790
|
+
def __repr__(self):
|
|
791
|
+
return f"linterp({self.x!r}, {self.xp!r}, {self.fp!r})"
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
class Bilerp(Expr):
|
|
795
|
+
"""2D bilinear interpolation for symbolic expressions.
|
|
796
|
+
|
|
797
|
+
Performs bilinear interpolation on a regular 2D grid. Given grid points
|
|
798
|
+
(xp, yp) and corresponding values fp, computes the bilinearly interpolated
|
|
799
|
+
value at query point (x, y). For values outside the grid, boundary values
|
|
800
|
+
are returned (clamping, no extrapolation).
|
|
801
|
+
|
|
802
|
+
This is useful for incorporating 2D tabulated data (e.g., engine thrust
|
|
803
|
+
as a function of altitude and Mach number, aerodynamic coefficients as
|
|
804
|
+
a function of angle of attack and sideslip) into trajectory optimization.
|
|
805
|
+
|
|
806
|
+
Attributes:
|
|
807
|
+
x: Query x-coordinate (symbolic expression)
|
|
808
|
+
y: Query y-coordinate (symbolic expression)
|
|
809
|
+
xp: 1D array of x grid coordinates (must be increasing), length N
|
|
810
|
+
yp: 1D array of y grid coordinates (must be increasing), length M
|
|
811
|
+
fp: 2D array of values with shape (N, M), where fp[i, j] is the
|
|
812
|
+
value at grid point (xp[i], yp[j])
|
|
813
|
+
|
|
814
|
+
Example:
|
|
815
|
+
Interpolate engine thrust from altitude and Mach number::
|
|
816
|
+
|
|
817
|
+
import openscvx as ox
|
|
818
|
+
import numpy as np
|
|
819
|
+
|
|
820
|
+
# Grid coordinates
|
|
821
|
+
alt_grid = np.array([0, 5000, 10000, 15000, 20000]) # meters
|
|
822
|
+
mach_grid = np.array([0.0, 0.5, 1.0, 1.5, 2.0])
|
|
823
|
+
|
|
824
|
+
# Thrust values: thrust_table[i, j] = thrust at (alt_grid[i], mach_grid[j])
|
|
825
|
+
thrust_table = np.array([...]) # shape (5, 5)
|
|
826
|
+
|
|
827
|
+
altitude = ox.State("altitude", shape=(1,))
|
|
828
|
+
mach = ox.State("mach", shape=(1,))
|
|
829
|
+
|
|
830
|
+
thrust = ox.Bilerp(altitude[0], mach[0], alt_grid, mach_grid, thrust_table)
|
|
831
|
+
|
|
832
|
+
Note:
|
|
833
|
+
- xp and yp must be strictly increasing
|
|
834
|
+
- fp must have shape (len(xp), len(yp))
|
|
835
|
+
- For query points outside the grid, boundary values are returned
|
|
836
|
+
- This node is only supported in JAX lowering (dynamics/cost), not CVXPy
|
|
837
|
+
"""
|
|
838
|
+
|
|
839
|
+
def __init__(self, x, y, xp, yp, fp):
|
|
840
|
+
"""Initialize a 2D bilinear interpolation node.
|
|
841
|
+
|
|
842
|
+
Args:
|
|
843
|
+
x: Query x-coordinate. Can be a scalar symbolic expression.
|
|
844
|
+
y: Query y-coordinate. Can be a scalar symbolic expression.
|
|
845
|
+
xp: 1D array of x grid coordinates. Must be increasing.
|
|
846
|
+
yp: 1D array of y grid coordinates. Must be increasing.
|
|
847
|
+
fp: 2D array of values with shape (len(xp), len(yp)).
|
|
848
|
+
"""
|
|
849
|
+
self.x = to_expr(x)
|
|
850
|
+
self.y = to_expr(y)
|
|
851
|
+
self.xp = to_expr(xp)
|
|
852
|
+
self.yp = to_expr(yp)
|
|
853
|
+
self.fp = to_expr(fp)
|
|
854
|
+
|
|
855
|
+
def children(self):
|
|
856
|
+
return [self.x, self.y, self.xp, self.yp, self.fp]
|
|
857
|
+
|
|
858
|
+
def canonicalize(self) -> "Expr":
|
|
859
|
+
"""Canonicalize by canonicalizing all operands."""
|
|
860
|
+
x = self.x.canonicalize()
|
|
861
|
+
y = self.y.canonicalize()
|
|
862
|
+
xp = self.xp.canonicalize()
|
|
863
|
+
yp = self.yp.canonicalize()
|
|
864
|
+
fp = self.fp.canonicalize()
|
|
865
|
+
return Bilerp(x, y, xp, yp, fp)
|
|
866
|
+
|
|
867
|
+
def check_shape(self) -> Tuple[int, ...]:
|
|
868
|
+
"""Output shape is scalar (single interpolated value).
|
|
869
|
+
|
|
870
|
+
Returns:
|
|
871
|
+
tuple: Empty tuple (scalar output)
|
|
872
|
+
|
|
873
|
+
Raises:
|
|
874
|
+
ValueError: If grid arrays have invalid shapes
|
|
875
|
+
"""
|
|
876
|
+
xp_shape = self.xp.check_shape()
|
|
877
|
+
yp_shape = self.yp.check_shape()
|
|
878
|
+
fp_shape = self.fp.check_shape()
|
|
879
|
+
x_shape = self.x.check_shape()
|
|
880
|
+
y_shape = self.y.check_shape()
|
|
881
|
+
|
|
882
|
+
if len(xp_shape) != 1:
|
|
883
|
+
raise ValueError(f"Bilerp xp must be 1D, got shape {xp_shape}")
|
|
884
|
+
if len(yp_shape) != 1:
|
|
885
|
+
raise ValueError(f"Bilerp yp must be 1D, got shape {yp_shape}")
|
|
886
|
+
if len(fp_shape) != 2:
|
|
887
|
+
raise ValueError(f"Bilerp fp must be 2D, got shape {fp_shape}")
|
|
888
|
+
if fp_shape != (xp_shape[0], yp_shape[0]):
|
|
889
|
+
raise ValueError(
|
|
890
|
+
f"Bilerp fp shape {fp_shape} must match (len(xp), len(yp)) = "
|
|
891
|
+
f"({xp_shape[0]}, {yp_shape[0]})"
|
|
892
|
+
)
|
|
893
|
+
if x_shape != ():
|
|
894
|
+
raise ValueError(f"Bilerp x must be scalar, got shape {x_shape}")
|
|
895
|
+
if y_shape != ():
|
|
896
|
+
raise ValueError(f"Bilerp y must be scalar, got shape {y_shape}")
|
|
897
|
+
|
|
898
|
+
return ()
|
|
899
|
+
|
|
900
|
+
def __repr__(self):
|
|
901
|
+
return f"bilerp({self.x!r}, {self.y!r}, {self.xp!r}, {self.yp!r}, {self.fp!r})"
|
|
@@ -134,6 +134,7 @@ from openscvx.symbolic.expr import (
|
|
|
134
134
|
CTCS,
|
|
135
135
|
Abs,
|
|
136
136
|
Add,
|
|
137
|
+
Bilerp,
|
|
137
138
|
Block,
|
|
138
139
|
Concat,
|
|
139
140
|
Constant,
|
|
@@ -147,6 +148,7 @@ from openscvx.symbolic.expr import (
|
|
|
147
148
|
Huber,
|
|
148
149
|
Index,
|
|
149
150
|
Inequality,
|
|
151
|
+
Linterp,
|
|
150
152
|
Log,
|
|
151
153
|
LogSumExp,
|
|
152
154
|
MatMul,
|
|
@@ -170,6 +172,7 @@ from openscvx.symbolic.expr import (
|
|
|
170
172
|
Vstack,
|
|
171
173
|
)
|
|
172
174
|
from openscvx.symbolic.expr.control import Control
|
|
175
|
+
from openscvx.symbolic.expr.linalg import Inv
|
|
173
176
|
from openscvx.symbolic.expr.state import State
|
|
174
177
|
|
|
175
178
|
_CVXPY_VISITORS: Dict[Type[Expr], Callable] = {}
|
|
@@ -1121,6 +1124,34 @@ class CvxpyLowerer:
|
|
|
1121
1124
|
operand = self.lower(node.operand)
|
|
1122
1125
|
return operand.T
|
|
1123
1126
|
|
|
1127
|
+
@visitor(Inv)
|
|
1128
|
+
def _visit_inv(self, node: Inv) -> cp.Expression:
|
|
1129
|
+
"""Raise NotImplementedError for matrix inverse.
|
|
1130
|
+
|
|
1131
|
+
Matrix inverse is not DCP-compliant in CVXPy as it is neither convex
|
|
1132
|
+
nor concave for variable matrices.
|
|
1133
|
+
|
|
1134
|
+
Args:
|
|
1135
|
+
node: Inv expression node
|
|
1136
|
+
|
|
1137
|
+
Raises:
|
|
1138
|
+
NotImplementedError: Always raised since matrix inverse is not DCP-compliant
|
|
1139
|
+
|
|
1140
|
+
Note:
|
|
1141
|
+
For optimization problems requiring matrix inverse:
|
|
1142
|
+
- If the matrix is constant/parameter, compute the inverse numerically
|
|
1143
|
+
before passing to CVXPy
|
|
1144
|
+
- Handle matrix inverse in the JAX dynamics/constraint layer instead
|
|
1145
|
+
- Consider reformulating the problem to avoid explicit matrix inverse
|
|
1146
|
+
"""
|
|
1147
|
+
raise NotImplementedError(
|
|
1148
|
+
"Matrix inverse (Inv) is not DCP-compliant in CVXPy. "
|
|
1149
|
+
"inv(X) is neither convex nor concave for variable matrices. "
|
|
1150
|
+
"Consider: (1) computing the inverse numerically if the matrix is constant, "
|
|
1151
|
+
"(2) handling this in the JAX layer instead, or "
|
|
1152
|
+
"(3) reformulating the problem to avoid explicit matrix inverse."
|
|
1153
|
+
)
|
|
1154
|
+
|
|
1124
1155
|
@visitor(Power)
|
|
1125
1156
|
def _visit_power(self, node: Power) -> cp.Expression:
|
|
1126
1157
|
"""Lower element-wise power (base**exponent) to CVXPy expression.
|
|
@@ -1238,6 +1269,37 @@ class CvxpyLowerer:
|
|
|
1238
1269
|
block_exprs = [[self.lower(block) for block in row] for row in node.blocks]
|
|
1239
1270
|
return cp.bmat(block_exprs)
|
|
1240
1271
|
|
|
1272
|
+
@visitor(Linterp)
|
|
1273
|
+
def _visit_linterp(self, node: Linterp) -> cp.Expression:
|
|
1274
|
+
"""Raise NotImplementedError for linear interpolation.
|
|
1275
|
+
|
|
1276
|
+
Linear interpolation (Linterp) is not DCP-compliant in CVXPy as it
|
|
1277
|
+
represents a piecewise-linear function that is neither convex nor
|
|
1278
|
+
concave in general.
|
|
1279
|
+
|
|
1280
|
+
Args:
|
|
1281
|
+
node: Linterp expression node
|
|
1282
|
+
|
|
1283
|
+
Raises:
|
|
1284
|
+
NotImplementedError: Always raised since Linterp is not DCP-compliant
|
|
1285
|
+
"""
|
|
1286
|
+
raise NotImplementedError("Linear interpolation (Linterp) is not DCP-compliant in CVXPy.")
|
|
1287
|
+
|
|
1288
|
+
@visitor(Bilerp)
|
|
1289
|
+
def _visit_bilerp(self, node: Bilerp) -> cp.Expression:
|
|
1290
|
+
"""Raise NotImplementedError for bilinear interpolation.
|
|
1291
|
+
|
|
1292
|
+
Bilinear interpolation (Bilerp) is not DCP-compliant in CVXPy as it
|
|
1293
|
+
represents a nonlinear function that is neither convex nor concave.
|
|
1294
|
+
|
|
1295
|
+
Args:
|
|
1296
|
+
node: Bilerp expression node
|
|
1297
|
+
|
|
1298
|
+
Raises:
|
|
1299
|
+
NotImplementedError: Always raised since Bilerp is not DCP-compliant
|
|
1300
|
+
"""
|
|
1301
|
+
raise NotImplementedError("Bilinear interpolation (Bilerp) is not DCP-compliant in CVXPy.")
|
|
1302
|
+
|
|
1241
1303
|
|
|
1242
1304
|
def lower_to_cvxpy(expr: Expr, variable_map: Dict[str, cp.Expression] = None) -> cp.Expression:
|
|
1243
1305
|
"""Lower symbolic expression to CVXPy expression or constraint.
|
|
@@ -121,6 +121,7 @@ from openscvx.symbolic.expr import (
|
|
|
121
121
|
Add,
|
|
122
122
|
Adjoint,
|
|
123
123
|
AdjointDual,
|
|
124
|
+
Bilerp,
|
|
124
125
|
Block,
|
|
125
126
|
Concat,
|
|
126
127
|
Constant,
|
|
@@ -136,6 +137,7 @@ from openscvx.symbolic.expr import (
|
|
|
136
137
|
Huber,
|
|
137
138
|
Index,
|
|
138
139
|
Inequality,
|
|
140
|
+
Linterp,
|
|
139
141
|
Log,
|
|
140
142
|
LogSumExp,
|
|
141
143
|
MatMul,
|
|
@@ -171,6 +173,7 @@ from openscvx.symbolic.expr.lie import (
|
|
|
171
173
|
SO3Exp,
|
|
172
174
|
SO3Log,
|
|
173
175
|
)
|
|
176
|
+
from openscvx.symbolic.expr.linalg import Inv
|
|
174
177
|
from openscvx.symbolic.expr.state import State
|
|
175
178
|
|
|
176
179
|
_JAX_VISITORS: Dict[Type[Expr], Callable] = {}
|
|
@@ -1227,6 +1230,22 @@ class JaxLowerer:
|
|
|
1227
1230
|
f = self.lower(node.operand)
|
|
1228
1231
|
return lambda x, u, node, params: jnp.diag(f(x, u, node, params))
|
|
1229
1232
|
|
|
1233
|
+
@visitor(Inv)
|
|
1234
|
+
def _visit_inv(self, node: Inv):
|
|
1235
|
+
"""Lower matrix inverse to JAX function.
|
|
1236
|
+
|
|
1237
|
+
Computes the inverse of a square matrix using jnp.linalg.inv.
|
|
1238
|
+
Supports batched inputs with shape (..., M, M).
|
|
1239
|
+
|
|
1240
|
+
Args:
|
|
1241
|
+
node: Inv expression node
|
|
1242
|
+
|
|
1243
|
+
Returns:
|
|
1244
|
+
Function (x, u, node, params) -> inverse of operand matrix
|
|
1245
|
+
"""
|
|
1246
|
+
f = self.lower(node.operand)
|
|
1247
|
+
return lambda x, u, node, params: jnp.linalg.inv(f(x, u, node, params))
|
|
1248
|
+
|
|
1230
1249
|
@visitor(Or)
|
|
1231
1250
|
def _visit_or(self, node: Or):
|
|
1232
1251
|
"""Lower STL disjunction (Or) to JAX using STLJax library.
|
|
@@ -1451,3 +1470,77 @@ class JaxLowerer:
|
|
|
1451
1470
|
return jax.vmap(inner, in_axes=axis)(data)
|
|
1452
1471
|
|
|
1453
1472
|
return vmapped_fn
|
|
1473
|
+
|
|
1474
|
+
@visitor(Linterp)
|
|
1475
|
+
def _visit_linterp(self, node: Linterp):
|
|
1476
|
+
"""Lower 1D linear interpolation to JAX function.
|
|
1477
|
+
|
|
1478
|
+
Uses jnp.interp which performs piecewise linear interpolation.
|
|
1479
|
+
For query points outside the data range, boundary values are returned.
|
|
1480
|
+
|
|
1481
|
+
Args:
|
|
1482
|
+
node: Linterp expression node with xp, fp, and x
|
|
1483
|
+
|
|
1484
|
+
Returns:
|
|
1485
|
+
Function (x, u, node, params) -> interpolated value(s)
|
|
1486
|
+
|
|
1487
|
+
Note:
|
|
1488
|
+
The xp and fp arrays are typically constants (tabulated data),
|
|
1489
|
+
while x is typically a symbolic expression (state or derived value).
|
|
1490
|
+
jnp.interp is differentiable through JAX's autodiff.
|
|
1491
|
+
"""
|
|
1492
|
+
f_xp = self.lower(node.xp)
|
|
1493
|
+
f_fp = self.lower(node.fp)
|
|
1494
|
+
f_x = self.lower(node.x)
|
|
1495
|
+
|
|
1496
|
+
def linterp_fn(x, u, node_idx, params):
|
|
1497
|
+
xp_val = f_xp(x, u, node_idx, params)
|
|
1498
|
+
fp_val = f_fp(x, u, node_idx, params)
|
|
1499
|
+
x_val = f_x(x, u, node_idx, params)
|
|
1500
|
+
return jnp.interp(x_val, xp_val, fp_val)
|
|
1501
|
+
|
|
1502
|
+
return linterp_fn
|
|
1503
|
+
|
|
1504
|
+
@visitor(Bilerp)
|
|
1505
|
+
def _visit_bilerp(self, node: Bilerp):
|
|
1506
|
+
"""Lower 2D bilinear interpolation to JAX function.
|
|
1507
|
+
|
|
1508
|
+
Uses jax.scipy.ndimage.map_coordinates for bilinear interpolation on a
|
|
1509
|
+
regular grid. For query points outside the grid, boundary values are
|
|
1510
|
+
returned (clamping via mode='nearest').
|
|
1511
|
+
|
|
1512
|
+
Args:
|
|
1513
|
+
node: Bilerp expression node with x, y, xp, yp, fp
|
|
1514
|
+
|
|
1515
|
+
Returns:
|
|
1516
|
+
Function (x, u, node, params) -> interpolated scalar value
|
|
1517
|
+
|
|
1518
|
+
Note:
|
|
1519
|
+
The grid arrays (xp, yp, fp) are typically constants (tabulated data),
|
|
1520
|
+
while x and y are symbolic expressions (state or derived values).
|
|
1521
|
+
Physical coordinates are converted to fractional indices before
|
|
1522
|
+
interpolation. The implementation is differentiable through JAX's autodiff.
|
|
1523
|
+
"""
|
|
1524
|
+
f_x = self.lower(node.x)
|
|
1525
|
+
f_y = self.lower(node.y)
|
|
1526
|
+
f_xp = self.lower(node.xp)
|
|
1527
|
+
f_yp = self.lower(node.yp)
|
|
1528
|
+
f_fp = self.lower(node.fp)
|
|
1529
|
+
|
|
1530
|
+
def bilerp_fn(x, u, node_idx, params):
|
|
1531
|
+
x_val = f_x(x, u, node_idx, params)
|
|
1532
|
+
y_val = f_y(x, u, node_idx, params)
|
|
1533
|
+
xp_val = f_xp(x, u, node_idx, params)
|
|
1534
|
+
yp_val = f_yp(x, u, node_idx, params)
|
|
1535
|
+
fp_val = f_fp(x, u, node_idx, params)
|
|
1536
|
+
|
|
1537
|
+
# Convert physical coordinates to fractional indices
|
|
1538
|
+
# jnp.interp maps physical coords to index space (handles non-uniform grids)
|
|
1539
|
+
idx_x = jnp.interp(x_val, xp_val, jnp.arange(len(xp_val)))
|
|
1540
|
+
idx_y = jnp.interp(y_val, yp_val, jnp.arange(len(yp_val)))
|
|
1541
|
+
|
|
1542
|
+
# Use map_coordinates with order=1 (bilinear) and mode='nearest' (clamp)
|
|
1543
|
+
coords = jnp.array([[idx_x], [idx_y]])
|
|
1544
|
+
return jax.scipy.ndimage.map_coordinates(fp_val, coords, order=1, mode="nearest")[0]
|
|
1545
|
+
|
|
1546
|
+
return bilerp_fn
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.3.2.
|
|
3
|
+
Version: 0.3.2.dev210
|
|
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
|