sleipnirgroup-jormungandr 0.6.7.dev128__tar.gz → 0.6.7.dev130__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 (137) hide show
  1. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/PKG-INFO +1 -1
  2. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/variable_matrix.hpp +59 -55
  3. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/autodiff/bind_variable.cpp +143 -1
  4. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/autodiff/bind_variable_block.cpp +5 -6
  5. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/autodiff/bind_variable_matrix.cpp +17 -6
  6. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/docstrings.hpp +39 -0
  7. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/postprocess_stubs.py +94 -29
  8. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/src/sleipnir/__init__.py +1 -1
  9. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/autodiff/variable_matrix_test.py +24 -7
  10. sleipnirgroup_jormungandr-0.6.7.dev130/python/test/autodiff/variable_test.py +85 -0
  11. sleipnirgroup_jormungandr-0.6.7.dev128/python/test/autodiff/variable_test.py +0 -31
  12. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/CMakeLists.txt +0 -0
  13. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/LICENSE.txt +0 -0
  14. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/README.md +0 -0
  15. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/SleipnirConfig.cmake.in +0 -0
  16. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/cmake/BuildTypes.cmake +0 -0
  17. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/cmake/CompilerFlags.cmake +0 -0
  18. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/cmake/Pybind11Mkdoc.cmake +0 -0
  19. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/cmake/Pybind11MkdocPostprocess.cmake +0 -0
  20. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/cmake/SubdirList.cmake +0 -0
  21. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/cmake/aarch64-linux-gnu.cmake +0 -0
  22. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/cmake/arm-none-eabi.cmake +0 -0
  23. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/expression.hpp +0 -0
  24. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/expression_functions.hpp +0 -0
  25. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/expression_graph.hpp +0 -0
  26. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/expression_type.hpp +0 -0
  27. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/gradient.hpp +0 -0
  28. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/hessian.hpp +0 -0
  29. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/jacobian.hpp +0 -0
  30. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/sleipnir_base.hpp +0 -0
  31. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/slice.hpp +0 -0
  32. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/variable.hpp +0 -0
  33. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/autodiff/variable_block.hpp +0 -0
  34. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/multistart.hpp +0 -0
  35. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/ocp/dynamics_type.hpp +0 -0
  36. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/ocp/timestep_method.hpp +0 -0
  37. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/ocp/transcription_method.hpp +0 -0
  38. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/ocp.hpp +0 -0
  39. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/problem.hpp +0 -0
  40. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/exit_status.hpp +0 -0
  41. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/ipm.hpp +0 -0
  42. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/ipm_matrix_callbacks.hpp +0 -0
  43. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/iteration_info.hpp +0 -0
  44. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/newton.hpp +0 -0
  45. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/newton_matrix_callbacks.hpp +0 -0
  46. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/options.hpp +0 -0
  47. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/sqp.hpp +0 -0
  48. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/sqp_matrix_callbacks.hpp +0 -0
  49. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/all_finite.hpp +0 -0
  50. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/append_as_triplets.hpp +0 -0
  51. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/bounds.hpp +0 -0
  52. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/constraint_violation.hpp +0 -0
  53. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/dense_kkt_solver.hpp +0 -0
  54. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/feasibility_restoration.hpp +0 -0
  55. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/feasibility_restoration_cycle_detector.hpp +0 -0
  56. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/filter.hpp +0 -0
  57. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/fraction_to_the_boundary_rule.hpp +0 -0
  58. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/inertia.hpp +0 -0
  59. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/kkt_error.hpp +0 -0
  60. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/kkt_ordering.hpp +0 -0
  61. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/kkt_solver.hpp +0 -0
  62. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/problem_scaling.hpp +0 -0
  63. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/regularization_limits.hpp +0 -0
  64. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/sparse_inf_norms.hpp +0 -0
  65. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/sparse_kkt_solver.hpp +0 -0
  66. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/optimization/solver/util/time_trace.hpp +0 -0
  67. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/assert.hpp +0 -0
  68. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/concepts.hpp +0 -0
  69. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/empty.hpp +0 -0
  70. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/force_inline.hpp +0 -0
  71. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/function_ref.hpp +0 -0
  72. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/intrusive_shared_ptr.hpp +0 -0
  73. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/pool.hpp +0 -0
  74. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/print.hpp +0 -0
  75. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/print_diagnostics.hpp +0 -0
  76. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/scope_exit.hpp +0 -0
  77. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/spy.hpp +0 -0
  78. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/symbol_exports.hpp +0 -0
  79. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/include/sleipnir/util/time_tracer.hpp +0 -0
  80. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/pyproject.toml +0 -0
  81. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/arity.hpp +0 -0
  82. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/autodiff/bind_expression_type.cpp +0 -0
  83. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/autodiff/bind_gradient.cpp +0 -0
  84. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/autodiff/bind_hessian.cpp +0 -0
  85. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/autodiff/bind_jacobian.cpp +0 -0
  86. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/binders.hpp +0 -0
  87. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/for_each_type.hpp +0 -0
  88. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/main.cpp +0 -0
  89. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/bind_equality_constraints.cpp +0 -0
  90. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/bind_inequality_constraints.cpp +0 -0
  91. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/bind_ocp.cpp +0 -0
  92. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/bind_problem.cpp +0 -0
  93. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/ocp/bind_dynamics_type.cpp +0 -0
  94. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/ocp/bind_timestep_method.cpp +0 -0
  95. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/ocp/bind_transcription_method.cpp +0 -0
  96. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/solver/bind_exit_status.cpp +0 -0
  97. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/optimization/solver/bind_iteration_info.cpp +0 -0
  98. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/slice_tuple.hpp +0 -0
  99. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/text_wrap.hpp +0 -0
  100. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/cpp/try_cast.hpp +0 -0
  101. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/src/sleipnir/autodiff/__init__.py +0 -0
  102. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/src/sleipnir/optimization/__init__.py +0 -0
  103. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/autodiff/gradient_test.py +0 -0
  104. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/autodiff/hessian_test.py +0 -0
  105. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/autodiff/jacobian_test.py +0 -0
  106. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/arm_on_elevator_problem_test.py +0 -0
  107. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/cart_pole_ocp_test.py +0 -0
  108. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/cart_pole_problem_test.py +0 -0
  109. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/cart_pole_util.py +0 -0
  110. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/constraints_test.py +0 -0
  111. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/decision_variable_test.py +0 -0
  112. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/differential_drive_ocp_test.py +0 -0
  113. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/differential_drive_problem_test.py +0 -0
  114. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/differential_drive_util.py +0 -0
  115. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/double_integrator_problem_test.py +0 -0
  116. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/flywheel_ocp_test.py +0 -0
  117. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/flywheel_problem_test.py +0 -0
  118. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/flywheel_util.py +0 -0
  119. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/linear_problem_test.py +0 -0
  120. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/multistart_test.py +0 -0
  121. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/nonlinear_problem_test.py +0 -0
  122. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/problem_spy_test.py +0 -0
  123. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/quadratic_problem_test.py +0 -0
  124. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/rk4.py +0 -0
  125. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/solver/exit_status_test.py +0 -0
  126. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/tolerance.py +0 -0
  127. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/python/test/optimization/trivial_problem_test.py +0 -0
  128. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/autodiff/gradient.cpp +0 -0
  129. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/autodiff/hessian.cpp +0 -0
  130. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/autodiff/jacobian.cpp +0 -0
  131. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/autodiff/variable_matrix.cpp +0 -0
  132. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/optimization/ocp.cpp +0 -0
  133. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/optimization/problem.cpp +0 -0
  134. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/optimization/solver/ipm.cpp +0 -0
  135. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/optimization/solver/newton.cpp +0 -0
  136. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/optimization/solver/sqp.cpp +0 -0
  137. {sleipnirgroup_jormungandr-0.6.7.dev128 → sleipnirgroup_jormungandr-0.6.7.dev130}/src/util/pool.cpp +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sleipnirgroup-jormungandr
