sleipnirgroup-jormungandr 0.6.7.dev55__tar.gz → 0.6.7.dev63__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.

Potentially problematic release.


This version of sleipnirgroup-jormungandr might be problematic. Click here for more details.

Files changed (130) hide show
  1. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/CMakeLists.txt +47 -22
  2. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/PKG-INFO +1 -1
  3. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/cmake/Pybind11Mkdoc.cmake +21 -1
  4. sleipnirgroup_jormungandr-0.6.7.dev63/cmake/Pybind11MkdocPostprocess.cmake +12 -0
  5. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/pyproject.toml +27 -0
  6. sleipnirgroup_jormungandr-0.6.7.dev63/python/cpp/arity.hpp +42 -0
  7. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/autodiff/bind_variable_block.cpp +55 -23
  8. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/autodiff/bind_variable_matrix.cpp +63 -52
  9. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/docstrings.hpp +422 -422
  10. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/bind_ocp.cpp +17 -0
  11. sleipnirgroup_jormungandr-0.6.7.dev63/python/cpp/optimization/bind_problem.cpp +216 -0
  12. sleipnirgroup_jormungandr-0.6.7.dev63/python/cpp/slice_tuple.hpp +21 -0
  13. sleipnirgroup_jormungandr-0.6.7.dev63/python/cpp/text_wrap.hpp +84 -0
  14. sleipnirgroup_jormungandr-0.6.7.dev63/python/postprocess_stubs.py +166 -0
  15. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/src/sleipnir/__init__.py +1 -1
  16. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/src/sleipnir/autodiff/__init__.py +1 -3
  17. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/src/sleipnir/optimization/__init__.py +5 -1
  18. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/autodiff/gradient_test.py +20 -20
  19. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/autodiff/hessian_test.py +31 -30
  20. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/autodiff/jacobian_test.py +11 -11
  21. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/autodiff/variable_matrix_test.py +21 -21
  22. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/autodiff/variable_test.py +3 -3
  23. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/arm_on_elevator_problem_test.py +1 -1
  24. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/cart_pole_ocp_test.py +3 -3
  25. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/cart_pole_problem_test.py +2 -2
  26. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/cart_pole_util.py +8 -3
  27. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/constraints_test.py +4 -4
  28. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/decision_variable_test.py +4 -4
  29. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/differential_drive_ocp_test.py +1 -1
  30. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/differential_drive_problem_test.py +2 -2
  31. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/differential_drive_util.py +8 -3
  32. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/double_integrator_problem_test.py +1 -1
  33. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/flywheel_ocp_test.py +5 -5
  34. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/flywheel_problem_test.py +1 -1
  35. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/linear_problem_test.py +2 -2
  36. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/multistart_test.py +5 -3
  37. sleipnirgroup_jormungandr-0.6.7.dev63/python/test/optimization/near.py +2 -0
  38. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/nonlinear_problem_test.py +7 -7
  39. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/problem_spy_test.py +7 -5
  40. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/quadratic_problem_test.py +6 -6
  41. sleipnirgroup_jormungandr-0.6.7.dev63/python/test/optimization/rk4.py +44 -0
  42. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/solver/exit_status_test.py +15 -15
  43. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/test/optimization/trivial_problem_test.py +3 -3
  44. sleipnirgroup_jormungandr-0.6.7.dev55/python/cpp/optimization/bind_problem.cpp +0 -156
  45. sleipnirgroup_jormungandr-0.6.7.dev55/python/test/optimization/near.py +0 -2
  46. sleipnirgroup_jormungandr-0.6.7.dev55/python/test/optimization/rk4.py +0 -18
  47. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/LICENSE.txt +0 -0
  48. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/README.md +0 -0
  49. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/SleipnirConfig.cmake.in +0 -0
  50. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/cmake/BuildTypes.cmake +0 -0
  51. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/cmake/CompilerFlags.cmake +0 -0
  52. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/cmake/SubdirList.cmake +0 -0
  53. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/cmake/arm-none-eabi.cmake +0 -0
  54. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/expression.hpp +0 -0
  55. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/expression_graph.hpp +0 -0
  56. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/expression_type.hpp +0 -0
  57. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/gradient.hpp +0 -0
  58. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/hessian.hpp +0 -0
  59. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/jacobian.hpp +0 -0
  60. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/sleipnir_base.hpp +0 -0
  61. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/slice.hpp +0 -0
  62. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/variable.hpp +0 -0
  63. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/variable_block.hpp +0 -0
  64. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/autodiff/variable_matrix.hpp +0 -0
  65. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/multistart.hpp +0 -0
  66. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/ocp/dynamics_type.hpp +0 -0
  67. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/ocp/timestep_method.hpp +0 -0
  68. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/ocp/transcription_method.hpp +0 -0
  69. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/ocp.hpp +0 -0
  70. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/problem.hpp +0 -0
  71. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/exit_status.hpp +0 -0
  72. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/ipm.hpp +0 -0
  73. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/ipm_matrix_callbacks.hpp +0 -0
  74. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/iteration_info.hpp +0 -0
  75. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/newton.hpp +0 -0
  76. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/newton_matrix_callbacks.hpp +0 -0
  77. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/options.hpp +0 -0
  78. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/sqp.hpp +0 -0
  79. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/sqp_matrix_callbacks.hpp +0 -0
  80. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/all_finite.hpp +0 -0
  81. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/append_as_triplets.hpp +0 -0
  82. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/bounds.hpp +0 -0
  83. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/dense_kkt_solver.hpp +0 -0
  84. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/feasibility_restoration.hpp +0 -0
  85. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/filter.hpp +0 -0
  86. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/fraction_to_the_boundary_rule.hpp +0 -0
  87. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/inertia.hpp +0 -0
  88. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/kkt_error.hpp +0 -0
  89. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/kkt_solver.hpp +0 -0
  90. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/problem_scaling.hpp +0 -0
  91. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/sparse_inf_norms.hpp +0 -0
  92. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/optimization/solver/util/sparse_kkt_solver.hpp +0 -0
  93. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/assert.hpp +0 -0
  94. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/concepts.hpp +0 -0
  95. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/empty.hpp +0 -0
  96. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/function_ref.hpp +0 -0
  97. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/intrusive_shared_ptr.hpp +0 -0
  98. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/pool.hpp +0 -0
  99. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/print.hpp +0 -0
  100. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/print_diagnostics.hpp +0 -0
  101. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/profiler.hpp +0 -0
  102. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/scope_exit.hpp +0 -0
  103. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/spy.hpp +0 -0
  104. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/include/sleipnir/util/symbol_exports.hpp +0 -0
  105. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/autodiff/bind_expression_type.cpp +0 -0
  106. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/autodiff/bind_gradient.cpp +0 -0
  107. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/autodiff/bind_hessian.cpp +0 -0
  108. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/autodiff/bind_jacobian.cpp +0 -0
  109. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/autodiff/bind_variable.cpp +0 -0
  110. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/binders.hpp +0 -0
  111. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/for_each_type.hpp +0 -0
  112. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/main.cpp +0 -0
  113. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/bind_equality_constraints.cpp +0 -0
  114. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/bind_inequality_constraints.cpp +0 -0
  115. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/ocp/bind_dynamics_type.cpp +0 -0
  116. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/ocp/bind_timestep_method.cpp +0 -0
  117. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/ocp/bind_transcription_method.cpp +0 -0
  118. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/solver/bind_exit_status.cpp +0 -0
  119. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/optimization/solver/bind_iteration_info.cpp +0 -0
  120. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/python/cpp/try_cast.hpp +0 -0
  121. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/autodiff/gradient.cpp +0 -0
  122. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/autodiff/hessian.cpp +0 -0
  123. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/autodiff/jacobian.cpp +0 -0
  124. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/autodiff/variable_matrix.cpp +0 -0
  125. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/optimization/ocp.cpp +0 -0
  126. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/optimization/problem.cpp +0 -0
  127. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/optimization/solver/ipm.cpp +0 -0
  128. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/optimization/solver/newton.cpp +0 -0
  129. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/optimization/solver/sqp.cpp +0 -0
  130. {sleipnirgroup_jormungandr-0.6.7.dev55 → sleipnirgroup_jormungandr-0.6.7.dev63}/src/util/pool.cpp +0 -0
