openscvx 0.3.2.dev328__tar.gz → 0.3.2.dev333__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.
Files changed (267) hide show
  1. {openscvx-0.3.2.dev328/openscvx.egg-info → openscvx-0.3.2.dev333}/PKG-INFO +1 -1
  2. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/_version.py +3 -3
  3. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/__init__.py +35 -0
  4. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +111 -0
  5. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/_registry.py +75 -0
  6. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +149 -0
  7. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/array.py +152 -0
  8. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/constraint.py +122 -0
  9. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/control.py +38 -0
  10. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/expr.py +135 -0
  11. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/linalg.py +91 -0
  12. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/logic.py +75 -0
  13. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/math.py +372 -0
  14. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/cvxpy/state.py +40 -0
  15. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/__init__.py +40 -0
  16. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/_lowerer.py +56 -0
  17. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/_registry.py +74 -0
  18. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/arithmetic.py +87 -0
  19. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/array.py +132 -0
  20. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/constraint.py +159 -0
  21. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/control.py +30 -0
  22. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/expr.py +108 -0
  23. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/lie.py +291 -0
  24. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/linalg.py +76 -0
  25. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/logic.py +161 -0
  26. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/math.py +268 -0
  27. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/spatial.py +120 -0
  28. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/state.py +32 -0
  29. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/stl.py +82 -0
  30. openscvx-0.3.2.dev333/openscvx/symbolic/lowerers/jax/vmap.py +152 -0
  31. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333/openscvx.egg-info}/PKG-INFO +1 -1
  32. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/SOURCES.txt +28 -2
  33. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_arithmetic.py +6 -6
  34. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_constraint.py +2 -2
  35. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_parameters.py +3 -3
  36. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_variable.py +4 -4
  37. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_lower_jax.py +6 -6
  38. openscvx-0.3.2.dev328/openscvx/symbolic/lowerers/cvxpy.py +0 -1431
  39. openscvx-0.3.2.dev328/openscvx/symbolic/lowerers/jax.py +0 -1789
  40. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/assets/logo.svg +0 -0
  41. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/release-drafter.yml +0 -0
  42. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/_docs.yml +0 -0
  43. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/branch-name.yml +0 -0
  44. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/docs.yml +0 -0
  45. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/lint.yml +0 -0
  46. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/nightly.yml +0 -0
  47. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/release-drafter.yml +0 -0
  48. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/release.yml +0 -0
  49. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/tests-integration.yml +0 -0
  50. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.github/workflows/tests-unit.yml +0 -0
  51. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/.gitignore +0 -0
  52. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/CONTRIBUTING.md +0 -0
  53. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/LICENSE +0 -0
  54. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/README.md +0 -0
  55. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/constraint_reformulation.md +0 -0
  56. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/control_parameterization.md +0 -0
  57. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/discretization.md +0 -0
  58. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/ocp.md +0 -0
  59. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/scvx.md +0 -0
  60. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/Foundations/time_dilation.md +0 -0
  61. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UnderTheHood/lowering_architecture.md +0 -0
  62. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  63. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/00_introduction.md +0 -0
  64. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  65. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  66. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  67. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  68. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/05_visualization.md +0 -0
  69. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/06_logic.md +0 -0
  70. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/UsersGuide/07_lie.md +0 -0
  71. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/favicon.png +0 -0
  72. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ct-scvx_dark.png +0 -0
  73. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ct-scvx_light.png +0 -0
  74. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ctcs_dark.png +0 -0
  75. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/ctcs_light.png +0 -0
  76. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/problem_class_dark.png +0 -0
  77. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/images/problem_class_light.png +0 -0
  78. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/assets/logo.svg +0 -0
  79. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/citation.md +0 -0
  80. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/examples.md +0 -0
  81. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/getting-started.md +0 -0
  82. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/index.md +0 -0
  83. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/docs/javascripts/mathjax.js +0 -0
  84. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/abstract/brachistochrone.py +0 -0
  85. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/arm/three_link_arm.py +0 -0
  86. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car.py +0 -0
  87. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car_conditional.py +0 -0
  88. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car_disjoint.py +0 -0
  89. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/car/dubins_car_stljax.py +0 -0
  90. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/cinema_vp.py +0 -0
  91. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/cinema_vp_realtime_base.py +0 -0
  92. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_double_integrator.py +0 -0
  93. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_vp.py +0 -0
  94. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_vp_nodal.py +0 -0
  95. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/dr_vp_polytope.py +0 -0
  96. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/drone_racing.py +0 -0
  97. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance.py +0 -0
  98. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  99. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance_realtime_base.py +0 -0
  100. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  101. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/plotting.py +0 -0
  102. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/plotting_viser.py +0 -0
  103. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/cinema_vp_realtime.py +0 -0
  104. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/drone_racing_realtime.py +0 -0
  105. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/dubins_car_realtime.py +0 -0
  106. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  107. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/rocket/3DoF_pdg.py +0 -0
  108. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/examples/spacecraft/proxops_cw.py +0 -0
  109. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/ctlos_cine.gif +0 -0
  110. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/ctlos_dr.gif +0 -0
  111. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/dtlos_cine.gif +0 -0
  112. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/dtlos_dr.gif +0 -0
  113. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/openscvx_logo.svg +0 -0
  114. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/openscvx_logo_square.png +0 -0
  115. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/oscvx_structure_full_dark.svg +0 -0
  116. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/figures/video_preview.png +0 -0
  117. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/__init__.py +0 -0
  118. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background.avif +0 -0
  119. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
  120. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
  121. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
  122. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
  123. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars.avif +0 -0
  124. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
  125. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
  126. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
  127. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
  128. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon.avif +0 -0
  129. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
  130. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
  131. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
  132. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
  133. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
  134. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
  135. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
  136. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
  137. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
  138. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space.avif +0 -0
  139. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
  140. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
  141. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
  142. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
  143. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth.avif +0 -0
  144. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
  145. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
  146. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
  147. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
  148. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/javascripts/parallax.js +0 -0
  149. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/logo.svg +0 -0
  150. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/stylesheets/custom.css +0 -0
  151. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/assets/stylesheets/parallax.css +0 -0
  152. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/home.html +0 -0
  153. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/main.html +0 -0
  154. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/partials/parallax/hero.html +0 -0
  155. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/material/overrides/partials/parallax.html +0 -0
  156. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/mkdocs.yml +0 -0
  157. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/__init__.py +0 -0
  158. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/__init__.py +0 -0
  159. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/autotuning.py +0 -0
  160. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/base.py +0 -0
  161. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/optimization_results.py +0 -0
  162. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/algorithms/penalized_trust_region.py +0 -0
  163. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/config.py +0 -0
  164. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/discretization/__init__.py +0 -0
  165. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/discretization/discretization.py +0 -0
  166. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/__init__.py +0 -0
  167. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/byof.py +0 -0
  168. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/lowering.py +0 -0
  169. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/expert/validation.py +0 -0
  170. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/init/__init__.py +0 -0
  171. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/init/interpolation.py +0 -0
  172. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/integrators/__init__.py +0 -0
  173. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/integrators/runge_kutta.py +0 -0
  174. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/__init__.py +0 -0
  175. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/cvxpy_constraints.py +0 -0
  176. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/cvxpy_variables.py +0 -0
  177. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/dynamics.py +0 -0
  178. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/jax_constraints.py +0 -0
  179. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/parameters.py +0 -0
  180. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/problem.py +0 -0
  181. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/lowered/unified.py +0 -0
  182. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/__init__.py +0 -0
  183. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/plotting.py +0 -0
  184. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/scp_iteration.py +0 -0
  185. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/__init__.py +0 -0
  186. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/animated.py +0 -0
  187. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/plotly_integration.py +0 -0
  188. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/primitives.py +0 -0
  189. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/scp.py +0 -0
  190. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/plotting/viser/server.py +0 -0
  191. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/problem.py +0 -0
  192. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/propagation/__init__.py +0 -0
  193. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/propagation/post_processing.py +0 -0
  194. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/propagation/propagation.py +0 -0
  195. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/solvers/__init__.py +0 -0
  196. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/solvers/base.py +0 -0
  197. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/solvers/ptr_solver.py +0 -0
  198. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/__init__.py +0 -0
  199. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/augmentation.py +0 -0
  200. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/builder.py +0 -0
  201. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/constraint_set.py +0 -0
  202. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/__init__.py +0 -0
  203. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/arithmetic.py +0 -0
  204. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/array.py +0 -0
  205. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/constraint.py +0 -0
  206. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/control.py +0 -0
  207. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/expr.py +0 -0
  208. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  209. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  210. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/se3.py +0 -0
  211. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/lie/so3.py +0 -0
  212. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/linalg.py +0 -0
  213. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/logic.py +0 -0
  214. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/math.py +0 -0
  215. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/spatial.py +0 -0
  216. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/state.py +0 -0
  217. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/stl.py +0 -0
  218. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/variable.py +0 -0
  219. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/expr/vmap.py +0 -0
  220. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/hashing.py +0 -0
  221. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/lower.py +0 -0
  222. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/lowerers/__init__.py +0 -0
  223. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/preprocessing.py +0 -0
  224. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/problem.py +0 -0
  225. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/time.py +0 -0
  226. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/symbolic/unified.py +0 -0
  227. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/__init__.py +0 -0
  228. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/cache.py +0 -0
  229. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/caching.py +0 -0
  230. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/printing.py +0 -0
  231. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/profiling.py +0 -0
  232. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx/utils/utils.py +0 -0
  233. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/dependency_links.txt +0 -0
  234. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/requires.txt +0 -0
  235. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/openscvx.egg-info/top_level.txt +0 -0
  236. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/pyproject.toml +0 -0
  237. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/scripts/gen_example_pages.py +0 -0
  238. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/scripts/gen_ref_pages.py +0 -0
  239. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/setup.cfg +0 -0
  240. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/__init__.py +0 -0
  241. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/brachistochrone_analytical.py +0 -0
  242. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/__init__.py +0 -0
  243. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/__init__.py +0 -0
  244. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_array.py +0 -0
  245. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_expr.py +0 -0
  246. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_lie.py +0 -0
  247. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_linalg.py +0 -0
  248. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_logic.py +0 -0
  249. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_math.py +0 -0
  250. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_node_reference.py +0 -0
  251. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_scaling.py +0 -0
  252. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_spatial.py +0 -0
  253. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/expr/test_vmap.py +0 -0
  254. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_augmentation.py +0 -0
  255. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_hashing.py +0 -0
  256. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_lower_cvxpy.py +0 -0
  257. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_preprocessing.py +0 -0
  258. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/symbolic/test_unified.py +0 -0
  259. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_brachistochrone.py +0 -0
  260. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_cvxpygen_optional.py +0 -0
  261. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_discretization.py +0 -0
  262. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_examples.py +0 -0
  263. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_expert.py +0 -0
  264. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_init.py +0 -0
  265. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_integrators.py +0 -0
  266. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/tests/test_plotting.py +0 -0
  267. {openscvx-0.3.2.dev328 → openscvx-0.3.2.dev333}/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.dev328
