openscvx 0.5.3.dev43__tar.gz → 0.5.3.dev45__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 (468) hide show
  1. {openscvx-0.5.3.dev43/openscvx.egg-info → openscvx-0.5.3.dev45}/PKG-INFO +2 -2
  2. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/abstract/brachistochrone.py +1 -0
  3. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/_version.py +3 -3
  4. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/solvers/cvxpy_ptr_solver.py +1 -1
  5. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/math.py +125 -26
  6. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/math.py +26 -11
  7. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/math.py +5 -6
  8. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45/openscvx.egg-info}/PKG-INFO +2 -2
  9. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx.egg-info/requires.txt +1 -1
  10. openscvx-0.5.3.dev45/openscvx.egg-info/scm_version.json +8 -0
  11. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/pyproject.toml +1 -1
  12. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_brachistochrone.py +8 -8
  13. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_math.py +166 -0
  14. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_loader.py +2 -2
  15. openscvx-0.5.3.dev43/openscvx.egg-info/scm_version.json +0 -8
  16. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/assets/logo.svg +0 -0
  17. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/release-drafter.yml +0 -0
  18. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/_docs.yml +0 -0
  19. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/_extra.yml +0 -0
  20. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/branch-name.yml +0 -0
  21. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/docs.yml +0 -0
  22. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/lint.yml +0 -0
  23. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/nightly.yml +0 -0
  24. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/release-drafter.yml +0 -0
  25. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/release.yml +0 -0
  26. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/tests-cvxpygen.yml +0 -0
  27. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/tests-examples.yml +0 -0
  28. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/tests-lie.yml +0 -0
  29. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/tests-mjx.yml +0 -0
  30. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/tests-qpax.yml +0 -0
  31. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.github/workflows/tests.yml +0 -0
  32. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.gitignore +0 -0
  33. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/.gitmodules +0 -0
  34. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/CITATION.cff +0 -0
  35. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/CONTRIBUTING.md +0 -0
  36. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/LICENSE +0 -0
  37. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/README.md +0 -0
  38. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/Foundations/constraint_reformulation.md +0 -0
  39. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/Foundations/control_parameterization.md +0 -0
  40. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/Foundations/discretization.md +0 -0
  41. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/Foundations/ocp.md +0 -0
  42. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/Foundations/scvx.md +0 -0
  43. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/Foundations/time_dilation.md +0 -0
  44. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UnderTheHood/batching_jit_grad.md +0 -0
  45. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UnderTheHood/custom_algorithms_autotuners.md +0 -0
  46. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UnderTheHood/lowering_architecture.md +0 -0
  47. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  48. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/00_introduction.md +0 -0
  49. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
  50. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
  51. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
  52. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
  53. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/05_visualization.md +0 -0
  54. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/06_logic.md +0 -0
  55. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/07_lie.md +0 -0
  56. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/08_mpcc.md +0 -0
  57. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/UsersGuide/09_mjx_dynamics.md +0 -0
  58. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/favicon.png +0 -0
  59. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/images/ct-scvx_dark.png +0 -0
  60. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/images/ct-scvx_light.png +0 -0
  61. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/images/ctcs_dark.png +0 -0
  62. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/images/ctcs_light.png +0 -0
  63. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/images/problem_class_dark.png +0 -0
  64. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/images/problem_class_light.png +0 -0
  65. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/logo.svg +0 -0
  66. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/openscvx_logo_square.png +0 -0
  67. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/viser-client/index.html +0 -0
  68. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/viser-recordings/drone_racing.viser +0 -0
  69. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/assets/viser-recordings/franka_fr3v2_pick_place.viser +0 -0
  70. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/changelog.md +0 -0
  71. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/citation.md +0 -0
  72. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/examples.md +0 -0
  73. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/index.md +0 -0
  74. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/installation.md +0 -0
  75. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/javascripts/mathjax.js +0 -0
  76. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/llms.txt +0 -0
  77. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/docs/versions.json +0 -0
  78. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/_viser_embed_export.py +0 -0
  79. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/abstract/brachistochrone_batched.py +0 -0
  80. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/abstract/flappy_bird.py +0 -0
  81. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/abstract/hypersensitive.py +0 -0
  82. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/abstract/impulsive.py +0 -0
  83. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/abstract/stl_integer_variable.py +0 -0
  84. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/abstract/stl_or.py +0 -0
  85. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/aircraft/dynamic_soaring.py +0 -0
  86. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/aircraft/supersonic_time_to_climb.py +0 -0
  87. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/7_dof_arm.py +0 -0
  88. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/_camera.py +0 -0
  89. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/_render.py +0 -0
  90. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/_sensor_view.py +0 -0
  91. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/dr_vp_polytope.py +0 -0
  92. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/franka_fr3v2_pick_place.py +0 -0
  93. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/logo.py +0 -0
  94. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/animations/obstacle_avoidance_vmap.py +0 -0
  95. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/arm/3_dof_arm.py +0 -0
  96. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/arm/7_dof_arm.py +0 -0
  97. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/arm/7_dof_arm_collision.py +0 -0
  98. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/arm/7_dof_arm_vp.py +0 -0
  99. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/arm/franka_fr3v2_pick_place.py +0 -0
  100. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/arm/franka_fr3v2_viewplanning.py +0 -0
  101. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/arm/franka_fr3v2_viewplanning_nodal.py +0 -0
  102. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/car/dubins_car.py +0 -0
  103. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/car/dubins_car_disjoint.py +0 -0
  104. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/car/dubins_car_obstacle_conditional.py +0 -0
  105. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/car/dubins_car_obstacle_stl.py +0 -0
  106. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/car/dubins_car_stl_or.py +0 -0
  107. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/car/dubins_car_waypoint_stl.py +0 -0
  108. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/double_integrator/_plotting.py +0 -0
  109. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/double_integrator/moving_safe_zones.py +0 -0
  110. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/2d_obstacle_avoidance_batched_ic.py +0 -0
  111. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/boresight_trace_mpcc.py +0 -0
  112. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/cinema_vp.py +0 -0
  113. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/cinema_vp_nodal.py +0 -0
  114. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/dr_double_integrator.py +0 -0
  115. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/dr_vp.py +0 -0
  116. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/dr_vp_nodal.py +0 -0
  117. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/dr_vp_polytope.py +0 -0
  118. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/drone_racing.py +0 -0
  119. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/drone_racing_batched_gates.py +0 -0
  120. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/logo.py +0 -0
  121. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/logo_utils/acl_logo.svg +0 -0
  122. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/logo_utils/circle.svg +0 -0
  123. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/logo_utils/openscvx_logo_single.svg +0 -0
  124. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/logo_utils/quadrotor_mesh.py +0 -0
  125. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/logo_utils/svg_path_utils.py +0 -0
  126. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/multi_agent_circle_swap.py +0 -0
  127. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/obstacle_avoidance.py +0 -0
  128. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  129. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  130. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/obstacle_avoidance_vmap_2d.py +0 -0
  131. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/drone/openscvx_logo.py +0 -0
  132. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/frax/panda_frax.py +0 -0
  133. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/frax/panda_frax_pick_place.py +0 -0
  134. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/frax/panda_frax_viewplanning.py +0 -0
  135. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/frax/panda_frax_waypoint.py +0 -0
  136. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/frax/ur5e_assets/ur5e.urdf +0 -0
  137. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/frax/ur5e_pen_trace.py +0 -0
  138. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mjx/cartpole_mjx.py +0 -0
  139. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mjx/double_cartpole_mjx.py +0 -0
  140. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mjx/skydio_x2_mjx.py +0 -0
  141. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mjx/triple_cartpole_3d_mjx.py +0 -0
  142. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mjx/triple_cartpole_game.py +0 -0
  143. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mjx/triple_cartpole_mjx.py +0 -0
  144. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mpc/double_integrator_discrete.py +0 -0
  145. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mpc/double_integrator_drone_racing.py +0 -0
  146. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mpc/dubins_car_circle_analytical.py +0 -0
  147. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mpc/dubins_car_circle_discrete.py +0 -0
  148. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
  149. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/plotting.py +0 -0
  150. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/plotting_viser.py +0 -0
  151. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/3DoF_pdg_realtime.py +0 -0
  152. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/6DoF_pdg_realtime.py +0 -0
  153. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
  154. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
  155. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
  156. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
  157. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
  158. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
  159. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/cinema_vp_realtime.py +0 -0
  160. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/drone_racing_realtime.py +0 -0
  161. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/dubins_car_realtime.py +0 -0
  162. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  163. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/rocket/3DoF_pdg.py +0 -0
  164. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/rocket/6DoF_pdg.py +0 -0
  165. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/rocket/6DoF_pdg_batched_ic.py +0 -0
  166. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/rocket/ascent_launch_vehicle.py +0 -0
  167. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/spacecraft/halo_orbit.py +0 -0
  168. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/spacecraft/hohmann_transfer.py +0 -0
  169. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/spacecraft/let_transfer.py +0 -0
  170. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/spacecraft/proxops_cw.py +0 -0
  171. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/examples/spacecraft/relative_loitering.py +0 -0
  172. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/ctlos_cine.gif +0 -0
  173. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/ctlos_dr.gif +0 -0
  174. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/dtlos_cine.gif +0 -0
  175. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/dtlos_dr.gif +0 -0
  176. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/openscvx_logo.svg +0 -0
  177. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/openscvx_logo_square.png +0 -0
  178. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/oscvx_structure_full_dark.svg +0 -0
  179. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/figures/video_preview.png +0 -0
  180. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/__init__.py +0 -0
  181. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/assets/stylesheets/custom.css +0 -0
  182. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/assets/stylesheets/home-dropin.css +0 -0
  183. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/assets/stylesheets/home-hero.css +0 -0
  184. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/assets/stylesheets/home-viser.css +0 -0
  185. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/home.html +0 -0
  186. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/main.html +0 -0
  187. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/partials/home-diagram.html +0 -0
  188. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/partials/home-dropin-banner.html +0 -0
  189. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/partials/home-hero.html +0 -0
  190. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/partials/home-pipeline.html +0 -0
  191. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/partials/home-viser-strip.html +0 -0
  192. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/material/overrides/sitemap.xml +0 -0
  193. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/mkdocs.yml +0 -0
  194. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/__init__.py +0 -0
  195. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/__main__.py +0 -0
  196. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/__init__.py +0 -0
  197. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/autotuner/__init__.py +0 -0
  198. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/autotuner/acceptance_ratio.py +0 -0
  199. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/autotuner/adaptive_proximal_weight.py +0 -0
  200. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/autotuner/augmented_lagrangian.py +0 -0
  201. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/autotuner/base.py +0 -0
  202. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/autotuner/constant_proximal_weight.py +0 -0
  203. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/autotuner/ramp_proximal_weight.py +0 -0
  204. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/base.py +0 -0
  205. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/history.py +0 -0
  206. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/hyperparams.py +0 -0
  207. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/loop.py +0 -0
  208. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/optimization_results.py +0 -0
  209. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/penalty.py +0 -0
  210. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/scvx/__init__.py +0 -0
  211. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/scvx/iteration.py +0 -0
  212. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/scvx/penalized_trust_region.py +0 -0
  213. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/state.py +0 -0
  214. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/algorithms/weights.py +0 -0
  215. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/config.py +0 -0
  216. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/__init__.py +0 -0
  217. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/base.py +0 -0
  218. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/discretize_linearize.py +0 -0
  219. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/linearize_discretize.py +0 -0
  220. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
  221. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/sparse_utils/__init__.py +0 -0
  222. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
  223. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
  224. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/expert/__init__.py +0 -0
  225. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/expert/byof.py +0 -0
  226. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/expert/lowering.py +0 -0
  227. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/expert/validation.py +0 -0
  228. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/init/__init__.py +0 -0
  229. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/init/interpolation.py +0 -0
  230. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/init/inverse_kinematics.py +0 -0
  231. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrations/__init__.py +0 -0
  232. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrations/_utils.py +0 -0
  233. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrations/base.py +0 -0
  234. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrations/frax.py +0 -0
  235. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrations/menagerie.py +0 -0
  236. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrations/mjx.py +0 -0
  237. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrators/__init__.py +0 -0
  238. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrators/diffrax.py +0 -0
  239. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/integrators/runge_kutta.py +0 -0
  240. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/loader.py +0 -0
  241. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/__init__.py +0 -0
  242. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/cvxpy_constraints.py +0 -0
  243. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/cvxpy_variables.py +0 -0
  244. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/dynamics.py +0 -0
  245. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/jax_constraints.py +0 -0
  246. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/parameters.py +0 -0
  247. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/problem.py +0 -0
  248. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/lowered/unified.py +0 -0
  249. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/__init__.py +0 -0
  250. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/plotting.py +0 -0
  251. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/publication.py +0 -0
  252. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/scp_iteration.py +0 -0
  253. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/__init__.py +0 -0
  254. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/animated.py +0 -0
  255. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/coordinates.py +0 -0
  256. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/orbits.py +0 -0
  257. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/plotly_integration.py +0 -0
  258. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/primitives.py +0 -0
  259. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/scp.py +0 -0
  260. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/plotting/viser/server.py +0 -0
  261. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/problem.py +0 -0
  262. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/propagation/__init__.py +0 -0
  263. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/propagation/post_processing.py +0 -0
  264. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/propagation/propagation.py +0 -0
  265. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/solvers/__init__.py +0 -0
  266. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/solvers/base.py +0 -0
  267. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/solvers/cones.py +0 -0
  268. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/solvers/moreau_ptr_solver.py +0 -0
  269. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/solvers/ptr_solver.py +0 -0
  270. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/solvers/qpax_ptr_solver.py +0 -0
  271. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/__init__.py +0 -0
  272. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/affine.py +0 -0
  273. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/augmentation.py +0 -0
  274. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/builder.py +0 -0
  275. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/canonicalize.py +0 -0
  276. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/constraint_set.py +0 -0
  277. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/__init__.py +0 -0
  278. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/arithmetic.py +0 -0
  279. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/array.py +0 -0
  280. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/constraint.py +0 -0
  281. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/control.py +0 -0
  282. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/expr.py +0 -0
  283. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  284. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  285. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/lie/se3.py +0 -0
  286. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/lie/so3.py +0 -0
  287. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/linalg.py +0 -0
  288. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/logic.py +0 -0
  289. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/parameter.py +0 -0
  290. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/spatial.py +0 -0
  291. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/state.py +0 -0
  292. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/stl.py +0 -0
  293. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/stljax.py +0 -0
  294. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/time.py +0 -0
  295. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/variable.py +0 -0
  296. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/expr/vmap.py +0 -0
  297. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/hashing.py +0 -0
  298. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lower.py +0 -0
  299. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/__init__.py +0 -0
  300. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
  301. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
  302. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
  303. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
  304. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
  305. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
  306. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
  307. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
  308. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
  309. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
  310. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
  311. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
  312. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
  313. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
  314. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
  315. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
  316. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/array.py +0 -0
  317. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
  318. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/control.py +0 -0
  319. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
  320. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
  321. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
  322. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
  323. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
  324. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/state.py +0 -0
  325. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
  326. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
  327. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
  328. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/__init__.py +0 -0
  329. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/_lowerer.py +0 -0
  330. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/_registry.py +0 -0
  331. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/arithmetic.py +0 -0
  332. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/array.py +0 -0
  333. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/constraint.py +0 -0
  334. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/control.py +0 -0
  335. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/expr.py +0 -0
  336. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/formulation.py +0 -0
  337. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/lie.py +0 -0
  338. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/linalg.py +0 -0
  339. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/logic.py +0 -0
  340. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/spatial.py +0 -0
  341. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/state.py +0 -0
  342. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/stl.py +0 -0
  343. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/lowerers/latex/vmap.py +0 -0
  344. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/__init__.py +0 -0
  345. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/_registry.py +0 -0
  346. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/array.py +0 -0
  347. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/constraint.py +0 -0
  348. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/lie.py +0 -0
  349. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/linalg.py +0 -0
  350. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/logic.py +0 -0
  351. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/math.py +0 -0
  352. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/parser.py +0 -0
  353. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/spatial.py +0 -0
  354. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/stl.py +0 -0
  355. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/stljax.py +0 -0
  356. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/parser/tokenizer.py +0 -0
  357. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/preprocessing.py +0 -0
  358. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/problem.py +0 -0
  359. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/sparsity.py +0 -0
  360. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/symbolic/unified.py +0 -0
  361. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/utils/__init__.py +0 -0
  362. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/utils/cache.py +0 -0
  363. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/utils/caching.py +0 -0
  364. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/utils/printing.py +0 -0
  365. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/utils/profiling.py +0 -0
  366. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx/utils/utils.py +0 -0
  367. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx.egg-info/SOURCES.txt +0 -0
  368. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx.egg-info/dependency_links.txt +0 -0
  369. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx.egg-info/entry_points.txt +0 -0
  370. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx.egg-info/scm_file_list.json +0 -0
  371. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/openscvx.egg-info/top_level.txt +0 -0
  372. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/scripts/gen_example_pages.py +0 -0
  373. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/scripts/gen_ref_pages.py +0 -0
  374. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/scripts/mkdocs_copy_viser_client_hook.py +0 -0
  375. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/scripts/mkdocs_seo_hook.py +0 -0
  376. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/setup.cfg +0 -0
  377. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/__init__.py +0 -0
  378. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/__init__.py +0 -0
  379. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/_iteration_helpers.py +0 -0
  380. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/autotuner/__init__.py +0 -0
  381. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/autotuner/test_defaults_agreement.py +0 -0
  382. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/autotuner/test_hyper_overrides.py +0 -0
  383. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/autotuner/test_update_weights_jit.py +0 -0
  384. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/test_algorithm_state_pytree.py +0 -0
  385. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/test_iteration_fn_jit.py +0 -0
  386. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/test_iteration_fn_parity.py +0 -0
  387. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/algorithms/test_make_solve_loop.py +0 -0
  388. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/brachistochrone_analytical.py +0 -0
  389. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/conftest.py +0 -0
  390. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/__init__.py +0 -0
  391. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_impulsive.py +0 -0
  392. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_multishot_propagation.py +0 -0
  393. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_solve_batched_brachistochrone.py +0 -0
  394. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_solve_batched_cvxpy_export_errors.py +0 -0
  395. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_solve_batched_export_roundtrip.py +0 -0
  396. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_solve_jax_bare_brachistochrone.py +0 -0
  397. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_solve_jax_jit_brachistochrone.py +0 -0
  398. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_solve_jax_vmap_brachistochrone.py +0 -0
  399. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/e2e/test_solve_jax_vmap_converged_no_drift.py +0 -0
  400. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/fixtures/brachistochrone.json +0 -0
  401. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/fixtures/brachistochrone.yaml +0 -0
  402. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/hohmann_analytical.py +0 -0
  403. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/integrations/__init__.py +0 -0
  404. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/integrations/test_mjx.py +0 -0
  405. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/integrations/test_mjx_dynamics.py +0 -0
  406. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/__init__.py +0 -0
  407. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/_iteration_callback_helpers.py +0 -0
  408. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_cvxpy_callback_jit_spike.py +0 -0
  409. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_iteration_callback_cvxpy.py +0 -0
  410. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_iteration_callback_moreau.py +0 -0
  411. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_iteration_callback_qpax.py +0 -0
  412. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_iteration_callback_vmap.py +0 -0
  413. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_moreau_ptr_solver.py +0 -0
  414. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_qpax_ptr_solver.py +0 -0
  415. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/solvers/test_subproblem_pytree.py +0 -0
  416. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/__init__.py +0 -0
  417. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/__init__.py +0 -0
  418. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_arithmetic.py +0 -0
  419. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_array.py +0 -0
  420. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_constraint.py +0 -0
  421. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_expr.py +0 -0
  422. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_lie.py +0 -0
  423. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_linalg.py +0 -0
  424. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_logic.py +0 -0
  425. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_node_reference.py +0 -0
  426. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_parameters.py +0 -0
  427. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_scaling.py +0 -0
  428. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_spatial.py +0 -0
  429. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_stl.py +0 -0
  430. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_variable.py +0 -0
  431. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/expr/test_vmap.py +0 -0
  432. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/__init__.py +0 -0
  433. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_array.py +0 -0
  434. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_constraint.py +0 -0
  435. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_lie.py +0 -0
  436. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_linalg.py +0 -0
  437. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_load.py +0 -0
  438. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_logic.py +0 -0
  439. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_math.py +0 -0
  440. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_parser.py +0 -0
  441. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_spatial.py +0 -0
  442. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_stl.py +0 -0
  443. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_tokenizer.py +0 -0
  444. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/parser/test_vmap.py +0 -0
  445. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_augmentation.py +0 -0
  446. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_gmsr.py +0 -0
  447. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_hashing.py +0 -0
  448. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_latex_formulation.py +0 -0
  449. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_lower_cvxpy.py +0 -0
  450. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_lower_jax.py +0 -0
  451. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_lower_latex.py +0 -0
  452. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_preprocessing.py +0 -0
  453. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_sparsity.py +0 -0
  454. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/symbolic/test_unified.py +0 -0
  455. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_autotuning.py +0 -0
  456. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_cvxpygen_optional.py +0 -0
  457. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_discretization.py +0 -0
  458. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_examples.py +0 -0
  459. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_expert.py +0 -0
  460. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_init.py +0 -0
  461. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_initialize_syncs_guesses.py +0 -0
  462. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_integrators.py +0 -0
  463. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_optimization_results.py +0 -0
  464. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_plotting.py +0 -0
  465. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_post_process_batched_tau_clamp.py +0 -0
  466. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_propagation.py +0 -0
  467. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/tests/test_results_parameters.py +0 -0
  468. {openscvx-0.5.3.dev43 → openscvx-0.5.3.dev45}/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.dev43