@@ -301,7 +301,9 @@ if(SLEIPNIR_BUILD_PYTHON)
301
301
  if(DEFINED PY_BUILD_CMAKE_MODULE_NAME)
302
302
  set(PY_DEST ${PY_BUILD_CMAKE_MODULE_NAME})
303
303
  else()
304
- set(PY_DEST lib/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR})
304
+ set(PY_DEST
305
+ lib/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/sleipnir
306
+ )
305
307
  endif()
306
308
 
307
309
  # nanobind dependency
@@ -343,47 +345,70 @@ if(SLEIPNIR_BUILD_PYTHON)
343
345
  LIBRARY DESTINATION ${PY_DEST}
344
346
  )
345
347
 
348
+ # py-build-cmake copies the pure Python sources into the wheel itself.
349
+ # Install them for plain CMake installs as well.
350
+ if(NOT DEFINED PY_BUILD_CMAKE_MODULE_NAME)
351
+ install(
352
+ DIRECTORY python/src/sleipnir/
353
+ DESTINATION ${PY_DEST}
354
+ COMPONENT python_modules
355
+ FILES_MATCHING
356
+ PATTERN "*.py"
357
+ PATTERN "__pycache__" EXCLUDE
358
+ )
359
+ endif()
360
+
361
+ # Generate stubs at install time because only the install tree has the
362
+ # sleipnir/ package layout needed to import the module by its fully
363
+ # qualified name `sleipnir._sleipnir`.
364
+ #
365
+ # Importing sleipnir._sleipnir requires the directory containing the
366
+ # sleipnir package (i.e., PY_DEST's parent) to be on the Python path. For
367
+ # py-build-cmake builds, PY_DEST has no parent. For plain CMake installs,
368
+ # PY_DEST's parent is lib/pythonX.Y.
369
+ cmake_path(GET PY_DEST PARENT_PATH PY_DEST_PARENT)
346
370
  nanobind_add_stub(
347
371
  _sleipnir_stub
348
372
  INSTALL_TIME
349
- MARKER_FILE sleipnir/py.typed
350
- MODULE _sleipnir
351
- OUTPUT sleipnir/__init__.pyi
352
- PYTHON_PATH $<TARGET_FILE_DIR:_sleipnir>
373
+ MARKER_FILE ${PY_DEST}/py.typed
374
+ MODULE sleipnir._sleipnir
375
+ OUTPUT ${PY_DEST}/_sleipnir/__init__.pyi
376
+ PYTHON_PATH ${PY_DEST_PARENT}
353
377
  DEPENDS _sleipnir
354
378
  COMPONENT python_modules
355
379
  )
