openscvx 0.3.2.dev228__tar.gz → 0.3.2.dev234__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 (238) hide show
  1. {openscvx-0.3.2.dev228/openscvx.egg-info → openscvx-0.3.2.dev234}/PKG-INFO +1 -1
  2. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/dr_double_integrator.py +5 -19
  3. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/dr_vp.py +11 -31
  4. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/dr_vp_nodal.py +11 -31
  5. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/dr_vp_polytope.py +11 -31
  6. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/drone_racing.py +4 -19
  7. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/__init__.py +2 -0
  8. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/_version.py +3 -3
  9. openscvx-0.3.2.dev234/openscvx/init/__init__.py +30 -0
  10. openscvx-0.3.2.dev234/openscvx/init/interpolation.py +327 -0
  11. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/preprocessing.py +6 -1
  12. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234/openscvx.egg-info}/PKG-INFO +1 -1
  13. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx.egg-info/SOURCES.txt +3 -0
  14. openscvx-0.3.2.dev234/tests/test_init.py +153 -0
  15. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/assets/logo.svg +0 -0
  16. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/release-drafter.yml +0 -0
  17. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/_docs.yml +0 -0
  18. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/docs.yml +0 -0
  19. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/lint.yml +0 -0
  20. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/nightly.yml +0 -0
  21. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/release-drafter.yml +0 -0
  22. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/release.yml +0 -0
  23. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/tests-integration.yml +0 -0
  24. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.github/workflows/tests-unit.yml +0 -0
  25. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/.gitignore +0 -0
  26. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/CONTRIBUTING.md +0 -0
  27. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/LICENSE +0 -0
  28. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/README.md +0 -0
  29. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Overview/constraint_reformulation.md +0 -0
  30. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Overview/control_parameterization.md +0 -0
  31. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Overview/discretization.md +0 -0
  32. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Overview/ocp.md +0 -0
  33. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Overview/scvx.md +0 -0
  34. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Overview/time_dilation.md +0 -0
  35. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/UnderTheHood/lowering_architecture.md +0 -0
  36. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
  37. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/advanced_problem_setup.md +0 -0
  38. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/api.md +0 -0
  39. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/api_constraints.md +0 -0
  40. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/api_control.md +0 -0
  41. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/api_integrators.md +0 -0
  42. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/api_state.md +0 -0
  43. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/api_trajoptproblem.md +0 -0
  44. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/api_variable.md +0 -0
  45. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/basic_problem_setup.md +0 -0
  46. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/tutorial_6dof_los_guidance.md +0 -0
  47. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/tutorial_6dof_obstacle_avoidance.md +0 -0
  48. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/Usage/tutorials.md +0 -0
  49. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/favicon.png +0 -0
  50. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/images/ct-scvx_dark.png +0 -0
  51. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/images/ct-scvx_light.png +0 -0
  52. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/images/ctcs_dark.png +0 -0
  53. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/images/ctcs_light.png +0 -0
  54. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/images/problem_class_dark.png +0 -0
  55. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/images/problem_class_light.png +0 -0
  56. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/assets/logo.svg +0 -0
  57. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/citation.md +0 -0
  58. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/examples.md +0 -0
  59. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/getting-started.md +0 -0
  60. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/index.md +0 -0
  61. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/docs/javascripts/mathjax.js +0 -0
  62. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/abstract/3DoF_pdg.py +0 -0
  63. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/abstract/brachistochrone.py +0 -0
  64. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/arm/three_link_arm.py +0 -0
  65. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/car/dubins_car.py +0 -0
  66. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/car/dubins_car_disjoint.py +0 -0
  67. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/car/dubins_car_stljax.py +0 -0
  68. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/cinema_vp.py +0 -0
  69. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/cinema_vp_realtime_base.py +0 -0
  70. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/obstacle_avoidance.py +0 -0
  71. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/obstacle_avoidance_nodal.py +0 -0
  72. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/obstacle_avoidance_realtime_base.py +0 -0
  73. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/drone/obstacle_avoidance_vmap.py +0 -0
  74. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/plotting.py +0 -0
  75. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/plotting_viser.py +0 -0
  76. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/realtime/cinema_vp_realtime.py +0 -0
  77. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/realtime/drone_racing_realtime.py +0 -0
  78. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/realtime/dubins_car_realtime.py +0 -0
  79. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
  80. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/examples/spacecraft/proxops_cw.py +0 -0
  81. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/ctlos_cine.gif +0 -0
  82. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/ctlos_dr.gif +0 -0
  83. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/dtlos_cine.gif +0 -0
  84. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/dtlos_dr.gif +0 -0
  85. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/openscvx_logo.svg +0 -0
  86. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/openscvx_logo_square.png +0 -0
  87. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/oscvx_structure_full_dark.svg +0 -0
  88. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/figures/video_preview.png +0 -0
  89. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/__init__.py +0 -0
  90. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/1-background.avif +0 -0
  91. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
  92. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
  93. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
  94. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
  95. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/2-mars.avif +0 -0
  96. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
  97. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
  98. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
  99. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
  100. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/3-moon.avif +0 -0
  101. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
  102. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
  103. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
  104. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
  105. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
  106. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
  107. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
  108. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
  109. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
  110. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/5-space.avif +0 -0
  111. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
  112. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
  113. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
  114. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
  115. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/6-earth.avif +0 -0
  116. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
  117. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
  118. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
  119. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
  120. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/javascripts/parallax.js +0 -0
  121. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/logo.svg +0 -0
  122. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/stylesheets/custom.css +0 -0
  123. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/assets/stylesheets/parallax.css +0 -0
  124. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/home.html +0 -0
  125. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/main.html +0 -0
  126. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/partials/parallax/hero.html +0 -0
  127. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/material/overrides/partials/parallax.html +0 -0
  128. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/mkdocs.yml +0 -0
  129. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/algorithms/__init__.py +0 -0
  130. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/algorithms/autotuning.py +0 -0
  131. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/algorithms/base.py +0 -0
  132. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/algorithms/optimization_results.py +0 -0
  133. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/algorithms/penalized_trust_region.py +0 -0
  134. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/config.py +0 -0
  135. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/discretization/__init__.py +0 -0
  136. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/discretization/discretization.py +0 -0
  137. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/expert/__init__.py +0 -0
  138. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/expert/byof.py +0 -0
  139. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/expert/lowering.py +0 -0
  140. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/expert/validation.py +0 -0
  141. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/integrators/__init__.py +0 -0
  142. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/integrators/runge_kutta.py +0 -0
  143. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/__init__.py +0 -0
  144. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/cvxpy_constraints.py +0 -0
  145. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/cvxpy_variables.py +0 -0
  146. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/dynamics.py +0 -0
  147. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/jax_constraints.py +0 -0
  148. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/parameters.py +0 -0
  149. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/problem.py +0 -0
  150. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/lowered/unified.py +0 -0
  151. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/__init__.py +0 -0
  152. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/plotting.py +0 -0
  153. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/scp_iteration.py +0 -0
  154. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/viser/__init__.py +0 -0
  155. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/viser/animated.py +0 -0
  156. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/viser/plotly_integration.py +0 -0
  157. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/viser/primitives.py +0 -0
  158. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/viser/scp.py +0 -0
  159. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/plotting/viser/server.py +0 -0
  160. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/problem.py +0 -0
  161. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/propagation/__init__.py +0 -0
  162. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/propagation/post_processing.py +0 -0
  163. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/propagation/propagation.py +0 -0
  164. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/solvers/__init__.py +0 -0
  165. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/solvers/cvxpy.py +0 -0
  166. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/__init__.py +0 -0
  167. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/augmentation.py +0 -0
  168. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/builder.py +0 -0
  169. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/constraint_set.py +0 -0
  170. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/__init__.py +0 -0
  171. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/arithmetic.py +0 -0
  172. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/array.py +0 -0
  173. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/constraint.py +0 -0
  174. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/control.py +0 -0
  175. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/expr.py +0 -0
  176. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/lie/__init__.py +0 -0
  177. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
  178. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/lie/se3.py +0 -0
  179. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/lie/so3.py +0 -0
  180. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/linalg.py +0 -0
  181. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/math.py +0 -0
  182. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/spatial.py +0 -0
  183. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/state.py +0 -0
  184. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/stl.py +0 -0
  185. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/variable.py +0 -0
  186. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/expr/vmap.py +0 -0
  187. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/hashing.py +0 -0
  188. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/lower.py +0 -0
  189. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/lowerers/__init__.py +0 -0
  190. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/lowerers/cvxpy.py +0 -0
  191. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/lowerers/jax.py +0 -0
  192. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/problem.py +0 -0
  193. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/time.py +0 -0
  194. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/symbolic/unified.py +0 -0
  195. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/utils/__init__.py +0 -0
  196. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/utils/cache.py +0 -0
  197. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/utils/caching.py +0 -0
  198. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/utils/printing.py +0 -0
  199. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/utils/profiling.py +0 -0
  200. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx/utils/utils.py +0 -0
  201. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx.egg-info/dependency_links.txt +0 -0
  202. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx.egg-info/requires.txt +0 -0
  203. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/openscvx.egg-info/top_level.txt +0 -0
  204. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/pyproject.toml +0 -0
  205. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/scripts/gen_example_pages.py +0 -0
  206. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/scripts/gen_ref_pages.py +0 -0
  207. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/setup.cfg +0 -0
  208. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/__init__.py +0 -0
  209. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/brachistochrone_analytical.py +0 -0
  210. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/__init__.py +0 -0
  211. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/__init__.py +0 -0
  212. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_arithmetic.py +0 -0
  213. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_array.py +0 -0
  214. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_constraint.py +0 -0
  215. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_expr.py +0 -0
  216. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_lie.py +0 -0
  217. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_linalg.py +0 -0
  218. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_math.py +0 -0
  219. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_node_reference.py +0 -0
  220. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_parameters.py +0 -0
  221. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_scaling.py +0 -0
  222. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_spatial.py +0 -0
  223. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_variable.py +0 -0
  224. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/expr/test_vmap.py +0 -0
  225. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/test_augmentation.py +0 -0
  226. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/test_hashing.py +0 -0
  227. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/test_lower_cvxpy.py +0 -0
  228. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/test_lower_jax.py +0 -0
  229. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/test_preprocessing.py +0 -0
  230. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/symbolic/test_unified.py +0 -0
  231. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_brachistochrone.py +0 -0
  232. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_cvxpygen_optional.py +0 -0
  233. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_discretization.py +0 -0
  234. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_examples.py +0 -0
  235. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_expert.py +0 -0
  236. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_integrators.py +0 -0
  237. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_plotting.py +0 -0
  238. {openscvx-0.3.2.dev228 → openscvx-0.3.2.dev234}/tests/test_propagation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.3.2.dev228
