openscvx 0.5.3.dev49__tar.gz → 0.5.3.dev50__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 (470) hide show
  1. {openscvx-0.5.3.dev49/openscvx.egg-info → openscvx-0.5.3.dev50}/PKG-INFO +1 -1
  2. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/01_hello_world_brachistochrone.md +29 -0
  3. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/_version.py +3 -3
  4. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/problem.py +5 -1
  5. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/builder.py +18 -2
  6. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/time.py +72 -15
  7. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/variable.py +68 -12
  8. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/state.py +20 -2
  9. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/preprocessing.py +159 -4
  10. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50/openscvx.egg-info}/PKG-INFO +1 -1
  11. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx.egg-info/SOURCES.txt +1 -0
  12. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx.egg-info/scm_file_list.json +1 -0
  13. openscvx-0.5.3.dev50/openscvx.egg-info/scm_version.json +8 -0
  14. openscvx-0.5.3.dev50/tests/symbolic/expr/test_guess_expr.py +502 -0
  15. openscvx-0.5.3.dev49/openscvx.egg-info/scm_version.json +0 -8
  16. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/assets/logo.svg +0 -0
  17. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/release-drafter.yml +0 -0
  18. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/_docs.yml +0 -0
  19. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/_extra.yml +0 -0
  20. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/branch-name.yml +0 -0
  21. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/docs.yml +0 -0
  22. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/lint.yml +0 -0
  23. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/nightly.yml +0 -0
  24. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/release-drafter.yml +0 -0
  25. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/release.yml +0 -0
  26. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/tests-cvxpygen.yml +0 -0
  27. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/tests-examples.yml +0 -0
  28. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/tests-lie.yml +0 -0
  29. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/tests-mjx.yml +0 -0
  30. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/tests-qpax.yml +0 -0
  31. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.github/workflows/tests.yml +0 -0
  32. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.gitignore +0 -0
  33. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/.gitmodules +0 -0
  34. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/CITATION.cff +0 -0
  35. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/CONTRIBUTING.md +0 -0
  36. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/LICENSE +0 -0
  37. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/README.md +0 -0
  38. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/Foundations/constraint_reformulation.md +0 -0
  39. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/Foundations/control_parameterization.md +0 -0
  40. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/Foundations/discretization.md +0 -0
  41. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/Foundations/ocp.md +0 -0
  42. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/Foundations/scvx.md +0 -0
  43. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/Foundations/time_dilation.md +0 -0
  44. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UnderTheHood/batching_jit_grad.md +0 -0
  45. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
  46. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UnderTheHood/lowering_architecture.md +0 -0
  47. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  48. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/00_introduction.md +0 -0
  49. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  50. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  51. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  52. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/05_visualization.md +0 -0
  53. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/06_logic.md +0 -0
  54. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/07_lie.md +0 -0
  55. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/08_mpcc.md +0 -0
  56. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  57. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/favicon.png +0 -0
  58. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/images/ct-scvx_dark.png +0 -0
  59. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/images/ct-scvx_light.png +0 -0
  60. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/images/ctcs_dark.png +0 -0
  61. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/images/ctcs_light.png +0 -0
  62. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/images/problem_class_dark.png +0 -0
  63. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/images/problem_class_light.png +0 -0
  64. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/logo.svg +0 -0
  65. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/openscvx_logo_square.png +0 -0
  66. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/viser-client/index.html +0 -0
  67. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  68. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  69. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/changelog.md +0 -0
  70. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/citation.md +0 -0
  71. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/examples.md +0 -0
  72. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/index.md +0 -0
  73. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/installation.md +0 -0
  74. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/javascripts/mathjax.js +0 -0
  75. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/llms.txt +0 -0
  76. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/docs/versions.json +0 -0
  77. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/_viser_embed_export.py +0 -0
  78. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/abstract/brachistochrone.py +0 -0
  79. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/abstract/brachistochrone_batched.py +0 -0
  80. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/abstract/flappy_bird.py +0 -0
  81. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/abstract/hypersensitive.py +0 -0
  82. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/abstract/impulsive.py +0 -0
  83. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/abstract/stl_integer_variable.py +0 -0
  84. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/abstract/stl_or.py +0 -0
  85. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/aircraft/dynamic_soaring.py +0 -0
  86. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/aircraft/supersonic_time_to_climb.py +0 -0
  87. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/7_dof_arm.py +0 -0
  88. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/_camera.py +0 -0
  89. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/_render.py +0 -0
  90. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/_sensor_view.py +0 -0
  91. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/dr_vp_polytope.py +0 -0
  92. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  93. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/logo.py +0 -0
  94. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  95. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/arm/3_dof_arm.py +0 -0
  96. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/arm/7_dof_arm.py +0 -0
  97. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/arm/7_dof_arm_collision.py +0 -0
  98. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/arm/7_dof_arm_vp.py +0 -0
  99. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  100. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  101. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  102. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/car/dubins_car.py +0 -0
  103. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/car/dubins_car_disjoint.py +0 -0
  104. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  105. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/car/dubins_car_obstacle_stl.py +0 -0
  106. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/car/dubins_car_stl_or.py +0 -0
  107. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/car/dubins_car_waypoint_stl.py +0 -0
  108. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/double_integrator/_plotting.py +0 -0
  109. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/double_integrator/moving_safe_zones.py +0 -0
  110. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  111. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/boresight_trace_mpcc.py +0 -0
  112. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/cinema_vp.py +0 -0
  113. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/cinema_vp_nodal.py +0 -0
  114. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/dr_double_integrator.py +0 -0
  115. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/dr_vp.py +0 -0
  116. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/dr_vp_nodal.py +0 -0
  117. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/dr_vp_polytope.py +0 -0
  118. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/drone_racing.py +0 -0
  119. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/drone_racing_batched_gates.py +0 -0
  120. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/logo.py +0 -0
  121. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/logo_utils/acl_logo.svg +0 -0
  122. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/logo_utils/circle.svg +0 -0
  123. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  124. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  125. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  126. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/multi_agent_circle_swap.py +0 -0
  127. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/obstacle_avoidance.py +0 -0
  128. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  129. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  130. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  131. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/drone/openscvx_logo.py +0 -0
  132. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/frax/panda_frax.py +0 -0
  133. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/frax/panda_frax_pick_place.py +0 -0
  134. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/frax/panda_frax_viewplanning.py +0 -0
  135. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/frax/panda_frax_waypoint.py +0 -0
  136. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/frax/ur5e_assets/ur5e.urdf +0 -0
  137. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/frax/ur5e_pen_trace.py +0 -0
  138. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/frax/ur5e_pen_trace_mpcc.py +0 -0
  139. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mjx/cartpole_mjx.py +0 -0
  140. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mjx/double_cartpole_mjx.py +0 -0
  141. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mjx/skydio_x2_mjx.py +0 -0
  142. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  143. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mjx/triple_cartpole_game.py +0 -0
  144. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mjx/triple_cartpole_mjx.py +0 -0
  145. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mpc/double_integrator_discrete.py +0 -0
  146. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mpc/double_integrator_drone_racing.py +0 -0
  147. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  148. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  149. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  150. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/plotting.py +0 -0
  151. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/plotting_viser.py +0 -0
  152. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  153. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  154. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  155. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  156. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  157. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  158. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  159. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  160. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/cinema_vp_realtime.py +0 -0
  161. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/drone_racing_realtime.py +0 -0
  162. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/dubins_car_realtime.py +0 -0
  163. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  164. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/rocket/3DoF_pdg.py +0 -0
  165. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/rocket/6DoF_pdg.py +0 -0
  166. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  167. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/rocket/ascent_launch_vehicle.py +0 -0
  168. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/spacecraft/halo_orbit.py +0 -0
  169. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/spacecraft/hohmann_transfer.py +0 -0
  170. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/spacecraft/let_transfer.py +0 -0
  171. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/spacecraft/proxops_cw.py +0 -0
  172. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/examples/spacecraft/relative_loitering.py +0 -0
  173. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/ctlos_cine.gif +0 -0
  174. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/ctlos_dr.gif +0 -0
  175. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/dtlos_cine.gif +0 -0
  176. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/dtlos_dr.gif +0 -0
  177. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/openscvx_logo.svg +0 -0
  178. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/openscvx_logo_square.png +0 -0
  179. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/oscvx_structure_full_dark.svg +0 -0
  180. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/figures/video_preview.png +0 -0
  181. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/__init__.py +0 -0
  182. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/assets/stylesheets/custom.css +0 -0
  183. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  184. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  185. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  186. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/home.html +0 -0
  187. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/main.html +0 -0
  188. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/partials/home-diagram.html +0 -0
  189. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/partials/home-dropin-banner.html +0 -0
  190. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/partials/home-hero.html +0 -0
  191. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/partials/home-pipeline.html +0 -0
  192. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/partials/home-viser-strip.html +0 -0
  193. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/material/overrides/sitemap.xml +0 -0
  194. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/mkdocs.yml +0 -0
  195. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/__init__.py +0 -0
  196. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/__main__.py +0 -0
  197. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/__init__.py +0 -0
  198. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/autotuner/__init__.py +0 -0
  199. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
  200. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  201. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
  202. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/autotuner/base.py +0 -0
  203. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  204. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  205. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/base.py +0 -0
  206. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/history.py +0 -0
  207. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/hyperparams.py +0 -0
  208. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/loop.py +0 -0
  209. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/optimization_results.py +0 -0
  210. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/penalty.py +0 -0
  211. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/scvx/__init__.py +0 -0
  212. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/scvx/iteration.py +0 -0
  213. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
  214. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/state.py +0 -0
  215. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/algorithms/weights.py +0 -0
  216. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/config.py +0 -0
  217. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/__init__.py +0 -0
  218. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/base.py +0 -0
  219. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/discretize_linearize.py +0 -0
  220. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/linearize_discretize.py +0 -0
  221. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  222. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  223. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  224. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  225. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/expert/__init__.py +0 -0
  226. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/expert/byof.py +0 -0
  227. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/expert/lowering.py +0 -0
  228. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/expert/validation.py +0 -0
  229. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/init/__init__.py +0 -0
  230. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/init/interpolation.py +0 -0
  231. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/init/inverse_kinematics.py +0 -0
  232. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrations/__init__.py +0 -0
  233. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrations/_utils.py +0 -0
  234. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrations/base.py +0 -0
  235. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrations/frax.py +0 -0
  236. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrations/menagerie.py +0 -0
  237. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrations/mjx.py +0 -0
  238. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrators/__init__.py +0 -0
  239. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrators/diffrax.py +0 -0
  240. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/integrators/runge_kutta.py +0 -0
  241. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/loader.py +0 -0
  242. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/__init__.py +0 -0
  243. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/cvxpy_constraints.py +0 -0
  244. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/cvxpy_variables.py +0 -0
  245. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/dynamics.py +0 -0
  246. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/jax_constraints.py +0 -0
  247. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/parameters.py +0 -0
  248. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/problem.py +0 -0
  249. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/lowered/unified.py +0 -0
  250. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/__init__.py +0 -0
  251. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/plotting.py +0 -0
  252. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/publication.py +0 -0
  253. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/scp_iteration.py +0 -0
  254. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/__init__.py +0 -0
  255. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/animated.py +0 -0
  256. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/coordinates.py +0 -0
  257. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/orbits.py +0 -0
  258. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/plotly_integration.py +0 -0
  259. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/primitives.py +0 -0
  260. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/scp.py +0 -0
  261. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/plotting/viser/server.py +0 -0
  262. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/propagation/__init__.py +0 -0
  263. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/propagation/post_processing.py +0 -0
  264. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/propagation/propagation.py +0 -0
  265. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/solvers/__init__.py +0 -0
  266. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/solvers/base.py +0 -0
  267. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/solvers/cones.py +0 -0
  268. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/solvers/cvxpy_ptr_solver.py +0 -0
  269. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  270. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/solvers/ptr_solver.py +0 -0
  271. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  272. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/__init__.py +0 -0
  273. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/affine.py +0 -0
  274. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/augmentation.py +0 -0
  275. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/canonicalize.py +0 -0
  276. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/constraint_set.py +0 -0
  277. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/__init__.py +0 -0
  278. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/arithmetic.py +0 -0
  279. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/array.py +0 -0
  280. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/constraint.py +0 -0
  281. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/control.py +0 -0
  282. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/expr.py +0 -0
  283. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  284. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  285. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/lie/se3.py +0 -0
  286. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/lie/so3.py +0 -0
  287. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/linalg.py +0 -0
  288. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/logic.py +0 -0
  289. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/math.py +0 -0
  290. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/parameter.py +0 -0
  291. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/spatial.py +0 -0
  292. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/state.py +0 -0
  293. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/stl.py +0 -0
  294. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/stljax.py +0 -0
  295. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/expr/vmap.py +0 -0
  296. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/hashing.py +0 -0
  297. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lower.py +0 -0
  298. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/__init__.py +0 -0
  299. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  300. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  301. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  302. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  303. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  304. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  305. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  306. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  307. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  308. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  309. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  310. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  311. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  312. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  313. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  314. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  315. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  316. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  317. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  318. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  319. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  320. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  321. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  322. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/math.py +0 -0
  323. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  324. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  325. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  326. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  327. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/__init__.py +0 -0
  328. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/_lowerer.py +0 -0
  329. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/_registry.py +0 -0
  330. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/arithmetic.py +0 -0
  331. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/array.py +0 -0
  332. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/constraint.py +0 -0
  333. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/control.py +0 -0
  334. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/expr.py +0 -0
  335. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/formulation.py +0 -0
  336. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/lie.py +0 -0
  337. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/linalg.py +0 -0
  338. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/logic.py +0 -0
  339. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/math.py +0 -0
  340. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/spatial.py +0 -0
  341. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/state.py +0 -0
  342. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/stl.py +0 -0
  343. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/lowerers/latex/vmap.py +0 -0
  344. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/__init__.py +0 -0
  345. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/_registry.py +0 -0
  346. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/array.py +0 -0
  347. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/constraint.py +0 -0
  348. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/lie.py +0 -0
  349. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/linalg.py +0 -0
  350. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/logic.py +0 -0
  351. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/math.py +0 -0
  352. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/parser.py +0 -0
  353. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/spatial.py +0 -0
  354. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/stl.py +0 -0
  355. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/stljax.py +0 -0
  356. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/parser/tokenizer.py +0 -0
  357. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/problem.py +0 -0
  358. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/sparsity.py +0 -0
  359. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/symbolic/unified.py +0 -0
  360. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/utils/__init__.py +0 -0
  361. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/utils/cache.py +0 -0
  362. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/utils/caching.py +0 -0
  363. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/utils/printing.py +0 -0
  364. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/utils/profiling.py +0 -0
  365. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx/utils/utils.py +0 -0
  366. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx.egg-info/dependency_links.txt +0 -0
  367. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx.egg-info/entry_points.txt +0 -0
  368. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx.egg-info/requires.txt +0 -0
  369. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/openscvx.egg-info/top_level.txt +0 -0
  370. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/pyproject.toml +0 -0
  371. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/scripts/gen_example_pages.py +0 -0
  372. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/scripts/gen_ref_pages.py +0 -0
  373. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  374. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/scripts/mkdocs_seo_hook.py +0 -0
  375. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/setup.cfg +0 -0
  376. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/__init__.py +0 -0
  377. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/__init__.py +0 -0
  378. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/_iteration_helpers.py +0 -0
  379. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/autotuner/__init__.py +0 -0
  380. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
  381. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
  382. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
  383. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  384. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  385. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/test_iteration_fn_parity.py +0 -0
  386. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/algorithms/test_make_solve_loop.py +0 -0
  387. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/brachistochrone_analytical.py +0 -0
  388. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/conftest.py +0 -0
  389. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/__init__.py +0 -0
  390. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_brachistochrone.py +0 -0
  391. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_impulsive.py +0 -0
  392. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_multishot_propagation.py +0 -0
  393. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_solve_batched_brachistochrone.py +0 -0
  394. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_solve_batched_cvxpy_export_errors.py +0 -0
  395. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_solve_batched_export_roundtrip.py +0 -0
  396. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_solve_jax_bare_brachistochrone.py +0 -0
  397. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_solve_jax_jit_brachistochrone.py +0 -0
  398. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_solve_jax_vmap_brachistochrone.py +0 -0
  399. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/e2e/test_solve_jax_vmap_converged_no_drift.py +0 -0
  400. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/fixtures/brachistochrone.json +0 -0
  401. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/fixtures/brachistochrone.yaml +0 -0
  402. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/hohmann_analytical.py +0 -0
  403. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/integrations/__init__.py +0 -0
  404. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/integrations/test_mjx.py +0 -0
  405. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/integrations/test_mjx_dynamics.py +0 -0
  406. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/__init__.py +0 -0
  407. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/_iteration_callback_helpers.py +0 -0
  408. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  409. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  410. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  411. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  412. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  413. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  414. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  415. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/solvers/test_subproblem_pytree.py +0 -0
  416. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/__init__.py +0 -0
  417. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/__init__.py +0 -0
  418. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_arithmetic.py +0 -0
  419. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_array.py +0 -0
  420. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_constraint.py +0 -0
  421. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_expr.py +0 -0
  422. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_lie.py +0 -0
  423. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_linalg.py +0 -0
  424. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_logic.py +0 -0
  425. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_math.py +0 -0
  426. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_node_reference.py +0 -0
  427. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_parameters.py +0 -0
  428. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_scaling.py +0 -0
  429. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_spatial.py +0 -0
  430. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_stl.py +0 -0
  431. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_variable.py +0 -0
  432. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/expr/test_vmap.py +0 -0
  433. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/__init__.py +0 -0
  434. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_array.py +0 -0
  435. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_constraint.py +0 -0
  436. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_lie.py +0 -0
  437. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_linalg.py +0 -0
  438. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_load.py +0 -0
  439. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_logic.py +0 -0
  440. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_math.py +0 -0
  441. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_parser.py +0 -0
  442. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_spatial.py +0 -0
  443. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_stl.py +0 -0
  444. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_tokenizer.py +0 -0
  445. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/parser/test_vmap.py +0 -0
  446. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_augmentation.py +0 -0
  447. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_gmsr.py +0 -0
  448. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_hashing.py +0 -0
  449. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_latex_formulation.py +0 -0
  450. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_lower_cvxpy.py +0 -0
  451. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_lower_jax.py +0 -0
  452. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_lower_latex.py +0 -0
  453. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_preprocessing.py +0 -0
  454. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_sparsity.py +0 -0
  455. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/symbolic/test_unified.py +0 -0
  456. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_autotuning.py +0 -0
  457. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_cvxpygen_optional.py +0 -0
  458. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_discretization.py +0 -0
  459. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_examples.py +0 -0
  460. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_expert.py +0 -0
  461. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_init.py +0 -0
  462. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_initialize_syncs_guesses.py +0 -0
  463. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_integrators.py +0 -0
  464. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_loader.py +0 -0
  465. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_optimization_results.py +0 -0
  466. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_plotting.py +0 -0
  467. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_post_process_batched_tau_clamp.py +0 -0
  468. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_propagation.py +0 -0
  469. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/tests/test_results_parameters.py +0 -0
  470. {openscvx-0.5.3.dev49 → openscvx-0.5.3.dev50}/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.dev50
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
@@ -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.dev50'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev50')
23
23
 