3
+ Version: 0.5.3.dev45
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
@@ -10,7 +10,7 @@ Classifier: License :: OSI Approved :: Apache Software License
10
10
  Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: cvxpy<1.9,>=1.8.1
13
+ Requires-Dist: cvxpy>=1.8.1
14
14
  Requires-Dist: qoco
15
15
  Requires-Dist: numpy
16
16
  Requires-Dist: jax
@@ -99,6 +99,7 @@ problem = Problem(
99
99
  "enforce_dpp": True,
100
100
  "abstol": 1e-8,
101
101
  "reltol": 1e-10,
102
+ "warm_start": False,
102
103
  },
103
104
  },
104
105
  )
@@ -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.dev43'
22
- __version_tuple__ = version_tuple = (0, 5, 3, 'dev43')
21
+ __version__ = version = '0.5.3.dev45'
22
+ __version_tuple__ = version_tuple = (0, 5, 3, 'dev45')
23
23
 
24
- __commit_id__ = commit_id = 'g3b8696f53'
24
+ __commit_id__ = commit_id = 'g7ded3ab51'
@@ -210,7 +210,7 @@ class CVXPyPTRSolver(PTRSolver):
210
210
  self.solver_args = (
211
211
  solver_args
212
212
  if solver_args is not None
213
- else {"abstol": 1e-06, "reltol": 1e-09, "enforce_dpp": True}
213
+ else {"abstol": 1e-06, "reltol": 1e-09, "enforce_dpp": True, "warm_start": False}
214
214
  )
