openscvx 0.3.2.dev279__tar.gz → 0.3.2.dev295__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.dev279/openscvx.egg-info → openscvx-0.3.2.dev295}/PKG-INFO +1 -1
- openscvx-0.3.2.dev295/examples/car/dubins_car_conditional.py +144 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/plotting.py +80 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/__init__.py +7 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/_version.py +3 -3
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/__init__.py +7 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/constraint.py +10 -6
- openscvx-0.3.2.dev295/openscvx/symbolic/expr/logic.py +410 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/lowerers/cvxpy.py +67 -2
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/lowerers/jax.py +151 -1
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx.egg-info/SOURCES.txt +3 -0
- openscvx-0.3.2.dev295/tests/symbolic/expr/test_logic.py +963 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_node_reference.py +5 -5
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/docs.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/lint.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/release.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/.gitignore +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/CONTRIBUTING.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/LICENSE +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/README.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Overview/constraint_reformulation.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Overview/control_parameterization.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Overview/discretization.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Overview/ocp.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Overview/scvx.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Overview/time_dilation.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/advanced_problem_setup.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/api.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/api_constraints.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/api_control.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/api_integrators.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/api_state.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/api_trajoptproblem.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/api_variable.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/basic_problem_setup.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/tutorial_6dof_los_guidance.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/tutorial_6dof_obstacle_avoidance.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/Usage/tutorials.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/favicon.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/citation.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/examples.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/getting-started.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/index.md +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/arm/three_link_arm.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/car/dubins_car.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/car/dubins_car_stljax.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/plotting_viser.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/figures/video_preview.png +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/home.html +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/main.html +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/mkdocs.yml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/algorithms/autotuning.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/config.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/discretization/discretization.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/expert/byof.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/expert/validation.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/init/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/viser/animated.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/problem.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/solvers/base.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/time.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/utils/cache.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/utils/caching.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/utils/printing.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx/utils/utils.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/pyproject.toml +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/setup.cfg +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_discretization.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_examples.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_expert.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_init.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_integrators.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/tests/test_plotting.py +0 -0
- {openscvx-0.3.2.dev279 → openscvx-0.3.2.dev295}/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.dev295
|
|
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
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Dubins car path planning with conditional velocity constraint using Cond operator.
|
|
2
|
+
|
|
3
|
+
This example demonstrates the use of the Cond operator for conditional logic
|
|
4
|
+
in constraints. The car has different maximum velocity limits based on proximity
|
|
5
|
+
to the obstacle:
|
|
6
|
+
|
|
7
|
+
- When far from obstacle: higher maximum velocity (10.0)
|
|
8
|
+
- When near obstacle: lower maximum velocity (5.0) for safer navigation
|
|
9
|
+
|
|
10
|
+
This showcases how to use ox.Cond for JAX-traceable conditional branching
|
|
11
|
+
in constraint expressions.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
import jax.numpy as jnp
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
# Add grandparent directory to path to import examples.plotting
|
|
21
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
22
|
+
grandparent_dir = os.path.dirname(os.path.dirname(current_dir))
|
|
23
|
+
sys.path.append(grandparent_dir)
|
|
24
|
+
|
|
25
|
+
import openscvx as ox
|
|
26
|
+
from examples.plotting import plot_dubins_car, plot_velocity_vs_distance
|
|
27
|
+
from openscvx import Problem
|
|
28
|
+
|
|
29
|
+
n = 8
|
|
30
|
+
total_time = 2.0 # Total simulation time
|
|
31
|
+
|
|
32
|
+
# Define state components
|
|
33
|
+
position = ox.State("position", shape=(2,)) # 2D position [x, y]
|
|
34
|
+
position.min = np.array([-5.0, -5.0])
|
|
35
|
+
position.max = np.array([5.0, 5.0])
|
|
36
|
+
position.initial = np.array([0, -2])
|
|
37
|
+
position.final = np.array([0, 2])
|
|
38
|
+
|
|
39
|
+
theta = ox.State("theta", shape=(1,)) # Heading angle
|
|
40
|
+
theta.min = np.array([-2 * jnp.pi])
|
|
41
|
+
theta.max = np.array([2 * jnp.pi])
|
|
42
|
+
theta.initial = np.array([0])
|
|
43
|
+
theta.final = [ox.Free(0)]
|
|
44
|
+
|
|
45
|
+
# Define control components
|
|
46
|
+
speed = ox.Control("speed", shape=(1,)) # Forward speed
|
|
47
|
+
speed.min = np.array([0])
|
|
48
|
+
speed.max = np.array([10])
|
|
49
|
+
speed.guess = np.ones((n, 1)) * 10.0
|
|
50
|
+
|
|
51
|
+
angular_rate = ox.Control("angular_rate", shape=(1,)) # Angular velocity
|
|
52
|
+
angular_rate.min = np.array([-5])
|
|
53
|
+
angular_rate.max = np.array([5])
|
|
54
|
+
angular_rate.guess = np.zeros((n, 1))
|
|
55
|
+
|
|
56
|
+
# Define list of all states and controls
|
|
57
|
+
states = [position, theta]
|
|
58
|
+
controls = [speed, angular_rate]
|
|
59
|
+
|
|
60
|
+
# Define Parameters with initial values for obstacle radius and center
|
|
61
|
+
obs_center = ox.Parameter("obs_center", shape=(2,), value=np.array([-0.01, 0.0]))
|
|
62
|
+
obs_radius = ox.Parameter("obs_radius", shape=(), value=1.0)
|
|
63
|
+
|
|
64
|
+
# Safety distance threshold for conditional velocity constraint
|
|
65
|
+
safety_threshold = 1.1 # Distance from obstacle where we reduce max velocity
|
|
66
|
+
|
|
67
|
+
# Generate box constraints for all states
|
|
68
|
+
constraints = []
|
|
69
|
+
for state in states:
|
|
70
|
+
constraints.extend([ox.ctcs(state <= state.max), ox.ctcs(state.min <= state)])
|
|
71
|
+
|
|
72
|
+
# Add obstacle avoidance constraint
|
|
73
|
+
constraints.append(ox.ctcs(obs_radius <= ox.linalg.Norm(position - obs_center)))
|
|
74
|
+
|
|
75
|
+
# Add the conditional velocity constraint
|
|
76
|
+
distance_to_obstacle = ox.linalg.Norm(position - obs_center)
|
|
77
|
+
constraints.append(
|
|
78
|
+
ox.ctcs(
|
|
79
|
+
speed <= ox.Cond(distance_to_obstacle <= safety_threshold, 5.0, 10.0),
|
|
80
|
+
idx=1,
|
|
81
|
+
penalty="smooth_relu",
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# Define normal dynamics (no conditional logic here)
|
|
87
|
+
dynamics = {
|
|
88
|
+
"position": ox.Concat(
|
|
89
|
+
speed * ox.Sin(theta), # x_dot
|
|
90
|
+
speed * ox.Cos(theta), # y_dot
|
|
91
|
+
),
|
|
92
|
+
"theta": angular_rate,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Build the problem (parameters auto-collected from Parameter objects)
|
|
97
|
+
time = ox.Time(
|
|
98
|
+
initial=0.0,
|
|
99
|
+
final=ox.Minimize(total_time),
|
|
100
|
+
min=0.0,
|
|
101
|
+
max=20,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
problem = Problem(
|
|
105
|
+
dynamics=dynamics,
|
|
106
|
+
states=states,
|
|
107
|
+
controls=controls,
|
|
108
|
+
time=time,
|
|
109
|
+
constraints=constraints,
|
|
110
|
+
N=n,
|
|
111
|
+
licq_max=1e-6,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Set solver parameters
|
|
115
|
+
problem.settings.scp.w_tr = 1e0
|
|
116
|
+
problem.settings.scp.w_tr_adapt = 1.1
|
|
117
|
+
problem.settings.scp.w_tr_max_scaling_factor = 1e2
|
|
118
|
+
problem.settings.scp.lam_cost = 1e0
|
|
119
|
+
problem.settings.scp.lam_vc = 1e3
|
|
120
|
+
problem.settings.scp.uniform_time_grid = True
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
plotting_dict = {
|
|
124
|
+
"obs_radius": problem.parameters["obs_radius"],
|
|
125
|
+
"obs_center": problem.parameters["obs_center"],
|
|
126
|
+
"safety_threshold": safety_threshold,
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if __name__ == "__main__":
|
|
130
|
+
print("Dubins Car with Conditional Velocity Constraint (using Cond operator)")
|
|
131
|
+
print("=" * 70)
|
|
132
|
+
print("Max velocity is 5.0 when within 2.0 units of obstacle, else 10.0")
|
|
133
|
+
print("=" * 70)
|
|
134
|
+
|
|
135
|
+
problem.initialize()
|
|
136
|
+
results = problem.solve()
|
|
137
|
+
results = problem.post_process()
|
|
138
|
+
results.update(plotting_dict)
|
|
139
|
+
|
|
140
|
+
# Plot trajectory
|
|
141
|
+
plot_dubins_car(results, problem.settings).show()
|
|
142
|
+
|
|
143
|
+
# Plot velocity vs distance to obstacle
|
|
144
|
+
plot_velocity_vs_distance(results, problem.settings).show()
|
|
@@ -322,6 +322,86 @@ def plot_dubins_car(results: OptimizationResults, params: Config):
|
|
|
322
322
|
return fig
|
|
323
323
|
|
|
324
324
|
|
|
325
|
+
def plot_velocity_vs_distance(results: OptimizationResults, params: Config):
|
|
326
|
+
"""Plot velocity against distance to obstacle.
|
|
327
|
+
|
|
328
|
+
This plot demonstrates how the conditional velocity constraint works,
|
|
329
|
+
showing how velocity changes based on proximity to the obstacle.
|
|
330
|
+
"""
|
|
331
|
+
fig = go.Figure()
|
|
332
|
+
|
|
333
|
+
# Extract position and velocity
|
|
334
|
+
position = results.trajectory["position"]
|
|
335
|
+
velocity = results.trajectory.get("speed")
|
|
336
|
+
|
|
337
|
+
if velocity is None:
|
|
338
|
+
# If speed is not available, try to get it from controls
|
|
339
|
+
velocity = results.controls.get("speed")
|
|
340
|
+
|
|
341
|
+
if velocity is None:
|
|
342
|
+
raise ValueError("Velocity data not found in results")
|
|
343
|
+
|
|
344
|
+
# Flatten velocity to 1D array
|
|
345
|
+
velocity = np.asarray(velocity).flatten()
|
|
346
|
+
|
|
347
|
+
# Get obstacle center and radius
|
|
348
|
+
obs_center = results.plotting_data["obs_center"]
|
|
349
|
+
_ = results.plotting_data["obs_radius"]
|
|
350
|
+
|
|
351
|
+
# Calculate distance to obstacle center for each point
|
|
352
|
+
# Distance = ||position - obs_center||
|
|
353
|
+
distance_from_center = np.linalg.norm(position - obs_center, axis=1)
|
|
354
|
+
|
|
355
|
+
# Plot velocity vs distance
|
|
356
|
+
fig.add_trace(
|
|
357
|
+
go.Scatter(
|
|
358
|
+
x=distance_from_center,
|
|
359
|
+
y=velocity,
|
|
360
|
+
mode="lines+markers",
|
|
361
|
+
line={"color": "blue", "width": 2},
|
|
362
|
+
marker={"size": 5},
|
|
363
|
+
name="Velocity",
|
|
364
|
+
)
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# Add vertical line at safety threshold if available
|
|
368
|
+
if "safety_threshold" in results.plotting_data:
|
|
369
|
+
safety_threshold = results.plotting_data["safety_threshold"]
|
|
370
|
+
fig.add_vline(
|
|
371
|
+
x=safety_threshold,
|
|
372
|
+
line_dash="dash",
|
|
373
|
+
line_color="red",
|
|
374
|
+
annotation_text=f"Safety threshold ({safety_threshold:.2f})",
|
|
375
|
+
annotation_position="top",
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Add horizontal lines for max velocities
|
|
379
|
+
fig.add_hline(
|
|
380
|
+
y=5.0,
|
|
381
|
+
line_dash="dot",
|
|
382
|
+
line_color="orange",
|
|
383
|
+
annotation_text="Max velocity (near): 5.0",
|
|
384
|
+
annotation_position="right",
|
|
385
|
+
)
|
|
386
|
+
fig.add_hline(
|
|
387
|
+
y=10.0,
|
|
388
|
+
line_dash="dot",
|
|
389
|
+
line_color="green",
|
|
390
|
+
annotation_text="Max velocity (far): 10.0",
|
|
391
|
+
annotation_position="right",
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
fig.update_layout(
|
|
395
|
+
title="Velocity vs Distance to Obstacle",
|
|
396
|
+
xaxis_title="Distance from Obstacle Center",
|
|
397
|
+
yaxis_title="Velocity",
|
|
398
|
+
template="plotly_dark",
|
|
399
|
+
title_x=0.5,
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
return fig
|
|
403
|
+
|
|
404
|
+
|
|
325
405
|
def plot_dubins_car_disjoint(results: OptimizationResults, params: Config):
|
|
326
406
|
# Plot the trajectory of the Dubins car, but show wp1 and wp2 as circles with centers and radii
|
|
327
407
|
fig = go.Figure()
|
|
@@ -16,9 +16,12 @@ from openscvx.symbolic.expr import (
|
|
|
16
16
|
CTCS,
|
|
17
17
|
Abs,
|
|
18
18
|
Add,
|
|
19
|
+
All,
|
|
20
|
+
Any,
|
|
19
21
|
Bilerp,
|
|
20
22
|
Block,
|
|
21
23
|
Concat,
|
|
24
|
+
Cond,
|
|
22
25
|
Constant,
|
|
23
26
|
Constraint,
|
|
24
27
|
Control,
|
|
@@ -114,6 +117,10 @@ __all__ = [
|
|
|
114
117
|
"Max",
|
|
115
118
|
"Linterp",
|
|
116
119
|
"Bilerp",
|
|
120
|
+
# Logical/control flow operations
|
|
121
|
+
"All",
|
|
122
|
+
"Any",
|
|
123
|
+
"Cond",
|
|
117
124
|
# Constraints
|
|
118
125
|
"Constraint",
|
|
119
126
|
"Equality",
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.3.2.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 3, 2, '
|
|
31
|
+
__version__ = version = '0.3.2.dev295'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 2, 'dev295')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g9a2fa0dbd'
|
|
@@ -115,6 +115,9 @@ from .lie import (
|
|
|
115
115
|
# Linear algebra operations
|
|
116
116
|
from .linalg import Diag, Inv, Norm, Sum, Transpose
|
|
117
117
|
|
|
118
|
+
# Logical/control flow operations
|
|
119
|
+
from .logic import All, Any, Cond
|
|
120
|
+
|
|
118
121
|
# Mathematical functions
|
|
119
122
|
from .math import (
|
|
120
123
|
Abs,
|
|
@@ -198,6 +201,10 @@ __all__ = [
|
|
|
198
201
|
"Max",
|
|
199
202
|
"Linterp",
|
|
200
203
|
"Bilerp",
|
|
204
|
+
# Logical/control flow operations
|
|
205
|
+
"All",
|
|
206
|
+
"Any",
|
|
207
|
+
"Cond",
|
|
201
208
|
# Linear algebra operations
|
|
202
209
|
"Transpose",
|
|
203
210
|
"Stack",
|
|
@@ -89,21 +89,25 @@ class Constraint(Expr):
|
|
|
89
89
|
return new_constraint
|
|
90
90
|
|
|
91
91
|
def check_shape(self) -> Tuple[int, ...]:
|
|
92
|
-
"""Check that constraint operands are broadcastable
|
|
92
|
+
"""Check that constraint operands are broadcastable and return the shape.
|
|
93
|
+
|
|
94
|
+
Returns the broadcasted shape of lhs and rhs, which represents the shape
|
|
95
|
+
of the constraint residual (lhs - rhs). Vector constraints are interpreted
|
|
96
|
+
element-wise.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
tuple: The broadcasted shape of lhs and rhs
|
|
100
|
+
"""
|
|
93
101
|
L_shape = self.lhs.check_shape()
|
|
94
102
|
R_shape = self.rhs.check_shape()
|
|
95
103
|
|
|
96
104
|
# Figure out their broadcasted shape (or error if incompatible)
|
|
97
105
|
try:
|
|
98
|
-
np.broadcast_shapes(L_shape, R_shape)
|
|
106
|
+
return np.broadcast_shapes(L_shape, R_shape)
|
|
99
107
|
except ValueError as e:
|
|
100
108
|
constraint_type = type(self).__name__
|
|
101
109
|
raise ValueError(f"{constraint_type} not broadcastable: {L_shape} vs {R_shape}") from e
|
|
102
110
|
|
|
103
|
-
# Allow vector constraints - they're interpreted element-wise
|
|
104
|
-
# Return () as constraints always produce a scalar
|
|
105
|
-
return ()
|
|
106
|
-
|
|
107
111
|
def at(self, nodes: Union[list, tuple]):
|
|
108
112
|
"""Apply this constraint only at specific discrete nodes.
|
|
109
113
|
|