356
380
  nanobind_add_stub(
357
381
  _sleipnir_autodiff_stub
358
382
  INSTALL_TIME
359
- MODULE _sleipnir.autodiff
360
- OUTPUT sleipnir/autodiff/__init__.pyi
361
- PYTHON_PATH $<TARGET_FILE_DIR:_sleipnir>
383
+ MODULE sleipnir._sleipnir.autodiff
384
+ OUTPUT ${PY_DEST}/_sleipnir/autodiff.pyi
385
+ PYTHON_PATH ${PY_DEST_PARENT}
362
386
  DEPENDS _sleipnir
363
387
  COMPONENT python_modules
364
388
  )
365
389
  nanobind_add_stub(
366
390
  _sleipnir_optimization_stub
367
391
  INSTALL_TIME
368
- MODULE _sleipnir.optimization
369
- OUTPUT sleipnir/optimization/__init__.pyi
370
- PYTHON_PATH $<TARGET_FILE_DIR:_sleipnir>
392
+ MODULE sleipnir._sleipnir.optimization
393
+ OUTPUT ${PY_DEST}/_sleipnir/optimization.pyi
394
+ PYTHON_PATH ${PY_DEST_PARENT}
371
395
  DEPENDS _sleipnir
372
396
  COMPONENT python_modules
373
397
  )
398
+ install(
399
+ CODE
400
+ "execute_process(
401
+ COMMAND \"${Python_EXECUTABLE}\"
402
+ \"${CMAKE_CURRENT_SOURCE_DIR}/python/postprocess_stubs.py\"
403
+ ${PY_DEST}/_sleipnir/autodiff.pyi
404
+ ${PY_DEST}/_sleipnir/optimization.pyi
405
+ WORKING_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}\"
406
+ COMMAND_ERROR_IS_FATAL ANY
407
+ )"
408
+ COMPONENT python_modules
409
+ )
374
410
 
375
411
  if(NOT CMAKE_CROSSCOMPILING)
