openscvx 0.3.2.dev215__tar.gz → 0.3.2.dev228__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.dev215/openscvx.egg-info → openscvx-0.3.2.dev228}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/abstract/3DoF_pdg.py +0 -3
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/abstract/brachistochrone.py +0 -2
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/car/dubins_car.py +0 -2
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/car/dubins_car_disjoint.py +0 -1
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/car/dubins_car_stljax.py +0 -3
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/cinema_vp.py +0 -1
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/dr_double_integrator.py +0 -2
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/drone_racing.py +0 -4
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance.py +0 -6
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance_nodal.py +0 -6
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance_realtime_base.py +0 -7
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/spacecraft/proxops_cw.py +0 -1
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/_version.py +3 -3
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/problem.py +4 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/builder.py +15 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/preprocessing.py +82 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/utils/caching.py +37 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/test_hashing.py +39 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/test_preprocessing.py +175 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/test_brachistochrone.py +2 -11
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/test_expert.py +2 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/docs.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/lint.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/release.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/.gitignore +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/CONTRIBUTING.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/LICENSE +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/README.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Overview/constraint_reformulation.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Overview/control_parameterization.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Overview/discretization.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Overview/ocp.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Overview/scvx.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Overview/time_dilation.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/advanced_problem_setup.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/api.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/api_constraints.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/api_control.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/api_integrators.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/api_state.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/api_trajoptproblem.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/api_variable.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/basic_problem_setup.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/tutorial_6dof_los_guidance.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/tutorial_6dof_obstacle_avoidance.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/Usage/tutorials.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/favicon.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/citation.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/examples.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/getting-started.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/index.md +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/arm/three_link_arm.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/plotting.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/plotting_viser.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/figures/video_preview.png +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/home.html +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/main.html +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/mkdocs.yml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/algorithms/autotuning.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/config.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/discretization/discretization.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/expert/byof.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/expert/validation.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/solvers/cvxpy.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/lowerers/cvxpy.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/lowerers/jax.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/time.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/utils/cache.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/utils/printing.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx/utils/utils.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx.egg-info/SOURCES.txt +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/pyproject.toml +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/setup.cfg +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/test_discretization.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/test_examples.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/test_integrators.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/tests/test_plotting.py +0 -0
- {openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/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.dev228
|
|
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
|
|
@@ -38,14 +38,12 @@ position.max = np.array([3000, 3000, 3000])
|
|
|
38
38
|
position.min = np.array([-3000, -3000, 0])
|
|
39
39
|
position.initial = np.array([2000, 0, 1500])
|
|
40
40
|
position.final = np.array([0, 0, 0])
|
|
41
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
42
41
|
|
|
43
42
|
velocity = ox.State("velocity", shape=(3,)) # 3D velocity [vx, vy, vz]
|
|
44
43
|
velocity.max = np.array([v_max, v_max, v_max])
|
|
45
44
|
velocity.min = np.array([-v_max, -v_max, -v_max])
|
|
46
45
|
velocity.initial = np.array([80, 30, -75])
|
|
47
46
|
velocity.final = np.array([0, 0, 0])
|
|
48
|
-
velocity.guess = np.linspace(velocity.initial, velocity.final, n)
|
|
49
47
|
|
|
50
48
|
mass = ox.State("mass", shape=(1,)) # Vehicle mass
|
|
51
49
|
mass.max = np.array([1905])
|
|
@@ -54,7 +52,6 @@ mass.initial = np.array([1905])
|
|
|
54
52
|
mass.final = [("maximize", 1690)]
|
|
55
53
|
mass.scaling_min = np.array([1690])
|
|
56
54
|
# mass.scaling_max = np.array([1700])
|
|
57
|
-
mass.guess = np.linspace(mass.initial, 1690, n).reshape(-1, 1)
|
|
58
55
|
|
|
59
56
|
# Define control
|
|
60
57
|
thrust = ox.Control("thrust", shape=(3,)) # Thrust force vector [Tx, Ty, Tz]
|
|
@@ -38,14 +38,12 @@ position.max = np.array([10.0, 10.0])
|
|
|
38
38
|
position.min = np.array([0.0, 0.0])
|
|
39
39
|
position.initial = np.array([0.0, 10.0])
|
|
40
40
|
position.final = [10.0, 5.0]
|
|
41
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
42
41
|
|
|
43
42
|
velocity = ox.State("velocity", shape=(1,)) # Scalar speed
|
|
44
43
|
velocity.max = np.array([10.0])
|
|
45
44
|
velocity.min = np.array([0.0])
|
|
46
45
|
velocity.initial = np.array([0.0])
|
|
47
46
|
velocity.final = [("free", 10.0)]
|
|
48
|
-
velocity.guess = np.linspace(0.0, 10.0, n).reshape(-1, 1)
|
|
49
47
|
|
|
50
48
|
# Define control
|
|
51
49
|
theta = ox.Control("theta", shape=(1,)) # Angle from vertical
|
|
@@ -35,14 +35,12 @@ position.min = np.array([-5.0, -5.0])
|
|
|
35
35
|
position.max = np.array([5.0, 5.0])
|
|
36
36
|
position.initial = np.array([0, -2])
|
|
37
37
|
position.final = np.array([0, 2])
|
|
38
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
39
38
|
|
|
40
39
|
theta = ox.State("theta", shape=(1,)) # Heading angle
|
|
41
40
|
theta.min = np.array([-2 * jnp.pi])
|
|
42
41
|
theta.max = np.array([2 * jnp.pi])
|
|
43
42
|
theta.initial = np.array([0])
|
|
44
43
|
theta.final = [ox.Free(0)]
|
|
45
|
-
theta.guess = np.zeros((n, 1))
|
|
46
44
|
|
|
47
45
|
# Define control components
|
|
48
46
|
speed = ox.Control("speed", shape=(1,)) # Forward speed
|
|
@@ -41,7 +41,6 @@ theta.min = np.array([-2 * jnp.pi])
|
|
|
41
41
|
theta.max = np.array([2 * jnp.pi])
|
|
42
42
|
theta.initial = np.array([0])
|
|
43
43
|
theta.final = [("free", 0)]
|
|
44
|
-
theta.guess = np.zeros((n, 1))
|
|
45
44
|
|
|
46
45
|
# Define control components
|
|
47
46
|
speed = ox.Control("speed", shape=(1,)) # Forward speed
|
|
@@ -37,14 +37,12 @@ position.min = np.array([-5.0, -5.0])
|
|
|
37
37
|
position.max = np.array([5.0, 5.0])
|
|
38
38
|
position.initial = np.array([0, -2])
|
|
39
39
|
position.final = np.array([0, 2])
|
|
40
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
41
40
|
|
|
42
41
|
theta = ox.State("theta", shape=(1,)) # Heading angle
|
|
43
42
|
theta.min = np.array([-2 * jnp.pi])
|
|
44
43
|
theta.max = np.array([2 * jnp.pi])
|
|
45
44
|
theta.initial = np.array([0])
|
|
46
45
|
theta.final = [("free", 0)]
|
|
47
|
-
theta.guess = np.zeros((n, 1))
|
|
48
46
|
|
|
49
47
|
# Define control components
|
|
50
48
|
speed = ox.Control("speed", shape=(1,)) # Forward speed
|
|
@@ -63,7 +61,6 @@ time.max = np.array([10])
|
|
|
63
61
|
time.min = np.array([0.0])
|
|
64
62
|
time.initial = np.array([0.0])
|
|
65
63
|
time.final = [ox.Minimize(total_time)]
|
|
66
|
-
time.guess = np.linspace(0.0, total_time, n).reshape(-1, 1)
|
|
67
64
|
|
|
68
65
|
|
|
69
66
|
# Define list of all states and controls
|
|
@@ -70,7 +70,6 @@ time.max = np.array([total_time])
|
|
|
70
70
|
time.min = np.array([0.0])
|
|
71
71
|
time.initial = np.array([0.0])
|
|
72
72
|
time.final = np.array([total_time])
|
|
73
|
-
time.guess = np.linspace(0.0, total_time, n).reshape(-1, 1)
|
|
74
73
|
|
|
75
74
|
# Define control components
|
|
76
75
|
thrust_force = ox.Control("thrust_force", shape=(3,)) # Thrust forces [fx, fy, fz]
|
|
@@ -38,14 +38,12 @@ position.max = np.array([200.0, 100, 50])
|
|
|
38
38
|
position.min = np.array([-200.0, -100, 15])
|
|
39
39
|
position.initial = np.array([10.0, 0, 20])
|
|
40
40
|
position.final = [10.0, 0, 20]
|
|
41
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
42
41
|
|
|
43
42
|
velocity = ox.State("velocity", shape=(3,)) # 3D velocity [vx, vy, vz]
|
|
44
43
|
velocity.max = np.array([100, 100, 100])
|
|
45
44
|
velocity.min = np.array([-100, -100, -100])
|
|
46
45
|
velocity.initial = np.array([0, 0, 0])
|
|
47
46
|
velocity.final = [("free", 0), ("free", 0), ("free", 0)]
|
|
48
|
-
velocity.guess = np.linspace(velocity.initial, [0, 0, 0], n)
|
|
49
47
|
|
|
50
48
|
# Define control
|
|
51
49
|
force = ox.Control("force", shape=(3,)) # Control forces [fx, fy, fz]
|
|
@@ -37,28 +37,24 @@ position.max = np.array([200.0, 100, 200])
|
|
|
37
37
|
position.min = np.array([-200.0, -100, 15])
|
|
38
38
|
position.initial = np.array([10.0, 0, 20])
|
|
39
39
|
position.final = [10.0, 0, 20]
|
|
40
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
41
40
|
|
|
42
41
|
velocity = ox.State("velocity", shape=(3,)) # 3D velocity [vx, vy, vz]
|
|
43
42
|
velocity.max = np.array([100, 100, 100])
|
|
44
43
|
velocity.min = np.array([-100, -100, -100])
|
|
45
44
|
velocity.initial = np.array([0, 0, 0])
|
|
46
45
|
velocity.final = [("free", 0), ("free", 0), ("free", 0)]
|
|
47
|
-
velocity.guess = np.linspace(velocity.initial, [0, 0, 0], n)
|
|
48
46
|
|
|
49
47
|
attitude = ox.State("attitude", shape=(4,)) # Quaternion [qw, qx, qy, qz]
|
|
50
48
|
attitude.max = np.array([1, 1, 1, 1])
|
|
51
49
|
attitude.min = np.array([-1, -1, -1, -1])
|
|
52
50
|
attitude.initial = [("free", 1.0), ("free", 0), ("free", 0), ("free", 0)]
|
|
53
51
|
attitude.final = [("free", 1), ("free", 0), ("free", 0), ("free", 0)]
|
|
54
|
-
attitude.guess = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
|
|
55
52
|
|
|
56
53
|
angular_velocity = ox.State("angular_velocity", shape=(3,)) # Angular velocity [wx, wy, wz]
|
|
57
54
|
angular_velocity.max = np.array([10, 10, 10])
|
|
58
55
|
angular_velocity.min = np.array([-10, -10, -10])
|
|
59
56
|
angular_velocity.initial = [("free", 0), ("free", 0), ("free", 0)]
|
|
60
57
|
angular_velocity.final = [("free", 0), ("free", 0), ("free", 0)]
|
|
61
|
-
angular_velocity.guess = np.zeros((n, 3))
|
|
62
58
|
|
|
63
59
|
# Define control components
|
|
64
60
|
thrust_force = ox.Control("thrust_force", shape=(3,)) # Thrust forces [fx, fy, fz]
|
|
@@ -137,12 +137,6 @@ for center, A in zip(obstacle_centers, A_obs):
|
|
|
137
137
|
obstacle_constraint = ox.ctcs(1.0 <= diff.T @ A_const @ diff)
|
|
138
138
|
constraints.append(obstacle_constraint)
|
|
139
139
|
|
|
140
|
-
# Set initial guesses
|
|
141
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
142
|
-
velocity.guess = np.linspace(velocity.initial, [0, 0, 0], n)
|
|
143
|
-
attitude.guess = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
|
|
144
|
-
angular_velocity.guess = np.zeros((n, 3))
|
|
145
|
-
|
|
146
140
|
|
|
147
141
|
time = ox.Time(
|
|
148
142
|
initial=0.0,
|
|
@@ -136,12 +136,6 @@ for center, A in zip(obstacle_centers, A_obs):
|
|
|
136
136
|
obstacle_constraint = 1.0 <= diff.T @ A_const @ diff
|
|
137
137
|
constraints.append(obstacle_constraint)
|
|
138
138
|
|
|
139
|
-
# Set initial guesses
|
|
140
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
141
|
-
velocity.guess = np.linspace(velocity.initial, [0, 0, 0], n)
|
|
142
|
-
attitude.guess = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
|
|
143
|
-
angular_velocity.guess = np.zeros((n, 3))
|
|
144
|
-
|
|
145
139
|
time = ox.Time(
|
|
146
140
|
initial=0.0,
|
|
147
141
|
final=("minimize", total_time),
|
{openscvx-0.3.2.dev215 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance_realtime_base.py
RENAMED
|
@@ -137,13 +137,6 @@ for center, A in zip(obstacle_centers, A_obs):
|
|
|
137
137
|
obstacle_constraint = ox.ctcs(1.0 <= diff.T @ A_const @ diff)
|
|
138
138
|
constraints.append(obstacle_constraint)
|
|
139
139
|
|
|
140
|
-
# Set initial guesses
|
|
141
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
142
|
-
velocity.guess = np.linspace(velocity.initial, [0, 0, 0], n)
|
|
143
|
-
attitude.guess = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
|
|
144
|
-
angular_velocity.guess = np.zeros((n, 3))
|
|
145
|
-
|
|
146
|
-
|
|
147
140
|
time = ox.Time(
|
|
148
141
|
initial=0.0,
|
|
149
142
|
final=("minimize", total_time),
|
|
@@ -54,7 +54,6 @@ position.max = np.array([100.0, 100.0, 100.0])
|
|
|
54
54
|
position.min = np.array([-100.0, -100.0, -100.0])
|
|
55
55
|
position.initial = np.array([0.0, -100.0, 0.0]) # Start 100m behind target (V-bar position)
|
|
56
56
|
position.final = np.array([0.0, 0.0, 0.0]) # Dock at origin
|
|
57
|
-
position.guess = np.linspace(position.initial, position.final, n_nodes)
|
|
58
57
|
|
|
59
58
|
# Velocity in CW frame [vx, vy, vz] in m/s
|
|
60
59
|
velocity = ox.State("velocity", shape=(3,))
|
|
@@ -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.dev228'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 2, 'dev228')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g44572a46d'
|
|
@@ -164,6 +164,9 @@ class Problem:
|
|
|
164
164
|
|
|
165
165
|
validate_byof(byof, self.symbolic.states, n_x, n_u, N)
|
|
166
166
|
|
|
167
|
+
# Store byof for cache hashing
|
|
168
|
+
self._byof = byof
|
|
169
|
+
|
|
167
170
|
# Lower to JAX and CVXPy (byof handling happens inside lower_symbolic_problem)
|
|
168
171
|
self._lowered: LoweredProblem = lower_symbolic_problem(self.symbolic, byof=byof)
|
|
169
172
|
|
|
@@ -458,6 +461,7 @@ class Problem:
|
|
|
458
461
|
self.symbolic,
|
|
459
462
|
dt=self.settings.prp.dt,
|
|
460
463
|
total_time=self.settings.sim.total_time,
|
|
464
|
+
byof=self._byof,
|
|
461
465
|
)
|
|
462
466
|
|
|
463
467
|
# Compile the discretization solver
|
|
@@ -47,11 +47,15 @@ from openscvx.symbolic.expr.state import State
|
|
|
47
47
|
from openscvx.symbolic.preprocessing import (
|
|
48
48
|
collect_and_assign_slices,
|
|
49
49
|
convert_dynamics_dict_to_expr,
|
|
50
|
+
fill_default_guesses,
|
|
50
51
|
validate_and_normalize_constraint_nodes,
|
|
52
|
+
validate_boundary_conditions,
|
|
53
|
+
validate_bounds,
|
|
51
54
|
validate_constraints_at_root,
|
|
52
55
|
validate_dynamics_dict,
|
|
53
56
|
validate_dynamics_dict_dimensions,
|
|
54
57
|
validate_dynamics_dimension,
|
|
58
|
+
validate_guesses,
|
|
55
59
|
validate_shapes,
|
|
56
60
|
validate_time_parameters,
|
|
57
61
|
validate_variable_names,
|
|
@@ -185,6 +189,17 @@ def preprocess_symbolic_problem(
|
|
|
185
189
|
print([s.name for s in problem.states_prop])
|
|
186
190
|
"""
|
|
187
191
|
|
|
192
|
+
# Validate user-provided variables have required attributes
|
|
193
|
+
validate_boundary_conditions(states)
|
|
194
|
+
validate_bounds(states + controls)
|
|
195
|
+
|
|
196
|
+
# Fill in default guesses for user-provided states
|
|
197
|
+
# (augmented states get their guesses set by augmentation code)
|
|
198
|
+
fill_default_guesses(states, N)
|
|
199
|
+
|
|
200
|
+
# Validate that all user-provided variables have guesses
|
|
201
|
+
validate_guesses(states + controls)
|
|
202
|
+
|
|
188
203
|
# ==================== PHASE 1: Time Handling & Validation ====================
|
|
189
204
|
|
|
190
205
|
# Validate time handling approach and get processed parameters
|
|
@@ -54,6 +54,7 @@ from openscvx.symbolic.expr import (
|
|
|
54
54
|
Expr,
|
|
55
55
|
NodalConstraint,
|
|
56
56
|
State,
|
|
57
|
+
Variable,
|
|
57
58
|
traverse,
|
|
58
59
|
)
|
|
59
60
|
|
|
@@ -755,3 +756,84 @@ def convert_dynamics_dict_to_expr(
|
|
|
755
756
|
dynamics_concat = Concat(*dynamics_exprs)
|
|
756
757
|
|
|
757
758
|
return dynamics_converted, dynamics_concat
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
def fill_default_guesses(states: List[State], N: int) -> None:
|
|
762
|
+
"""Fill in default linspace guesses for states with guess=None.
|
|
763
|
+
|
|
764
|
+
For states with both initial and final conditions set, generates a linear
|
|
765
|
+
interpolation from initial to final values.
|
|
766
|
+
|
|
767
|
+
This function modifies states in-place.
|
|
768
|
+
|
|
769
|
+
Args:
|
|
770
|
+
states: List of State objects to fill guesses for
|
|
771
|
+
N: Number of discretization nodes
|
|
772
|
+
"""
|
|
773
|
+
for state in states:
|
|
774
|
+
if state.guess is None and state.initial is not None and state.final is not None:
|
|
775
|
+
# state.initial and state.final are already numpy arrays of values
|
|
776
|
+
# (the setter handles parsing tuples like ("free", value))
|
|
777
|
+
state.guess = np.linspace(state.initial, state.final, N)
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
def validate_boundary_conditions(states: List[State]) -> None:
|
|
781
|
+
"""Validate that all states have initial and final boundary conditions set.
|
|
782
|
+
|
|
783
|
+
Args:
|
|
784
|
+
states: List of State objects to validate
|
|
785
|
+
|
|
786
|
+
Raises:
|
|
787
|
+
ValueError: If any state is missing initial or final conditions
|
|
788
|
+
"""
|
|
789
|
+
for state in states:
|
|
790
|
+
if state.initial is None:
|
|
791
|
+
raise ValueError(
|
|
792
|
+
f"State '{state.name}' is missing initial condition. "
|
|
793
|
+
f"Please set {state.name}.initial"
|
|
794
|
+
)
|
|
795
|
+
if state.final is None:
|
|
796
|
+
raise ValueError(
|
|
797
|
+
f"State '{state.name}' is missing final condition. Please set {state.name}.final"
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
def validate_bounds(variables: List[Variable]) -> None:
|
|
802
|
+
"""Validate that all variables have min and max bounds set.
|
|
803
|
+
|
|
804
|
+
Args:
|
|
805
|
+
variables: List of Variable objects (State or Control) to validate
|
|
806
|
+
|
|
807
|
+
Raises:
|
|
808
|
+
ValueError: If any variable is missing min or max bounds
|
|
809
|
+
"""
|
|
810
|
+
for var in variables:
|
|
811
|
+
if var.min is None:
|
|
812
|
+
raise ValueError(
|
|
813
|
+
f"Variable '{var.name}' is missing min bound. Please set {var.name}.min"
|
|
814
|
+
)
|
|
815
|
+
if var.max is None:
|
|
816
|
+
raise ValueError(
|
|
817
|
+
f"Variable '{var.name}' is missing max bound. Please set {var.name}.max"
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
def validate_guesses(variables: List[Variable]) -> None:
|
|
822
|
+
"""Validate that all variables have initial guesses set.
|
|
823
|
+
|
|
824
|
+
Args:
|
|
825
|
+
variables: List of Variable objects (State or Control) to validate
|
|
826
|
+
|
|
827
|
+
Raises:
|
|
828
|
+
ValueError: If any variable is missing a guess
|
|
829
|
+
"""
|
|
830
|
+
for var in variables:
|
|
831
|
+
if var.guess is None:
|
|
832
|
+
if isinstance(var, Control):
|
|
833
|
+
raise ValueError(
|
|
834
|
+
f"Control '{var.name}' is missing initial guess. "
|
|
835
|
+
f"Please set {var.name}.guess (controls require explicit guesses)"
|
|
836
|
+
)
|
|
837
|
+
raise ValueError(
|
|
838
|
+
f"State '{var.name}' is missing initial guess. Please set {var.name}.guess"
|
|
839
|
+
)
|
|
@@ -9,14 +9,45 @@ from jax import export
|
|
|
9
9
|
from openscvx.utils.cache import get_cache_dir
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
+
from openscvx.expert.byof import ByofSpec
|
|
12
13
|
from openscvx.symbolic.problem import SymbolicProblem
|
|
13
14
|
|
|
14
15
|
|
|
16
|
+
def _hash_byof(byof: Optional["ByofSpec"]) -> bytes:
|
|
17
|
+
"""Hash BYOF functions by their bytecode and constants.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
byof: Optional ByofSpec containing raw JAX functions
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Concatenated bytecode and constants of all functions, or empty bytes if no byof
|
|
24
|
+
"""
|
|
25
|
+
if not byof:
|
|
26
|
+
return b""
|
|
27
|
+
|
|
28
|
+
codes = []
|
|
29
|
+
for f in byof.get("dynamics", {}).values():
|
|
30
|
+
codes.append(f.__code__.co_code)
|
|
31
|
+
codes.append(repr(f.__code__.co_consts).encode())
|
|
32
|
+
for c in byof.get("nodal_constraints", []):
|
|
33
|
+
codes.append(c["constraint_fn"].__code__.co_code)
|
|
34
|
+
codes.append(repr(c["constraint_fn"].__code__.co_consts).encode())
|
|
35
|
+
for f in byof.get("cross_nodal_constraints", []):
|
|
36
|
+
codes.append(f.__code__.co_code)
|
|
37
|
+
codes.append(repr(f.__code__.co_consts).encode())
|
|
38
|
+
for c in byof.get("ctcs_constraints", []):
|
|
39
|
+
codes.append(c["constraint_fn"].__code__.co_code)
|
|
40
|
+
codes.append(repr(c["constraint_fn"].__code__.co_consts).encode())
|
|
41
|
+
|
|
42
|
+
return b"".join(codes)
|
|
43
|
+
|
|
44
|
+
|
|
15
45
|
def get_solver_cache_paths(
|
|
16
46
|
symbolic_problem: "SymbolicProblem",
|
|
17
47
|
dt: float,
|
|
18
48
|
total_time: float,
|
|
19
49
|
cache_dir: Optional[Path] = None,
|
|
50
|
+
byof: Optional["ByofSpec"] = None,
|
|
20
51
|
) -> Tuple[Path, Path]:
|
|
21
52
|
"""Generate cache file paths using symbolic AST hashing.
|
|
22
53
|
|
|
@@ -30,6 +61,8 @@ def get_solver_cache_paths(
|
|
|
30
61
|
total_time: Total simulation time
|
|
31
62
|
cache_dir: Directory to store cached solvers. If None, uses the default
|
|
32
63
|
cache directory (see :func:`openscvx.get_cache_dir`).
|
|
64
|
+
byof: Optional ByofSpec containing raw JAX functions. If provided,
|
|
65
|
+
function bytecode is included in the hash.
|
|
33
66
|
|
|
34
67
|
Returns:
|
|
35
68
|
Tuple of (discretization_solver_path, propagation_solver_path)
|
|
@@ -44,6 +77,10 @@ def get_solver_cache_paths(
|
|
|
44
77
|
final_hasher.update(problem_hash.encode())
|
|
45
78
|
final_hasher.update(f"dt:{dt}".encode())
|
|
46
79
|
final_hasher.update(f"total_time:{total_time}".encode())
|
|
80
|
+
|
|
81
|
+
# Include BYOF function bytecode in the hash
|
|
82
|
+
final_hasher.update(_hash_byof(byof))
|
|
83
|
+
|
|
47
84
|
final_hash = final_hasher.hexdigest()[:32]
|
|
48
85
|
|
|
49
86
|
solver_dir = cache_dir if cache_dir is not None else get_cache_dir()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.3.2.
|
|
3
|
+
Version: 0.3.2.dev228
|
|
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
|
|
@@ -1047,3 +1047,42 @@ def test_duplicate_constraints_same_hash():
|
|
|
1047
1047
|
# Different number of duplicates should hash differently
|
|
1048
1048
|
p3 = make_problem(2)
|
|
1049
1049
|
assert hash_symbolic_problem(p1) != hash_symbolic_problem(p3)
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
# =============================================================================
|
|
1053
|
+
# BYOF Hashing Tests
|
|
1054
|
+
# =============================================================================
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
def test_byof_hash_none():
|
|
1058
|
+
"""None byof should return empty bytes."""
|
|
1059
|
+
from openscvx.utils.caching import _hash_byof
|
|
1060
|
+
|
|
1061
|
+
assert _hash_byof(None) == b""
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
def test_byof_hash_empty():
|
|
1065
|
+
"""Empty byof dict should return empty bytes."""
|
|
1066
|
+
from openscvx.utils.caching import _hash_byof
|
|
1067
|
+
|
|
1068
|
+
assert _hash_byof({}) == b""
|
|
1069
|
+
|
|
1070
|
+
|
|
1071
|
+
def test_byof_hash_changes_with_function():
|
|
1072
|
+
"""Different lambda implementations should produce different hashes."""
|
|
1073
|
+
from openscvx.utils.caching import _hash_byof
|
|
1074
|
+
|
|
1075
|
+
byof1 = {"nodal_constraints": [{"constraint_fn": lambda x, u, n, p: x[0] - 10.0}]}
|
|
1076
|
+
byof2 = {"nodal_constraints": [{"constraint_fn": lambda x, u, n, p: x[0] - 20.0}]}
|
|
1077
|
+
|
|
1078
|
+
assert _hash_byof(byof1) != _hash_byof(byof2)
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
def test_byof_hash_same_function_same_hash():
|
|
1082
|
+
"""Identical lambda implementations should produce same hash."""
|
|
1083
|
+
from openscvx.utils.caching import _hash_byof
|
|
1084
|
+
|
|
1085
|
+
byof1 = {"nodal_constraints": [{"constraint_fn": lambda x, u, n, p: x[0] - 10.0}]}
|
|
1086
|
+
byof2 = {"nodal_constraints": [{"constraint_fn": lambda x, u, n, p: x[0] - 10.0}]}
|
|
1087
|
+
|
|
1088
|
+
assert _hash_byof(byof1) == _hash_byof(byof2)
|
|
@@ -6,11 +6,15 @@ from openscvx.symbolic.expr import Add, Concat, Constant, Control, CrossNodeCons
|
|
|
6
6
|
from openscvx.symbolic.preprocessing import (
|
|
7
7
|
collect_and_assign_slices,
|
|
8
8
|
convert_dynamics_dict_to_expr,
|
|
9
|
+
fill_default_guesses,
|
|
10
|
+
validate_boundary_conditions,
|
|
11
|
+
validate_bounds,
|
|
9
12
|
validate_constraints_at_root,
|
|
10
13
|
validate_cross_node_constraint,
|
|
11
14
|
validate_dynamics_dict,
|
|
12
15
|
validate_dynamics_dict_dimensions,
|
|
13
16
|
validate_dynamics_dimension,
|
|
17
|
+
validate_guesses,
|
|
14
18
|
validate_variable_names,
|
|
15
19
|
)
|
|
16
20
|
|
|
@@ -801,3 +805,174 @@ def test_cross_node_constraint_both_sides():
|
|
|
801
805
|
constraint2 = CrossNodeConstraint(velocity <= position.at(5))
|
|
802
806
|
with pytest.raises(ValueError, match="without .at\\(\\).*vel"):
|
|
803
807
|
validate_cross_node_constraint(constraint2, N)
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
# =============================================================================
|
|
811
|
+
# fill_default_guesses Tests
|
|
812
|
+
# =============================================================================
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
def test_fill_default_guesses_state_linspace():
|
|
816
|
+
"""Test that state guesses are filled with linspace from initial to final."""
|
|
817
|
+
N = 11 # Use 11 so middle index (5) is exactly at midpoint
|
|
818
|
+
x = State("x", shape=(3,))
|
|
819
|
+
x.initial = np.array([0.0, 1.0, 2.0])
|
|
820
|
+
x.final = np.array([10.0, 11.0, 12.0])
|
|
821
|
+
|
|
822
|
+
fill_default_guesses([x], N)
|
|
823
|
+
|
|
824
|
+
assert x.guess is not None
|
|
825
|
+
assert x.guess.shape == (N, 3)
|
|
826
|
+
# Check first and last rows match initial and final
|
|
827
|
+
np.testing.assert_array_almost_equal(x.guess[0], [0.0, 1.0, 2.0])
|
|
828
|
+
np.testing.assert_array_almost_equal(x.guess[-1], [10.0, 11.0, 12.0])
|
|
829
|
+
# Check it's actually a linspace (middle index should be exactly at midpoint)
|
|
830
|
+
np.testing.assert_array_almost_equal(x.guess[N // 2], [5.0, 6.0, 7.0])
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
def test_fill_default_guesses_preserves_existing():
|
|
834
|
+
"""Test that existing guesses are not overwritten."""
|
|
835
|
+
N = 10
|
|
836
|
+
x = State("x", shape=(2,))
|
|
837
|
+
x.initial = np.array([0.0, 0.0])
|
|
838
|
+
x.final = np.array([10.0, 10.0])
|
|
839
|
+
custom_guess = np.ones((N, 2)) * 99.0
|
|
840
|
+
x.guess = custom_guess
|
|
841
|
+
|
|
842
|
+
fill_default_guesses([x], N)
|
|
843
|
+
|
|
844
|
+
# Guess should be unchanged
|
|
845
|
+
np.testing.assert_array_equal(x.guess, custom_guess)
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
def test_fill_default_guesses_with_free_boundary_conditions():
|
|
849
|
+
"""Test that states with free boundary conditions use the guess values."""
|
|
850
|
+
N = 10
|
|
851
|
+
x = State("x", shape=(3,))
|
|
852
|
+
# Mixed: first fixed, second free, third fixed
|
|
853
|
+
x.initial = [0.0, ("free", 5.0), 2.0]
|
|
854
|
+
x.final = [10.0, ("free", 15.0), 12.0]
|
|
855
|
+
|
|
856
|
+
fill_default_guesses([x], N)
|
|
857
|
+
|
|
858
|
+
assert x.guess is not None
|
|
859
|
+
assert x.guess.shape == (N, 3)
|
|
860
|
+
# The setter extracts values from tuples, so initial=[0, 5, 2], final=[10, 15, 12]
|
|
861
|
+
np.testing.assert_array_almost_equal(x.guess[0], [0.0, 5.0, 2.0])
|
|
862
|
+
np.testing.assert_array_almost_equal(x.guess[-1], [10.0, 15.0, 12.0])
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
def test_fill_default_guesses_multiple_states():
|
|
866
|
+
"""Test filling guesses for multiple states at once."""
|
|
867
|
+
N = 5
|
|
868
|
+
x1 = State("x1", shape=(2,))
|
|
869
|
+
x1.initial = np.array([0.0, 0.0])
|
|
870
|
+
x1.final = np.array([4.0, 8.0])
|
|
871
|
+
|
|
872
|
+
x2 = State("x2", shape=(1,))
|
|
873
|
+
x2.initial = np.array([10.0])
|
|
874
|
+
x2.final = np.array([20.0])
|
|
875
|
+
|
|
876
|
+
fill_default_guesses([x1, x2], N)
|
|
877
|
+
|
|
878
|
+
# Check x1
|
|
879
|
+
assert x1.guess.shape == (N, 2)
|
|
880
|
+
np.testing.assert_array_almost_equal(x1.guess[0], [0.0, 0.0])
|
|
881
|
+
np.testing.assert_array_almost_equal(x1.guess[-1], [4.0, 8.0])
|
|
882
|
+
|
|
883
|
+
# Check x2
|
|
884
|
+
assert x2.guess.shape == (N, 1)
|
|
885
|
+
np.testing.assert_array_almost_equal(x2.guess[0], [10.0])
|
|
886
|
+
np.testing.assert_array_almost_equal(x2.guess[-1], [20.0])
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
# =============================================================================
|
|
890
|
+
# validate_boundary_conditions Tests
|
|
891
|
+
# =============================================================================
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
def test_validate_boundary_conditions_passes():
|
|
895
|
+
"""Test that validation passes when all states have initial and final."""
|
|
896
|
+
x = State("position", shape=(3,))
|
|
897
|
+
x.initial = np.zeros(3)
|
|
898
|
+
x.final = np.ones(3)
|
|
899
|
+
|
|
900
|
+
validate_boundary_conditions([x])
|
|
901
|
+
validate_boundary_conditions([])
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
def test_validate_boundary_conditions_raises_missing():
|
|
905
|
+
"""Test that validation fails fast on first missing attribute."""
|
|
906
|
+
x = State("position", shape=(2,))
|
|
907
|
+
# No initial or final set
|
|
908
|
+
|
|
909
|
+
with pytest.raises(ValueError, match="'position' is missing initial"):
|
|
910
|
+
validate_boundary_conditions([x])
|
|
911
|
+
|
|
912
|
+
# With initial but no final
|
|
913
|
+
x.initial = np.zeros(2)
|
|
914
|
+
with pytest.raises(ValueError, match="'position' is missing final"):
|
|
915
|
+
validate_boundary_conditions([x])
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
# =============================================================================
|
|
919
|
+
# validate_bounds Tests
|
|
920
|
+
# =============================================================================
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
def test_validate_bounds_passes():
|
|
924
|
+
"""Test that validation passes when all variables have min and max."""
|
|
925
|
+
x = State("position", shape=(3,))
|
|
926
|
+
x.min = np.array([-10, -10, -10])
|
|
927
|
+
x.max = np.array([10, 10, 10])
|
|
928
|
+
|
|
929
|
+
u = Control("thrust", shape=(2,))
|
|
930
|
+
u.min = np.zeros(2)
|
|
931
|
+
u.max = np.array([100, 100])
|
|
932
|
+
|
|
933
|
+
validate_bounds([x, u])
|
|
934
|
+
validate_bounds([])
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
def test_validate_bounds_raises_missing():
|
|
938
|
+
"""Test that validation fails fast on first missing attribute."""
|
|
939
|
+
u = Control("thrust", shape=(2,))
|
|
940
|
+
# No min or max set
|
|
941
|
+
|
|
942
|
+
with pytest.raises(ValueError, match="'thrust' is missing min"):
|
|
943
|
+
validate_bounds([u])
|
|
944
|
+
|
|
945
|
+
# With min but no max
|
|
946
|
+
u.min = np.zeros(2)
|
|
947
|
+
with pytest.raises(ValueError, match="'thrust' is missing max"):
|
|
948
|
+
validate_bounds([u])
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
# =============================================================================
|
|
952
|
+
# validate_guesses Tests
|
|
953
|
+
# =============================================================================
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
def test_validate_guesses_passes():
|
|
957
|
+
"""Test that validation passes when all variables have guesses."""
|
|
958
|
+
N = 10
|
|
959
|
+
x = State("position", shape=(3,))
|
|
960
|
+
x.guess = np.zeros((N, 3))
|
|
961
|
+
|
|
962
|
+
u = Control("thrust", shape=(2,))
|
|
963
|
+
u.guess = np.ones((N, 2))
|
|
964
|
+
|
|
965
|
+
validate_guesses([x, u])
|
|
966
|
+
validate_guesses([])
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
def test_validate_guesses_raises_missing():
|
|
970
|
+
"""Test that validation fails fast on first missing guess."""
|
|
971
|
+
u = Control("thrust", shape=(2,))
|
|
972
|
+
# No guess set
|
|
973
|
+
|
|
974
|
+
with pytest.raises(
|
|
975
|
+
ValueError,
|
|
976
|
+
match="Control 'thrust' is missing initial guess.*controls require explicit guesses",
|
|
977
|
+
):
|
|
978
|
+
validate_guesses([u])
|