3
+ Version: 0.3.2.dev333
4
4
  Summary: A general Python-based successive convexification implementation which uses a JAX backend.
5
5
  Author-email: Chris Hayner and Griffin Norris <haynec@uw.edu>
6
6
  License: Apache Software License
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.3.2.dev328'
32
- __version_tuple__ = version_tuple = (0, 3, 2, 'dev328')
31
+ __version__ = version = '0.3.2.dev333'
32
+ __version_tuple__ = version_tuple = (0, 3, 2, 'dev333')
33
33
 
34
- __commit_id__ = commit_id = 'g63a14061a'
34
+ __commit_id__ = commit_id = 'g298f4bc4f'
@@ -0,0 +1,35 @@
1
+ """CVXPy backend for lowering symbolic expressions to disciplined convex programs.
2
+
3
+ This package implements the CVXPy lowering backend that converts symbolic
4
+ expression AST nodes into CVXPy expressions and constraints for convex
5
+ optimization. The lowering uses a visitor pattern where each expression
6
+ type has a corresponding visitor function registered via ``@visitor``.
7
+
8
+ The visitor functions are split across submodules that mirror the
9
+ ``openscvx.symbolic.expr`` package structure. Importing this package
10
+ triggers registration of all visitors.
11
+
12
+ Example::
13
+
14
+ from openscvx.symbolic.lowerers.cvxpy import CvxpyLowerer
15
+
16
+ lowerer = CvxpyLowerer(variable_map={"x": cvx_x, "u": cvx_u})
17
+ cvx_expr = lowerer.lower(expr)
18
+ """
19
+
20
+ # Import visitor modules to trigger @visitor registration.
21
+ # Each module populates _CVXPY_VISITORS as a side effect of import.
22
+ from openscvx.symbolic.lowerers.cvxpy import (
23
+ arithmetic, # noqa: F401
24
+ array, # noqa: F401
25
+ constraint, # noqa: F401
26
+ control, # noqa: F401
27
+ expr, # noqa: F401
28
+ linalg, # noqa: F401
29
+ logic, # noqa: F401
30
+ math, # noqa: F401
31
+ state, # noqa: F401
32
+ )
33
+ from openscvx.symbolic.lowerers.cvxpy._lowerer import CvxpyLowerer, lower_to_cvxpy
34
+
35
+ __all__ = ["CvxpyLowerer", "lower_to_cvxpy"]
@@ -0,0 +1,111 @@
1
+ """CvxpyLowerer class definition.
2
+
3
+ The visitor methods that populate the registry live in sibling modules
4
+ (``arithmetic``, ``math``, ``linalg``, etc.) and are registered via
5
+ ``@visitor`` at import time.
6
+ """
7
+
8
+ from typing import Dict
9
+
10
+ import cvxpy as cp
11
+
12
+ from openscvx.symbolic.expr import Expr
13
+ from openscvx.symbolic.lowerers.cvxpy._registry import dispatch
14
+
15
+
16
+ class CvxpyLowerer:
17
+ """CVXPy backend for lowering symbolic expressions to disciplined convex programs.
18
+
19
+ This class implements the visitor pattern for converting symbolic expression
20
+ AST nodes to CVXPy expressions and constraints. Each expression type has a
21
+ corresponding visitor function decorated with @visitor that handles the
22
+ lowering logic.
23
+
24
+ The lowering process is recursive: each visitor lowers its child expressions
25
+ first, then composes them into a CVXPy operation. CVXPy will validate DCP
26
+ (Disciplined Convex Programming) compliance when the problem is constructed.
27
+
28
+ Attributes:
29
+ variable_map (dict): Dictionary mapping variable names to CVXPy expressions.
30
+ Must include "x" for states and "u" for controls. May include parameter
31
+ names mapped to CVXPy Parameter objects or constants.
32
+
33
+ Example:
34
+ Lower an expression to CVXPy::
35
+
36
+ import cvxpy as cp
37
+ lowerer = CvxpyLowerer(variable_map={
38
+ "x": cp.Variable(3),
39
+ "u": cp.Variable(2),
40
+ })
41
+ expr = ox.Norm(x)**2 + 0.1 * ox.Norm(u)**2
42
+ cvx_expr = lowerer.lower(expr)
43
+
44
+ Note:
45
+ The lowerer is stateful (stores variable_map) unlike JaxLowerer which
46
+ is stateless. Variables must be registered before lowering expressions
47
+ that reference them.
48
+ """
49
+
50
+ def __init__(self, variable_map: Dict[str, cp.Expression] = None):
51
+ """Initialize the CVXPy lowerer.
52
+
53
+ Args:
54
+ variable_map: Dictionary mapping variable names to CVXPy expressions.
55
+ For State/Control objects, keys should be "x" and "u" respectively.
56
+ For Parameter objects, keys should match their names. If None, an
57
+ empty dictionary is created.
58
+ """
59
+ self.variable_map = variable_map or {}
60
+
61
+ def register_variable(self, name: str, value: cp.Expression):
62
+ """Register a variable in the variable map.
63
+
64
+ Args:
65
+ name: Variable name (e.g., "x", "u", or parameter name)
66
+ value: CVXPy expression to associate with the name
67
+ """
68
+ self.variable_map[name] = value
69
+
70
+ def lower(self, expr: Expr) -> cp.Expression:
71
+ """Lower a symbolic expression to a CVXPy expression.
72
+
73
+ Main entry point for lowering. Delegates to dispatch() which looks up
74
+ the appropriate visitor method based on the expression type.
75
+
76
+ Args:
77
+ expr: Symbolic expression to lower (any Expr subclass)
78
+
79
+ Returns:
80
+ CVXPy expression or constraint
81
+
82
+ Raises:
83
+ NotImplementedError: If no visitor exists for the expression type
84
+ ValueError: If required variables are missing from variable_map
85
+ """
86
+ return dispatch(self, expr)
87
+
88
+
89
+ def lower_to_cvxpy(expr: Expr, variable_map: Dict[str, cp.Expression] = None) -> cp.Expression:
90
+ """Lower symbolic expression to CVXPy expression or constraint.
91
+
92
+ Convenience wrapper that creates a CvxpyLowerer and lowers a single
93
+ symbolic expression to a CVXPy expression. The result can be used in
94
+ CVXPy optimization problems.
95
+
96
+ Args:
97
+ expr: Symbolic expression to lower (any Expr subclass)
98
+ variable_map: Dictionary mapping variable names to CVXPy expressions.
99
+ Must include "x" for states and "u" for controls. May include
100
+ parameter names mapped to CVXPy Parameters or constants.
101
+
102
+ Returns:
103
+ CVXPy expression for arithmetic expressions (Add, Mul, Norm, etc.)
104
+ or CVXPy constraint for constraint expressions (Equality, Inequality)
105
+
106
+ Raises:
107
+ NotImplementedError: If the expression type is not supported
108
+ ValueError: If required variables are missing from variable_map
109
+ """
110
+ lowerer = CvxpyLowerer(variable_map)
111
+ return lowerer.lower(expr)
@@ -0,0 +1,75 @@
1
+ """Visitor registry for the CVXPy lowerer.
2
+
3
+ This module holds the shared visitor dictionary, the ``@visitor`` decorator,
4
+ and the ``dispatch`` function. It is deliberately kept free of heavyweight
5
+ imports (no CVXPy, no expression subclasses beyond the base ``Expr``) so that
6
+ the visitor modules can import from it without circular-dependency issues.
7
+ """
8
+
9
+ from typing import Any, Callable, Dict, Type
10
+
11
+ from openscvx.symbolic.expr import Expr
12
+
13
+ _CVXPY_VISITORS: Dict[Type[Expr], Callable] = {}
14
+ """Registry mapping expression types to their visitor functions."""
15
+
16
+
17
+ def visitor(expr_cls: Type[Expr]) -> Callable[[Callable], Callable]:
18
+ """Decorator to register a visitor function for an expression type.
19
+
20
+ This decorator registers a visitor method to handle a specific expression
21
+ type during CVXPy lowering. The decorated function is stored in
22
+ _CVXPY_VISITORS and will be called by dispatch() when lowering that
23
+ expression type.
24
+
25
+ Args:
26
+ expr_cls: The Expr subclass this visitor handles (e.g., Add, Mul, Norm)
27
+
28
+ Returns:
29
+ Decorator function that registers the visitor and returns it unchanged
30
+
31
+ Example:
32
+ Register a visitor function for the Add expression::
33
+
34
+ @visitor(Add)
35
+ def _visit_add(lowerer, node: Add):
36
+ ...
37
+
38
+ Note:
39
+ Multiple expression types can share a visitor by stacking decorators::
40
+
41
+ @visitor(Equality)
42
+ @visitor(Inequality)
43
+ def _visit_constraint(lowerer, node: Constraint):
44
+ ...
45
+ """
46
+
47
+ def register(fn: Callable[[Any, Expr], Any]):
48
+ _CVXPY_VISITORS[expr_cls] = fn
49
+ return fn
50
+
51
+ return register
52
+
53
+
54
+ def dispatch(lowerer: Any, expr: Expr) -> Any:
55
+ """Dispatch an expression to its registered visitor function.
56
+
57
+ Looks up the visitor function for the expression's type and calls it.
58
+ This is the core of the visitor pattern implementation.
59
+
60
+ Args:
61
+ lowerer: The CvxpyLowerer instance (provides context for visitor methods)
62
+ expr: The expression node to lower
63
+
64
+ Returns:
65
+ The result of calling the visitor function (CVXPy expression or constraint)
66
+
67
+ Raises:
68
+ NotImplementedError: If no visitor is registered for the expression type
69
+ """
70
+ fn = _CVXPY_VISITORS.get(type(expr))
71
+ if fn is None:
72
+ raise NotImplementedError(
73
+ f"{lowerer.__class__.__name__!r} has no visitor for {type(expr).__name__}"
74
+ )
75
+ return fn(lowerer, expr)
@@ -0,0 +1,149 @@
1
+ """CVXPy visitors for arithmetic expressions.
2
+
3
+ Visitors: Add, Sub, Mul, Div, MatMul, Neg, Power
4
+ """
5
+
6
+ import cvxpy as cp
7
+
8
+ # Expression types to handle — uncomment as you paste visitors:
9
+ from openscvx.symbolic.expr.arithmetic import Add, Div, MatMul, Mul, Neg, Power, Sub
10
+ from openscvx.symbolic.lowerers.cvxpy._registry import visitor # noqa: F401
11
+
12
+
13
+ @visitor(Add)
14
+ def _visit_add(lowerer, node: Add) -> cp.Expression:
15
+ """Lower addition to CVXPy expression.
16
+
17
+ Recursively lowers all terms and composes them with element-wise addition.
18
+ Addition is affine and always DCP-compliant.
19
+
20
+ Args:
21
+ node: Add expression node with multiple terms
22
+
23
+ Returns:
24
+ CVXPy expression representing the sum of all terms
25
+ """
26
+ terms = [lowerer.lower(term) for term in node.terms]
27
+ result = terms[0]
28
+ for term in terms[1:]:
29
+ result = result + term
30
+ return result
31
+
32
+
33
+ @visitor(Sub)
34
+ def _visit_sub(lowerer, node: Sub) -> cp.Expression:
35
+ """Lower subtraction to CVXPy expression (element-wise left - right).
36
+
37
+ Subtraction is affine and always DCP-compliant.
38
+
39
+ Args:
40
+ node: Sub expression node
41
+
42
+ Returns:
43
+ CVXPy expression representing left - right
44
+ """
45
+ left = lowerer.lower(node.left)
46
+ right = lowerer.lower(node.right)
47
+ return left - right
48
+
49
+
50
+ @visitor(Mul)
51
+ def _visit_mul(lowerer, node: Mul) -> cp.Expression:
52
+ """Lower element-wise multiplication to CVXPy expression.
53
+
54
+ Element-wise multiplication is DCP-compliant when at least one operand
55
+ is constant. For quadratic forms, use MatMul instead.
56
+
57
+ Args:
58
+ node: Mul expression node with multiple factors
59
+
60
+ Returns:
61
+ CVXPy expression representing element-wise product
62
+
63
+ Note:
64
+ For convex optimization, typically one factor should be constant.
65
+ CVXPy will raise a DCP error if the composition violates DCP rules.
66
+ """
67
+ factors = [lowerer.lower(factor) for factor in node.factors]
68
+ result = factors[0]
69
+ for factor in factors[1:]:
70
+ result = result * factor
71
+ return result
72
+
73
+
74
+ @visitor(Div)
75
+ def _visit_div(lowerer, node: Div) -> cp.Expression:
76
+ """Lower element-wise division to CVXPy expression.
77
+
78
+ Division is DCP-compliant when the denominator is constant or when
79
+ the numerator is constant and the denominator is concave.
80
+
81
+ Args:
82
+ node: Div expression node
83
+
84
+ Returns:
85
+ CVXPy expression representing left / right
86
+
87
+ Note:
88
+ CVXPy will raise a DCP error if the division violates DCP rules.
89
+ """
90
+ left = lowerer.lower(node.left)
91
+ right = lowerer.lower(node.right)
92
+ return left / right
93
+
94
+
95
+ @visitor(MatMul)
96
+ def _visit_matmul(lowerer, node: MatMul) -> cp.Expression:
97
+ """Lower matrix multiplication to CVXPy expression using @ operator.
98
+
99
+ Matrix multiplication is DCP-compliant when at least one operand is
100
+ constant. Used for quadratic forms like x.T @ Q @ x.
101
+
102
+ Args:
103
+ node: MatMul expression node
104
+
105
+ Returns:
106
+ CVXPy expression representing left @ right
107
+ """
108
+ left = lowerer.lower(node.left)
109
+ right = lowerer.lower(node.right)
110
+ return left @ right
111
+
112
+
113
+ @visitor(Neg)
114
+ def _visit_neg(lowerer, node: Neg) -> cp.Expression:
115
+ """Lower negation (unary minus) to CVXPy expression.
116
+
117
+ Negation preserves DCP properties (negating convex gives concave).
118
+
119
+ Args:
120
+ node: Neg expression node
121
+
122
+ Returns:
123
+ CVXPy expression representing -operand
124
+ """
125
+ operand = lowerer.lower(node.operand)
126
+ return -operand
127
+
128
+
129
+ @visitor(Power)
130
+ def _visit_power(lowerer, node: Power) -> cp.Expression:
131
+ """Lower element-wise power (base**exponent) to CVXPy expression.
132
+
133
+ Power is DCP-compliant for specific exponent values:
134
+ - exponent >= 1: convex (when base >= 0)
135
+ - 0 <= exponent <= 1: concave (when base >= 0)
136
+
137
+ Args:
138
+ node: Power expression node
139
+
140
+ Returns:
141
+ CVXPy expression representing base**exponent
142
+
143
+ Note:
144
+ CVXPy will verify DCP compliance at problem construction time.
145
+ Common convex cases: x^2, x^3, x^4 (even powers)
146
+ """
147
+ base = lowerer.lower(node.base)
148
+ exponent = lowerer.lower(node.exponent)
149
+ return cp.power(base, exponent)
@@ -0,0 +1,152 @@
1
+ """CVXPy visitors for array expressions.
2
+
3
+ Visitors: Index, Concat, Stack, Hstack, Vstack, Block
4
+ """
5
+
6
+ import cvxpy as cp
7
+
8
+ # Expression types to handle — uncomment as you paste visitors:
9
+ from openscvx.symbolic.expr.array import Block, Concat, Hstack, Index, Stack, Vstack
10
+ from openscvx.symbolic.lowerers.cvxpy._registry import visitor # noqa: F401
11
+
12
+
13
+ @visitor(Index)
14
+ def _visit_index(lowerer, node: Index) -> cp.Expression:
15
+ """Lower indexing/slicing operation to CVXPy expression.
16
+
17
+ Indexing preserves DCP properties (indexing into convex is convex).
18
+
19
+ Args:
20
+ node: Index expression node
21
+
22
+ Returns:
23
+ CVXPy expression representing base[index]
24
+ """
25
+ base = lowerer.lower(node.base)
26
+ return base[node.index]
27
+
28
+
29
+ @visitor(Concat)
30
+ def _visit_concat(lowerer, node: Concat) -> cp.Expression:
31
+ """Lower concatenation to CVXPy expression.
32
+
33
+ Concatenates expressions horizontally along axis 0. Scalars are
34
+ promoted to 1D arrays before concatenation. Preserves DCP properties.
35
+
36
+ Args:
37
+ node: Concat expression node
38
+
39
+ Returns:
40
+ CVXPy expression representing horizontal concatenation
41
+
42
+ Note:
43
+ Uses cp.hstack for concatenation. Scalars are reshaped to (1,).
44
+ """
45
+ exprs = [lowerer.lower(child) for child in node.exprs]
46
+ # Ensure all expressions are at least 1D for concatenation
47
+ exprs_1d = []
48
+ for expr in exprs:
49
+ if expr.ndim == 0: # scalar
50
+ exprs_1d.append(cp.reshape(expr, (1,), order="C"))
51
+ else:
52
+ exprs_1d.append(expr)
53
+ return cp.hstack(exprs_1d)
54
+
55
+
56
+ @visitor(Stack)
57
+ def _visit_stack(lowerer, node: Stack) -> cp.Expression:
58
+ """Lower vertical stacking to CVXPy expression.
59
+
60
+ Stacks expressions vertically using cp.vstack. Preserves DCP properties.
61
+
62
+ Args:
63
+ node: Stack expression node with multiple rows
64
+
65
+ Returns:
66
+ CVXPy expression representing vertical stack of rows
67
+
68
+ Note:
69
+ Each row is stacked along axis 0 to create a 2D array.
70
+ """
71
+ rows = [lowerer.lower(row) for row in node.rows]
72
+ # Stack rows vertically
73
+ return cp.vstack(rows)
74
+
75
+
76
+ @visitor(Hstack)
77
+ def _visit_hstack(lowerer, node: Hstack) -> cp.Expression:
78
+ """Lower horizontal stacking to CVXPy expression.
79
+
80
+ For 1D arrays, uses cp.hstack (concatenation). For 2D+ arrays, uses
81
+ cp.bmat with a single row to achieve proper horizontal stacking along
82
+ axis 1, matching numpy.hstack semantics.
83
+
84
+ Args:
85
+ node: Hstack expression node with multiple arrays
86
+
87
+ Returns:
88
+ CVXPy expression representing horizontal stack of arrays
89
+ """
90
+ arrays = [lowerer.lower(arr) for arr in node.arrays]
91
+
92
+ # Check dimensionality from the symbolic node's shape
93
+ shape = node.check_shape()
94
+ if len(shape) == 1:
95
+ # 1D: simple concatenation
96
+ return cp.hstack(arrays)
97
+ else:
98
+ # 2D+: use bmat with single row for proper horizontal stacking
99
+ return cp.bmat([arrays])
100
+
101
+
102
+ @visitor(Vstack)
103
+ def _visit_vstack(lowerer, node: Vstack) -> cp.Expression:
104
+ """Lower vertical stacking to CVXPy expression.
105
+
106
+ Stacks expressions vertically using cp.vstack. Preserves DCP properties.
107
+
108
+ Args:
109
+ node: Vstack expression node with multiple arrays
110
+
111
+ Returns:
112
+ CVXPy expression representing vertical stack of arrays
113
+ """
114
+ arrays = [lowerer.lower(arr) for arr in node.arrays]
115
+ return cp.vstack(arrays)
116
+
117
+
118
+ @visitor(Block)
119
+ def _visit_block(lowerer, node: Block) -> cp.Expression:
120
+ """Lower block matrix construction to CVXPy expression.
121
+
122
+ Assembles a block matrix from nested lists of expressions using cp.bmat.
123
+ This is the CVXPy equivalent of numpy.block() for block matrix construction.
124
+
125
+ Args:
126
+ node: Block expression node with 2D nested structure of expressions
127
+
128
+ Returns:
129
+ CVXPy expression representing the assembled block matrix
130
+
131
+ Raises:
132
+ NotImplementedError: If any block has more than 2 dimensions
133
+
134
+ Note:
135
+ cp.bmat preserves DCP properties when all blocks are DCP-compliant.
136
+ Block matrices are commonly used for constraint aggregation.
137
+ For 3D+ tensors, use JAX lowering instead.
138
+ """
139
+ # Check for 3D+ blocks - CVXPy's bmat only supports 2D
140
+ for i, row in enumerate(node.blocks):
141
+ for j, block in enumerate(row):
142
+ block_shape = block.check_shape()
143
+ if len(block_shape) > 2:
144
+ raise NotImplementedError(
145
+ f"CVXPy does not support Block with tensors of dimension > 2. "
146
+ f"Block[{i}][{j}] has shape {block_shape} ({len(block_shape)}D). "
147
+ f"For N-D tensor block assembly, use JAX lowering instead."
148
+ )
149
+
150
+ # Lower each block expression
151
+ block_exprs = [[lowerer.lower(block) for block in row] for row in node.blocks]
152
+ return cp.bmat(block_exprs)
@@ -0,0 +1,122 @@
1
+ """CVXPy visitors for constraint expressions.
2
+
3
+ Visitors: Equality, Inequality, CrossNodeConstraint, CTCS
4
+ """
5
+
6
+ import cvxpy as cp
7
+
8
+ # Expression types to handle — uncomment as you paste visitors:
9
+ from openscvx.symbolic.expr.constraint import (
10
+ CTCS,
11
+ CrossNodeConstraint,
12
+ Equality,
13
+ Inequality,
14
+ )
15
+ from openscvx.symbolic.lowerers.cvxpy._registry import visitor # noqa: F401
16
+
17
+
18
+ @visitor(Equality)
19
+ def _visit_equality(lowerer, node: Equality) -> cp.Constraint:
20
+ """Lower equality constraint to CVXPy constraint (lhs == rhs).
21
+
22
+ Equality constraints require affine expressions on both sides for
23
+ DCP compliance.
24
+
25
+ Args:
26
+ node: Equality constraint node
27
+
28
+ Returns:
29
+ CVXPy equality constraint object
30
+
31
+ Note:
32
+ For DCP compliance, both lhs and rhs must be affine. CVXPy will
33
+ raise a DCP error if either side is non-affine.
34
+ """
35
+ left = lowerer.lower(node.lhs)
36
+ right = lowerer.lower(node.rhs)
37
+ return left == right
38
+
39
+
40
+ @visitor(Inequality)
41
+ def _visit_inequality(lowerer, node: Inequality) -> cp.Constraint:
42
+ """Lower inequality constraint to CVXPy constraint (lhs <= rhs).
43
+
44
+ Inequality constraints must satisfy DCP rules: convex <= concave.
45
+
46
+ Args:
47
+ node: Inequality constraint node
48
+
49
+ Returns:
50
+ CVXPy inequality constraint object
51
+
52
+ Note:
53
+ For DCP compliance: lhs must be convex and rhs must be concave.
54
+ Common form: convex_expr(x) <= constant
55
+ """
56
+ left = lowerer.lower(node.lhs)
57
+ right = lowerer.lower(node.rhs)
58
+ return left <= right
59
+
60
+
61
+ @visitor(CrossNodeConstraint)
62
+ def _visit_cross_node_constraint(lowerer, node: CrossNodeConstraint) -> cp.Constraint:
63
+ """Lower CrossNodeConstraint to CVXPy constraint.
64
+
65
+ CrossNodeConstraint wraps constraints that reference multiple trajectory
66
+ nodes via NodeReference (e.g., rate limits like x.at(k) - x.at(k-1) <= r).
67
+
68
+ For CVXPy lowering, this simply lowers the inner constraint. The NodeReference
69
+ nodes within the constraint will handle extracting values from the full
70
+ trajectory arrays (which must be provided in variable_map as "x" and "u").
71
+
72
+ Args:
73
+ node: CrossNodeConstraint expression wrapping the inner constraint
74
+
75
+ Returns:
76
+ CVXPy constraint object
77
+
78
+ Note:
79
+ The variable_map must contain full trajectory arrays:
80
+ - "x": (N, n_x) CVXPy expression (e.g., cp.vstack(x_nonscaled))
81
+ - "u": (N, n_u) CVXPy expression (e.g., cp.vstack(u_nonscaled))
82
+
83
+ NodeReference visitors will index into these arrays using the fixed
84
+ node indices baked into the expression.
85
+
86
+ Example:
87
+ For constraint: position.at(5) - position.at(4) <= max_step
88
+
89
+ With variable_map = {"x": cp.vstack([x[k] for k in range(N)])}
90
+
91
+ The lowered constraint evaluates:
92
+ x[5, pos_slice] - x[4, pos_slice] <= max_step
93
+ """
94
+ # Simply lower the inner constraint - NodeReference handles indexing
95
+ return lowerer.lower(node.constraint)
96
+
97
+
98
+ @visitor(CTCS)
99
+ def _visit_ctcs(lowerer, node: CTCS) -> cp.Expression:
100
+ """Raise NotImplementedError for CTCS constraints.
101
+
102
+ CTCS (Continuous-Time Constraint Satisfaction) constraints are handled
103
+ through dynamics augmentation using JAX, not CVXPy. They represent
104
+ non-convex continuous-time constraints.
105
+
106
+ Args:
107
+ node: CTCS constraint node
108
+
109
+ Raises:
110
+ NotImplementedError: Always raised since CTCS uses JAX, not CVXPy
111
+
112
+ Note:
113
+ CTCS constraints are lowered to JAX during dynamics augmentation.
114
+ They add virtual states and controls to enforce constraints over
115
+ continuous time intervals. See JaxLowerer.visit_ctcs() instead.
116
+ """
117
+ raise NotImplementedError(
118
+ "CTCS constraints are for continuous-time constraint satisfaction and "
119
+ "should be handled through dynamics augmentation with JAX lowering, "
120
+ "not CVXPy lowering. CTCS constraints represent non-convex dynamics "
121
+ "augmentation."
122
+ )