openscvx 0.5.3.dev49__tar.gz → 0.5.3.dev51__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 (475) hide show
  1. {openscvx-0.5.3.dev49/openscvx.egg-info → openscvx-0.5.3.dev51}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/Foundations/discretization.md +38 -1
  3. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/01_hello_world_brachistochrone.md +29 -0
  4. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/_version.py +3 -3
  5. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/problem.py +5 -1
  6. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/builder.py +18 -2
  7. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/__init__.py +10 -0
  8. openscvx-0.5.3.dev51/openscvx/symbolic/expr/autodiff.py +159 -0
  9. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/expr.py +41 -0
  10. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/time.py +72 -15
  11. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/variable.py +74 -12
  12. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/__init__.py +1 -0
  13. openscvx-0.5.3.dev51/openscvx/symbolic/lowerers/cvxpy/autodiff.py +36 -0
  14. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/__init__.py +1 -0
  15. openscvx-0.5.3.dev51/openscvx/symbolic/lowerers/jax/autodiff.py +82 -0
  16. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/state.py +20 -2
  17. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/__init__.py +1 -0
  18. openscvx-0.5.3.dev51/openscvx/symbolic/lowerers/latex/autodiff.py +17 -0
  19. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/preprocessing.py +159 -4
  20. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51/openscvx.egg-info}/PKG-INFO +1 -1
  21. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx.egg-info/SOURCES.txt +6 -0
  22. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx.egg-info/scm_file_list.json +6 -0
  23. openscvx-0.5.3.dev51/openscvx.egg-info/scm_version.json +8 -0
  24. openscvx-0.5.3.dev51/tests/symbolic/expr/test_autodiff.py +450 -0
  25. openscvx-0.5.3.dev51/tests/symbolic/expr/test_guess_expr.py +502 -0
  26. openscvx-0.5.3.dev49/openscvx.egg-info/scm_version.json +0 -8
  27. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/assets/logo.svg +0 -0
  28. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/release-drafter.yml +0 -0
  29. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/_docs.yml +0 -0
  30. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/_extra.yml +0 -0
  31. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/branch-name.yml +0 -0
  32. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/docs.yml +0 -0
  33. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/lint.yml +0 -0
  34. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/nightly.yml +0 -0
  35. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/release-drafter.yml +0 -0
  36. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/release.yml +0 -0
  37. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/tests-cvxpygen.yml +0 -0
  38. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/tests-examples.yml +0 -0
  39. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/tests-lie.yml +0 -0
  40. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/tests-mjx.yml +0 -0
  41. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/tests-qpax.yml +0 -0
  42. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.github/workflows/tests.yml +0 -0
  43. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.gitignore +0 -0
  44. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/.gitmodules +0 -0
  45. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/CITATION.cff +0 -0
  46. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/CONTRIBUTING.md +0 -0
  47. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/LICENSE +0 -0
  48. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/README.md +0 -0
  49. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/Foundations/constraint_reformulation.md +0 -0
  50. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/Foundations/control_parameterization.md +0 -0
  51. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/Foundations/ocp.md +0 -0
  52. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/Foundations/scvx.md +0 -0
  53. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/Foundations/time_dilation.md +0 -0
  54. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UnderTheHood/batching_jit_grad.md +0 -0
  55. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
  56. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UnderTheHood/lowering_architecture.md +0 -0
  57. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  58. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/00_introduction.md +0 -0
  59. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  60. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  61. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  62. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/05_visualization.md +0 -0
  63. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/06_logic.md +0 -0
  64. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/07_lie.md +0 -0
  65. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/08_mpcc.md +0 -0
  66. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  67. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/favicon.png +0 -0
  68. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/images/ct-scvx_dark.png +0 -0
  69. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/images/ct-scvx_light.png +0 -0
  70. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/images/ctcs_dark.png +0 -0
  71. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/images/ctcs_light.png +0 -0
  72. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/images/problem_class_dark.png +0 -0
  73. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/images/problem_class_light.png +0 -0
  74. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/logo.svg +0 -0
  75. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/openscvx_logo_square.png +0 -0
  76. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/viser-client/index.html +0 -0
  77. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  78. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  79. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/changelog.md +0 -0
  80. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/citation.md +0 -0
  81. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/examples.md +0 -0
  82. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/index.md +0 -0
  83. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/installation.md +0 -0
  84. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/javascripts/mathjax.js +0 -0
  85. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/llms.txt +0 -0
  86. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/docs/versions.json +0 -0
  87. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/_viser_embed_export.py +0 -0
  88. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/abstract/brachistochrone.py +0 -0
  89. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/abstract/brachistochrone_batched.py +0 -0
  90. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/abstract/flappy_bird.py +0 -0
  91. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/abstract/hypersensitive.py +0 -0
  92. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/abstract/impulsive.py +0 -0
  93. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/abstract/stl_integer_variable.py +0 -0
  94. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/abstract/stl_or.py +0 -0
  95. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/aircraft/dynamic_soaring.py +0 -0
  96. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/aircraft/supersonic_time_to_climb.py +0 -0
  97. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/7_dof_arm.py +0 -0
  98. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/_camera.py +0 -0
  99. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/_render.py +0 -0
  100. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/_sensor_view.py +0 -0
  101. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/dr_vp_polytope.py +0 -0
  102. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  103. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/logo.py +0 -0
  104. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  105. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/arm/3_dof_arm.py +0 -0
  106. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/arm/7_dof_arm.py +0 -0
  107. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/arm/7_dof_arm_collision.py +0 -0
  108. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/arm/7_dof_arm_vp.py +0 -0
  109. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  110. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  111. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  112. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/car/dubins_car.py +0 -0
  113. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/car/dubins_car_disjoint.py +0 -0
  114. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  115. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/car/dubins_car_obstacle_stl.py +0 -0
  116. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/car/dubins_car_stl_or.py +0 -0
  117. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/car/dubins_car_waypoint_stl.py +0 -0
  118. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/double_integrator/_plotting.py +0 -0
  119. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/double_integrator/moving_safe_zones.py +0 -0
  120. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  121. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/boresight_trace_mpcc.py +0 -0
  122. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/cinema_vp.py +0 -0
  123. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/cinema_vp_nodal.py +0 -0
  124. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/dr_double_integrator.py +0 -0
  125. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/dr_vp.py +0 -0
  126. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/dr_vp_nodal.py +0 -0
  127. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/dr_vp_polytope.py +0 -0
  128. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/drone_racing.py +0 -0
  129. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/drone_racing_batched_gates.py +0 -0
  130. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/logo.py +0 -0
  131. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/acl_logo.svg +0 -0
  132. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/circle.svg +0 -0
  133. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  134. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  135. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  136. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/multi_agent_circle_swap.py +0 -0
  137. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance.py +0 -0
  138. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  139. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  140. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  141. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/drone/openscvx_logo.py +0 -0
  142. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/frax/panda_frax.py +0 -0
  143. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/frax/panda_frax_pick_place.py +0 -0
  144. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/frax/panda_frax_viewplanning.py +0 -0
  145. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/frax/panda_frax_waypoint.py +0 -0
  146. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/frax/ur5e_assets/ur5e.urdf +0 -0
  147. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/frax/ur5e_pen_trace.py +0 -0
  148. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/frax/ur5e_pen_trace_mpcc.py +0 -0
  149. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mjx/cartpole_mjx.py +0 -0
  150. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mjx/double_cartpole_mjx.py +0 -0
  151. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mjx/skydio_x2_mjx.py +0 -0
  152. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  153. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mjx/triple_cartpole_game.py +0 -0
  154. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mjx/triple_cartpole_mjx.py +0 -0
  155. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mpc/double_integrator_discrete.py +0 -0
  156. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mpc/double_integrator_drone_racing.py +0 -0
  157. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  158. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  159. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  160. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/plotting.py +0 -0
  161. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/plotting_viser.py +0 -0
  162. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  163. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  164. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  165. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  166. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  167. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  168. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  169. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  170. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/cinema_vp_realtime.py +0 -0
  171. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/drone_racing_realtime.py +0 -0
  172. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/dubins_car_realtime.py +0 -0
  173. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  174. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/rocket/3DoF_pdg.py +0 -0
  175. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/rocket/6DoF_pdg.py +0 -0
  176. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  177. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/rocket/ascent_launch_vehicle.py +0 -0
  178. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/spacecraft/halo_orbit.py +0 -0
  179. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/spacecraft/hohmann_transfer.py +0 -0
  180. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/spacecraft/let_transfer.py +0 -0
  181. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/spacecraft/proxops_cw.py +0 -0
  182. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/examples/spacecraft/relative_loitering.py +0 -0
  183. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/ctlos_cine.gif +0 -0
  184. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/ctlos_dr.gif +0 -0
  185. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/dtlos_cine.gif +0 -0
  186. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/dtlos_dr.gif +0 -0
  187. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/openscvx_logo.svg +0 -0
  188. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/openscvx_logo_square.png +0 -0
  189. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/oscvx_structure_full_dark.svg +0 -0
  190. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/figures/video_preview.png +0 -0
  191. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/__init__.py +0 -0
  192. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/custom.css +0 -0
  193. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  194. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  195. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  196. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/home.html +0 -0
  197. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/main.html +0 -0
  198. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/partials/home-diagram.html +0 -0
  199. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/partials/home-dropin-banner.html +0 -0
  200. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/partials/home-hero.html +0 -0
  201. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/partials/home-pipeline.html +0 -0
  202. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/partials/home-viser-strip.html +0 -0
  203. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/material/overrides/sitemap.xml +0 -0
  204. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/mkdocs.yml +0 -0
  205. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/__init__.py +0 -0
  206. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/__main__.py +0 -0
  207. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/__init__.py +0 -0
  208. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/__init__.py +0 -0
  209. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
  210. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  211. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
  212. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/base.py +0 -0
  213. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  214. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  215. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/base.py +0 -0
  216. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/history.py +0 -0
  217. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/hyperparams.py +0 -0
  218. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/loop.py +0 -0
  219. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/optimization_results.py +0 -0
  220. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/penalty.py +0 -0
  221. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/scvx/__init__.py +0 -0
  222. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/scvx/iteration.py +0 -0
  223. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
  224. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/state.py +0 -0
  225. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/algorithms/weights.py +0 -0
  226. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/config.py +0 -0
  227. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/__init__.py +0 -0
  228. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/base.py +0 -0
  229. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/discretize_linearize.py +0 -0
  230. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/linearize_discretize.py +0 -0
  231. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  232. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  233. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  234. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  235. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/expert/__init__.py +0 -0
  236. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/expert/byof.py +0 -0
  237. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/expert/lowering.py +0 -0
  238. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/expert/validation.py +0 -0
  239. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/init/__init__.py +0 -0
  240. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/init/interpolation.py +0 -0
  241. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/init/inverse_kinematics.py +0 -0
  242. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrations/__init__.py +0 -0
  243. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrations/_utils.py +0 -0
  244. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrations/base.py +0 -0
  245. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrations/frax.py +0 -0
  246. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrations/menagerie.py +0 -0
  247. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrations/mjx.py +0 -0
  248. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrators/__init__.py +0 -0
  249. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrators/diffrax.py +0 -0
  250. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/integrators/runge_kutta.py +0 -0
  251. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/loader.py +0 -0
  252. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/__init__.py +0 -0
  253. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/cvxpy_constraints.py +0 -0
  254. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/cvxpy_variables.py +0 -0
  255. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/dynamics.py +0 -0
  256. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/jax_constraints.py +0 -0
  257. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/parameters.py +0 -0
  258. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/problem.py +0 -0
  259. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/lowered/unified.py +0 -0
  260. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/__init__.py +0 -0
  261. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/plotting.py +0 -0
  262. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/publication.py +0 -0
  263. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/scp_iteration.py +0 -0
  264. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/__init__.py +0 -0
  265. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/animated.py +0 -0
  266. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/coordinates.py +0 -0
  267. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/orbits.py +0 -0
  268. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/plotly_integration.py +0 -0
  269. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/primitives.py +0 -0
  270. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/scp.py +0 -0
  271. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/plotting/viser/server.py +0 -0
  272. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/propagation/__init__.py +0 -0
  273. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/propagation/post_processing.py +0 -0
  274. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/propagation/propagation.py +0 -0
  275. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/solvers/__init__.py +0 -0
  276. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/solvers/base.py +0 -0
  277. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/solvers/cones.py +0 -0
  278. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
  279. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  280. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/solvers/ptr_solver.py +0 -0
  281. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  282. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/__init__.py +0 -0
  283. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/affine.py +0 -0
  284. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/augmentation.py +0 -0
  285. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/canonicalize.py +0 -0
  286. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/constraint_set.py +0 -0
  287. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/arithmetic.py +0 -0
  288. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/array.py +0 -0
  289. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/constraint.py +0 -0
  290. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/control.py +0 -0
  291. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  292. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  293. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/se3.py +0 -0
  294. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/lie/so3.py +0 -0
  295. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/linalg.py +0 -0
  296. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/logic.py +0 -0
  297. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/math.py +0 -0
  298. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/parameter.py +0 -0
  299. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/spatial.py +0 -0
  300. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/state.py +0 -0
  301. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/stl.py +0 -0
  302. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/stljax.py +0 -0
  303. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/expr/vmap.py +0 -0
  304. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/hashing.py +0 -0
  305. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lower.py +0 -0
  306. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/__init__.py +0 -0
  307. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  308. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  309. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  310. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  311. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  312. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  313. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  314. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  315. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  316. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  317. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  318. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  319. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  320. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  321. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  322. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  323. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  324. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  325. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  326. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  327. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  328. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  329. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  330. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  331. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  332. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  333. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/_lowerer.py +0 -0
  334. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/_registry.py +0 -0
  335. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/arithmetic.py +0 -0
  336. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/array.py +0 -0
  337. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/constraint.py +0 -0
  338. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/control.py +0 -0
  339. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/expr.py +0 -0
  340. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/formulation.py +0 -0
  341. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/lie.py +0 -0
  342. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/linalg.py +0 -0
  343. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/logic.py +0 -0
  344. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/math.py +0 -0
  345. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/spatial.py +0 -0
  346. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/state.py +0 -0
  347. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/stl.py +0 -0
  348. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/lowerers/latex/vmap.py +0 -0
  349. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/__init__.py +0 -0
  350. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/_registry.py +0 -0
  351. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/array.py +0 -0
  352. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/constraint.py +0 -0
  353. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/lie.py +0 -0
  354. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/linalg.py +0 -0
  355. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/logic.py +0 -0
  356. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/math.py +0 -0
  357. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/parser.py +0 -0
  358. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/spatial.py +0 -0
  359. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/stl.py +0 -0
  360. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/stljax.py +0 -0
  361. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/parser/tokenizer.py +0 -0
  362. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/problem.py +0 -0
  363. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/sparsity.py +0 -0
  364. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/symbolic/unified.py +0 -0
  365. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/utils/__init__.py +0 -0
  366. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/utils/cache.py +0 -0
  367. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/utils/caching.py +0 -0
  368. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/utils/printing.py +0 -0
  369. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/utils/profiling.py +0 -0
  370. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx/utils/utils.py +0 -0
  371. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx.egg-info/dependency_links.txt +0 -0
  372. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx.egg-info/entry_points.txt +0 -0
  373. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx.egg-info/requires.txt +0 -0
  374. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/openscvx.egg-info/top_level.txt +0 -0
  375. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/pyproject.toml +0 -0
  376. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/scripts/gen_example_pages.py +0 -0
  377. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/scripts/gen_ref_pages.py +0 -0
  378. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  379. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/scripts/mkdocs_seo_hook.py +0 -0
  380. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/setup.cfg +0 -0
  381. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/__init__.py +0 -0
  382. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/__init__.py +0 -0
  383. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/_iteration_helpers.py +0 -0
  384. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/__init__.py +0 -0
  385. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
  386. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
  387. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
  388. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  389. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  390. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/test_iteration_fn_parity.py +0 -0
  391. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/algorithms/test_make_solve_loop.py +0 -0
  392. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/brachistochrone_analytical.py +0 -0
  393. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/conftest.py +0 -0
  394. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/__init__.py +0 -0
  395. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_brachistochrone.py +0 -0
  396. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_impulsive.py +0 -0
  397. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_multishot_propagation.py +0 -0
  398. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_batched_brachistochrone.py +0 -0
  399. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_batched_cvxpy_export_errors.py +0 -0
  400. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_batched_export_roundtrip.py +0 -0
  401. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_bare_brachistochrone.py +0 -0
  402. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_jit_brachistochrone.py +0 -0
  403. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_vmap_brachistochrone.py +0 -0
  404. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/e2e/test_solve_jax_vmap_converged_no_drift.py +0 -0
  405. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/fixtures/brachistochrone.json +0 -0
  406. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/fixtures/brachistochrone.yaml +0 -0
  407. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/hohmann_analytical.py +0 -0
  408. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/integrations/__init__.py +0 -0
  409. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/integrations/test_mjx.py +0 -0
  410. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/integrations/test_mjx_dynamics.py +0 -0
  411. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/__init__.py +0 -0
  412. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/_iteration_callback_helpers.py +0 -0
  413. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  414. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  415. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  416. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  417. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  418. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  419. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  420. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/solvers/test_subproblem_pytree.py +0 -0
  421. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/__init__.py +0 -0
  422. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/__init__.py +0 -0
  423. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_arithmetic.py +0 -0
  424. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_array.py +0 -0
  425. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_constraint.py +0 -0
  426. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_expr.py +0 -0
  427. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_lie.py +0 -0
  428. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_linalg.py +0 -0
  429. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_logic.py +0 -0
  430. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_math.py +0 -0
  431. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_node_reference.py +0 -0
  432. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_parameters.py +0 -0
  433. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_scaling.py +0 -0
  434. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_spatial.py +0 -0
  435. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_stl.py +0 -0
  436. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_variable.py +0 -0
  437. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/expr/test_vmap.py +0 -0
  438. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/__init__.py +0 -0
  439. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_array.py +0 -0
  440. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_constraint.py +0 -0
  441. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_lie.py +0 -0
  442. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_linalg.py +0 -0
  443. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_load.py +0 -0
  444. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_logic.py +0 -0
  445. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_math.py +0 -0
  446. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_parser.py +0 -0
  447. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_spatial.py +0 -0
  448. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_stl.py +0 -0
  449. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_tokenizer.py +0 -0
  450. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/parser/test_vmap.py +0 -0
  451. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_augmentation.py +0 -0
  452. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_gmsr.py +0 -0
  453. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_hashing.py +0 -0
  454. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_latex_formulation.py +0 -0
  455. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_lower_cvxpy.py +0 -0
  456. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_lower_jax.py +0 -0
  457. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_lower_latex.py +0 -0
  458. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_preprocessing.py +0 -0
  459. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_sparsity.py +0 -0
  460. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/symbolic/test_unified.py +0 -0
  461. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_autotuning.py +0 -0
  462. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_cvxpygen_optional.py +0 -0
  463. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_discretization.py +0 -0
  464. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_examples.py +0 -0
  465. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_expert.py +0 -0
  466. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_init.py +0 -0
  467. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_initialize_syncs_guesses.py +0 -0
  468. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_integrators.py +0 -0
  469. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_loader.py +0 -0
  470. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_optimization_results.py +0 -0
  471. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_plotting.py +0 -0
  472. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_post_process_batched_tau_clamp.py +0 -0
  473. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_propagation.py +0 -0
  474. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_results_parameters.py +0 -0
  475. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev51}/tests/test_solve_batched_inference.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev49