3
+ Version: 0.3.2.dev234
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
@@ -115,25 +115,11 @@ dynamics = {
115
115
  }
116
116
 
117
117
 
118
- position_bar = np.linspace(position.initial, position.final, n)
119
-
120
- i = 0
121
- origins = [position.initial]
122
- ends = []
123
- for center in gate_centers:
124
- origins.append(center)
125
- ends.append(center)
126
- ends.append(position.final)
127
- gate_idx = 0
128
- for _ in range(n_gates + 1):
129
- for k in range(n // (n_gates + 1)):
130
- position_bar[i] = origins[gate_idx] + (k / (n // (n_gates + 1))) * (
131
- ends[gate_idx] - origins[gate_idx]
132
- )
133
- i += 1
134
- gate_idx += 1
135
-
136
- position.guess = position_bar
118
+ # Generate initial guess for position trajectory through gates
119
+ position.guess = ox.init.linspace(
120
+ keyframes=[position.initial] + gate_centers + [position.final],
121
+ nodes=[0] + list(gate_nodes) + [n - 1],
122
+ )
137
123
 
138
124
  t = ox.Time(
139
125
  initial=0.0,
@@ -187,33 +187,16 @@ dynamics = {
187
187
  }
188
188
 
189
189
 
190
- # Initialize initial guess (will be modified by gate logic)
191
- position_bar = np.linspace(position.initial, position.final, n)
192
- velocity_bar = np.zeros((n, 3))
193
- attitude_bar = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
194
- angular_velocity_bar = np.zeros((n, 3))
195
-
196
- # Modify position to go through gates
197
- i = 0
198
- origins = [position.initial]
199
- ends = []
200
- for center in gate_centers:
201
- origins.append(center)
202
- ends.append(center)
203
- ends.append(position.final)
204
- gate_idx = 0
205
- for _ in range(n_gates + 1):
206
- for k in range(n // (n_gates + 1)):
207
- position_bar[i] = origins[gate_idx] + (k / (n // (n_gates + 1))) * (
208
- ends[gate_idx] - origins[gate_idx]
209
- )
210
- i += 1
211
- gate_idx += 1
212
-
213
- # Modify attitude to point sensor at targets
214
- R_sb = R_sb # Sensor to body frame
190
+ # Generate initial guess for position trajectory through gates
191
+ position_bar = ox.init.linspace(
192
+ keyframes=[position.initial] + gate_centers + [position.final],
193
+ nodes=[0] + list(gate_nodes) + [n - 1],
194
+ )
195
+
196
+ # Generate attitude guess to point sensor at mean target position
215
197
  b = R_sb @ np.array([0, 1, 0])
216
- mean_target = np.mean(init_poses, axis=0) # Average target position
198
+ mean_target = np.mean(init_poses, axis=0)
199
+ attitude_bar = np.zeros((n, 4))
217
200
  for k in range(n):
218
201
  a = mean_target - position_bar[k]
219
202
  # Determine the direction cosine matrix that aligns the z-axis of the sensor frame with the
@@ -221,14 +204,11 @@ for k in range(n):
221
204
  q_xyz = np.cross(b, a)
222
205
  q_w = np.sqrt(la.norm(a) ** 2 + la.norm(b) ** 2) + np.dot(a, b)
223
206
  q_no_norm = np.hstack((q_w, q_xyz))
224
- q = q_no_norm / la.norm(q_no_norm)
225
- attitude_bar[k] = q
207
+ attitude_bar[k] = q_no_norm / la.norm(q_no_norm)
226
208
 
227
- # Set all guesses
209
+ # Set guesses
228
210
  position.guess = position_bar
229
- velocity.guess = velocity_bar
230
211
  attitude.guess = attitude_bar
231
- angular_velocity.guess = angular_velocity_bar
232
212
 
233
213
  time = ox.Time(
234
214
  initial=0.0,
@@ -187,33 +187,16 @@ dynamics = {
187
187
  }
188
188
 
189
189
 
190
- # Initialize initial guess (will be modified by gate logic)
191
- position_bar = np.linspace(position.initial, position.final, n)
192
- velocity_bar = np.zeros((n, 3))
193
- attitude_bar = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
194
- angular_velocity_bar = np.zeros((n, 3))
195
-
196
- # Modify position to go through gates
197
- i = 0
198
- origins = [position.initial]
199
- ends = []
200
- for center in gate_centers:
201
- origins.append(center)
202
- ends.append(center)
203
- ends.append(position.final)
204
- gate_idx = 0
205
- for _ in range(n_gates + 1):
206
- for k in range(n // (n_gates + 1)):
207
- position_bar[i] = origins[gate_idx] + (k / (n // (n_gates + 1))) * (
208
- ends[gate_idx] - origins[gate_idx]
209
- )
210
- i += 1
211
- gate_idx += 1
212
-
213
- # Modify attitude to point sensor at targets
214
- R_sb = R_sb # Sensor to body frame
190
+ # Generate initial guess for position trajectory through gates
191
+ position_bar = ox.init.linspace(
192
+ keyframes=[position.initial] + gate_centers + [position.final],
193
+ nodes=[0] + list(gate_nodes) + [n - 1],
194
+ )
195
+
196
+ # Generate attitude guess to point sensor at mean target position
215
197
  b = R_sb @ np.array([0, 1, 0])
216
- mean_target = np.mean(init_poses, axis=0) # Average target position
198
+ mean_target = np.mean(init_poses, axis=0)
199
+ attitude_bar = np.zeros((n, 4))
217
200
  for k in range(n):
218
201
  a = mean_target - position_bar[k]
219
202
  # Determine the direction cosine matrix that aligns the z-axis of the sensor frame with the
@@ -221,14 +204,11 @@ for k in range(n):
221
204
  q_xyz = np.cross(b, a)
222
205
  q_w = np.sqrt(la.norm(a) ** 2 + la.norm(b) ** 2) + np.dot(a, b)
223
206
  q_no_norm = np.hstack((q_w, q_xyz))
224
- q = q_no_norm / la.norm(q_no_norm)
225
- attitude_bar[k] = q
207
+ attitude_bar[k] = q_no_norm / la.norm(q_no_norm)
226
208
 
227
- # Set all guesses
209
+ # Set guesses
228
210
  position.guess = position_bar
229
- velocity.guess = velocity_bar
230
211
  attitude.guess = attitude_bar
231
- angular_velocity.guess = angular_velocity_bar
232
212
 
233
213
  time = ox.Time(
234
214
  initial=0.0,
@@ -205,33 +205,16 @@ dynamics = {
205
205
  }
206
206
 
207
207
 
208
- # Initialize initial guess (will be modified by gate logic)
209
- position_bar = np.linspace(position.initial, position.final, n)
210
- velocity_bar = np.zeros((n, 3))
211
- attitude_bar = np.tile([1.0, 0.0, 0.0, 0.0], (n, 1))
212
- angular_velocity_bar = np.zeros((n, 3))
213
-
214
- # Modify position to go through gates
215
- i = 0
216
- origins = [position.initial]
217
- ends = []
218
- for center in gate_centers:
219
- origins.append(center)
220
- ends.append(center)
221
- ends.append(position.final)
222
- gate_idx = 0
223
- for _ in range(n_gates + 1):
224
- for k in range(n // (n_gates + 1)):
225
- position_bar[i] = origins[gate_idx] + (k / (n // (n_gates + 1))) * (
226
- ends[gate_idx] - origins[gate_idx]
227
- )
228
- i += 1
229
- gate_idx += 1
230
-
231
- # Modify attitude to point sensor at targets
232
- R_sb = R_sb # Sensor to body frame
208
+ # Generate initial guess for position trajectory through gates
209
+ position_bar = ox.init.linspace(
210
+ keyframes=[position.initial] + gate_centers + [position.final],
211
+ nodes=[0] + list(gate_nodes) + [n - 1],
212
+ )
213
+
214
+ # Generate attitude guess to point sensor at mean target position
233
215
  b = R_sb @ np.array([0, 1, 0])
234
- mean_target = np.mean(init_poses, axis=0) # Average target position
216
+ mean_target = np.mean(init_poses, axis=0)
217
+ attitude_bar = np.zeros((n, 4))
235
218
  for k in range(n):
236
219
  a = mean_target - position_bar[k]
237
220
  # Determine the direction cosine matrix that aligns the z-axis of the sensor frame with the
@@ -239,14 +222,11 @@ for k in range(n):
239
222
  q_xyz = np.cross(b, a)
240
223
  q_w = np.sqrt(la.norm(a) ** 2 + la.norm(b) ** 2) + np.dot(a, b)
241
224
  q_no_norm = np.hstack((q_w, q_xyz))
242
- q = q_no_norm / la.norm(q_no_norm)
243
- attitude_bar[k] = q
225
+ attitude_bar[k] = q_no_norm / la.norm(q_no_norm)
244
226
 
245
- # Set all guesses
227
+ # Set guesses
246
228
  position.guess = position_bar
247
- velocity.guess = velocity_bar
248
229
  attitude.guess = attitude_bar
249
- angular_velocity.guess = angular_velocity_bar
250
230
  time = ox.Time(
251
231
  initial=0.0,
252
232
  final=("minimize", total_time),
@@ -233,25 +233,10 @@ dynamics = {
233
233
 
234
234
 
235
235
  # Generate initial guess for position trajectory through gates
236
- position_bar = np.linspace(position.initial, position.final, n)
237
-
238
- i = 0
239
- origins = [position.initial]
240
- ends = []
241
- for center in modified_centers: # Use modified centers for initial guess
242
- origins.append(center)
243
- ends.append(center)
244
- ends.append(position.final)
245
- gate_idx = 0
246
- for _ in range(n_gates + 1):
247
- for k in range(n // (n_gates + 1)):
248
- position_bar[i] = origins[gate_idx] + (k / (n // (n_gates + 1))) * (
249
- ends[gate_idx] - origins[gate_idx]
250
- )
251
- i += 1
252
- gate_idx += 1
253
-
254
- position.guess = position_bar
236
+ position.guess = ox.init.linspace(
237
+ keyframes=[position.initial] + modified_centers + [position.final],
238
+ nodes=[0] + list(gate_nodes) + [n - 1],
239
+ )
255
240
 
256
241
  time = ox.Time(
257
242
  initial=0.0,
@@ -5,6 +5,7 @@ os.environ["EQX_ON_ERROR"] = "nan"
5
5
 
6
6
  # Cache management
7
7
  # Core symbolic expressions - flat namespace for most common functions
8
+ import openscvx.init as init
8
9
  import openscvx.symbolic.expr.lie as lie
9
10
  import openscvx.symbolic.expr.linalg as linalg
10
11
  import openscvx.symbolic.expr.spatial as spatial
@@ -123,6 +124,7 @@ __all__ = [
123
124
  # Data parallelism
124
125
  "Vmap",
125
126
  # Submodules
127
+ "init",
126
128
  "stl",
127
129
  "spatial",
128
130
  "linalg",
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.3.2.dev228'
32
- __version_tuple__ = version_tuple = (0, 3, 2, 'dev228')
31
+ __version__ = version = '0.3.2.dev234'
32
+ __version_tuple__ = version_tuple = (0, 3, 2, 'dev234')
33
33
 
34
- __commit_id__ = commit_id = 'g44572a46d'
34
+ __commit_id__ = commit_id = 'g81cc96a04'
@@ -0,0 +1,30 @@
1
+ """Trajectory initialization utilities.
2
+
3
+ This module provides functions for generating initial trajectory guesses
4
+ using various interpolation methods. Keyframe-based APIs allow specifying
5
+ values at specific nodes with automatic interpolation for intermediate nodes.
6
+
7
+ Example:
8
+ Generate initial guess for a quadrotor passing through gates::
9
+
10
+ import openscvx as ox
11
+
12
+ n = 50
13
+ position.guess = ox.init.linspace(
14
+ keyframes=[start_pos, gate1, gate2, end_pos],
15
+ nodes=[0, 15, 35, n-1],
16
+ )
17
+
18
+ attitude.guess = ox.init.nlerp(
19
+ keyframes=[q_start, q_gate1, q_gate2, q_end],
20
+ nodes=[0, 15, 35, n-1],
21
+ )
22
+ """
23
+
24
+ from openscvx.init.interpolation import linspace, nlerp, slerp
25
+
26
+ __all__ = [
27
+ "linspace",
28
+ "nlerp",
29
+ "slerp",
30
+ ]
@@ -0,0 +1,327 @@
1
+ """Trajectory initialization utilities for generating initial guesses.
2
+
3
+ This module provides interpolation methods for constructing initial trajectory
4
+ guesses from keyframe values at specified nodes. Keyframes define values at
5
+ specific nodes, and the interpolation fills in values for all intermediate nodes.
6
+ """
7
+
8
+ from typing import List, Sequence, Tuple, Union
9
+
10
+ import numpy as np
11
+
12
+ # Type aliases for clarity
13
+ Quaternion = Union[np.ndarray, Tuple[float, float, float, float], List[float]]
14
+ Keyframe = Union[np.ndarray, Sequence[float], float]
15
+
16
+
17
+ def linspace(
18
+ keyframes: Sequence[Keyframe],
19
+ nodes: Sequence[int],
20
+ ) -> np.ndarray:
21
+ """Generate trajectory guess via piecewise linear interpolation between keyframes.
22
+
23
+ Keyframes specify values at particular nodes, and linear interpolation fills
24
+ in the values for all nodes in between. This generalizes np.linspace to support
25
+ multiple waypoints.
26
+
27
+ Args:
28
+ keyframes: Sequence of values at keyframe nodes. Each keyframe should be
29
+ array-like with the same shape, or a scalar.
30
+ nodes: Sequence of node indices where keyframes occur. Must be sorted in
31
+ ascending order and have the same length as keyframes. The last node
32
+ determines the output size (N = nodes[-1] + 1).
33
+
34
+ Returns:
35
+ np.ndarray of shape (N, *keyframe_shape) containing interpolated values
36
+ for all nodes, where N = nodes[-1] + 1.
37
+
38
+ Raises:
39
+ ValueError: If keyframes and nodes have different lengths, or nodes are
40
+ not sorted.
41
+
42
+ Note:
43
+ The first node should typically be 0 and the last node should be N-1
44
+ (where N is your trajectory length). Nodes before the first keyframe
45
+ or after the last will be left as zeros.
46
+
47
+ Example:
48
+ Interpolate position through three waypoints::
49
+
50
+ import openscvx as ox
51
+
52
+ position_guess = ox.init.linspace(
53
+ keyframes=[[0, 0, 0], [5, 10, 5], [10, 0, 0]],
54
+ nodes=[0, 25, 49],
55
+ ) # Returns shape (50, 3)
56
+ position.guess = position_guess
57
+
58
+ Simple start-to-end interpolation (equivalent to np.linspace)::
59
+
60
+ position_guess = ox.init.linspace(
61
+ keyframes=[[0, 0, 0], [10, 0, 0]],
62
+ nodes=[0, 49],
63
+ ) # Returns shape (50, 3)
64
+ """
65
+ _validate_keyframe_inputs(keyframes, nodes)
66
+ N = nodes[-1] + 1
67
+
68
+ # Convert keyframes to numpy arrays
69
+ keyframes_arr = [np.atleast_1d(np.asarray(kf, dtype=np.float64)) for kf in keyframes]
70
+ keyframe_shape = keyframes_arr[0].shape
71
+
72
+ # Validate all keyframes have the same shape
73
+ for i, kf in enumerate(keyframes_arr):
74
+ if kf.shape != keyframe_shape:
75
+ raise ValueError(f"Keyframe {i} has shape {kf.shape}, expected {keyframe_shape}")
76
+
77
+ # Initialize output array
78
+ result = np.zeros((N, *keyframe_shape), dtype=np.float64)
79
+
80
+ # Interpolate between consecutive keyframe pairs
81
+ for i in range(len(nodes) - 1):
82
+ start_node = nodes[i]
83
+ end_node = nodes[i + 1]
84
+ start_val = keyframes_arr[i]
85
+ end_val = keyframes_arr[i + 1]
86
+
87
+ # Number of nodes in this segment (inclusive of start, exclusive of end)
88
+ n_segment = end_node - start_node
89
+
90
+ for j in range(n_segment):
91
+ t = j / n_segment
92
+ result[start_node + j] = (1 - t) * start_val + t * end_val
93
+
94
+ # Set the final keyframe value
95
+ result[nodes[-1]] = keyframes_arr[-1]
96
+
97
+ return result
98
+
99
+
100
+ def nlerp(
101
+ keyframes: Sequence[Quaternion],
102
+ nodes: Sequence[int],
103
+ ) -> np.ndarray:
104
+ """Generate quaternion trajectory guess via normalized linear interpolation.
105
+
106
+ NLERP performs linear interpolation between quaternions followed by
107
+ normalization. This is faster than SLERP but produces non-constant angular
108
+ velocity. For initial guesses this is typically sufficient.
109
+
110
+ Quaternion convention: [w, x, y, z] (scalar-first).
111
+
112
+ Args:
113
+ keyframes: Sequence of unit quaternions at keyframe nodes. Each quaternion
114
+ should be array-like with shape (4,) in [w, x, y, z] order.
115
+ nodes: Sequence of node indices where keyframes occur. Must be sorted in
116
+ ascending order and have the same length as keyframes.
117
+
118
+ Returns:
119
+ np.ndarray of shape (N, 4) containing normalized interpolated quaternions
120
+ for all nodes, where N = nodes[-1] + 1.
121
+
122
+ Raises:
123
+ ValueError: If keyframes and nodes have different lengths, nodes are not
124
+ sorted, or quaternions don't have shape (4,).
125
+
126
+ Note:
127
+ The first node should typically be 0 and the last node should be N-1.
128
+ Nodes outside the keyframe range will be left as zeros.
129
+
130
+ Example:
131
+ Interpolate attitude from identity to 180-degree rotation about z-axis::
132
+
133
+ import openscvx as ox
134
+
135
+ attitude_guess = ox.init.nlerp(
136
+ keyframes=[
137
+ [1, 0, 0, 0], # Identity quaternion
138
+ [0, 0, 0, 1], # 180 deg about z
139
+ ],
140
+ nodes=[0, 49],
141
+ ) # Returns shape (50, 4)
142
+ attitude.guess = attitude_guess
143
+
144
+ Interpolate through intermediate attitudes::
145
+
146
+ attitude_guess = ox.init.nlerp(
147
+ keyframes=[
148
+ [1, 0, 0, 0], # Identity
149
+ [0.707, 0, 0, 0.707], # 90 deg about z
150
+ [0, 0, 0, 1], # 180 deg about z
151
+ ],
152
+ nodes=[0, 25, 49],
153
+ )
154
+ """
155
+ _validate_keyframe_inputs(keyframes, nodes)
156
+ N = nodes[-1] + 1
157
+
158
+ # Convert keyframes to numpy arrays and validate shape
159
+ keyframes_arr = []
160
+ for i, kf in enumerate(keyframes):
161
+ q = np.asarray(kf, dtype=np.float64)
162
+ if q.shape != (4,):
163
+ raise ValueError(f"Keyframe {i} has shape {q.shape}, expected (4,) for quaternion")
164
+ # Normalize input quaternions
165
+ q = q / np.linalg.norm(q)
166
+ keyframes_arr.append(q)
167
+
168
+ # Initialize output array
169
+ result = np.zeros((N, 4), dtype=np.float64)
170
+
171
+ # Interpolate between consecutive keyframe pairs
172
+ for i in range(len(nodes) - 1):
173
+ start_node = nodes[i]
174
+ end_node = nodes[i + 1]
175
+ q0 = keyframes_arr[i]
176
+ q1 = keyframes_arr[i + 1]
177
+
178
+ # Ensure shortest path interpolation
179
+ if np.dot(q0, q1) < 0:
180
+ q1 = -q1
181
+
182
+ n_segment = end_node - start_node
183
+
184
+ for j in range(n_segment):
185
+ t = j / n_segment
186
+ # Linear interpolation
187
+ q_interp = (1 - t) * q0 + t * q1
188
+ # Normalize
189
+ result[start_node + j] = q_interp / np.linalg.norm(q_interp)
190
+
191
+ # Set the final keyframe value (normalized)
192
+ result[nodes[-1]] = keyframes_arr[-1]
193
+
194
+ return result
195
+
196
+
197
+ def slerp(
198
+ keyframes: Sequence[Quaternion],
199
+ nodes: Sequence[int],
200
+ ) -> np.ndarray:
201
+ """Generate quaternion trajectory guess via spherical linear interpolation.
202
+
203
+ SLERP interpolates along the great arc on the unit quaternion sphere,
204
+ producing constant angular velocity between keyframes. This is more accurate
205
+ than NLERP but slightly more expensive to compute.
206
+
207
+ Quaternion convention: [w, x, y, z] (scalar-first).
208
+
209
+ Args:
210
+ keyframes: Sequence of unit quaternions at keyframe nodes. Each quaternion
211
+ should be array-like with shape (4,) in [w, x, y, z] order.
212
+ nodes: Sequence of node indices where keyframes occur. Must be sorted in
213
+ ascending order and have the same length as keyframes.
214
+
215
+ Returns:
216
+ np.ndarray of shape (N, 4) containing interpolated quaternions for all nodes,
217
+ where N = nodes[-1] + 1.
218
+
219
+ Raises:
220
+ ValueError: If keyframes and nodes have different lengths, nodes are not
221
+ sorted, or quaternions don't have shape (4,).
222
+
223
+ Note:
224
+ The first node should typically be 0 and the last node should be N-1.
225
+ Nodes outside the keyframe range will be left as zeros.
226
+
227
+ Example:
228
+ Interpolate attitude with constant angular velocity::
229
+
230
+ import openscvx as ox
231
+
232
+ attitude_guess = ox.init.slerp(
233
+ keyframes=[
234
+ [1, 0, 0, 0], # Identity quaternion
235
+ [0, 0, 0, 1], # 180 deg about z
236
+ ],
237
+ nodes=[0, 49],
238
+ ) # Returns shape (50, 4)
239
+ attitude.guess = attitude_guess
240
+ """
241
+ _validate_keyframe_inputs(keyframes, nodes)
242
+ N = nodes[-1] + 1
243
+
244
+ # Convert keyframes to numpy arrays and validate shape
245
+ keyframes_arr = []
246
+ for i, kf in enumerate(keyframes):
247
+ q = np.asarray(kf, dtype=np.float64)
248
+ if q.shape != (4,):
249
+ raise ValueError(f"Keyframe {i} has shape {q.shape}, expected (4,) for quaternion")
250
+ # Normalize input quaternions
251
+ q = q / np.linalg.norm(q)
252
+ keyframes_arr.append(q)
253
+
254
+ # Initialize output array
255
+ result = np.zeros((N, 4), dtype=np.float64)
256
+
257
+ # Interpolate between consecutive keyframe pairs
258
+ for i in range(len(nodes) - 1):
259
+ start_node = nodes[i]
260
+ end_node = nodes[i + 1]
261
+ q0 = keyframes_arr[i]
262
+ q1 = keyframes_arr[i + 1]
263
+
264
+ # Ensure shortest path interpolation
265
+ dot = np.dot(q0, q1)
266
+ if dot < 0:
267
+ q1 = -q1
268
+ dot = -dot
269
+
270
+ n_segment = end_node - start_node
271
+
272
+ # Handle near-identical quaternions (fall back to NLERP)
273
+ if dot > 0.9995:
274
+ for j in range(n_segment):
275
+ t = j / n_segment
276
+ q_interp = (1 - t) * q0 + t * q1
277
+ result[start_node + j] = q_interp / np.linalg.norm(q_interp)
278
+ else:
279
+ # SLERP formula
280
+ theta = np.arccos(dot)
281
+ sin_theta = np.sin(theta)
282
+
283
+ for j in range(n_segment):
284
+ t = j / n_segment
285
+ s0 = np.sin((1 - t) * theta) / sin_theta
286
+ s1 = np.sin(t * theta) / sin_theta
287
+ result[start_node + j] = s0 * q0 + s1 * q1
288
+
289
+ # Set the final keyframe value (normalized)
290
+ result[nodes[-1]] = keyframes_arr[-1]
291
+
292
+ return result
293
+
294
+
295
+ def _validate_keyframe_inputs(
296
+ keyframes: Sequence,
297
+ nodes: Sequence[int],
298
+ ) -> None:
299
+ """Validate common inputs for keyframe interpolation functions.
300
+
301
+ Args:
302
+ keyframes: Sequence of keyframe values
303
+ nodes: Sequence of node indices
304
+
305
+ Raises:
306
+ ValueError: If inputs are invalid
307
+ """
308
+ if len(keyframes) != len(nodes):
309
+ raise ValueError(
310
+ f"keyframes and nodes must have the same length, "
311
+ f"got {len(keyframes)} keyframes and {len(nodes)} nodes"
312
+ )
313
+
314
+ if len(keyframes) < 2:
315
+ raise ValueError("At least 2 keyframes are required for interpolation")
316
+
317
+ # Check nodes are sorted
318
+ for i in range(len(nodes) - 1):
319
+ if nodes[i] >= nodes[i + 1]:
320
+ raise ValueError(
321
+ f"nodes must be strictly increasing, "
322
+ f"but nodes[{i}]={nodes[i]} >= nodes[{i + 1}]={nodes[i + 1]}"
323
+ )
324
+
325
+ # Check first node is non-negative
326
+ if nodes[0] < 0:
327
+ raise ValueError(f"Node indices must be >= 0, got nodes[0]={nodes[0]}")
@@ -770,11 +770,16 @@ def fill_default_guesses(states: List[State], N: int) -> None:
770
770
  states: List of State objects to fill guesses for
771
771
  N: Number of discretization nodes
772
772
  """
773
+ from openscvx.init import linspace
774
+
773
775
  for state in states:
774
776
  if state.guess is None and state.initial is not None and state.final is not None:
775
777
  # state.initial and state.final are already numpy arrays of values
776
778
  # (the setter handles parsing tuples like ("free", value))
777
- state.guess = np.linspace(state.initial, state.final, N)
779
+ state.guess = linspace(
780
+ keyframes=[state.initial, state.final],
781
+ nodes=[0, N - 1],
782
+ )
778
783
 
779
784
 
780
785
  def validate_boundary_conditions(states: List[State]) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscvx
3
- Version: 0.3.2.dev228
3
+ Version: 0.3.2.dev234
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
@@ -138,6 +138,8 @@ openscvx/expert/__init__.py
138
138
  openscvx/expert/byof.py
139
139
  openscvx/expert/lowering.py
140
140
  openscvx/expert/validation.py
141
+ openscvx/init/__init__.py
142
+ openscvx/init/interpolation.py
141
143
  openscvx/integrators/__init__.py
142
144
  openscvx/integrators/runge_kutta.py
143
145
  openscvx/lowered/__init__.py
@@ -207,6 +209,7 @@ tests/test_cvxpygen_optional.py
207
209
  tests/test_discretization.py
208
210
  tests/test_examples.py
209
211
  tests/test_expert.py
212
+ tests/test_init.py
210
213
  tests/test_integrators.py
211
214
  tests/test_plotting.py
212
215
  tests/test_propagation.py