24
- __commit_id__ = commit_id = 'g02b83a786'
24
+ __commit_id__ = commit_id = 'g7ab51dee3'
@@ -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}
@@ -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
@@ -4,7 +4,7 @@ from typing import List, Optional, Tuple
4
4
  import numpy as np
5
5
  from pydantic import BaseModel, ConfigDict
6
6
 
7
- from .expr import Leaf
7
+ from .expr import Expr, Leaf
8
8
 
9
9
 
10
10
  class Variable(Leaf):
@@ -32,6 +32,8 @@ class Variable(Leaf):
32
32
  _min (np.ndarray | None): Minimum bounds for each element of the variable
33
33
  _max (np.ndarray | None): Maximum bounds for each element of the variable
34
34
  _guess (np.ndarray | None): Initial guess for the variable trajectory (n_points, n_vars)
35
+ _guess_expr (Expr | None): Symbolic initial guess awaiting resolution to an
36
+ array at problem-build time; None once resolved
35
37
 
36
38
  Example:
37
39
  # Typically, use State or Control instead of Variable directly:
@@ -51,6 +53,7 @@ class Variable(Leaf):
51
53
  self._min = None
52
54
  self._max = None
53
55
  self._guess = None
56
+ self._guess_expr = None
54
57
 
55
58
  def __repr__(self) -> str:
56
59
  return f"Var({self.name!r})"
@@ -189,14 +192,16 @@ class Variable(Leaf):
189
192
 
190
193
  @property
191
194
  def guess(self) -> Optional[np.ndarray]:
192
- """Get the initial guess for the variable trajectory.
195
+ """Get the initial guess for the variable trajectory, as an array.
193
196
 
194
197
  The guess provides a starting point for the optimizer. A good initial guess
195
198
  can significantly improve convergence speed and help avoid local minima.
196
199
 
197
200
  Returns:
198
201
  2D array of shape (n_points, n_vars) representing the variable trajectory
199
- over time, or None if no guess is provided.
202
+ over time, or None if no guess is provided. A guess assigned symbolically
203
+ also reads back as None until the problem is built and the expression has
204
+ been evaluated on the node grid.
200
205
 
201
206
  Example:
202
207
  x = Variable("x", shape=(2,))
@@ -207,20 +212,36 @@ class Variable(Leaf):
207
212
  return self._guess
208
213
 
209
214
  @guess.setter
210
- def guess(self, arr):
215
+ def guess(self, value):
211
216
  """Set the initial guess for the variable trajectory.
212
217
 
213
- The guess should be a 2D array where each row represents the variable value
214
- at a particular time point or trajectory node.
218
+ Three forms are accepted:
219
+
220
+ - **Array** — a 2D ``(N, n)`` array, one row per trajectory node, validated
221
+ immediately.
222
+ - **Expression** — a symbolic expression in other states and controls. It is
223
+ evaluated once per node at build time, with every referenced variable at its
224
+ own guess value, so ``speed.guess = ox.linalg.Norm(vel)`` gives the per-node speed
225
+ of the velocity guess. The expression itself is the dependency graph:
226
+ referenced guesses are resolved first, and circular references raise.
227
+ - **Callable of tau** — a one-argument function returning an expression, called
228
+ once here with a symbolic normalized node coordinate running 0 → 1, for
229
+ guesses shaped along the grid rather than by other variables:
230
+ ``pos.guess = lambda tau: p0 + (pf - p0) * tau``.
231
+
232
+ Symbolic forms are evaluated node-by-node, so they cannot express
233
+ trajectory-level constructions (finite differences, cumulative sums). Build
234
+ those eagerly with numpy instead, e.g. ``vel.guess = np.gradient(pos.guess,
235
+ axis=0)``.
215
236
 
216
237
  Args:
217
- arr: 2D array of shape (n_points, n_vars) where n_vars matches the
218
- variable dimension. Can be fewer points than the final trajectory -
219
- the solver will interpolate as needed.
238
+ value: An ``(N, n)`` array, an ``Expr``, or a callable taking tau and
239
+ returning an ``Expr``.
220
240
 
221
241
  Raises:
222
- ValueError: If the array is not 2D or if the second dimension doesn't
223
- match the variable dimension
242
+ ValueError: If an array guess is not 2D or its second dimension doesn't
243
+ match the variable dimension, or if a callable returns a non-Expr.
244
+ Shape errors in symbolic guesses surface when the problem is built.
224
245
 
225
246
  Example:
226
247
  pos = Variable("pos", shape=(3,))
@@ -228,7 +249,29 @@ class Variable(Leaf):
228
249
  n_points = 50
229
250
  pos.guess = np.linspace([0, 0, 0], [10, 5, 3], n_points)
230
251
  """