376
- # pybind11_mkdoc dependency
377
- FetchContent_Declare(
378
- pybind11_mkdoc
379
- GIT_REPOSITORY https://github.com/pybind/pybind11_mkdoc.git
380
- GIT_TAG v3.0.0
381
- GIT_SHALLOW ON
382
- EXCLUDE_FROM_ALL
383
- SYSTEM
384
- )
385
- FetchContent_MakeAvailable(pybind11_mkdoc)
386
-
387
412
  set(sleipnir_headers
388
413
  ${CMAKE_CURRENT_SOURCE_DIR}/include/sleipnir/autodiff/expression_type.hpp
389
414
  ${CMAKE_CURRENT_SOURCE_DIR}/include/sleipnir/autodiff/gradient.hpp
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sleipnirgroup-jormungandr
3
- Version: 0.6.7.dev55
3
+ Version: 0.6.7.dev63
4
4
  Summary: Reverse mode autodiff library and NLP solver DSL
5
5
  License-Expression: BSD-3-Clause
6
6
  License-File: LICENSE.txt
@@ -1,6 +1,20 @@
1
1
  function(pybind11_mkdoc target headers)
2
2
  find_package(Python3 REQUIRED COMPONENTS Interpreter)
3
3
 
4
+ # Check that pybind11_mkdoc is installed
5
+ execute_process(
6
+ COMMAND ${Python3_EXECUTABLE} -c "import pybind11_mkdoc"
7
+ RESULT_VARIABLE pybind11_mkdoc_result
8
+ OUTPUT_QUIET
9
+ ERROR_QUIET
10
+ )
11
+ if(NOT pybind11_mkdoc_result EQUAL 0)
12
+ message(
13
+ FATAL_ERROR
14
+ "pybind11_mkdoc not found for ${Python3_EXECUTABLE}. Install it with `pip install --group docstrings`."
15
+ )
16
+ endif()
17
+
4
18
  # Target compiler flags
5
19
  get_target_property(target_flags ${target} INCLUDE_DIRECTORIES)
6
20
  list(TRANSFORM target_flags PREPEND "-I")
@@ -60,7 +74,13 @@ function(pybind11_mkdoc target headers)
60
74
  ${CMAKE_CURRENT_SOURCE_DIR}/python/cpp/docstrings.hpp
61
75
  ${target_flags} ${clang_flags} ${eigen_flags} ${small_vector_flags}
62
76
  -std=c++23
63
- DEPENDS ${headers}
77
+ COMMAND
78
+ ${CMAKE_COMMAND}
79
+ -DFILE=${CMAKE_CURRENT_SOURCE_DIR}/python/cpp/docstrings.hpp -P
80
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Pybind11MkdocPostprocess.cmake
81
+ DEPENDS
82
+ ${headers}
83
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Pybind11MkdocPostprocess.cmake
64
84
  )
65
85
 
66
86
  # Add docstrings target
@@ -0,0 +1,12 @@
1
+ # Replaces pybind11_mkdoc's docstring pointers with constexpr arrays
2
+ #
3
+ # Usage: cmake -DFILE=<docstrings.hpp> -P Pybind11MkdocPostprocess.cmake
4
+
5
+ file(READ ${FILE} contents)
6
+ string(
7
+ REGEX REPLACE "\nstatic const char \\*([A-Za-z0-9_]+) ="
8
+ "\nconstexpr char \\1[] ="
9
+ contents
10
+ "${contents}"
11
+ )
12
+ file(WRITE ${FILE} "${contents}")
@@ -21,8 +21,11 @@ build-backend = "py_build_cmake.build"
21
21
 
22
22
  [dependency-groups]
23
23
  dev = [
24
+ "mypy>=2.4.0",
24
25
  "pytest>=9.1.1",
26
+ "scipy-stubs",
25
27
  ]
28
+ docstrings = ["pybind11-mkdoc~=3.0.0"]
26
29
 
27
30
  [tool.py-build-cmake.cmake]
28
31
  build_type = "Release"
@@ -54,8 +57,29 @@ exclude = []
54
57
  python_abi = "abi3"
55
58
  abi3_minimum_cpython_version = 312
56
59
 
