openscvx 0.3.2.dev219__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.dev219/openscvx.egg-info → openscvx-0.3.2.dev228}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/abstract/3DoF_pdg.py +0 -3
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/abstract/brachistochrone.py +0 -2
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/car/dubins_car.py +0 -2
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/car/dubins_car_disjoint.py +0 -1
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/car/dubins_car_stljax.py +0 -3
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/cinema_vp.py +0 -1
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/dr_double_integrator.py +0 -2
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/drone_racing.py +0 -4
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance.py +0 -6
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance_nodal.py +0 -6
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance_realtime_base.py +0 -7
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/spacecraft/proxops_cw.py +0 -1
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/_version.py +3 -3
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/builder.py +15 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/preprocessing.py +82 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/test_preprocessing.py +175 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/test_brachistochrone.py +2 -11
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/test_expert.py +2 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/docs.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/lint.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/release.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/.gitignore +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/CONTRIBUTING.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/LICENSE +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/README.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Overview/constraint_reformulation.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Overview/control_parameterization.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Overview/discretization.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Overview/ocp.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Overview/scvx.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Overview/time_dilation.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/advanced_problem_setup.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/api.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/api_constraints.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/api_control.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/api_integrators.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/api_state.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/api_trajoptproblem.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/api_variable.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/basic_problem_setup.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/tutorial_6dof_los_guidance.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/tutorial_6dof_obstacle_avoidance.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/Usage/tutorials.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/favicon.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/citation.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/examples.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/getting-started.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/index.md +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/arm/three_link_arm.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/plotting.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/plotting_viser.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/figures/video_preview.png +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/home.html +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/main.html +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/mkdocs.yml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/algorithms/autotuning.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/config.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/discretization/discretization.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/expert/byof.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/expert/validation.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/problem.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/solvers/cvxpy.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/lowerers/cvxpy.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/lowerers/jax.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/time.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/utils/cache.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/utils/caching.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/utils/printing.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx/utils/utils.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx.egg-info/SOURCES.txt +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/pyproject.toml +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/setup.cfg +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/test_discretization.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/test_examples.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/test_integrators.py +0 -0
- {openscvx-0.3.2.dev219 → openscvx-0.3.2.dev228}/tests/test_plotting.py +0 -0
- {openscvx-0.3.2.dev219 → 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.dev219 → 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'
|
|
@@ -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
|
+
)
|
|
@@ -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
|
|
@@ -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])
|
|
@@ -158,7 +158,6 @@ def test_monolithic():
|
|
|
158
158
|
x.min = np.array([0.0, 0.0, 0.0]) # Lower bounds
|
|
159
159
|
x.initial = np.array([x0, y0, 0.0]) # [x0, y0, v0]
|
|
160
160
|
x.final = [x1, y1, ("free", 10.0)] # [x1, y1, v_free]
|
|
161
|
-
x.guess = np.linspace(x.initial, x.final, n)
|
|
162
161
|
|
|
163
162
|
# Define control
|
|
164
163
|
u = ox.Control("u", shape=(1,)) # Angle from vertical
|
|
@@ -261,14 +260,12 @@ def test_constraint_types(constraint_type):
|
|
|
261
260
|
position.min = np.array([0.0, 0.0])
|
|
262
261
|
position.initial = np.array([x0, y0])
|
|
263
262
|
position.final = [x1, y1]
|
|
264
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
265
263
|
|
|
266
264
|
velocity = ox.State("velocity", shape=(1,)) # Scalar speed
|
|
267
265
|
velocity.max = np.array([10.0])
|
|
268
266
|
velocity.min = np.array([0.0])
|
|
269
267
|
velocity.initial = np.array([0.0])
|
|
270
268
|
velocity.final = [("free", 10.0)]
|
|
271
|
-
velocity.guess = np.linspace(0.0, 10.0, n).reshape(-1, 1)
|
|
272
269
|
|
|
273
270
|
# Define control
|
|
274
271
|
theta = ox.Control("theta", shape=(1,)) # Angle from vertical
|
|
@@ -407,14 +404,12 @@ def test_cross_nodal(test_case):
|
|
|
407
404
|
position.min = np.array([0.0, 0.0])
|
|
408
405
|
position.initial = np.array([x0, y0])
|
|
409
406
|
position.final = [x1, y1]
|
|
410
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
411
407
|
|
|
412
408
|
velocity = ox.State("velocity", shape=(1,)) # Scalar speed
|
|
413
409
|
velocity.max = np.array([10.0])
|
|
414
410
|
velocity.min = np.array([0.0])
|
|
415
411
|
velocity.initial = np.array([0.0])
|
|
416
412
|
velocity.final = [("free", 10.0)]
|
|
417
|
-
velocity.guess = np.linspace(0.0, 10.0, n).reshape(-1, 1)
|
|
418
413
|
|
|
419
414
|
# Define control
|
|
420
415
|
theta = ox.Control("theta", shape=(1,)) # Angle from vertical
|
|
@@ -556,14 +551,12 @@ def test_parameters():
|
|
|
556
551
|
position.min = np.array([0.0, 0.0])
|
|
557
552
|
position.initial = np.array([x0, y0])
|
|
558
553
|
position.final = [x1, y1]
|
|
559
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
560
554
|
|
|
561
555
|
velocity = ox.State("velocity", shape=(1,)) # Scalar speed
|
|
562
556
|
velocity.max = np.array([10.0])
|
|
563
557
|
velocity.min = np.array([0.0])
|
|
564
558
|
velocity.initial = np.array([0.0])
|
|
565
559
|
velocity.final = [("free", 10.0)]
|
|
566
|
-
velocity.guess = np.linspace(0.0, 10.0, n).reshape(-1, 1)
|
|
567
560
|
|
|
568
561
|
# Define control
|
|
569
562
|
theta = ox.Control("theta", shape=(1,)) # Angle from vertical
|
|
@@ -735,14 +728,12 @@ def test_propagation():
|
|
|
735
728
|
position.min = np.array([0.0, 0.0])
|
|
736
729
|
position.initial = np.array([x0, y0])
|
|
737
730
|
position.final = [x1, y1]
|
|
738
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
739
731
|
|
|
740
732
|
velocity = ox.State("velocity", shape=(1,)) # Scalar speed
|
|
741
733
|
velocity.max = np.array([10.0])
|
|
742
734
|
velocity.min = np.array([0.0])
|
|
743
735
|
velocity.initial = np.array([0.0])
|
|
744
736
|
velocity.final = [("free", 10.0)]
|
|
745
|
-
velocity.guess = np.linspace(0.0, 10.0, n).reshape(-1, 1)
|
|
746
737
|
|
|
747
738
|
# Define control
|
|
748
739
|
theta = ox.Control("theta", shape=(1,)) # Angle from vertical
|
|
@@ -755,6 +746,8 @@ def test_propagation():
|
|
|
755
746
|
controls = [theta]
|
|
756
747
|
|
|
757
748
|
# Define propagation-only state for tracking total distance traveled
|
|
749
|
+
# Note: propagation states need explicit guesses since fill_default_guesses
|
|
750
|
+
# only runs on main optimization states
|
|
758
751
|
distance = ox.State("distance", shape=(1,))
|
|
759
752
|
distance.initial = np.array([0.0])
|
|
760
753
|
distance.min = np.array([0.0])
|
|
@@ -1003,14 +996,12 @@ def test_byof(byof_mode):
|
|
|
1003
996
|
position.min = np.array([0.0, 0.0])
|
|
1004
997
|
position.initial = np.array([x0, y0])
|
|
1005
998
|
position.final = [x1, y1]
|
|
1006
|
-
position.guess = np.linspace(position.initial, position.final, n)
|
|
1007
999
|
|
|
1008
1000
|
velocity = ox.State("velocity", shape=(1,))
|
|
1009
1001
|
velocity.max = np.array([10.0])
|
|
1010
1002
|
velocity.min = np.array([0.0])
|
|
1011
1003
|
velocity.initial = np.array([0.0])
|
|
1012
1004
|
velocity.final = [("free", 10.0)]
|
|
1013
|
-
velocity.guess = np.linspace(0.0, 10.0, n).reshape(-1, 1)
|
|
1014
1005
|
|
|
1015
1006
|
# Define control
|
|
1016
1007
|
theta = ox.Control("theta", shape=(1,))
|
|
@@ -651,10 +651,12 @@ def test_problem_validates_byof_during_construction():
|
|
|
651
651
|
velocity.min = np.array([0.0])
|
|
652
652
|
velocity.max = np.array([10.0])
|
|
653
653
|
velocity.initial = np.array([0.0])
|
|
654
|
+
velocity.final = [("free", 5.0)]
|
|
654
655
|
|
|
655
656
|
theta = ox.Control("theta", shape=(1,))
|
|
656
657
|
theta.min = np.array([0.0])
|
|
657
658
|
theta.max = np.array([np.pi / 2])
|
|
659
|
+
theta.guess = np.zeros((2, 1))
|
|
658
660
|
|
|
659
661
|
dynamics = {"position": ox.Concat(velocity[0], velocity[0])}
|
|
660
662
|
time = ox.Time(initial=0.0, final=1.0, min=0.0, max=2.0)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|