215
215
  self.cvxpygen = cvxpygen
216
216
  self.cvxpygen_override = cvxpygen_override
@@ -1135,23 +1135,40 @@ _CINTERP_METHODS = {
1135
1135
 
1136
1136
 
1137
1137
  class Cinterp(Expr):
1138
- """1D cubic spline interpolation for symbolic expressions.
1139
-
1140
- Computes a cubic spline through data points (xp, fp) and evaluates it at
1141
- query point x. Spline coefficients are precomputed at construction time
1142
- via scipy so that JAX evaluation reduces to a segment lookup and
1143
- polynomial eval.
1138
+ """1D piecewise-cubic interpolation for symbolic expressions.
1139
+
1140
+ Evaluates a piecewise-cubic polynomial at query point ``x`` by a segment
1141
+ lookup on the fixed breakpoints ``xp`` followed by Horner evaluation. The
1142
+ polynomial table is held as ``coeffs`` of shape ``(4, n_segments)`` where
1143
+ ``n_segments = len(xp) - 1``; row ``k`` holds the degree-``k`` coefficients,
1144
+ so the value in segment ``i`` at local coordinate ``t = x - xp[i]`` is
1145
+ ``coeffs[0, i] + coeffs[1, i]*t + coeffs[2, i]*t**2 + coeffs[3, i]*t**3``.
1146
+
1147
+ The table can be supplied two ways, and exactly one must be chosen:
1148
+
1149
+ - **Fit from data (default).** Pass ``fp`` (values at the breakpoints) and
1150
+ an optional ``method``; scipy fits the spline once at construction and the
1151
+ coefficients are baked into the compiled function as constants.
1152
+ - **Coefficient override.** Pass ``coeffs`` directly — either a numeric
1153
+ ``(4, n_segments)`` array or a symbolic :class:`~openscvx.Parameter` of
1154
+ that shape. A symbolic override is *not* baked in: the compiled function
1155
+ gathers the current parameter value at run time, so the interpolated
1156
+ function can be swapped **between solves** — with any host-side fitting
1157
+ method you like — without recompiling. ``method`` is meaningless with an
1158
+ override and passing it is an error.
1144
1159
 
1145
1160
  Attributes:
1146
1161
  x: Query point at which to evaluate the spline (symbolic expression).
1147
- xp: 1D array of breakpoints (must be strictly increasing).
1148
- fp: 1D array of values at the breakpoints (same length as xp).
1149
- method: Spline method used — ``"cubic"`` (not-a-knot, C2),
1162
+ xp: 1D array of breakpoints (must be strictly increasing). Fixed at
1163
+ construction; it drives the segment lookup and cannot be symbolic.
1164
+ fp: 1D array of values at the breakpoints (fit path only; ``None`` for a
1165
+ coefficient override).
1166
+ method: Spline method used to fit ``fp`` — ``"cubic"`` (not-a-knot, C2),
1150
1167
  ``"pchip"`` (monotonicity-preserving, C1), or ``"akima"`` (C1).
1151
- coeffs: Precomputed polynomial coefficients, shape (4, n_segments).
1152
- Row k contains the degree-k coefficients, so the value in segment i
1153
- at local coordinate t = x - xp[i] is
1154
- ``coeffs[0, i] + coeffs[1, i]*t + coeffs[2, i]*t**2 + coeffs[3, i]*t**3``.
1168
+ ``None`` for a coefficient override.
1169
+ coeffs: The polynomial table. A numeric ``(4, n_segments)`` array for
1170
+ the fit and numeric-override paths, or the coefficient ``Expr`` for a
1171
+ symbolic override.
1155
1172
 
1156
1173
  Example:
1157
1174
  Interpolate a discrete reference path::
@@ -1173,34 +1190,101 @@ class Cinterp(Expr):
1173
1190
  altitude = ox.State("altitude", shape=(1,))
1174
1191
  rho = ox.Cinterp(altitude[0], alt_data, rho_data, method="pchip")
1175
1192
 
1193
+ Drive the table with a :class:`~openscvx.Parameter` so the interpolated
1194
+ function can be retuned between solves without recompiling. Fit the
1195
+ spline host-side with any scipy method and push its coefficients (scipy
1196
+ stores them highest-degree-first, so reverse to this class's
1197
+ ascending-degree layout)::
1198
+
1199
+ from scipy.interpolate import PchipInterpolator
1200
+
1201
+ xp = np.linspace(0, 1, 11)
1202
+ n_seg = len(xp) - 1
1203
+
1204
+ cs = PchipInterpolator(xp, fp_data)
1205
+ coeffs = ox.Parameter("spline_coeffs", shape=(4, n_seg),
1206
+ value=cs.c[::-1])
1207
+
1208
+ progress = ox.State("progress", shape=(1,))
1209
+ ref = ox.Cinterp(progress[0], xp, coeffs=coeffs)
1210
+
1211
+ # ... build and solve the problem, then before the next solve:
1212
+ cs = PchipInterpolator(xp, new_fp_data)
1213
+ problem.parameters["spline_coeffs"] = cs.c[::-1]
1214
+
1176
1215
  !!! note
1177
1216
  `xp` must be strictly increasing.
1178
1217
 
1179
1218
  !!! warning "Extrapolation behavior"
1180
1219
  For query points outside `[xp[0], xp[-1]]`, boundary segment
1181
1220
  polynomials are extrapolated (consistent with scipy defaults).
1221
+
1222
+ !!! warning "Continuity is the caller's responsibility"
1223
+ With a coefficient override the library no longer guarantees that the
1224
+ table describes a continuous function — that is now the caller's job.
1225
+ A table whose segment polynomials disagree at a breakpoint yields a
1226
+ discontinuous dynamics function, which the discretizer will linearize
1227
+ and integrate without complaint, silently degrading accuracy.
1182
1228
  """
1183
1229
 
1184
1230
  def __init__(
1185
1231
  self,
1186
1232
  x: Union[Expr, float, int, np.ndarray],
1187
1233
  xp: Union[np.ndarray, list],
1188
- fp: Union[np.ndarray, list],
1234
+ fp: Union[np.ndarray, list, None] = None,
1189
1235
  *,
1190
- method: str = "cubic",
1236
+ coeffs: Union[Expr, np.ndarray, list, None] = None,
1237
+ method: Union[str, None] = None,
1191
1238
  _coeffs: Union[np.ndarray, None] = None,
1192
1239
  ):
1193
1240
  self.x = to_expr(x)
1194
1241
  xp = np.asarray(xp, dtype=float)
1195
- fp = np.asarray(fp, dtype=float)
1242
+ if xp.ndim != 1:
1243
+ raise ValueError(f"Cinterp xp must be 1D, got shape {xp.shape}")
1244
+ self.xp_np = xp
1245
+ n_seg = xp.shape[0] - 1
1246
+
1247
+ if (fp is None) == (coeffs is None):
1248
+ raise ValueError(
1249
+ "Cinterp requires exactly one of fp or coeffs: pass fp to fit a "
1250
+ "spline through breakpoint values, or coeffs to supply the "
1251
+ "polynomial table directly."
1252
+ )
1196
1253
 
1254
+ if coeffs is not None:
1255
+ # --- Coefficient-override path (numeric array or symbolic Expr). ---
1256
+ if method is not None:
1257
+ raise ValueError(
1258
+ "Cinterp method is meaningless with a coeffs override "
1259
+ "(the table is supplied, not fit); drop the method argument."
1260
+ )
1261
+ expected = (4, n_seg)
1262
+ if isinstance(coeffs, Expr):
1263
+ got = coeffs.check_shape()
1264
+ if got != expected:
1265
+ raise ValueError(
1266
+ f"Cinterp coeffs must have shape {expected} (4 by len(xp) - 1), got {got}"
1267
+ )
1268
+ self.coeffs = coeffs
1269
+ else:
1270
+ arr = np.asarray(coeffs, dtype=float)
1271
+ if arr.shape != expected:
1272
+ raise ValueError(
1273
+ f"Cinterp coeffs must have shape {expected} "
1274
+ f"(4 by len(xp) - 1), got {arr.shape}"
1275
+ )
1276
+ self.coeffs = arr
1277
+ self.fp_np = None
1278
+ self.method = None
1279
+ return
1280
+
1281
+ # --- Fit path: precompute spline coefficients via scipy. ---
1282
+ method = "cubic" if method is None else method
1197
1283
  if method not in _CINTERP_METHODS:
1198
1284
  raise ValueError(
1199
1285
  f"Cinterp method must be one of {set(_CINTERP_METHODS)}, got {method!r}"
1200
1286
  )
1201
-
1202
- if xp.ndim != 1:
1203
- raise ValueError(f"Cinterp xp must be 1D, got shape {xp.shape}")
1287
+ fp = np.asarray(fp, dtype=float)
1204
1288
  if fp.ndim != 1:
1205
1289
  raise ValueError(f"Cinterp fp must be 1D, got shape {fp.shape}")
1206
1290
  if xp.shape != fp.shape:
@@ -1208,38 +1292,53 @@ class Cinterp(Expr):
1208
1292
  f"Cinterp xp and fp must have same length, got {xp.shape} vs {fp.shape}"
1209
1293
  )
1210
1294
 
1211
- self.xp_np = xp
1212
1295
  self.fp_np = fp
1213
1296
  self.method = method
1214
1297
 
1215
1298
  if _coeffs is not None:
1216
1299
  self.coeffs = _coeffs
1217
1300
  else:
1218
- # Precompute spline coefficients via scipy.
1219
1301
  # scipy returns shape (4, n_seg) with c[0]=cubic, c[1]=quadratic, ...
1220
1302
  # We reorder to ascending-degree layout for Horner evaluation.
1221
1303
  cs = _CINTERP_METHODS[method](xp, fp)
1222
1304
  self.coeffs = cs.c[::-1].copy() # row 0 = const, row 3 = cubic
1223
1305
 
1224
1306
  def children(self):
1307
+ if isinstance(self.coeffs, Expr):
1308
+ return [self.x, self.coeffs]
1225
1309
  return [self.x]
1226
1310
 
1227
1311
  def canonicalize(self) -> "Expr":
1228
1312
  x = self.x.canonicalize()
1229
- return Cinterp(x, self.xp_np, self.fp_np, method=self.method, _coeffs=self.coeffs)
1313
+ if isinstance(self.coeffs, Expr):
1314
+ return Cinterp(x, self.xp_np, coeffs=self.coeffs.canonicalize())
1315
+ if self.fp_np is not None:
1316
+ return Cinterp(x, self.xp_np, self.fp_np, method=self.method, _coeffs=self.coeffs)
1317
+ return Cinterp(x, self.xp_np, coeffs=self.coeffs)
1230
1318
 
1231
1319
  def check_shape(self) -> Tuple[int, ...]:
1232
1320
  return self.x.check_shape()
1233
1321
 
1234
1322
  def _hash_into(self, hasher: "hashlib._Hash") -> None:
1235
1323
  hasher.update(b"Cinterp")
1236
- hasher.update(self.method.encode())
1237
- hasher.update(self.xp_np.tobytes())
1238
- hasher.update(self.fp_np.tobytes())
1324
+ if isinstance(self.coeffs, Expr):
1325
+ hasher.update(b"coeffs_expr")
1326
+ hasher.update(self.xp_np.tobytes())
1327
+ self.coeffs._hash_into(hasher)
1328
+ elif self.fp_np is not None:
1329
+ hasher.update(self.method.encode())
1330
+ hasher.update(self.xp_np.tobytes())
1331
+ hasher.update(self.fp_np.tobytes())
1332
+ else:
1333
+ hasher.update(b"coeffs_num")
1334
+ hasher.update(self.xp_np.tobytes())
1335
+ hasher.update(np.asarray(self.coeffs).tobytes())
1239
1336
  self.x._hash_into(hasher)
1240
1337
 
1241
1338
  def __repr__(self) -> str:
1242
- if self.method == "cubic":
1339
+ if isinstance(self.coeffs, Expr):
1340
+ return f"cinterp({self.x!r}, coeffs={self.coeffs!r})"
1341
+ if self.method == "cubic" or self.method is None:
1243
1342
  return f"cinterp({self.x!r})"
1244
1343
  return f"cinterp({self.x!r}, method={self.method!r})"
1245
1344
 
@@ -17,6 +17,8 @@ import jax
17
17
  import jax.numpy as jnp
18
18
  from jax.scipy.special import logsumexp
19
19
 
20
+ from openscvx.symbolic.expr.expr import Expr
21
+
20
22
  # Expression types to handle — uncomment as you paste visitors:
21
23
  from openscvx.symbolic.expr.math import (
22
24
  Abs,
@@ -285,33 +287,46 @@ def _visit_linterp(lowerer, node: Linterp):
285
287
 
286
288
  @visitor(Cinterp)
287
289
  def _visit_cinterp(lowerer, node: Cinterp):
288
- """Lower 1D cubic spline interpolation to JAX function.
290
+ """Lower 1D piecewise-cubic interpolation to a JAX function.
289
291
 
290
- Evaluates a precomputed cubic spline via segment lookup and Horner's
291
- method. Coefficients are baked in as constants; only the query point
292
- is symbolic. For queries outside the data range the boundary segment
293
- polynomial is extrapolated.
292
+ Evaluates the polynomial table via segment lookup on the fixed breakpoints
293
+ and Horner's method. When ``node.coeffs`` is a numeric array it is baked in
294
+ as a constant; when it is a symbolic ``Expr`` (e.g. a ``Parameter``) it is
295
+ lowered too and gathered at run time, so the table can change between solves
296
+ without recompiling. Either way only ``xp`` is fixed. For queries outside
297
+ the data range the boundary segment polynomial is extrapolated.
294
298
 
295
299
  Args:
296
- node: Cinterp expression node with precomputed coeffs and xp_np.
300
+ node: Cinterp expression node with xp_np and numeric-or-symbolic coeffs.
297
301
 
298
302
  Returns:
299
303
  Function (x, u, node_idx, params) -> interpolated value(s)
300
304
  """
301
305
  f_x = lowerer.lower(node.x)
302
306
  xp = jnp.asarray(node.xp_np)
303
- coeffs = jnp.asarray(node.coeffs) # (4, n_seg)
304
307
 
305
- def cinterp_fn(x, u, node_idx, params):
306
- x_val = f_x(x, u, node_idx, params)
307
- # Segment index (clamp to valid range)
308
+ def evaluate(x_val, coeffs):
309
+ # Segment index (clamp to valid range), then Horner: c0 + t*(c1 + t*(c2 + t*c3)).
308
310
  idx = jnp.searchsorted(xp, x_val, side="right") - 1
309
311
  idx = jnp.clip(idx, 0, xp.shape[0] - 2)
310
312
  t = x_val - xp[idx]
311
- # Horner evaluation: c0 + t*(c1 + t*(c2 + t*c3))
312
313
  c = coeffs[:, idx]
313
314
  return c[0] + t * (c[1] + t * (c[2] + t * c[3]))
314
315
 
316
+ if isinstance(node.coeffs, Expr):
317
+ f_coeffs = lowerer.lower(node.coeffs)
318
+
319
+ def cinterp_fn(x, u, node_idx, params):
320
+ coeffs = f_coeffs(x, u, node_idx, params) # (4, n_seg)
321
+ return evaluate(f_x(x, u, node_idx, params), coeffs)
322
+
323
+ return cinterp_fn
324
+
325
+ coeffs = jnp.asarray(node.coeffs) # (4, n_seg)
326
+
327
+ def cinterp_fn(x, u, node_idx, params):
328
+ return evaluate(f_x(x, u, node_idx, params), coeffs)
329
+
315
330
  return cinterp_fn
316
331
 
317
332
 
@@ -171,14 +171,13 @@ def _visit_linterp(lowerer, node: Linterp):
171
171
 
172
172
  @visitor(Cinterp)
173
173
  def _visit_cinterp(lowerer, node: Cinterp):
174
- """Render 1-D cubic-spline interpolation as ``\\operatorname{cinterp}(x)``.
174
+ """Render 1-D piecewise-cubic interpolation as ``\\operatorname{cinterp}(x)``.
175
175
 
176
- Only the query point is a symbolic operand — the breakpoints and spline
177
- coefficients are baked in at construction — so it is the only rendered
178
- argument.
176
+ Only the query point is rendered; the breakpoints and the polynomial table
177
+ (whether baked-in coefficients or a symbolic override) are structural and
178
+ stay implicit.
179
179
  """
180
- args = ", ".join(lowerer.lower(c) for c in node.children())
181
- return _call(r"\operatorname{cinterp}", args)
180
+ return _call(r"\operatorname{cinterp}", lowerer.lower(node.x))
182
181
 
183
182
 
184
183
  @visitor(Bilerp)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.5.3.dev43
3
+ Version: 0.5.3.dev45
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
@@ -10,7 +10,7 @@ Classifier: License :: OSI Approved :: Apache Software License
10
10
  Requires-Python: >=3.11
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
- Requires-Dist: cvxpy<1.9,>=1.8.1
13
+ Requires-Dist: cvxpy>=1.8.1
14
14
  Requires-Dist: qoco
15
15
  Requires-Dist: numpy
16
16
  Requires-Dist: jax
@@ -1,4 +1,4 @@
1
- cvxpy<1.9,>=1.8.1
1
+ cvxpy>=1.8.1
2
2
  qoco
3
3
  numpy
4
4
  jax
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.5.2",
3
+ "distance": 45,
4
+ "node": "g7ded3ab51a28708979ea5b09cfdf9002fc1dbeac",
5
+ "dirty": false,
6
+ "branch": "main",
7
+ "node_date": "2026-07-22"
8
+ }
@@ -17,7 +17,7 @@ classifiers = [
17
17
  "License :: OSI Approved :: Apache Software License",
18
18
  ]
19
19
  dependencies = [
20
- "cvxpy>=1.8.1,<1.9",
20
+ "cvxpy>=1.8.1",
21
21
  "qoco",
22
22
  "numpy",
23
23
  "jax",
@@ -270,7 +270,7 @@ def test_monolithic():
270
270
  )
271
271
 
272
272
  problem.settings.prp.dt = 0.01
273
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
273
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
274
274
  problem.settings.sim.save_compiled = False
275
275
 
276
276
  # Disable printing for cleaner test output
@@ -398,7 +398,7 @@ def test_backend(backend, constraint_type, with_parameters):
398
398
 
399
399
  problem.settings.prp.dt = 0.01
400
400
  if backend == "cvxpy":
401
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
401
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
402
402
  problem.settings.sim.save_compiled = False
403
403
  if hasattr(problem.settings, "dev"):
404
404
  problem.settings.dev.printing = False
@@ -687,7 +687,7 @@ def test_constraint_types(constraint_type):
687
687
  )
688
688
 
689
689
  problem.settings.prp.dt = 0.01
690
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
690
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
691
691
  problem.settings.sim.save_compiled = False
692
692
 
693
693
  # Disable printing for cleaner test output
@@ -827,7 +827,7 @@ def test_autotuning(autotuner_spec):
827
827
  )
828
828
 
829
829
  problem.settings.prp.dt = 0.01
830
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
830
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
831
831
  problem.settings.sim.save_compiled = False
832
832
 
833
833
  # Disable printing for cleaner test output
@@ -969,7 +969,7 @@ def test_cross_nodal(test_case):
969
969
  )
970
970
 
971
971
  problem.settings.prp.dt = 0.01
972
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
972
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
973
973
  problem.settings.sim.save_compiled = False
974
974
 
975
975
  # Disable printing for cleaner test output
@@ -1107,7 +1107,7 @@ def test_parameters():
1107
1107
  },
1108
1108
  )
1109
1109
 
1110
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
1110
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
1111
1111
  problem.settings.sim.save_compiled = False
1112
1112
 
1113
1113
  # Disable printing for cleaner test output
@@ -1304,7 +1304,7 @@ def test_propagation():
1304
1304
  )
1305
1305
 
1306
1306
  problem.settings.prp.dt = 0.01
1307
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
1307
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
1308
1308
  problem.settings.sim.save_compiled = False
1309
1309
 
1310
1310
  # Disable printing for cleaner test output
@@ -1701,7 +1701,7 @@ def test_byof(byof_mode):
1701
1701
  )
1702
1702
 
1703
1703
  problem.settings.prp.dt = 0.01
1704
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
1704
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
1705
1705
  problem.settings.sim.save_compiled = False
1706
1706
 
1707
1707
  # Disable printing for cleaner test output
@@ -3533,6 +3533,172 @@ def test_cvxpy_cinterp_not_implemented():
3533
3533
  lowerer.lower(expr)
3534
3534
 
3535
3535
 
3536
+ # --- Cinterp: Coefficient Override ---
3537
+
3538
+
3539
+ def _reverse_coeffs(cs):
3540
+ """scipy stores coefficients highest-degree-first; Cinterp uses ascending."""
3541
+ return np.asarray(cs.c[::-1], dtype=float)
3542
+
3543
+
3544
+ def test_cinterp_numeric_coeffs_override_matches_fit():
3545
+ """A numeric coeffs override reproduces the fitted spline exactly."""
3546
+ import jax.numpy as jnp
3547
+ from scipy.interpolate import CubicSpline
3548
+
3549
+ from openscvx.symbolic.expr import Cinterp, Constant
3550
+ from openscvx.symbolic.lower import lower_to_jax
3551
+
3552
+ xp = np.array([0.0, 1.0, 2.0, 3.0])
3553
+ fp = np.array([0.0, 2.0, 1.0, 3.0])
3554
+ query = np.linspace(0.0, 3.0, 50)
3555
+
3556
+ coeffs = _reverse_coeffs(CubicSpline(xp, fp))
3557
+
3558
+ fitted = lower_to_jax(Cinterp(Constant(query), xp, fp))(None, None, None, None)
3559
+ override = lower_to_jax(Cinterp(Constant(query), xp, coeffs=coeffs))(None, None, None, None)
3560
+
3561
+ assert jnp.allclose(fitted, override)
3562
+
3563
+
3564
+ def test_cinterp_symbolic_coeffs_matches_scipy():
3565
+ """Symbolic coeffs (via a Parameter) evaluate to the host-side scipy spline.
3566
+
3567
+ Covers each host-side fitting method: cubic, pchip, akima.
3568
+ """
3569
+ import jax.numpy as jnp
3570
+ from scipy.interpolate import Akima1DInterpolator, CubicSpline, PchipInterpolator
3571
+
3572
+ from openscvx.symbolic.expr import Cinterp, Constant, Parameter
3573
+ from openscvx.symbolic.lower import lower_to_jax
3574
+
3575
+ xp = np.linspace(0.0, 5.0, 8)
3576
+ fp = np.array([0.0, 1.5, 1.0, 2.0, 0.5, 2.5, 1.0, 3.0])
3577
+ n_seg = len(xp) - 1
3578
+ query = np.linspace(0.0, 5.0, 120)
3579
+
3580
+ for fitter in (CubicSpline, PchipInterpolator, Akima1DInterpolator):
3581
+ cs = fitter(xp, fp)
3582
+ coeffs = _reverse_coeffs(cs)
3583
+ param = Parameter("spline_coeffs", shape=(4, n_seg), value=coeffs)
3584
+
3585
+ fn = lower_to_jax(Cinterp(Constant(query), xp, coeffs=param))
3586
+ result = fn(None, None, None, {"spline_coeffs": coeffs})
3587
+
3588
+ assert jnp.allclose(result, cs(query)), fitter.__name__
3589
+
3590
+
3591
+ def test_cinterp_symbolic_coeffs_update_between_evals_no_recompile():
3592
+ """Updating the parameter value changes the SAME lowered function's output."""
3593
+ import jax.numpy as jnp
3594
+ from scipy.interpolate import PchipInterpolator
3595
+
3596
+ from openscvx.symbolic.expr import Cinterp, Constant, Parameter
3597
+ from openscvx.symbolic.lower import lower_to_jax
3598
+
3599
+ xp = np.linspace(0.0, 1.0, 6)
3600
+ n_seg = len(xp) - 1
3601
+ query = np.linspace(0.0, 1.0, 40)
3602
+
3603
+ fp_a = np.array([0.0, 0.4, 0.2, 0.9, 0.3, 1.0])
3604
+ fp_b = np.array([1.0, 0.2, 0.7, 0.1, 0.8, 0.0])
3605
+ cs_a = PchipInterpolator(xp, fp_a)
3606
+ cs_b = PchipInterpolator(xp, fp_b)
3607
+
3608
+ param = Parameter("c", shape=(4, n_seg), value=_reverse_coeffs(cs_a))
3609
+ fn = lower_to_jax(Cinterp(Constant(query), xp, coeffs=param))
3610
+
3611
+ result_a = fn(None, None, None, {"c": _reverse_coeffs(cs_a)})
3612
+ result_b = fn(None, None, None, {"c": _reverse_coeffs(cs_b)})
3613
+
3614
+ assert jnp.allclose(result_a, cs_a(query))
3615
+ assert jnp.allclose(result_b, cs_b(query))
3616
+ assert not jnp.allclose(result_a, result_b)
3617
+
3618
+
3619
+ def test_cinterp_symbolic_coeffs_children_and_canonicalize():
3620
+ """Symbolic coeffs appear as a child (so the Parameter binds) and survive canonicalize."""
3621
+ from openscvx.symbolic.expr import Cinterp, Parameter, State
3622
+
3623
+ xp = np.array([0.0, 1.0, 2.0, 3.0])
3624
+ n_seg = len(xp) - 1
3625
+ param = Parameter("c", shape=(4, n_seg), value=np.ones((4, n_seg)))
3626
+
3627
+ state = State("s", shape=(1,))
3628
+ interp = Cinterp(state[0], xp, coeffs=param)
3629
+
3630
+ children = interp.children()
3631
+ assert len(children) == 2
3632
+ assert param in children
3633
+
3634
+ canonical = interp.canonicalize()
3635
+ assert isinstance(canonical, Cinterp)
3636
+ assert isinstance(canonical.coeffs, Parameter)
3637
+ assert canonical.coeffs.name == "c"
3638
+ assert canonical.fp_np is None
3639
+ assert canonical.method is None
3640
+
3641
+
3642
+ # --- Cinterp: Coefficient-Override Validation ---
3643
+
3644
+
3645
+ def test_cinterp_coeffs_wrong_shape():
3646
+ """A coeffs table that is not (4, len(xp) - 1) raises, stating the expected shape."""
3647
+ from openscvx.symbolic.expr import Cinterp, State
3648
+
3649
+ xp = np.array([0.0, 1.0, 2.0, 3.0]) # n_seg = 3, expected (4, 3)
3650
+ x = State("s", shape=(1,))[0]
3651
+
3652
+ with pytest.raises(ValueError, match=r"Cinterp coeffs must have shape \(4, 3\)"):
3653
+ Cinterp(x, xp, coeffs=np.ones((4, 5)))
3654
+
3655
+
3656
+ def test_cinterp_symbolic_coeffs_wrong_shape():
3657
+ """A Parameter of the wrong shape raises, stating the expected shape."""
3658
+ from openscvx.symbolic.expr import Cinterp, Parameter, State
3659
+
3660
+ xp = np.array([0.0, 1.0, 2.0, 3.0]) # expected (4, 3)
3661
+ x = State("s", shape=(1,))[0]
3662
+ param = Parameter("c", shape=(3, 3), value=np.ones((3, 3)))
3663
+
3664
+ with pytest.raises(ValueError, match=r"Cinterp coeffs must have shape \(4, 3\)"):
3665
+ Cinterp(x, xp, coeffs=param)
3666
+
3667
+
3668
+ def test_cinterp_both_fp_and_coeffs():
3669
+ """Passing both fp and coeffs is ambiguous and raises."""
3670
+ from openscvx.symbolic.expr import Cinterp, State
3671
+
3672
+ xp = np.array([0.0, 1.0, 2.0, 3.0])
3673
+ fp = np.array([0.0, 1.0, 2.0, 3.0])
3674
+ x = State("s", shape=(1,))[0]
3675
+
3676
+ with pytest.raises(ValueError, match="exactly one of fp or coeffs"):
3677
+ Cinterp(x, xp, fp, coeffs=np.ones((4, 3)))
3678
+
3679
+
3680
+ def test_cinterp_neither_fp_nor_coeffs():
3681
+ """Passing neither fp nor coeffs raises."""
3682
+ from openscvx.symbolic.expr import Cinterp, State
3683
+
3684
+ xp = np.array([0.0, 1.0, 2.0, 3.0])
3685
+ x = State("s", shape=(1,))[0]
3686
+
3687
+ with pytest.raises(ValueError, match="exactly one of fp or coeffs"):
3688
+ Cinterp(x, xp)
3689
+
3690
+
3691
+ def test_cinterp_method_with_coeffs_rejected():
3692
+ """method is meaningless with a coeffs override and is rejected."""
3693
+ from openscvx.symbolic.expr import Cinterp, State
3694
+
3695
+ xp = np.array([0.0, 1.0, 2.0, 3.0])
3696
+ x = State("s", shape=(1,))[0]
3697
+
3698
+ with pytest.raises(ValueError, match="method is meaningless with a coeffs override"):
3699
+ Cinterp(x, xp, coeffs=np.ones((4, 3)), method="pchip")
3700
+
3701
+
3536
3702
  # =============================================================================
3537
3703
  # Bilerp (2D Bilinear Interpolation)
3538
3704
  # =============================================================================
@@ -44,7 +44,7 @@ G = 9.81
44
44
  def _configure_and_solve(problem):
45
45
  """Apply standard solver settings, solve, and post-process."""
46
46
  problem.settings.prp.dt = 0.01
47
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
47
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
48
48
  problem.settings.sim.save_compiled = False
49
49
  problem.settings.dev.printing = False
50
50
 
@@ -354,7 +354,7 @@ def test_cross_nodal(feasible):
354
354
  )
355
355
 
356
356
  problem.settings.prp.dt = 0.01
357
- problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9}
357
+ problem.solver.solver_args = {"abstol": 1e-6, "reltol": 1e-9, "warm_start": False}
358
358
  problem.settings.sim.save_compiled = False
359
359
  problem.settings.dev.printing = False
360
360