60
+ [tool.mypy]
61
+ files = [
62
+ "benchmarks",
63
+ "docs/generate_website.py",
64
+ "examples",
65
+ "python/postprocess_stubs.py",
66
+ "python/test",
67
+ "tools",
68
+ ]
69
+ allow_redefinition_new = true
70
+ disallow_incomplete_defs = true
71
+ disallow_untyped_defs = true
72
+ explicit_package_bases = true
73
+ local_partial_types = true
74
+ mypy_path = ["examples/current_manager", "python/test/optimization"]
75
+
76
+ [[tool.mypy.overrides]]
77
+ module = "mpl_toolkits.*"
78
+ ignore_missing_imports = true
79
+
57
80
  [tool.pytest.ini_options]
58
81
  minversion = "6.0"
82
+ pythonpath = ["examples/current_manager"]
59
83
  testpaths = ["python/test", "examples/current_manager/test"]
60
84
 
61
85
  [tool.uv]
@@ -66,8 +90,11 @@ cache-keys = [
66
90
  { file = "include/**" },
67
91
  { file = "pyproject.toml" },
68
92
  { file = "python/cpp/**/*.cpp" },
93
+ { file = "python/cpp/arity.hpp" },
69
94
  { file = "python/cpp/binders.hpp" },
70
95
  { file = "python/cpp/for_each_type.hpp" },
96
+ { file = "python/cpp/slice_tuple.hpp" },
97
+ { file = "python/cpp/text_wrap.hpp" },
71
98
  { file = "python/cpp/try_cast.hpp" },
72
99
  { file = "python/src/**" },
73
100
  { file = "src/**" },
@@ -0,0 +1,42 @@
1
+ // Copyright (c) Sleipnir contributors
2
+
3
+ #pragma once
4
+
5
+ #include <cstddef>
6
+ #include <type_traits>
7
+
8
+ namespace slp {
9
+
10
+ /// Type implicitly convertible to any type. Used for counting aggregate
11
+ /// members.
12
+ struct AnyType {
13
+ template <typename T>
14
+ // NOLINTNEXTLINE (google-explicit-constructor)
15
+ operator T() const;
16
+ };
17
+
18
+ /// Returns the number of members in aggregate type T.
19
+ ///
20
+ /// @tparam T Aggregate type.
21
+ /// @tparam Args Initializers for the members counted so far.
22
+ template <typename T, typename... Args>
23
+ requires std::is_aggregate_v<T>
24
+ consteval size_t member_count() {
25
+ if constexpr (requires { T{Args{}..., AnyType{}}; }) {
26
+ return member_count<T, Args..., AnyType>();
27
+ } else {
28
+ return sizeof...(Args);
29
+ }
30
+ }
31
+
32
+ /// Returns the number of parameters of a lambda.
33
+ ///
34
+ /// @tparam F Lambda type.
35
+ template <typename F>
36
+ consteval size_t lambda_param_count() {
37
+ return []<typename R, typename C, typename... Args>(R (C::*)(Args...) const) {
38
+ return sizeof...(Args);
39
+ }(&F::operator());
40
+ }
41
+
42
+ } // namespace slp
@@ -6,6 +6,7 @@
6
6
  #include <nanobind/operators.h>
7
7
  #include <nanobind/stl/function.h>
8
8
  #include <nanobind/stl/string.h>
9
+ #include <nanobind/stl/tuple.h>
9
10
  #include <nanobind/stl/vector.h>
10
11
 
11
12
  #include <stdint.h>
@@ -15,6 +16,7 @@
15
16
  #include <functional>
16
17
  #include <stdexcept>
17
18
  #include <string>
19
+ #include <tuple>
18
20
 
19
21
  #include <Eigen/Core>
20
22
  #include <sleipnir/autodiff/slice.hpp>
@@ -25,6 +27,7 @@
25
27
 
26
28
  #include "docstrings.hpp"
27
29
  #include "for_each_type.hpp"
30
+ #include "slice_tuple.hpp"
28
31
  #include "try_cast.hpp"
29
32
 
30
33
  namespace nb = nanobind;
@@ -68,7 +71,7 @@ void bind_variable_block(
68
71
  "row"_a, "value"_a);
69
72
  cls.def(
70
73
  "__setitem__",
71
- [](VariableBlock<VariableMatrix<double>>& self, nb::tuple slices,
74
+ [](VariableBlock<VariableMatrix<double>>& self, SliceTuple slices,
72
75
  nb::object value) {
73
76
  if (slices.size() != 2) {
74
77
  throw nb::index_error(
@@ -151,31 +154,32 @@ void bind_variable_block(
151
154
  cls.def(
152
155
  "__getitem__",
153
156
  [](VariableBlock<VariableMatrix<double>>& self,
154
- nb::tuple slices) -> nb::object {
157
+ std::tuple<int, int> slices) -> Variable<double>& {
158
+ auto [row, col] = slices;
159
+
160
+ if (row >= self.rows() || col >= self.cols()) {
161
+ throw std::out_of_range("Index out of bounds");
162
+ }
163
+
164
+ if (row < 0) {
165
+ row += self.rows();
166
+ }
167
+ if (col < 0) {
168
+ col += self.cols();
169
+ }
170
+ return self[row, col];
171
+ },
172
+ nb::rv_policy::reference_internal, "slices"_a,
173
+ DOC(slp, VariableBlock, operator, array));
174
+ cls.def(
175
+ "__getitem__",
176
+ [](VariableBlock<VariableMatrix<double>>& self,
177
+ SliceTuple slices) -> VariableBlock<VariableMatrix<double>> {
155
178
  if (slices.size() != 2) {
156
179
  throw nb::index_error(
157
180
  std::format("Expected 2 slices, got {}.", slices.size()).c_str());
158
181
  }
159
182
 
160
- // If both indices are integers instead of slices, return Variable
161
- // instead of VariableBlock
162
- if (nb::isinstance<int>(slices[0]) && nb::isinstance<int>(slices[1])) {
163
- int row = nb::cast<int>(slices[0]);
164
- int col = nb::cast<int>(slices[1]);
165
-
166
- if (row >= self.rows() || col >= self.cols()) {
167
- throw std::out_of_range("Index out of bounds");
168
- }
169
-
170
- if (row < 0) {
171
- row += self.rows();
172
- }
173
- if (col < 0) {
174
- col += self.cols();
175
- }
176
- return nb::cast(self[row, col]);
177
- }
178
-
179
183
  Slice row_slice;
180
184
  int row_slice_length;
181
185
  Slice col_slice;
@@ -211,8 +215,7 @@ void bind_variable_block(
211
215
  col_slice_length = 1;
212
216
  }
213
217
 
214
- return nb::cast(
215
- self[row_slice, row_slice_length, col_slice, col_slice_length]);
218
+ return self[row_slice, row_slice_length, col_slice, col_slice_length];
216
219
  },
217
220
  nb::keep_alive<0, 1>(), DOC(slp, VariableBlock, operator, array),
218
221
  "slices"_a);
@@ -223,6 +226,31 @@ void bind_variable_block(
223
226
  nb::overload_cast<int>(&VariableBlock<VariableMatrix<double>>::col),
224
227
  "col"_a, DOC(slp, VariableBlock, col));
225
228
 
229
+ // Matrix-matrix multiplication. Products with a VariableMatrix on the left
230
+ // are bound on VariableMatrix.
231
+ for (const char* name : {"__mul__", "__matmul__"}) {
232
+ cls.def(
233
+ name,
234
+ [](const VariableBlock<VariableMatrix<double>>& lhs,
235
+ const VariableBlock<VariableMatrix<double>>& rhs) {
236
+ return lhs * rhs;
237
+ },
238
+ nb::is_operator(), "rhs"_a);
239
+ }
240
+
241
+ // Matrix multiplication with NumPy arrays. These are also handled by
242
+ // __array_ufunc__ below, but type checkers only see these overloads.
243
+ cls.def(
244
+ "__matmul__",
245
+ [](const VariableBlock<VariableMatrix<double>>& lhs,
246
+ nb::DRef<Eigen::MatrixXd> rhs) { return lhs * rhs; },
247
+ nb::is_operator(), "rhs"_a);
248
+ cls.def(
249
+ "__rmatmul__",
250
+ [](const VariableBlock<VariableMatrix<double>>& rhs,
251
+ nb::DRef<Eigen::MatrixXd> lhs) { return lhs * rhs; },
252
+ nb::is_operator(), "lhs"_a);
253
+
226
254
  // https://numpy.org/doc/stable/user/basics.dispatch.html
227
255
  cls.def(
228
256
  "__array_ufunc__",
@@ -302,6 +330,10 @@ void bind_variable_block(
302
330
 
303
331
  return nb::not_implemented();
304
332
  },
333
+ // nanobind can't annotate nb::args or nb::kwargs, so the stub needs an
334
+ // explicit signature
335
+ nb::sig("def __array_ufunc__(self, ufunc: object, method: str, "
336
+ "*inputs: object, **kwargs: object) -> object"),
305
337
  "ufunc"_a, "method"_a, "inputs"_a, "kwargs"_a);
306
338
 
307
339
  cls.def(nb::self + nb::self, "rhs"_a);
@@ -6,6 +6,7 @@
6
6
  #include <nanobind/operators.h>
7
7
  #include <nanobind/stl/function.h>
8
8
  #include <nanobind/stl/string.h>
9
+ #include <nanobind/stl/tuple.h>
9
10
  #include <nanobind/stl/vector.h>
10
11
 
11
12
  #include <stdint.h>
@@ -15,6 +16,7 @@
15
16
  #include <functional>
16
17
  #include <stdexcept>
17
18
  #include <string>
19
+ #include <tuple>
18
20
  #include <vector>
19
21
 
20
22
  #include <Eigen/Core>
@@ -26,6 +28,7 @@
26
28
 
27
29
  #include "docstrings.hpp"
28
30
  #include "for_each_type.hpp"
31
+ #include "slice_tuple.hpp"
29
32
  #include "try_cast.hpp"
30
33
 
31
34
  namespace nb = nanobind;
@@ -90,7 +93,7 @@ void bind_variable_matrix(nb::module_& autodiff,
90
93
  "row"_a, "value"_a);
91
94
  cls.def(
92
95
  "__setitem__",
93
- [](VariableMatrix<double>& self, nb::tuple slices, nb::object value) {
96
+ [](VariableMatrix<double>& self, SliceTuple slices, nb::object value) {
94
97
  if (slices.size() != 2) {
95
98
  throw nb::index_error(
96
99
  std::format("Expected 2 slices, got {}.", slices.size()).c_str());
@@ -170,31 +173,33 @@ void bind_variable_matrix(nb::module_& autodiff,
170
173
  DOC(slp, VariableMatrix, operator, array, 3));
171
174
  cls.def(
172
175
  "__getitem__",
173
- [](VariableMatrix<double>& self, nb::tuple slices) -> nb::object {
176
+ [](VariableMatrix<double>& self,
177
+ std::tuple<int, int> slices) -> Variable<double>& {
178
+ auto [row, col] = slices;
179
+
180
+ if (row >= self.rows() || col >= self.cols()) {
181
+ throw std::out_of_range("Index out of bounds");
182
+ }
183
+
184
+ if (row < 0) {
185
+ row += self.rows();
186
+ }
187
+ if (col < 0) {
188
+ col += self.cols();
189
+ }
190
+ return self[row, col];
191
+ },
192
+ nb::rv_policy::reference_internal, "slices"_a,
193
+ DOC(slp, VariableMatrix, operator, array));
194
+ cls.def(
195
+ "__getitem__",
196
+ [](VariableMatrix<double>& self,
197
+ SliceTuple slices) -> VariableBlock<VariableMatrix<double>> {
174
198
  if (slices.size() != 2) {
175
199
  throw nb::index_error(
176
200
  std::format("Expected 2 slices, got {}.", slices.size()).c_str());
177
201
  }
178
202
 
179
- // If both indices are integers instead of slices, return Variable
180
- // instead of VariableBlock
181
- if (nb::isinstance<int>(slices[0]) && nb::isinstance<int>(slices[1])) {
182
- int row = nb::cast<int>(slices[0]);
183
- int col = nb::cast<int>(slices[1]);
184
-
185
- if (row >= self.rows() || col >= self.cols()) {
186
- throw std::out_of_range("Index out of bounds");
187
- }
188
-
189
- if (row < 0) {
190
- row += self.rows();
191
- }
192
- if (col < 0) {
193
- col += self.cols();
194
- }
195
- return nb::cast(self[row, col]);
196
- }
197
-
198
203
  Slice row_slice;
199
204
  int row_slice_length;
200
205
  Slice col_slice;
@@ -227,8 +232,7 @@ void bind_variable_matrix(nb::module_& autodiff,
227
232
  col_slice_length = 1;
228
233
  }
229
234
 
230
- return nb::cast(
231
- self[row_slice, row_slice_length, col_slice, col_slice_length]);
235
+ return self[row_slice, row_slice_length, col_slice, col_slice_length];
232
236
  },
233
237
  nb::keep_alive<0, 1>(), "slices"_a,
234
238
  DOC(slp, VariableMatrix, operator, array));
@@ -237,43 +241,46 @@ void bind_variable_matrix(nb::module_& autodiff,
237
241
  cls.def("col", nb::overload_cast<int>(&VariableMatrix<double>::col), "col"_a,
238
242
  DOC(slp, VariableMatrix, col));
239
243
 
240
- // Matrix-matrix multiplication
241
- cls.def(
242
- "__mul__",
243
- [](const VariableMatrix<double>& lhs, const VariableMatrix<double>& rhs) {
244
- return lhs * rhs;
245
- },
246
- nb::is_operator(), "rhs"_a);
244
+ // Matrix-matrix multiplication. Products with a VariableBlock on the left are
245
+ // bound on VariableBlock.
246
+ for (const char* name : {"__mul__", "__matmul__"}) {
247
+ cls.def(
248
+ name,
249
+ [](const VariableMatrix<double>& lhs,
250
+ const VariableMatrix<double>& rhs) { return lhs * rhs; },
251
+ nb::is_operator(), "rhs"_a);
252
+ cls.def(
253
+ name,
254
+ [](const VariableMatrix<double>& lhs,
255
+ const VariableBlock<VariableMatrix<double>>& rhs) {
256
+ return lhs * rhs;
257
+ },
258
+ nb::is_operator(), "rhs"_a);
259
+ }
260
+ for (const char* name : {"__rmul__", "__rmatmul__"}) {
261
+ cls.def(
262
+ name,
263
+ [](const VariableMatrix<double>& rhs,
264
+ const VariableBlock<VariableMatrix<double>>& lhs) {
265
+ return lhs * rhs;
266
+ },
267
+ nb::is_operator(), "lhs"_a);
268
+ }
269
+
270
+ // Matrix multiplication with NumPy arrays. These are also handled by
271
+ // __array_ufunc__ below, but type checkers only see these overloads.
247
272
  cls.def(
248
- "__mul__",
249
- [](const VariableMatrix<double>& lhs,
250
- const VariableBlock<VariableMatrix<double>>& rhs) {
273
+ "__matmul__",
274
+ [](const VariableMatrix<double>& lhs, nb::DRef<Eigen::MatrixXd> rhs) {
251
275
  return lhs * rhs;
252
276
  },
253
277
  nb::is_operator(), "rhs"_a);
254
278
  cls.def(
255
- "__rmul__",
256
- [](const VariableMatrix<double>& rhs,
257
- const VariableBlock<VariableMatrix<double>>& lhs) {
279
+ "__rmatmul__",
280
+ [](const VariableMatrix<double>& rhs, nb::DRef<Eigen::MatrixXd> lhs) {
258
281
  return lhs * rhs;
259
282
  },
260
283
  nb::is_operator(), "lhs"_a);
261
- cls.def(
262
- "__mul__",
263
- [](const VariableBlock<VariableMatrix<double>>& lhs,
264
- const VariableBlock<VariableMatrix<double>>& rhs) {
265
- return lhs * rhs;
266
- },
267
- nb::is_operator(), "rhs"_a);
268
- for_each_type<VariableMatrix<double>, VariableBlock<VariableMatrix<double>>>(
269
- [&]<typename L> {
270
- for_each_type<VariableMatrix<double>,
271
- VariableBlock<VariableMatrix<double>>>([&]<typename R> {
272
- cls.def(
273
- "__matmul__", [](L&& lhs, R&& rhs) { return lhs * rhs; },
274
- nb::is_operator(), "rhs"_a);
275
- });
276
- });
277
284
 
278
285
  // https://numpy.org/doc/stable/user/basics.dispatch.html
279
286
  cls.def(
@@ -354,6 +361,10 @@ void bind_variable_matrix(nb::module_& autodiff,
354
361
 
355
362
  return nb::not_implemented();
356
363
  },
364
+ // nanobind can't annotate nb::args or nb::kwargs, so the stub needs an
365
+ // explicit signature
366
+ nb::sig("def __array_ufunc__(self, ufunc: object, method: str, "
367
+ "*inputs: object, **kwargs: object) -> object"),
357
368
  "ufunc"_a, "method"_a, "inputs"_a, "kwargs"_a);
358
369
 
359
370
  cls.def(nb::self + nb::self, "rhs"_a);