3
- Version: 0.6.7.dev128
3
+ Version: 0.6.7.dev130
4
4
  Summary: Reverse mode autodiff library and NLP solver DSL
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE.txt
@@ -9,6 +9,7 @@
9
9
  #include <initializer_list>
10
10
  #include <iterator>
11
11
  #include <span>
12
+ #include <type_traits>
12
13
  #include <utility>
13
14
  #include <vector>
14
15
 
@@ -566,24 +567,6 @@ class VariableMatrix : public SleipnirBase {
566
567
  return result;
567
568
  }
568
569
 
569
- /// Matrix-scalar multiplication operator.
570
- ///
571
- /// @param lhs Operator left-hand side.
572
- /// @param rhs Operator right-hand side.
573
- template <EigenMatrixLike LHS>
574
- friend VariableMatrix<Scalar> operator*(const LHS& lhs,
575
- const Variable<Scalar>& rhs) {
576
- VariableMatrix<Scalar> result(detail::empty, lhs.rows(), lhs.cols());
577
-
578
- for (int row = 0; row < result.rows(); ++row) {
579
- for (int col = 0; col < result.cols(); ++col) {
580
- result[row, col] = lhs[row, col] * rhs;
581
- }
582
- }
583
-
584
- return result;
585
- }
586
-
587
570
  /// Matrix-scalar multiplication operator.