3
+ Version: 0.5.3.dev51
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
@@ -91,4 +91,41 @@ def dVdt(self, tau: float, V: jnp.ndarray, u_cur: np.ndarray, u_next: np.ndarray
91
91
  )
92
92
  return dVdt.flatten()
93
93
  ```
94
-
94
+
95
+ ## Supplying your own Jacobian
96
+
97
+ The state and control Jacobians above (`dfdx`, `dfdu`) come from automatic
98
+ differentiation of the dynamics you wrote. Occasionally the exact Jacobian is
99
+ not the one you want: a drag law, a contact model, or a lookup table can be
100
+ smooth enough to integrate while its true derivative makes the convex
101
+ subproblem badly conditioned, so the trust region collapses and the SCP loop
102
+ crawls. The standard remedy is to linearize with a deliberately simplified
103
+ (inexact) Jacobian.
104
+
105
+ `Expr.with_jacobian` applies that remedy to a single term:
106
+
107
+ ``` py
108
+ drag = -0.5 * rho * ox.Norm(vel) * vel
109
+ J_drag = -0.5 * rho * ox.Norm(vel) * np.eye(3) # drops the d||v||/dv term
110
+
111
+ dynamics = {"pos": vel, "vel": thrust / m + drag.with_jacobian({vel: J_drag})}
112
+ ```
113
+
114
+ The keys are the `State` or `Control` objects the derivative is taken with
115
+ respect to, and each value is an expression (or constant array) of shape
116
+ `(*term.shape, *variable.shape)`. Directions you do not name are still
117
+ differentiated automatically, so the example above hands over `∂/∂vel` while
118
+ `∂/∂thrust` still comes from autodiff.
119
+
120
+ The *value* of the term is untouched — only the search direction changes — so a
121
+ converged trajectory still satisfies the original nonlinear dynamics; the
122
+ defect and the propagated solution are computed with the term as written. An
123
+ inexact Jacobian trades linearization accuracy (and hence convergence rate) for
124
+ conditioning, so reach for it when a term is a known source of stiffness, not
125
+ as a default.
126
+
127
+ The override lives inside the lowered JAX function, so every downstream
128
+ derivative picks it up: the discretizer's `A`/`B`, nonconvex constraint
129
+ linearization, and the sparsity pattern used for coloring. It has no meaning
130
+ inside a constraint that is handed to the convex solver as written, and lowering
131
+ one there raises.
@@ -164,6 +164,35 @@ Here, we do _not_ specify an initial or final value for the control but we _do_
164
164
  The initial guess must be of shape $(n_u \times n_{\mathrm{nodes}})$, providing an initial guess for each control at every node.
165
165
  Technically, we can also provide a `.guess` for states. However, these default to a linear interpolation between initial and final conditions which is sufficient in most cases.
166
166
 
167
+ #### Symbolic initial guesses
168
+
169
+ `.guess` accepts three forms, on both states and controls:
170
+
171
+ - an array of shape $(n_{\mathrm{nodes}} \times n)$, as above;
172
+ - a **symbolic expression** in other states and controls;
173
+ - a **callable of `tau`**, the normalized node coordinate, returning a symbolic expression.
174
+
175
+ A guess expression is evaluated at every node, with each referenced variable at its guess value and `tau` running $0 \to 1$ across the grid — the same per-node mental model as dynamics and constraints.
176
+
177
+ ```python
178
+ # Cross-variable: the speed guess follows whatever velocity's guess is
179
+ speed.guess = ox.linalg.Norm(velocity)
180
+
181
+ # Along the grid: a straight line from p0 to pf
182
+ position.guess = lambda tau: p0 + (pf - p0) * tau
183
+ ```
184
+
185
+ References between guesses are the dependency graph: `speed` above is resolved after `velocity`, and a circular reference raises. Everything is evaluated once, when the `Problem` is built (and again on `reset()` if you assign a new expression between solves), so the solver only ever sees ordinary arrays.
186
+
187
+ Because evaluation is per node, guess expressions cannot express trajectory-level constructions such as finite differences or cumulative sums. Build those eagerly with NumPy instead:
188
+
189
+ ```python
190
+ velocity.guess = np.gradient(position.guess, axis=0)
191
+ ```
192
+
193
+ !!! Note
194
+ `time.guess` accepts all three forms, but `time_dilation_guess` remains array-only.
195
+
167
196
  ### Dynamics
168
197
 
169
198
  Dynamics are defined as a dictionary mapping state names to their time derivatives using symbolic expressions:
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.5.3.dev49'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev49')
21
+ __version__ = version = '0.5.3.dev51'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev51')
23
23
 
24
- __commit_id__ = commit_id = 'g02b83a786'
24
+ __commit_id__ = commit_id = 'g21d5581a4'
@@ -75,6 +75,7 @@ from openscvx.symbolic.expr.control import Control
75
75
  from openscvx.symbolic.expr.state import State
76
76
  from openscvx.symbolic.expr.time import Time
77
77
  from openscvx.symbolic.lower import lower_symbolic_problem
78
+ from openscvx.symbolic.preprocessing import resolve_guess_exprs
78
79
  from openscvx.symbolic.problem import SymbolicProblem
79
80
  from openscvx.utils import printing, profiling
80
81
  from openscvx.utils.caching import (
@@ -958,7 +959,8 @@ class Problem:
958
959
  This method reads the current `.guess` values from the original State and
959
960
  Control objects and updates the unified representations. This enables warm-starting
960
961
  workflows where the initial trajectory guess is updated between solves (e.g., shifting
961
- the previous solution).
962
+ the previous solution). Guesses re-assigned symbolically between solves are
963
+ evaluated on the node grid first.
962
964
 
963
965
  Note:
964
966
  This only updates the unified representation. The AlgorithmState is
@@ -968,6 +970,8 @@ class Problem:
968
970
  if self._lowered is None:
969
971
  return
970
972
 
973
+ resolve_guess_exprs(self.symbolic.states, self.symbolic.controls, self.symbolic.N)
974
+
971
975
  # Sync optimization state guesses
972
976
  for state in self.symbolic.states:
973
977
  if state.guess is not None:
@@ -48,6 +48,7 @@ from openscvx.symbolic.preprocessing import (
48
48
  collect_and_assign_slices,
49
49
  convert_dynamics_dict_to_expr,
50
50
  fill_default_guesses,
51
+ resolve_guess_exprs,
51
52
  validate_and_normalize_constraint_nodes,
52
53
  validate_boundary_conditions,
53
54
  validate_bounds,
@@ -220,8 +221,9 @@ def preprocess_symbolic_problem(
220
221
  states = list(states) + [time]
221
222
  time_state = time
222
223
 
223
- # Fill in default guess if needed (for Time instances)
224
- if isinstance(time_state, Time) and time_state.guess is None:
224
+ # Fill in default guess if needed (for Time instances); a symbolic time guess
225
+ # is resolved in Phase 2, so it must not be overwritten here.
226
+ if isinstance(time_state, Time) and time_state.guess is None and time_state._guess_expr is None:
225
227
  time_state.guess = time_state._generate_default_guess(N)
226
228
 
227
229
  # Add CTCS constraints for time bounds
@@ -287,6 +289,9 @@ def preprocess_symbolic_problem(
287
289
  # ==================== PHASE 2: Expression Validation ====================
288
290
  # Validate all expressions (use unsorted constraints)
289
291
  collect_and_assign_slices(states, controls)
292
+ # Evaluate symbolic guesses now that slices exist and time has been added, and
293
+ # before augmentation derives the time-dilation guess from time's guess numerically.
294
+ resolve_guess_exprs(states, controls, N)
290
295
  validate_constraints_at_root(constraints.unsorted)
291
296
  validate_and_normalize_constraint_nodes(constraints.unsorted, N)
292
297
  validate_dynamics_dimension(dynamics_concat, states)
@@ -521,6 +526,17 @@ def add_propagation_states(
521
526
 
522
527
  # ==================== PHASE 1: Validate Extra States ====================
523
528
 
529
+ # Propagation-only states are integrated from their initial condition, never
530
+ # seeded from a guess trajectory, so a symbolic guess has nothing to resolve on.
531
+ for state in states_extra:
532
+ if state._guess_expr is not None:
533
+ raise ValueError(
534
+ f"State '{state.name}': symbolic initial guesses are not supported for "
535
+ f"propagation-only states. These states are integrated forward from "
536
+ f"their initial condition after the solve, so they carry no guess "
537
+ f"trajectory."
538
+ )
539
+
524
540
  # Validate that extra states don't conflict with optimization state names
525
541
  opt_state_names = {s.name for s in states_opt}
526
542
  extra_state_names = {s.name for s in states_extra}
@@ -33,6 +33,11 @@ Module Organization:
33
33
  Array manipulation operations including `Index`, `Concat`, `Stack`, `Hstack`,
34
34
  and `Vstack` for indexing, slicing, and combining arrays.
35
35
 
36
+ User-Supplied Jacobians (autodiff.py):
37
+ `WithJacobian`, built by `Expr.with_jacobian`, replaces a subexpression's
38
+ derivative with respect to chosen variables — the inexact-Jacobian knob for
39
+ SCP conditioning.
40
+
36
41
  Constraints (constraint.py):
37
42
  Constraint types including `Constraint`, `Equality`, `Inequality`,
38
43
  `NodalConstraint`, and `CTCS` (Continuous-Time Constraint Satisfaction).
@@ -80,6 +85,9 @@ from .arithmetic import Add, Div, MatMul, Mul, Neg, Power, Sub
80
85
  # Array operations
81
86
  from .array import Block, Concat, Hstack, Index, Stack, Vstack
82
87
 
88
+ # User-supplied Jacobians
89
+ from .autodiff import WithJacobian
90
+
83
91
  # Specialized constraints
84
92
  from .constraint import (
85
93
  CTCS,
@@ -258,4 +266,6 @@ __all__ = [
258
266
  "ctcs",
259
267
  # Vmap
260
268
  "Vmap",
269
+ # User-supplied Jacobians
270
+ "WithJacobian",
261
271
  ]
@@ -0,0 +1,159 @@
1
+ """User-supplied Jacobians for a subexpression.
2
+
3
+ Successive convexification linearizes the dynamics and constraints at every
4
+ iteration, so the *Jacobian* — not the value — is what shapes each convex
5
+ subproblem. Occasionally the exact Jacobian is the wrong one to hand the
6
+ solver: an aerodynamic drag term, a contact model, or a lookup table can be
7
+ smooth enough to integrate but stiff enough that its true derivative wrecks the
8
+ conditioning of the subproblem. The standard remedy is a deliberately
9
+ simplified (inexact) Jacobian — the trajectory still converges to a solution of
10
+ the *nonlinear* problem, because the value used for the defect is untouched;
11
+ only the search direction changes.
12
+
13
+ :class:`WithJacobian` is that remedy, written at sub-expression granularity::
14
+
15
+ drag = -0.5 * rho * ox.Norm(vel) * vel
16
+ accel = thrust / m + drag.with_jacobian({vel: J_drag})
17
+
18
+ The node wraps a subexpression and carries an override Jacobian per variable.
19
+ Lowering to JAX emits a :func:`jax.custom_jvp` rule around the wrapped
20
+ subexpression, so every downstream differentiation — the discretizer's
21
+ ``jacfwd``, constraint linearization, sparse coloring — sees the user's
22
+ Jacobian in the overridden directions and autodiff everywhere else, with no
23
+ further special-casing. The primal value is always the wrapped expression
24
+ itself.
25
+ """
26
+
27
+ import hashlib
28
+ from typing import Dict, List, Tuple
29
+
30
+ import numpy as np
31
+
32
+ from .expr import Expr, to_expr
33
+ from .variable import Variable
34
+
35
+
36
+ def _without_unit_axes(shape: Tuple[int, ...]) -> Tuple[int, ...]:
37
+ """Drop length-1 axes, the way :class:`Constant` squeezes a wrapped array."""
38
+ return tuple(d for d in shape if d != 1)
39
+
40
+
41
+ class WithJacobian(Expr):
42
+ """A subexpression whose derivative w.r.t. chosen variables is user-supplied.
43
+
44
+ Construct this through :meth:`Expr.with_jacobian` rather than directly. The
45
+ node evaluates exactly like the expression it wraps; only differentiation
46
+ differs, and only in the overridden directions (see the module docstring for
47
+ the motivation).
48
+
49
+ Attributes:
50
+ expr: The wrapped expression, and the node's value.
51
+ overrides: ``(variable, jacobian)`` pairs in the order given, each
52
+ Jacobian shaped ``(*expr.shape, *variable.shape)``.
53
+ """
54
+
55
+ def __init__(self, expr: Expr, jacobians: Dict[Variable, Expr]):
56
+ """Wrap ``expr`` with an override Jacobian per variable.
57
+
58
+ Args:
59
+ expr: Expression whose derivative is being overridden.
60
+ jacobians: Map from a ``State`` or ``Control`` to the Jacobian of
61
+ ``expr`` with respect to it. Values are coerced with
62
+ :func:`to_expr`, so constant matrices are accepted.
63
+
64
+ Raises:
65
+ TypeError: If a key is not a decision variable.
66
+ ValueError: If no Jacobian is given.
67
+ """
68
+ if not jacobians:
69
+ raise ValueError(
70
+ "with_jacobian needs at least one {variable: jacobian} entry; an empty "
71
+ "mapping would wrap the expression without changing anything."
72
+ )
73
+ self.expr = to_expr(expr)
74
+ overrides = []
75
+ for var, jac in jacobians.items():
76
+ if not isinstance(var, Variable):
77
+ raise TypeError(
78
+ f"with_jacobian keys must be the State or Control the derivative is "
79
+ f"taken with respect to, got {type(var).__name__}. Write "
80
+ f"`expr.with_jacobian({{vel: J_vel}})` with `vel` the variable itself."
81
+ )
82
+ overrides.append((var, to_expr(jac)))
83
+ self.overrides: List[Tuple[Variable, Expr]] = overrides
84
+
85
+ def children(self) -> List[Expr]:
86
+ """Return the wrapped expression followed by each override Jacobian.
87
+
88
+ The overridden variables are not children: they identify *directions*,
89
+ not operands, and appear as leaves inside the Jacobian expressions only
90
+ if the user put them there.
91
+ """
92
+ return [self.expr, *(jac for _, jac in self.overrides)]
93
+
94
+ def canonicalize(self) -> Expr:
95
+ """Canonicalize the wrapped expression and every override Jacobian."""
96
+ return WithJacobian(
97
+ self.expr.canonicalize(),
98
+ {var: jac.canonicalize() for var, jac in self.overrides},
99
+ )
100
+
101
+ def check_shape(self) -> Tuple[int, ...]:
102
+ """Return the wrapped expression's shape, validating each Jacobian.
103
+
104
+ A Jacobian must be shaped ``(*expr.shape, *var.shape)``. Unit axes are
105
+ ignored in the comparison: a constant is squeezed when it is wrapped, so
106
+ an honest ``(3, 1)`` Jacobian arrives as ``(3,)``. The JAX lowering
107
+ reshapes it back before contracting.
108
+
109
+ Returns:
110
+ The shape of the wrapped expression — the wrapper is value-transparent.
111
+
112
+ Raises:
113
+ ValueError: If a Jacobian's shape is not ``(*expr.shape, *var.shape)``.
114
+ """
115
+ shape = self.expr.check_shape()
116
+ for var, jac in self.overrides:
117
+ expected = (*shape, *var.shape)
118
+ got = jac.check_shape()
119
+ if _without_unit_axes(got) != _without_unit_axes(expected):
120
+ raise ValueError(
121
+ f"Jacobian for {var.__class__.__name__} '{var.name}' has shape {got}, "
122
+ f"expected {expected}: the derivative of an expression of shape "
123
+ f"{shape} with respect to a variable of shape {var.shape}."
124
+ )
125
+ return shape
126
+
127
+ def sparsity(self, n_x: int, n_u: int) -> Tuple[np.ndarray, np.ndarray]:
128
+ """Conservative pattern: the children's, widened to the overridden columns.
129
+
130
+ The default union over children is not enough here. A user Jacobian may
131
+ be a constant (no dependence of its own) yet still couple outputs to
132
+ every entry of the overridden variable, so those columns are marked
133
+ dense on top of the children's pattern.
134
+ """
135
+ from .control import Control
136
+
137
+ S_x, S_u = super().sparsity(n_x, n_u)
138
+ for var, _ in self.overrides:
139
+ if var._slice is None:
140
+ continue
141
+ S = S_u if isinstance(var, Control) else S_x
142
+ S[:, var._slice] = True
143
+ return S_x, S_u
144
+
145
+ def _hash_into(self, hasher: "hashlib._Hash") -> None:
146
+ """Hash the wrapper, the wrapped expression, and each override in order.
147
+
148
+ Args:
149
+ hasher: A hashlib hash object to update
150
+ """
151
+ hasher.update(b"WithJacobian")
152
+ self.expr._hash_into(hasher)
153
+ for var, jac in self.overrides:
154
+ var._hash_into(hasher)
155
+ jac._hash_into(hasher)
156
+
157
+ def __repr__(self) -> str:
158
+ vars_ = ", ".join(var.name for var, _ in self.overrides)
159
+ return f"{self.expr!r}.with_jacobian({{{vars_}}})"
@@ -308,6 +308,47 @@ class Expr:
308
308
  """
309
309
  return NodeReference(self, k)
310
310
 
311
+ def with_jacobian(self, jacobians: dict) -> "Expr":
312
+ """Override this expression's derivative w.r.t. chosen variables.
313
+
314
+ Successive convexification linearizes at every iteration, so the Jacobian
315
+ of a term — not its value — is what conditions the convex subproblem. A
316
+ deliberately simplified (inexact) Jacobian is a standard remedy for a term
317
+ that is smooth enough to integrate but whose true derivative makes the
318
+ subproblem badly conditioned. The value of the expression is untouched, so
319
+ the converged trajectory still satisfies the original nonlinear problem;
320
+ only the search direction changes.
321
+
322
+ Directions that are not overridden are still differentiated automatically,
323
+ so a single term can hand-specify its state Jacobian and let the control
324
+ Jacobian fall out of autodiff.
325
+
326
+ Args:
327
+ jacobians: Map from a ``State`` or ``Control`` to the Jacobian of this
328
+ expression with respect to it, shaped ``(*self.shape, *var.shape)``
329
+ (a variable of shape ``(n,)`` and a scalar expression give shape
330
+ ``(n,)``). Constant matrices are accepted alongside expressions.
331
+
332
+ Returns:
333
+ Expr: A ``WithJacobian`` node wrapping this expression.
334
+
335
+ Example:
336
+ Damp the drag Jacobian without changing the drag force:
337
+
338
+ drag = -0.5 * rho * ox.Norm(vel) * vel
339
+ J_drag = -0.5 * rho * ox.Norm(vel) * np.eye(3) # drops the d|v|/dv term
340
+
341
+ dynamics = {"vel": thrust / m + drag.with_jacobian({vel: J_drag})}
342
+
343
+ Note:
344
+ The override applies on the JAX path — dynamics linearization and
345
+ constraint linearization. Inside a constraint lowered to CVXPy the
346
+ wrapper has no meaning and raises.
347
+ """
348
+ from .autodiff import WithJacobian
349
+
350
+ return WithJacobian(self, jacobians)
351
+
311
352
  def children(self) -> List["Expr"]:
312
353
  """Return the child expressions of this node.
313
354
 
@@ -1,11 +1,57 @@
1
- from typing import Any, List, Optional, Union
1
+ from typing import Any, List, Optional, Tuple, Union
2
2
 
3
3
  import numpy as np
4
4
  from pydantic import ConfigDict, field_validator
5
5
 
6
+ from openscvx.symbolic.expr.expr import Expr, Leaf
6
7
  from openscvx.symbolic.expr.state import State, StateSpec
7
8
  from openscvx.symbolic.expr.variable import Variable
8
9
 
10
+ #: Key under which the normalized node grid is passed to a lowered guess expression.
11
+ TAU_PARAM = "__tau__"
12
+
13
+
14
+ class Tau(Leaf):
15
+ """Normalized node coordinate, running 0 at the first node to 1 at the last.
16
+
17
+ ``Tau`` is internal plumbing for initial guesses, not part of the user-facing
18
+ vocabulary. A user who needs the node coordinate writes their guess as a
19
+ callable of one argument::
20
+
21
+ pos.guess = lambda tau: p0 + (pf - p0) * tau
22
+
23
+ and the library applies that callable once, at assignment, with a ``Tau``
24
+ instance. The result is an ordinary expression that the guess-resolution pass
25
+ evaluates node by node (see
26
+ :func:`openscvx.symbolic.preprocessing.resolve_guess_exprs`).
27
+
28
+ Physical time is a ``Time`` state; ``Tau`` is the dimensionless grid
29
+ coordinate the trajectory is discretized on, and is meaningful only while
30
+ building a guess.
31
+ """
32
+
33
+ def __init__(self):
34
+ super().__init__("tau", shape=())
35
+
36
+ def check_shape(self) -> Tuple[int, ...]:
37
+ """Reject tau outside of an initial-guess expression.
38
+
39
+ Raises:
40
+ ValueError: Always. Dynamics, constraints, and costs are shape-checked
41
+ eagerly, so this fires exactly when a captured ``tau`` has leaked
42
+ out of the guess it was created for.
43
+ """
44
+ raise ValueError(
45
+ "tau is only meaningful inside initial-guess expressions. It was received "
46
+ "by a `guess = lambda tau: ...` callable and then used in dynamics, a "
47
+ "constraint, or a cost, where there is no node grid to evaluate it on. "
48
+ "Use the `time` state for physical time, or index nodes explicitly with "
49
+ "`.at(k)`."
50
+ )
51
+
52
+ def __repr__(self) -> str:
53
+ return "Tau()"
54
+
9
55
 
10
56
  class Time(State):
11
57
  """Time state variable for trajectory optimization.
@@ -92,15 +138,17 @@ class Time(State):
92
138
  min: Minimum time bound.
93
139
  max: Maximum time bound.
94
140
  guess: Initial guess for the time trajectory. 1D array of shape
95
- (N,) or 2D of shape (N, 1). If not provided, a linear
141
+ (N,), 2D of shape (N, 1), or any symbolic form accepted by
142
+ :attr:`Variable.guess`. If not provided, a linear
96
143
  interpolation from initial to final is generated.
97
144
  time_dilation_min: Absolute minimum bound for time dilation.
98
145
  Defaults to `0.3 * time_final` if not set.
99
146
  time_dilation_max: Absolute maximum bound for time dilation.
100
147
  Defaults to `3.0 * time_final` if not set.
101
148
  time_dilation_guess: Initial guess for time dilation.
102
- 1D array of shape (N,) or 2D of shape (N, 1). Overrides
103
- the default finite-difference computation.
149
+ 1D array of shape (N,) or 2D of shape (N, 1) — arrays only,
150
+ symbolic guesses are not accepted here. Overrides the default
151
+ finite-difference computation.
104
152
  uniform_time_grid: If True, constrain the time dilation to be
105
153
  the same across all nodes (uniform time steps). Defaults
106
154
  to False.
@@ -125,11 +173,7 @@ class Time(State):
125
173
 
126
174
  super().__init__("time", shape=(1,), min=min, max=max, initial=initial, final=final)
127
175
 
128
- # guess: normalize 1D → 2D before assigning
129
176
  if guess is not None:
130
- guess = np.asarray(guess, dtype=float)
131
- if guess.ndim == 1:
132
- guess = guess.reshape(-1, 1)
133
177
  self.guess = guess
134
178
  if time_dilation_min is not None:
135
179
  self.time_dilation_min = time_dilation_min
@@ -167,12 +211,25 @@ class Time(State):
167
211
  State.final.fset(self, val)
168
212
 
169
213
  @Variable.guess.setter
170
- def guess(self, arr):
171
- """Set the time guess. Accepts 1D (N,) or 2D (N, 1) arrays."""
172
- arr = np.asarray(arr, dtype=float)
173
- if arr.ndim == 1:
174
- arr = arr.reshape(-1, 1)
175
- Variable.guess.fset(self, arr)
214
+ def guess(self, value):
215
+ """Set the time guess.
216
+
217
+ Accepts everything :attr:`Variable.guess` accepts — an array, a symbolic
218
+ expression, or a callable of tau — and additionally reshapes a 1D ``(N,)``
219
+ array to ``(N, 1)`` since Time is always shape ``(1,)``. A symbolic guess
220
+ resolving to one value per node is reshaped the same way at build time::
221
+
222
+ time.guess = lambda tau: t0 + (tf - t0) * tau**2
223
+
224
+ Note:
225
+ ``time_dilation_guess`` is a separate, array-only setting; it is not
226
+ resolved from expressions.
227
+ """
228
+ if not isinstance(value, Expr) and not callable(value):
229
+ value = np.asarray(value, dtype=float)
230
+ if value.ndim == 1:
231
+ value = value.reshape(-1, 1)
232
+ Variable.guess.fset(self, value)
176
233
 
177
234
  @property
178
235
  def time_dilation_min(self) -> Optional[float]:
@@ -199,7 +256,7 @@ class Time(State):
199
256
 
200
257
  @property
201
258
  def time_dilation_guess(self) -> Optional[np.ndarray]:
202
- """Initial guess for time dilation, shape (N, 1)."""
259
+ """Initial guess for time dilation, shape (N, 1). Arrays only."""
203
260
  return self._time_dilation_guess
204
261
 
205
262
  @time_dilation_guess.setter