openscvx 0.3.2.dev195__tar.gz → 0.3.2.dev210__tar.gz

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