588
571
  ///
589
572
  /// @param lhs Operator left-hand side.
@@ -601,24 +584,6 @@ class VariableMatrix : public SleipnirBase {
601
584
  return result;
602
585
  }
603
586
 
604
- /// Scalar-matrix multiplication operator.
605
- ///
606
- /// @param lhs Operator left-hand side.
607
- /// @param rhs Operator right-hand side.
608
- template <EigenMatrixLike RHS>
609
- friend VariableMatrix<Scalar> operator*(const Variable<Scalar>& lhs,
610
- const RHS& rhs) {
611
- VariableMatrix<Scalar> result(detail::empty, rhs.rows(), rhs.cols());
612
-
613
- for (int row = 0; row < result.rows(); ++row) {
614
- for (int col = 0; col < result.cols(); ++col) {
615
- result[row, col] = rhs[row, col] * lhs;
616
- }
617
- }
618
-
619
- return result;
620
- }
621
-
622
587
  /// Scalar-matrix multiplication operator.
623
588
  ///
624
589
  /// @param lhs Operator left-hand side.
@@ -671,25 +636,6 @@ class VariableMatrix : public SleipnirBase {
671
636
  return *this;
672
637
  }
673
638
 
674
- /// Binary division operator.
675
- ///
676
- /// @param lhs Operator left-hand side.
677
- /// @param rhs Operator right-hand side.
678
- /// @return Result of division.
679
- template <EigenMatrixLike LHS>
680
- friend VariableMatrix<Scalar> operator/(const LHS& lhs,
681
- const Variable<Scalar>& rhs) {
682
- VariableMatrix<Scalar> result(detail::empty, lhs.rows(), lhs.cols());
683
-
684
- for (int row = 0; row < result.rows(); ++row) {
685
- for (int col = 0; col < result.cols(); ++col) {
686
- result[row, col] = lhs[row, col] / rhs;
687
- }
688
- }
689
-
690
- return result;
691
- }
692
-
693
639
  /// Binary division operator.
694
640
  ///
695
641
  /// @param lhs Operator left-hand side.
@@ -1373,6 +1319,64 @@ template <typename Derived>
1373
1319
  VariableMatrix(const Eigen::DiagonalBase<Derived>&)
1374
1320
  -> VariableMatrix<typename Derived::Scalar>;
1375
1321
 
1322
+ /// Matrix-scalar multiplication operator.
1323
+ ///
1324
+ /// @tparam Scalar Scalar type.
1325
+ /// @param lhs Operator left-hand side.
1326
+ /// @param rhs Operator right-hand side.
1327
+ template <typename Scalar, EigenMatrixLike LHS>
1328
+ requires std::same_as<typename std::decay_t<LHS>::Scalar, Scalar>
1329
+ VariableMatrix<Scalar> operator*(const LHS& lhs, const Variable<Scalar>& rhs) {
1330
+ VariableMatrix<Scalar> result(detail::empty, lhs.rows(), lhs.cols());
1331
+
1332
+ for (int row = 0; row < result.rows(); ++row) {
1333
+ for (int col = 0; col < result.cols(); ++col) {
1334
+ result[row, col] = lhs[row, col] * rhs;
1335
+ }
1336
+ }
1337
+
1338
+ return result;
1339
+ }
1340
+
1341
+ /// Scalar-matrix multiplication operator.
1342
+ ///
1343
+ /// @tparam Scalar Scalar type.
1344
+ /// @param lhs Operator left-hand side.
1345
+ /// @param rhs Operator right-hand side.
1346
+ template <typename Scalar, EigenMatrixLike RHS>
1347
+ requires std::same_as<typename std::decay_t<RHS>::Scalar, Scalar>
1348
+ VariableMatrix<Scalar> operator*(const Variable<Scalar>& lhs, const RHS& rhs) {
1349
+ VariableMatrix<Scalar> result(detail::empty, rhs.rows(), rhs.cols());
1350
+
1351
+ for (int row = 0; row < result.rows(); ++row) {
1352
+ for (int col = 0; col < result.cols(); ++col) {
1353
+ result[row, col] = rhs[row, col] * lhs;
1354
+ }
1355
+ }
1356
+
1357
+ return result;
1358
+ }
1359
+
1360
+ /// Binary division operator.
1361
+ ///
1362
+ /// @tparam Scalar Scalar type.
1363
+ /// @param lhs Operator left-hand side.
1364
+ /// @param rhs Operator right-hand side.
1365
+ /// @return Result of division.
1366
+ template <typename Scalar, EigenMatrixLike LHS>
1367
+ requires std::same_as<typename std::decay_t<LHS>::Scalar, Scalar>
1368
+ VariableMatrix<Scalar> operator/(const LHS& lhs, const Variable<Scalar>& rhs) {
1369
+ VariableMatrix<Scalar> result(detail::empty, lhs.rows(), lhs.cols());
1370
+
1371
+ for (int row = 0; row < result.rows(); ++row) {
1372
+ for (int col = 0; col < result.cols(); ++col) {
1373
+ result[row, col] = lhs[row, col] / rhs;
1374
+ }
1375
+ }
1376
+
1377
+ return result;
1378
+ }
1379
+
1376
1380
  /// Applies a coefficient-wise reduce operation to two matrices.