231
- arr = np.asarray(arr, dtype=float)
252
+ if callable(value):
253
+ from .time import Tau
254
+
255
+ expr = value(Tau())
256
+ if not isinstance(expr, Expr):
257
+ raise ValueError(
258
+ f"{self.__class__.__name__} '{self.name}': guess callable returned "
259
+ f"{type(expr).__name__}, not a symbolic expression. The callable "
260
+ f"receives the normalized node coordinate as an Expr and must return "
261
+ f"one built from openscvx operations, e.g. "
262
+ f"lambda tau: p0 + (pf - p0) * tau. Computing on tau with numpy or "
263
+ f"jax.numpy will not work — the guess is composed symbolically and "
264
+ f"only evaluated on the node grid later. For a purely numeric guess, "
265
+ f"assign the array itself."
266
+ )
267
+ value = expr
268
+
269
+ if isinstance(value, Expr):
270
+ self._guess_expr = value
271
+ self._guess = None
272
+ return
273
+
274
+ arr = np.asarray(value, dtype=float)
232
275
  if arr.ndim != 2:
233
276
  raise ValueError(
234
277
  f"{self.__class__.__name__} '{self.name}': guess expected 2D array of shape"
@@ -240,6 +283,7 @@ class Variable(Leaf):
240
283
  f" {self.shape[0]}, got {arr.shape[1]}"
241
284
  )