1377
1381
  ///
1378
1382
  /// @tparam Scalar Scalar type.
@@ -3,8 +3,12 @@
3
3
  #include <nanobind/eigen/dense.h>
4
4
  #include <nanobind/nanobind.h>
5
5
  #include <nanobind/operators.h>
6
+ #include <nanobind/stl/string.h>
6
7
 
8
+ #include <algorithm>
9
+ #include <array>
7
10
  #include <concepts>
11
+ #include <string>
8
12
  #include <utility>
9
13
 
10
14
  #include <sleipnir/autodiff/variable.hpp>
@@ -13,6 +17,7 @@
13
17
 
14
18
  #include "docstrings.hpp"
15
19
  #include "for_each_type.hpp"
20
+ #include "try_cast.hpp"
16
21
 
17
22
  namespace nb = nanobind;
18
23
 
@@ -93,7 +98,8 @@ void bind_variable(nb::module_& autodiff, nb::class_<Variable<double>>& cls) {
93
98
  using namespace nb::literals;
94
99
 
95
100
  cls.def(nb::init<>(), DOC(slp, Variable, Variable));
96
- cls.def(nb::init<double>(), "value"_a, DOC(slp, Variable, Variable, 2));
101
+ cls.def(nb::init_implicit<double>(), "value"_a,
102
+ DOC(slp, Variable, Variable, 2));
97
103
  cls.def("set_value", nb::overload_cast<double>(&Variable<double>::set_value),
98
104
  "value"_a, DOC(slp, Variable, set_value));
99
105
  cls.def("value", &Variable<double>::value, DOC(slp, Variable, value));
@@ -116,6 +122,142 @@ void bind_variable(nb::module_& autodiff, nb::class_<Variable<double>>& cls) {
116
122
  }
117
123
  });
118
124
 
125
+ // Scalar-matrix multiplication and division with NumPy arrays. These are also
126
+ // handled by __array_ufunc__ below, but type checkers only see these
127
+ // overloads.
128
+ cls.def(
129
+ "__mul__",
130
+ [](const Variable<double>& lhs, nb::DRef<Eigen::MatrixXd> rhs) {
131
+ return lhs * rhs;
132
+ },
133
+ nb::is_operator(), "rhs"_a);
134
+ cls.def(
135
+ "__imul__",
136
+ [](const Variable<double>& lhs, nb::DRef<Eigen::MatrixXd> rhs) {
137
+ return lhs * rhs;
138
+ },
139
+ nb::is_operator(), "rhs"_a);
140
+ cls.def(
141
+ "__rmul__",
142
+ [](const Variable<double>& rhs, nb::DRef<Eigen::MatrixXd> lhs) {
143
+ return lhs * rhs;
144
+ },
145
+ nb::is_operator(), "lhs"_a);
146
+ cls.def(
147
+ "__rtruediv__",
148
+ [](const Variable<double>& rhs, nb::DRef<Eigen::MatrixXd> lhs) {
149
+ return lhs / rhs;
150
+ },
151
+ nb::is_operator(), "lhs"_a);
152
+
153
+ // Map NumPy ufunc reprs to the equivalent function names in Python's
154
+ // operator module
155
+ static constexpr std::array scalar_operators{
156
+ std::pair{"<ufunc 'add'>", "add"},
157
+ std::pair{"<ufunc 'subtract'>", "sub"},
158
+ std::pair{"<ufunc 'multiply'>", "mul"},
159
+ std::pair{"<ufunc 'divide'>", "truediv"},
160
+ std::pair{"<ufunc 'equal'>", "eq"},
161
+ std::pair{"<ufunc 'less'>", "lt"},
162
+ std::pair{"<ufunc 'less_equal'>", "le"},
163
+ std::pair{"<ufunc 'greater'>", "gt"},
164
+ std::pair{"<ufunc 'greater_equal'>", "ge"}};
165
+
166
+ // https://numpy.org/doc/stable/user/basics.dispatch.html
167
+ cls.def(
168
+ "__array_ufunc__",
169
+ [](Variable<double>& self, nb::object ufunc, nb::str method,
170
+ nb::args inputs, const nb::kwargs&) -> nb::object {
171
+ std::string method_name = nb::cast<std::string>(method);
172
+ std::string ufunc_name =
173
+ nb::cast<std::string>(ufunc.attr("__repr__")());
174
+
175
+ // VariableMatrix only represents 2D arrays
176
+ auto is_2d_array = [](const nb::handle& obj) {
177
+ return nb::isinstance<nb::ndarray<>>(obj) &&
178
+ nb::cast<nb::ndarray<>>(obj).ndim() == 2;
179
+ };
180
+
181
+ if (method_name == "__call__" && inputs.size() == 2) {
182
+ if (auto op = std::ranges::find(
183
+ scalar_operators, ufunc_name,
184
+ [](const auto& pair) { return pair.first; });
185
+ op != scalar_operators.end()) {
186
+ auto np = nb::module_::import_("numpy");
187
+
188
+ auto is_0d = [&](const nb::handle& obj) {
189
+ // np.ndim() returns 0 for any non-array object
190
+ return !nb::isinstance<Variable<double>>(obj) &&
191
+ nb::cast<int>(np.attr("ndim")(obj)) == 0;
192
+ };
193
+
194
+ // Convert NumPy scalars and 0D arrays to the equivalent Python
195
+ // scalar (e.g., np.float64 to float) and return other objects
196
+ // unchanged
197
+ auto numpy_to_python_scalar =
198
+ [&](const nb::handle& obj) -> nb::object {
199
+ nb::object numpy_types =
200
+ nb::make_tuple(np.attr("generic"), np.attr("ndarray"));
201
+ if (PyObject_IsInstance(obj.ptr(), numpy_types.ptr()) == 1) {
202
+ return obj.attr("item")();
203
+ } else {
204
+ return nb::borrow(obj);
205
+ }
206
+ };
207
+
208
+ // If an operand is 0D, apply the Python operator to its Python
209
+ // scalar and the other operand, which dispatches to Variable's
210
+ // scalar overloads
211
+ if (is_0d(inputs[0])) {
212
+ return nb::module_::import_("operator")
213
+ .attr(op->second)(numpy_to_python_scalar(inputs[0]),
214
+ inputs[1]);
215
+ } else if (is_0d(inputs[1])) {
216
+ return nb::module_::import_("operator")
217
+ .attr(op->second)(inputs[0],
218
+ numpy_to_python_scalar(inputs[1]));
219
+ }
220
+ }
221
+
222
+ if (ufunc_name == "<ufunc 'multiply'>") {
223
+ if (is_2d_array(inputs[0])) {
224
+ if (auto result = apply_eigen_op(
225
+ [&](auto& lhs) {
226
+ return lhs.template cast<double>() * self;
227
+ },
228
+ inputs[0])) {
229
+ return result.value();
230
+ }
231
+ } else if (is_2d_array(inputs[1])) {
232
+ if (auto result = apply_eigen_op(
233
+ [&](auto& rhs) {
234
+ return self * rhs.template cast<double>();
235
+ },
236
+ inputs[1])) {
237
+ return result.value();
238
+ }
239
+ }
240
+ } else if (ufunc_name == "<ufunc 'divide'>") {
241
+ if (is_2d_array(inputs[0])) {
242
+ if (auto result = apply_eigen_op(
243
+ [&](auto& lhs) {
244
+ return lhs.template cast<double>() / self;
245
+ },
246
+ inputs[0])) {
247
+ return result.value();
248
+ }
249
+ }
250
+ }
251
+ }
252
+
253
+ return nb::not_implemented();
254
+ },
255
+ // nanobind can't annotate nb::args or nb::kwargs, so the stub needs an
256
+ // explicit signature
257
+ nb::sig("def __array_ufunc__(self, ufunc: object, method: str, "
258
+ "*inputs: object, **kwargs: object) -> object"),
259
+ "ufunc"_a, "method"_a, "inputs"_a, "kwargs"_a);
260
+
119
261
  cls.def(
120
262
  "__pow__",
121
263
  [](const Variable<double>& self, int power) { return pow(self, power); },
@@ -340,12 +340,11 @@ void bind_variable_block(
340
340
  cls.def(-nb::self);
341
341
 
342
342
  // Matrix-scalar/scalar-matrix operations
343
- for_each_type<double, int, Variable<double>>([&]<typename T> {
344
- cls.def(nb::self * T(), "rhs"_a);
345
- cls.def(T() * nb::self, "lhs"_a);
346
- cls.def(nb::self / T(), "rhs"_a);
347
- cls.def(nb::self /= T(), "rhs"_a, DOC(slp, VariableBlock, operator, idiv));
348
- });
343
+ cls.def(nb::self * Variable<double>(), "rhs"_a);
344
+ cls.def(Variable<double>() * nb::self, "lhs"_a);
345
+ cls.def(nb::self / Variable<double>(), "rhs"_a);
346
+ cls.def(nb::self /= Variable<double>(), "rhs"_a,
347
+ DOC(slp, VariableBlock, operator, idiv));
349
348
  for_each_type<double, int, const Variable<double>&,
350
349
  nb::DRef<Eigen::MatrixXd>>([&]<typename T> {
351
350
  cls.def(
@@ -372,12 +372,11 @@ void bind_variable_matrix(nb::module_& autodiff,
372
372
  cls.def(-nb::self);
373
373
 
374
374
  // Matrix-scalar/scalar-matrix operations
375
- for_each_type<double, int, Variable<double>>([&]<typename T> {
376
- cls.def(nb::self * T(), "rhs"_a);
377
- cls.def(T() * nb::self, "lhs"_a);
378
- cls.def(nb::self / T(), "rhs"_a);
379
- cls.def(nb::self /= T(), "rhs"_a, DOC(slp, VariableMatrix, operator, idiv));
380
- });
375
+ cls.def(nb::self * Variable<double>(), "rhs"_a);
376
+ cls.def(Variable<double>() * nb::self, "lhs"_a);
377
+ cls.def(nb::self / Variable<double>(), "rhs"_a);
378
+ cls.def(nb::self /= Variable<double>(), "rhs"_a,
379
+ DOC(slp, VariableMatrix, operator, idiv));
381
380
  for_each_type<double, int, const Variable<double>&,
382
381
  const VariableBlock<VariableMatrix<double>>,
383
382
  nb::DRef<Eigen::MatrixXd>>([&]<typename T> {
@@ -529,6 +528,18 @@ void bind_variable_matrix(nb::module_& autodiff,
529
528
  nb::overload_cast<const VariableMatrix<double>&,
530
529
  const VariableMatrix<double>&>(&solve<double>),
531
530
  "A"_a, "B"_a, DOC(slp, solve));
531
+ autodiff.def(
532
+ "solve",
533
+ [](const VariableMatrix<double>& A, nb::DRef<Eigen::MatrixXd> B) {
534
+ return solve(A, VariableMatrix<double>(B));
535
+ },
536
+ "A"_a, "B"_a, DOC(slp, solve));
537
+ autodiff.def(
538
+ "solve",
539
+ [](nb::DRef<Eigen::MatrixXd> A, const VariableMatrix<double>& B) {
540
+ return solve(VariableMatrix<double>(A), B);
541
+ },
542
+ "A"_a, "B"_a, DOC(slp, solve));
532
543
  }
533
544
 
534
545
  } // namespace slp
@@ -2959,6 +2959,21 @@ Template Args:
2959
2959
 
2960
2960
  )doc";
2961
2961
 
2962
+ constexpr char mkd_doc_slp_operator_div[] =
2963
+ R"doc(Binary division operator.
2964
+
2965
+ Args:
2966
+ lhs: Operator left-hand side.
2967
+ rhs: Operator right-hand side.
2968
+
2969
+ Template Args:
2970
+ Scalar: Scalar type.
2971
+
2972
+ Returns:
2973
+ Result of division.
2974
+
2975
+ )doc";
2976
+
2962
2977
  constexpr char mkd_doc_slp_operator_eq[] =
2963
2978
  R"doc(Equality operator that returns an equality constraint for two
2964
2979
  Variables.
@@ -3049,6 +3064,30 @@ Args:
3049
3064
 
3050
3065
  )doc";
3051
3066
 
3067
+ constexpr char mkd_doc_slp_operator_mul[] =
3068
+ R"doc(Matrix-scalar multiplication operator.
3069
+
3070
+ Args:
3071
+ lhs: Operator left-hand side.
3072
+ rhs: Operator right-hand side.
3073
+
3074
+ Template Args:
3075
+ Scalar: Scalar type.
3076
+
3077
+ )doc";
3078
+
3079
+ constexpr char mkd_doc_slp_operator_mul_2[] =
3080
+ R"doc(Scalar-matrix multiplication operator.
3081
+
3082
+ Args:
3083
+ lhs: Operator left-hand side.
3084
+ rhs: Operator right-hand side.
3085
+
3086
+ Template Args:
3087
+ Scalar: Scalar type.
3088
+
3089
+ )doc";
3090
+
3052
3091
  constexpr char mkd_doc_slp_pow[] =
3053
3092
  R"doc(pow() for Variables.
3054
3093
 
@@ -5,9 +5,11 @@ Fixes up type stubs generated by nanobind's stubgen.
5
5
 
6
6
  stubgen can't express some things the bindings support at runtime:
7
7
 
8
- 1. VariableBlock implicitly converts to VariableMatrix, so every VariableMatrix
9
- parameter also accepts a VariableBlock. Return types and callback arguments
10
- are left alone since those are always VariableMatrix.
8
+ 1. Implicit conversions widen what parameters accept: VariableBlock converts
9
+ to VariableMatrix, and float converts to Variable. Every VariableMatrix
10
+ parameter also accepts a VariableBlock, and every Variable parameter also
11
+ accepts a float. Return types and callback arguments are left alone since
12
+ those are always VariableMatrix or Variable.
11
13
  2. Sparse matrices are annotated as scipy.sparse.csc_matrix[float], but
12
14
  scipy-stubs expects a NumPy numeric scalar type argument.
13
15
  """
@@ -15,6 +17,7 @@ stubgen can't express some things the bindings support at runtime:
15
17
  import argparse
16
18
  import ast
17
19
  import re
20
+ from dataclasses import dataclass
18
21
  from pathlib import Path
19
22
 
20
23
  PREFIX = r"(?:sleipnir\._sleipnir\.autodiff\.)?"
@@ -26,14 +29,53 @@ PREFIX = r"(?:sleipnir\._sleipnir\.autodiff\.)?"
26
29
  # -> x: VariableMatrix | VariableBlock | None
27
30
  VARIABLE_MATRIX = re.compile(
28
31
  rf"""
29
- (?<![\w.]) # Not part of another name
30
- ({PREFIX}) # Optional module prefix
31
- VariableMatrix\b # Type name
32
- (?!\ \|\ {PREFIX}VariableBlock\b) # Not already widened
32
+ (?<![\w.]) # Not part of another name
33
+ ({PREFIX}) # Optional module prefix
34
+ VariableMatrix\b # Type name
35
+ (?!\ \|\ {PREFIX}VariableBlock\b) # Not already widened
33
36
  """,
34
37
  re.VERBOSE,
35
38
  )
36
39
 
40
+ # Variable, optionally module-qualified. The word boundary excludes
41
+ # VariableMatrix and VariableBlock, and the lookahead prevents already-widened
42
+ # annotations from matching again.
43
+ #
44
+ # x: Sequence[Variable]
45
+ # -> x: Sequence[Variable | float]
46
+ VARIABLE = re.compile(
47
+ rf"""
48
+ (?<![\w.]) # Not part of another name
49
+ ({PREFIX}) # Optional module prefix
50
+ Variable\b # Type name
51
+ (?!\ \|\ float\b) # Not already widened
52
+ """,
53
+ re.VERBOSE,
54
+ )
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class Widening:
59
+ """A type that also accepts another type via implicit conversion."""
60
+
61
+ # Matches the narrow type
62
+ pattern: re.Pattern[str]
63
+
64
+ # Replaces the narrow type with the type that converts to it
65
+ source: str
66
+
67
+ # Replaces the narrow type with the widened type
68
+ widened: str
69
+
70
+
71
+ # \1 is "sleipnir._sleipnir.autodiff." prefix or empty
72
+ WIDENINGS = [
73
+ Widening(
74
+ VARIABLE_MATRIX, r"\1VariableBlock", r"\1VariableMatrix | \1VariableBlock"
75
+ ),
76
+ Widening(VARIABLE, "float", r"\1Variable | float"),
77
+ ]
78
+
37
79
 
38
80
  def is_callable(annotation: ast.expr) -> bool:
39
81
  """Returns True if an annotation contains a Callable type."""
@@ -44,6 +86,17 @@ def is_callable(annotation: ast.expr) -> bool:
44
86
  )
45
87
 
46
88
 
89
+ def is_nested(annotation: ast.expr, pattern: re.Pattern[str]) -> bool:
90
+ """
91
+ Returns True if a type matching the pattern appears inside a subscript of
92
+ an annotation (e.g., Variable in Sequence[Variable]).
93
+ """
94
+ return any(
95
+ isinstance(node, ast.Subscript) and pattern.search(ast.unparse(node.slice))
96
+ for node in ast.walk(annotation)
97
+ )
98
+
99
+
47
100
  def parameters(node: ast.FunctionDef) -> list[ast.arg | None]:
48
101
  """Returns a function's parameters in signature order."""
49
102
  args = node.args
@@ -68,11 +121,13 @@ def signature(node: ast.FunctionDef) -> list[str | None]:
68
121
  def widen_signatures(stub: str) -> str:
69
122
  """
70
123
  Widens every VariableMatrix in function parameter annotations to
71
- VariableMatrix | VariableBlock.
124
+ VariableMatrix | VariableBlock, and every Variable to Variable | float.
72
125
 
73
126
  A parameter isn't widened if a sibling overload is identical except it
74
- takes VariableBlock there; widening it would make that overload
75
- unreachable.
127
+ takes the source type there (e.g., float instead of Variable); widening it
128
+ would make that overload unreachable. Types nested in a subscript (e.g.,
129
+ Sequence[Variable]) are always widened, since the sibling overloads don't
130
+ accept containers that mix both types.
76
131
  """
77
132
  # Group overloads by name within each module or class body
78
133
  overload_sets: dict[tuple[int, str], list[ast.FunctionDef]] = {}
@@ -81,25 +136,35 @@ def widen_signatures(stub: str) -> str:
81
136
  if isinstance(child, ast.FunctionDef):
82
137
  overload_sets.setdefault((id(node), child.name), []).append(child)
83
138
 
84
- annotations = []
139
+ # Annotations to widen, and the widenings that apply to each
140
+ annotations: list[tuple[ast.expr, list[Widening]]] = []
85
141
  for overloads in overload_sets.values():
86
142
  signatures = [signature(overload) for overload in overloads]
87
143
  for overload, sig in zip(overloads, signatures):
88
144
  for i, arg in enumerate(parameters(overload)):
89
- # Callbacks receive VariableMatrix, so their annotations are
90
- # left alone
145
+ # Callbacks receive VariableMatrix or Variable, so their
146
+ # annotations are left alone
91
147
  if arg is None or arg.annotation is None or is_callable(arg.annotation):
92
148
  continue
93
149
 
94
- # Skip if a sibling overload already takes VariableBlock here
95
- block_sig = sig.copy()
96
- block_sig[i] = VARIABLE_MATRIX.sub(
97
- r"\1VariableBlock", ast.unparse(arg.annotation)
98
- )
99
- if block_sig != sig and block_sig in signatures:
100
- continue
101
-
102
- annotations.append(arg.annotation)
150
+ widenings = []
151
+ for widening in WIDENINGS:
152
+ # Skip if a sibling overload already takes the source type
153
+ # here, unless the type is nested in a subscript
154
+ source_sig = sig.copy()
155
+ source_sig[i] = widening.pattern.sub(
156
+ widening.source, ast.unparse(arg.annotation)
157
+ )
158
+ if (
159
+ source_sig != sig
160
+ and source_sig in signatures
161
+ and not is_nested(arg.annotation, widening.pattern)
162
+ ):
163
+ continue
164
+
165
+ widenings.append(widening)
166
+
167
+ annotations.append((arg.annotation, widenings))
103
168
 
104
169
  # Encode stub string into UTF-8 bytes
105
170
  source_bytes = stub.encode()
@@ -110,8 +175,10 @@ def widen_signatures(stub: str) -> str:
110
175
  line_byte_offsets.append(line_byte_offsets[-1] + len(line))
111
176
 
112
177
  # Edit back to front so earlier offsets stay valid
113
- for annotation in sorted(
114
- annotations, key=lambda node: (node.lineno, node.col_offset), reverse=True
178
+ for annotation, widenings in sorted(
179
+ annotations,
180
+ key=lambda item: (item[0].lineno, item[0].col_offset),
181
+ reverse=True,
115
182
  ):
116
183
  # Assertions to satisfy mypy. They can't fail in practice because
117
184
  # ast.parse() always sets those fields.
@@ -123,11 +190,9 @@ def widen_signatures(stub: str) -> str:
123
190
  end = line_byte_offsets[annotation.end_lineno - 1] + annotation.end_col_offset
124
191
 
125
192
  # Splice widened type annotations into source_bytes
126
- #
127
- # \1 is "sleipnir._sleipnir.autodiff." prefix or empty
128
- widened = VARIABLE_MATRIX.sub(
129
- r"\1VariableMatrix | \1VariableBlock", source_bytes[start:end].decode()
130
- )
193
+ widened = source_bytes[start:end].decode()
194
+ for widening in widenings:
195
+ widened = widening.pattern.sub(widening.widened, widened)
131
196
  source_bytes = source_bytes[:start] + widened.encode() + source_bytes[end:]
132
197
  return source_bytes.decode()
133
198
 
@@ -2,4 +2,4 @@
2
2
 
3
3
  from ._sleipnir import *
4
4
 
5
- __version__ = "0.6.7.dev128"
5
+ __version__ = "0.6.7.dev130"