242
285
  self._guess = arr
286
+ self._guess_expr = None
243
287
 
244
288
  def append(
245
289
  self,
@@ -267,6 +311,9 @@ class Variable(Leaf):
267
311
  guess: Initial guess value for the new dimension (only used if other is None).
268
312
  Defaults to 0.0.
269
313
 
314
+ Raises:
315
+ ValueError: If either variable still carries an unresolved symbolic guess.
316
+
270
317
  Example:
271
318
  Create a 2D variable and extend it to 3D:
272
319
 
@@ -285,6 +332,15 @@ class Variable(Leaf):
285
332
  pos.append(vel) # Now pos has shape (6,)
286
333
  """
287
334
 
335
+ for var in (self, other):
336
+ if isinstance(var, Variable) and var._guess_expr is not None:
337
+ raise ValueError(
338
+ f"{var.__class__.__name__} '{var.name}' has a symbolic initial guess "
339
+ f"that has not been evaluated yet, so it cannot be concatenated. "
340
+ f"Symbolic guesses are resolved when the problem is built; append "
341
+ f"dimensions first, or assign an array guess."
342
+ )
343
+
288
344
  def process_array(val, is_guess=False):
289
345
  """Process input array to ensure correct shape and type.
290
346
 
@@ -1,16 +1,18 @@
1
1
  """JAX visitors for state/time expressions.
2
2
 
3
- Visitors: State, Time
3
+ Visitors: State, Time, Tau
4
4
 
5
5
  Lowers a ``State`` leaf to a JAX function that slices the corresponding entries
6
6
  out of the unified state vector ``x``, using the slice assigned during
7
7
  unification. ``Time`` is a ``State`` subclass and shares the same visitor;
8
8
  lowering a state whose slice is still unset is a usage error and raises.
9
+ ``Tau`` — the normalized node coordinate used by initial-guess expressions —
10
+ reads its value off the node grid carried in ``params``.
9
11
  """
10
12
 
11
13
  # Expression types to handle — uncomment as you paste visitors:
12
14
  from openscvx.symbolic.expr.state import State
13
- from openscvx.symbolic.expr.time import Time
15
+ from openscvx.symbolic.expr.time import TAU_PARAM, Tau, Time
14
16
  from openscvx.symbolic.lowerers.jax._registry import visitor # noqa: F401
15
17
 
16
18
 
@@ -35,3 +37,19 @@ def _visit_state(lowerer, node: State):
35
37
  if sl is None:
36
38
  raise ValueError(f"State {node.name!r} has no slice assigned")
37
39
  return lambda x, u, node, params: x[sl]
40
+
41
+
42
+ @visitor(Tau)
43
+ def _visit_tau(lowerer, node: Tau):
44
+ """Lower the normalized node coordinate to a JAX function.
45
+
46
+ The tau grid is supplied by the guess-resolution pass under the reserved
47
+ ``params`` key, so tau is read at the node currently being evaluated.
48
+
49
+ Args:
50
+ node: Tau expression node
51
+
52
+ Returns:
53
+ Function (x, u, node, params) -> tau at that node
54
+ """
55
+ return lambda x, u, node, params: params[TAU_PARAM][node]
@@ -687,7 +687,8 @@ def fill_default_guesses(states: List[State], N: int) -> None:
687
687
  """Fill in default linspace guesses for states with guess=None.
688
688
 
689
689
  For states with both initial and final conditions set, generates a linear
690
- interpolation from initial to final values.
690
+ interpolation from initial to final values. States carrying a symbolic guess
691
+ are left alone — theirs is filled by :func:`resolve_guess_exprs`.
691
692
 
692
693
  This function modifies states in-place.
693
694
 
@@ -698,6 +699,8 @@ def fill_default_guesses(states: List[State], N: int) -> None:
698
699
  from openscvx.init import linspace
699
700
 
700
701
  for state in states:
702
+ if state._guess_expr is not None:
703
+ continue
701
704
  if state.guess is None and state.initial is not None and state.final is not None:
702
705
  # state.initial and state.final are already numpy arrays of values
703
706
  # (the setter handles parsing tuples like ("free", value))
@@ -707,6 +710,151 @@ def fill_default_guesses(states: List[State], N: int) -> None:
707
710
  )
708
711
 
709
712
 
713
+ def resolve_guess_exprs(states: List[State], controls: List[Control], N: int) -> None:
714
+ """Evaluate symbolic initial guesses on the node grid, in dependency order.
715
+
716
+ A symbolic guess (``speed.guess = ox.linalg.Norm(vel)``, ``pos.guess = lambda tau: ...``)
717
+ defines the guess *per node*: the expression is evaluated at every node with each
718
+ referenced variable at its own guess value and tau running 0 → 1 across the grid —
719
+ the same mental model as dynamics and constraints. Guesses that reference other
720
+ symbolic guesses are resolved first; the expressions themselves are the dependency
721
+ graph.
722
+
723
+ Each resolved variable has its ``_guess`` array filled and its pending expression
724
+ cleared, so everything downstream sees an ordinary eager guess. Variables without
725
+ a symbolic guess are untouched, and the function returns immediately when there
726
+ are none.
727
+
728
+ This function modifies variables in-place, and requires slices to have been
729
+ assigned (see :func:`collect_and_assign_slices`).
730
+
731
+ Args:
732
+ states: State objects whose guesses may be referenced or resolved
733
+ controls: Control objects whose guesses may be referenced or resolved
734
+ N: Number of discretization nodes
735
+
736
+ Raises:
737
+ ValueError: If a guess references a variable outside this problem, if the
738
+ guesses reference each other circularly, or if an evaluated guess does
739
+ not have shape ``(N, n)``.
740
+ """
741
+ import jax
742
+ import jax.numpy as jnp
743
+
744
+ from openscvx.symbolic.expr.parameter import Parameter
745
+ from openscvx.symbolic.expr.time import TAU_PARAM
746
+ from openscvx.symbolic.lower import lower_to_jax
747
+
748
+ variables = list(states) + list(controls)
749
+ pending = [var for var in variables if var._guess_expr is not None]
750
+ if not pending:
751
+ return
752
+
753
+ known = {id(var) for var in variables}
754
+ dependencies = {id(var): _guess_dependencies(var, known) for var in pending}
755
+
756
+ # Kahn's algorithm over the pending variables: a guess is ready once every
757
+ # pending variable it references has been resolved.
758
+ order, resolved, unordered = [], set(), list(pending)
759
+ while unordered:
760
+ ready = [
761
+ var
762
+ for var in unordered
763
+ if all(
764
+ id(dep) not in dependencies or id(dep) in resolved for dep in dependencies[id(var)]
765
+ )
766
+ ]
767
+ if not ready:
768
+ raise ValueError(
769
+ f"Circular initial-guess dependency among "
770
+ f"{sorted(var.name for var in unordered)}. Each guess expression is "
771
+ f"evaluated from the guesses it references, so the references cannot "
772
+ f"form a cycle — break it by giving one of them an array guess."
773
+ )
774
+ order.extend(ready)
775
+ resolved.update(id(var) for var in ready)
776
+ unordered = [var for var in unordered if id(var) not in resolved]
777
+
778
+ tau = jnp.linspace(0.0, 1.0, N)
779
+ nodes = jnp.arange(N)
780
+ for var in order:
781
+ expr = var._guess_expr
782
+ params = {TAU_PARAM: tau}
783
+
784
+ def bind_parameter(node, params=params):
785
+ if isinstance(node, Parameter):
786
+ params[node.name] = node.value
787
+
788
+ traverse(expr, bind_parameter)
789
+ fn = lower_to_jax(expr)
790
+ values = jax.vmap(fn, in_axes=(0, 0, 0, None))(
791
+ _guess_trajectory(states, N), _guess_trajectory(controls, N), nodes, params
792
+ )
793
+
794
+ guess = np.asarray(values, dtype=float)
795
+ if guess.ndim == 1 and var.shape[0] == 1:
796
+ guess = guess.reshape(-1, 1)
797
+ if guess.shape != (N, var.shape[0]):
798
+ raise ValueError(
799
+ f"{var.__class__.__name__} '{var.name}': guess expression evaluated to "
800
+ f"shape {guess.shape}, expected ({N}, {var.shape[0]}). The expression is "
801
+ f"evaluated once per node, so it must produce one row of "
802
+ f"{var.shape[0]} value(s) per node."
803
+ )
804
+ var._guess = guess
805
+ var._guess_expr = None
806
+
807
+
808
+ def _guess_dependencies(var: Variable, known: Set[int]) -> List[Variable]:
809
+ """Collect the variables a symbolic guess reads, in first-seen order.
810
+
811
+ Args:
812
+ var: Variable carrying the pending guess expression
813
+ known: Ids of the variables belonging to this problem
814
+
815
+ Raises:
816
+ ValueError: If the expression references a variable outside the problem
817
+ """
818
+ dependencies = {}
819
+
820
+ def visit(node):
821
+ if not isinstance(node, Variable):
822
+ return
823
+ if id(node) not in known:
824
+ raise ValueError(
825
+ f"{var.__class__.__name__} '{var.name}': guess expression references "
826
+ f"{node.__class__.__name__} '{node.name}', which is not one of this "
827
+ f"problem's states or controls. Guess expressions may only reference "
828
+ f"variables passed to Problem."
829
+ )
830
+ dependencies.setdefault(id(node), node)
831
+
832
+ traverse(var._guess_expr, visit)
833
+ return list(dependencies.values())
834
+
835
+
836
+ def _guess_trajectory(variables: List[Variable], N: int) -> np.ndarray:
837
+ """Assemble the (N, n) guess trajectory for a set of states or controls.
838
+
839
+ Columns of variables whose guess is not yet resolved are left at zero;
840
+ dependency ordering guarantees the columns a guess expression reads are filled.
841
+ """
842
+ n = max((var._slice.stop for var in variables), default=0)
843
+ trajectory = np.zeros((N, n))
844
+ for var in variables:
845
+ if var._guess is None:
846
+ continue
847
+ if var._guess.shape[0] != N:
848
+ raise ValueError(
849
+ f"{var.__class__.__name__} '{var.name}': guess spans "
850
+ f"{var._guess.shape[0]} nodes but the problem has N={N}. Guess "
851
+ f"expressions are evaluated node by node, so every guess they read "
852
+ f"must cover the whole grid."
853
+ )
854
+ trajectory[:, var._slice] = var._guess
855
+ return trajectory
856
+
857
+
710
858
  def validate_boundary_conditions(states: List[State]) -> None:
711
859
  """Validate that all states have initial and final boundary conditions set.
712
860
 
@@ -908,6 +1056,9 @@ def validate_propagation_input_types(
908
1056
  def validate_guesses(variables: List[Variable]) -> None:
909
1057
  """Validate that all variables have initial guesses set.
910
1058
 
1059
+ A guess assigned symbolically counts as set even though it has not been
1060
+ evaluated to an array yet.
1061
+
911
1062
  Args:
912
1063
  variables: List of Variable objects (State or Control) to validate
913
1064
 
@@ -915,12 +1066,16 @@ def validate_guesses(variables: List[Variable]) -> None:
915
1066
  ValueError: If any variable is missing a guess
916
1067
  """
917
1068
  for var in variables:
918
- if var.guess is None:
1069
+ if var.guess is None and var._guess_expr is None:
919
1070
  if isinstance(var, Control):
920
1071
  raise ValueError(
921
1072
  f"Control '{var.name}' is missing initial guess. "
922
- f"Please set {var.name}.guess (controls require explicit guesses)"
1073
+ f"Please set {var.name}.guess to an array, an expression in other "
1074
+ f"states and controls, or a callable of tau "
1075
+ f"(controls require explicit guesses)"
923
1076
  )
924
1077
  raise ValueError(
925
- f"State '{var.name}' is missing initial guess. Please set {var.name}.guess"
1078
+ f"State '{var.name}' is missing initial guess. Please set {var.name}.guess "
1079
+ f"to an array, an expression in other states and controls, or a "
1080
+ f"callable of tau"
926
1081
  )
@@ -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.dev50
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