scikit-robot 0.4.1__tar.gz → 0.4.2__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 (221) hide show
  1. {scikit_robot-0.4.1/scikit_robot.egg-info → scikit_robot-0.4.2}/PKG-INFO +1 -1
  2. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/pyproject.toml +1 -1
  3. {scikit_robot-0.4.1 → scikit_robot-0.4.2/scikit_robot.egg-info}/PKG-INFO +1 -1
  4. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/scikit_robot.egg-info/SOURCES.txt +3 -0
  5. scikit_robot-0.4.2/skrobot/backend/math_utils.py +78 -0
  6. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/coordinates/base.py +33 -17
  7. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/kinematics/__init__.py +16 -0
  8. scikit_robot-0.4.2/skrobot/kinematics/_base_placement_jax.py +268 -0
  9. scikit_robot-0.4.2/skrobot/kinematics/base_placement.py +1340 -0
  10. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/kinematics/differentiable.py +63 -60
  11. scikit_robot-0.4.2/skrobot/kinematics/inverse_reachability_map.py +422 -0
  12. scikit_robot-0.4.1/skrobot/backend/math_utils.py +0 -74
  13. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/LICENSE +0 -0
  14. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/MANIFEST.in +0 -0
  15. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/README.md +0 -0
  16. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/scikit_robot.egg-info/dependency_links.txt +0 -0
  17. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/scikit_robot.egg-info/entry_points.txt +0 -0
  18. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/scikit_robot.egg-info/not-zip-safe +0 -0
  19. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/scikit_robot.egg-info/requires.txt +0 -0
  20. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/scikit_robot.egg-info/top_level.txt +0 -0
  21. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/setup.cfg +0 -0
  22. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/__init__.py +0 -0
  23. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/_lazy_imports.py +0 -0
  24. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/__init__.py +0 -0
  25. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/canonicalize_urdf.py +0 -0
  26. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/change_urdf_root.py +0 -0
  27. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/cli.py +0 -0
  28. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/convert_urdf_mesh.py +0 -0
  29. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/convert_urdf_to_mjcf.py +0 -0
  30. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/convert_urdf_to_primitives.py +0 -0
  31. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/convert_wheel_collision.py +0 -0
  32. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/extract_sub_urdf.py +0 -0
  33. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/generate_robot_class.py +0 -0
  34. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/modularize_urdf.py +0 -0
  35. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/scale_urdf.py +0 -0
  36. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/transform_urdf.py +0 -0
  37. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/urdf_hash.py +0 -0
  38. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/urdf_tree.py +0 -0
  39. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/visualize_mesh.py +0 -0
  40. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/apps/visualize_urdf.py +0 -0
  41. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/assembly/__init__.py +0 -0
  42. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/assembly/module_assembly.py +0 -0
  43. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/assembly/module_registry.py +0 -0
  44. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/backend/__init__.py +0 -0
  45. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/backend/jax_backend.py +0 -0
  46. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/backend/numpy_backend.py +0 -0
  47. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/backend/registry.py +0 -0
  48. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/collision/__init__.py +0 -0
  49. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/collision/distance.py +0 -0
  50. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/collision/geometry.py +0 -0
  51. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/collision/robot_collision.py +0 -0
  52. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/collision/self_collision.py +0 -0
  53. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/coordinates/__init__.py +0 -0
  54. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/coordinates/geo.py +0 -0
  55. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/coordinates/math.py +0 -0
  56. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/__init__.py +0 -0
  57. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/kuka.urdf +0 -0
  58. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/finger_base_left.stl +0 -0
  59. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/finger_base_right.stl +0 -0
  60. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/finger_tip_left.stl +0 -0
  61. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/finger_tip_right.stl +0 -0
  62. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_0.mtl +0 -0
  63. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_0.obj +0 -0
  64. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_0.stl +0 -0
  65. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_1.mtl +0 -0
  66. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_1.obj +0 -0
  67. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_1.stl +0 -0
  68. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_2.mtl +0 -0
  69. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_2.obj +0 -0
  70. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_2.stl +0 -0
  71. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_3.mtl +0 -0
  72. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_3.obj +0 -0
  73. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_3.stl +0 -0
  74. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_4.mtl +0 -0
  75. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_4.obj +0 -0
  76. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_4.stl +0 -0
  77. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_5.mtl +0 -0
  78. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_5.obj +0 -0
  79. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_5.stl +0 -0
  80. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_6.mtl +0 -0
  81. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_6.obj +0 -0
  82. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_6.stl +0 -0
  83. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_7.mtl +0 -0
  84. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_7.obj +0 -0
  85. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/kuka_description/meshes/link_7.stl +0 -0
  86. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/robot_descriptions/urdf/r8_6.urdf +0 -0
  87. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/CMakeLists.txt.ros2.template +0 -0
  88. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/gazebo.launch.py.template +0 -0
  89. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/gazebo_moveit.launch.py.template +0 -0
  90. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/isaac_fjt_server.py.template +0 -0
  91. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/moveit.rviz.template +0 -0
  92. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/package.xml.ros2.template +0 -0
  93. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/ros2_control.xacro.joint.template +0 -0
  94. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/ros2_control.xacro.template +0 -0
  95. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/data/ros_config_templates/setup_assistant.template +0 -0
  96. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/dynamics/__init__.py +0 -0
  97. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/dynamics/differentiable.py +0 -0
  98. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/dynamics/gravity.py +0 -0
  99. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/export/__init__.py +0 -0
  100. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/export/contact_links.py +0 -0
  101. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/export/isaac/__init__.py +0 -0
  102. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/export/isaac/fjt_server.py +0 -0
  103. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/export/task.py +0 -0
  104. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/export/usd.py +0 -0
  105. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/__init__.py +0 -0
  106. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/_pybullet.py +0 -0
  107. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/__init__.py +0 -0
  108. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/base.py +0 -0
  109. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/move_base.py +0 -0
  110. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/nextage.py +0 -0
  111. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/panda.py +0 -0
  112. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/pr2.py +0 -0
  113. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/tf_utils.py +0 -0
  114. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros/transform_listener.py +0 -0
  115. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros2/__init__.py +0 -0
  116. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros2/base.py +0 -0
  117. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros2/gripper.py +0 -0
  118. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/interfaces/ros2/panda.py +0 -0
  119. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/kinematics/loop_closure.py +0 -0
  120. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/kinematics/reachability_map.py +0 -0
  121. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/model/__init__.py +0 -0
  122. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/model/joint.py +0 -0
  123. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/model/joint_limit_table.py +0 -0
  124. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/model/link.py +0 -0
  125. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/model/primitives.py +0 -0
  126. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/model/robot_model.py +0 -0
  127. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/model/skeleton.py +0 -0
  128. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/__init__.py +0 -0
  129. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/aero.py +0 -0
  130. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/differential_wrist_sample.py +0 -0
  131. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/fetch.py +0 -0
  132. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/g1.py +0 -0
  133. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/griphis.py +0 -0
  134. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/hydrus.py +0 -0
  135. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/jaxon_jvrc.py +0 -0
  136. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/jedy.py +0 -0
  137. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/kuka.py +0 -0
  138. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/nextage.py +0 -0
  139. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/panda.py +0 -0
  140. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/pr2.py +0 -0
  141. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/r8_6.py +0 -0
  142. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/tycoon.py +0 -0
  143. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/models/urdf.py +0 -0
  144. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/__init__.py +0 -0
  145. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/collision_checker.py +0 -0
  146. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/inverse_kinematics_optimization.py +0 -0
  147. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/sqp_based.py +0 -0
  148. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/swept_sphere.py +0 -0
  149. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/__init__.py +0 -0
  150. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/collision.py +0 -0
  151. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/fk_utils.py +0 -0
  152. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/gridsdf_collision.py +0 -0
  153. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/problem.py +0 -0
  154. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/residuals.py +0 -0
  155. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/solvers/__init__.py +0 -0
  156. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/solvers/augmented_lagrangian.py +0 -0
  157. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/solvers/base.py +0 -0
  158. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/solvers/gradient_descent.py +0 -0
  159. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/solvers/jaxls_solver.py +0 -0
  160. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/solvers/scipy_solver.py +0 -0
  161. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/solvers/solver_utils.py +0 -0
  162. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/trajectory.py +0 -0
  163. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/trajectory_optimization/world_surface_collision.py +0 -0
  164. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/planner/utils.py +0 -0
  165. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/pycompat.py +0 -0
  166. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/sdf/__init__.py +0 -0
  167. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/sdf/signed_distance_function.py +0 -0
  168. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/__init__.py +0 -0
  169. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/aggregate.py +0 -0
  170. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/canonicalize.py +0 -0
  171. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/compare.py +0 -0
  172. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/extract_sub_urdf.py +0 -0
  173. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/flip_axis.py +0 -0
  174. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/hash.py +0 -0
  175. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/link_origins.py +0 -0
  176. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/llm_grouping.py +0 -0
  177. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/merge_fixed_links.py +0 -0
  178. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/modularize_urdf.py +0 -0
  179. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/primitives_converter.py +0 -0
  180. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/robot_class_generator.py +0 -0
  181. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_config/__init__.py +0 -0
  182. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_config/export.py +0 -0
  183. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_config/gazebo_generator.py +0 -0
  184. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_config/moveit_generator.py +0 -0
  185. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_config/moveit_package.py +0 -0
  186. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_config/urdf_parser.py +0 -0
  187. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_package.py +0 -0
  188. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/ros_package_exporter.py +0 -0
  189. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/sanitize.py +0 -0
  190. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/scale_urdf.py +0 -0
  191. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/structure.py +0 -0
  192. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/transform_urdf.py +0 -0
  193. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/wheel_collision_converter.py +0 -0
  194. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/urdf/xml_root_link_changer.py +0 -0
  195. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/__init__.py +0 -0
  196. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/_blender_decimate_core.py +0 -0
  197. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/_blender_remesh_core.py +0 -0
  198. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/archive.py +0 -0
  199. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/blender_mesh.py +0 -0
  200. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/checksum.py +0 -0
  201. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/convex_decomposition.py +0 -0
  202. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/draco.py +0 -0
  203. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/inertia.py +0 -0
  204. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/listify.py +0 -0
  205. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/mesh.py +0 -0
  206. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/mjcf_converter.py +0 -0
  207. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/package.py +0 -0
  208. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/primitive_fitting.py +0 -0
  209. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/urdf.py +0 -0
  210. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/urdf_mesh.py +0 -0
  211. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/video.py +0 -0
  212. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/utils/visualization.py +0 -0
  213. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/__init__.py +0 -0
  214. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_base.py +0 -0
  215. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_manipulability_ellipse.py +0 -0
  216. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_mitsuba.py +0 -0
  217. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_notebook.py +0 -0
  218. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_path_utils.py +0 -0
  219. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_pyrender.py +0 -0
  220. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_trimesh.py +0 -0
  221. {scikit_robot-0.4.1 → scikit_robot-0.4.2}/skrobot/viewers/_viser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scikit-robot
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: A Flexible Framework for Robot Control in Python
5
5
  Author-email: iory <ab.ioryz@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "scikit-robot"
7
- version = "0.4.1"
7
+ version = "0.4.2"
8
8
  description = "A Flexible Framework for Robot Control in Python"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scikit-robot
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: A Flexible Framework for Robot Control in Python
5
5
  Author-email: iory <ab.ioryz@gmail.com>
6
6
  License: MIT
@@ -110,7 +110,10 @@ skrobot/interfaces/ros2/base.py
110
110
  skrobot/interfaces/ros2/gripper.py
111
111
  skrobot/interfaces/ros2/panda.py
112
112
  skrobot/kinematics/__init__.py
113
+ skrobot/kinematics/_base_placement_jax.py
114
+ skrobot/kinematics/base_placement.py
113
115
  skrobot/kinematics/differentiable.py
116
+ skrobot/kinematics/inverse_reachability_map.py
114
117
  skrobot/kinematics/loop_closure.py
115
118
  skrobot/kinematics/reachability_map.py
116
119
  skrobot/model/__init__.py
@@ -0,0 +1,78 @@
1
+ """Backend-agnostic math utilities for differentiable computation.
2
+
3
+ This module provides common mathematical operations that work with
4
+ any backend (NumPy, JAX) for use in kinematics and dynamics computations.
5
+ """
6
+
7
+ import numpy as np
8
+
9
+
10
+ # _CROSS[i, j, k] = -epsilon_ijk, so _CROSS @ v is the cross-product
11
+ # matrix of v. One matmul builds it for a single vector or a batch; nested
12
+ # stacks would cost several times as much per call on the NumPy FK path.
13
+ _CROSS = np.zeros((3, 3, 3))
14
+ for _i, _j, _k in ((0, 1, 2), (1, 2, 0), (2, 0, 1)):
15
+ _CROSS[_i, _j, _k] = -1.0
16
+ _CROSS[_i, _k, _j] = 1.0
17
+
18
+
19
+ def rodrigues_rotation(backend, axis, angle):
20
+ """Compute rotation matrix from axis-angle using Rodrigues' formula.
21
+
22
+ R = I + sin(θ)K + (1-cos(θ))K²
23
+
24
+ where K is the skew-symmetric matrix of the normalized axis.
25
+
26
+ Parameters
27
+ ----------
28
+ backend : DifferentiableBackend or module
29
+ Backend to use for computation (numpy or jax). The ``numpy`` and
30
+ ``jax.numpy`` modules work as well.
31
+ axis : array, shape (3,) or (..., 3)
32
+ Rotation axis (will be normalized), or a batch of them.
33
+ angle : float or array, shape () or (...)
34
+ Rotation angle in radians, one per axis.
35
+
36
+ Returns
37
+ -------
38
+ rotation : array, shape (3, 3) or (..., 3, 3)
39
+ Rotation matrix, or one per axis.
40
+
41
+ Examples
42
+ --------
43
+ >>> from skrobot.backend import get_backend
44
+ >>> from skrobot.backend.math_utils import rodrigues_rotation
45
+ >>> backend = get_backend('numpy')
46
+ >>> axis = backend.array([0.0, 0.0, 1.0])
47
+ >>> R = rodrigues_rotation(backend, axis, 0.5)
48
+ """
49
+ # Normalize axis
50
+ axis = axis / (backend.sqrt((axis ** 2).sum(axis=-1, keepdims=True))
51
+ + 1e-10)
52
+ K = skew_symmetric(backend, axis)
53
+
54
+ # Rodrigues formula
55
+ sin = backend.sin(angle)[..., None, None]
56
+ cos = backend.cos(angle)[..., None, None]
57
+ return backend.eye(3) + sin * K + (1.0 - cos) * (K @ K)
58
+
59
+
60
+ def skew_symmetric(backend, v):
61
+ """Create skew-symmetric matrix from a 3D vector.
62
+
63
+ The skew-symmetric matrix [v]_× satisfies: [v]_× @ u = v × u
64
+
65
+ Parameters
66
+ ----------
67
+ backend : DifferentiableBackend or module
68
+ Backend to use for computation. The ``numpy`` and ``jax.numpy``
69
+ modules work as well.
70
+ v : array, shape (3,) or (..., 3)
71
+ Input vector, or a batch of them.
72
+
73
+ Returns
74
+ -------
75
+ K : array, shape (3, 3) or (..., 3, 3)
76
+ Skew-symmetric matrix, or one per vector.
77
+ """
78
+ return (_CROSS @ v[..., None, :, None])[..., 0]
@@ -1794,6 +1794,7 @@ class CascadedCoords(Coordinates):
1794
1794
  "`relative_coords`'s type should be"
1795
1795
  "skrobot.coordinates.Coordinates, but is {}"
1796
1796
  .format(type(relative_coords)))
1797
+ # The parent setter removes child from its previous parent.
1797
1798
  child.parent = self
1798
1799
  child.newcoords(relative_coords, check_validity=False, relative_coords='local')
1799
1800
  self._descendants.append(child)
@@ -1997,7 +1998,8 @@ class CascadedCoords(Coordinates):
1997
1998
  """Rotate this coordinate.
1998
1999
 
1999
2000
  Rotate this coordinate relative to axis by theta radians
2000
- with respect to wrt.
2001
+ with respect to wrt. The origin of this coordinate is kept for
2002
+ every ``wrt``; only its orientation changes.
2001
2003
 
2002
2004
  Parameters
2003
2005
  ----------
@@ -2006,6 +2008,13 @@ class CascadedCoords(Coordinates):
2006
2008
  axis : str or numpy.ndarray
2007
2009
  'x', 'y', 'z' or vector
2008
2010
  wrt : str or Coordinates
2011
+ Frame in which ``axis`` is expressed.
2012
+
2013
+ - ``'local'`` or ``self``: this coordinate's own axes.
2014
+ - ``'parent'`` or the parent object: the parent's axes. Without
2015
+ a parent, this is the world frame.
2016
+ - ``'world'``: the world axes.
2017
+ - other ``Coordinates``: that coordinate's axes.
2009
2018
  skip_normalization : bool
2010
2019
  if `True`, skip normalization for axis.
2011
2020
 
@@ -2043,22 +2052,9 @@ class CascadedCoords(Coordinates):
2043
2052
  if isinstance(axis, np.ndarray) and axis.shape == (3, 3):
2044
2053
  return self.rotate_with_matrix(theta, wrt)
2045
2054
 
2046
- if wrt == 'local' or wrt == self:
2047
- rotation = rotate_matrix_by_axis_angle(
2048
- self._rotation, theta, axis,
2049
- skip_normalization=skip_normalization)
2050
- return self.newcoords(rotation, self._translation,
2051
- check_validity=False, relative_coords='local')
2052
- elif wrt == 'parent' or wrt == self.parent:
2053
- rotation = rotate_matrix_by_axis_angle(
2054
- self._rotation, theta, axis,
2055
- skip_normalization=skip_normalization)
2056
- return self.newcoords(rotation, self._translation,
2057
- check_validity=False, relative_coords='local')
2058
- else:
2059
- return self.rotate_with_matrix(
2060
- rotation_matrix(theta, axis,
2061
- skip_normalization=skip_normalization), wrt)
2055
+ return self.rotate_with_matrix(
2056
+ rotation_matrix(theta, axis,
2057
+ skip_normalization=skip_normalization), wrt)
2062
2058
 
2063
2059
  def orient_with_matrix(self, rotation_matrix, wrt='world'):
2064
2060
  """Force update this coordinate system's rotation.
@@ -2192,7 +2188,27 @@ class CascadedCoords(Coordinates):
2192
2188
  if not (c is None or coordinates_p(c)):
2193
2189
  raise ValueError('parent should be None or Coordinates. '
2194
2190
  'get type=={}'.format(type(c)))
2191
+ previous = getattr(self, '_parent', None)
2192
+ if previous is c:
2193
+ self._parent = c
2194
+ return
2195
+ # A parent chain through self would make worldcoords() recurse
2196
+ # forever.
2197
+ ancestor = c
2198
+ while ancestor is not None:
2199
+ if ancestor is self:
2200
+ raise ValueError(
2201
+ 'Cannot make {!r} a parent of {!r}: it is already one '
2202
+ 'of its descendants.'.format(c.name, self.name))
2203
+ ancestor = getattr(ancestor, 'parent', None)
2204
+ # Leave the previous parent's descendants, so that re-parenting by
2205
+ # either assoc or a direct assignment leaves no stale entry there.
2206
+ if (isinstance(previous, CascadedCoords)
2207
+ and self in previous._descendants):
2208
+ previous._descendants.remove(self)
2195
2209
  self._parent = c
2210
+ # The cached world pose was taken under the previous parent.
2211
+ self.changed()
2196
2212
 
2197
2213
  def __getstate__(self):
2198
2214
  assert self._worldcoords._hook == self.update
@@ -11,6 +11,12 @@ The algorithms support multiple backends (NumPy, JAX) for
11
11
  different performance and autodiff requirements.
12
12
  """
13
13
 
14
+ # Mobile-base placement for several end-effector targets
15
+ from skrobot.kinematics.base_placement import BasePlacementResult
16
+ from skrobot.kinematics.base_placement import find_base_placement
17
+ from skrobot.kinematics.base_placement import set_base_pose
18
+ from skrobot.kinematics.base_placement import vectorized_target
19
+
14
20
  # Differentiable kinematics (backend-agnostic)
15
21
  from skrobot.kinematics.differentiable import create_batch_ik_solver
16
22
  from skrobot.kinematics.differentiable import create_dynamic_limit_mask
@@ -18,6 +24,10 @@ from skrobot.kinematics.differentiable import extract_fk_parameters
18
24
  from skrobot.kinematics.differentiable import forward_kinematics
19
25
  from skrobot.kinematics.differentiable import forward_kinematics_ee
20
26
 
27
+ # Inverse reachability map: base poses that reach a hand pose
28
+ from skrobot.kinematics.inverse_reachability_map import BaseCandidates
29
+ from skrobot.kinematics.inverse_reachability_map import InverseReachabilityMap
30
+
21
31
  # Loop-closure solving for cut kinematic loops
22
32
  from skrobot.kinematics.loop_closure import LoopClosureSolver
23
33
 
@@ -33,4 +43,10 @@ __all__ = [
33
43
  'create_dynamic_limit_mask',
34
44
  'LoopClosureSolver',
35
45
  'ReachabilityMap',
46
+ 'BasePlacementResult',
47
+ 'find_base_placement',
48
+ 'set_base_pose',
49
+ 'vectorized_target',
50
+ 'BaseCandidates',
51
+ 'InverseReachabilityMap',
36
52
  ]
@@ -0,0 +1,268 @@
1
+ """JAX version of the shared-base Levenberg-Marquardt loop.
2
+
3
+ The NumPy loop in :mod:`skrobot.kinematics.base_placement` drops finished
4
+ starts from the batch every iteration, which keeps the work small but
5
+ spends most of its time in Python and in small ``einsum`` calls. Here one
6
+ iteration -- linearize, Schur step, trial residual, accept or reject --
7
+ is a single jitted function over a fixed-size batch. The batch shrinks to
8
+ the next power of sixteen when fifteen sixteenths of it have finished,
9
+ so a solve compiles for two or three sizes only; each costs seconds,
10
+ which is why the sizes are spaced so far apart.
11
+
12
+ Everything runs in float64, inside ``jax.enable_x64`` so the global
13
+ setting is left alone. In float32 the accept and stall tests round
14
+ differently, and the solve takes a different path than the NumPy one.
15
+
16
+ Targets that follow the base are evaluated on the host, as in the NumPy
17
+ loop, together with their finite-difference derivative; within one
18
+ iteration the trial step moves them along that derivative.
19
+ """
20
+
21
+ import numpy as np
22
+
23
+ from skrobot.backend.math_utils import rodrigues_rotation
24
+
25
+
26
+ def _enable_x64(jax):
27
+ """Context manager turning on float64 for the code inside it.
28
+
29
+ It is ``jax.enable_x64`` in current JAX and only
30
+ ``jax.experimental.enable_x64`` up to 0.7.
31
+ """
32
+ if hasattr(jax, 'enable_x64'):
33
+ return jax.enable_x64(True)
34
+ from jax.experimental import enable_x64
35
+ return enable_x64(True)
36
+
37
+
38
+ class JaxLevenbergMarquardt(object):
39
+ """Jitted LM iterations for one :class:`_SharedBaseProblem`."""
40
+
41
+ def __init__(self, problem, thre, rthre, max_pos_step, max_rot_step,
42
+ bounds):
43
+ import jax
44
+ import jax.numpy as jnp
45
+
46
+ from skrobot.kinematics.base_placement import _clip_joints
47
+ from skrobot.kinematics.base_placement import _clip_rows
48
+ from skrobot.kinematics.base_placement import _cost
49
+ from skrobot.kinematics.base_placement import _margin_terms
50
+ from skrobot.kinematics.base_placement import _place_on_base
51
+ from skrobot.kinematics.base_placement import _pose_residual
52
+ from skrobot.kinematics.base_placement import _residual_jacobians
53
+ from skrobot.kinematics.base_placement import _schur_step
54
+ from skrobot.kinematics.differentiable import compute_geometric_jacobian_jax
55
+
56
+ self.jax = jax
57
+ self.jnp = jnp
58
+ self.problem = problem
59
+ fk = problem.fk_params
60
+ n_joints = fk['n_joints']
61
+ non_mimic = problem.non_mimic
62
+ n_opt = problem.n_opt
63
+ n_targets = problem.n_targets
64
+
65
+ jac_one = jax.vmap(lambda a: compute_geometric_jacobian_jax(a, fk))
66
+ row_mask = jnp.asarray(problem.row_mask)
67
+ tolerance = (None if problem.rotation_tolerance is None
68
+ else jnp.asarray(problem.rotation_tolerance))
69
+ # Kept in NumPy: only its pattern is read, at trace time.
70
+ base_frame = problem.base_frame
71
+ lower = jnp.asarray(problem.lower)
72
+ upper = jnp.asarray(problem.upper)
73
+ unbounded = jnp.asarray(problem.unbounded)
74
+ bounded = jnp.asarray(problem.bounded)
75
+ span = jnp.asarray(problem.span)
76
+ margin_weight = problem.margin_weight
77
+ has_moving = bool(problem.target_fns)
78
+ moving_idx = jnp.asarray([i for i, _ in problem.target_fns],
79
+ dtype=jnp.int32)
80
+ # The fixed targets stay on the device; only the few that follow
81
+ # the base cross over each iteration.
82
+ static_pos = jnp.asarray(problem.target_pos)
83
+ static_rot = jnp.asarray(problem.target_rot)
84
+ lo = None if bounds is None else jnp.asarray(bounds[0])
85
+ hi = None if bounds is None else jnp.asarray(bounds[1])
86
+
87
+ def chain(q):
88
+ n_cand = q.shape[0]
89
+ angles = jnp.zeros((n_cand * n_targets, n_joints), q.dtype)
90
+ angles = angles.at[:, non_mimic].set(q.reshape(-1, n_opt))
91
+ jac, pos, rot = jac_one(angles)
92
+ return (jac.reshape(n_cand, n_targets, 6, n_opt),
93
+ pos.reshape(n_cand, n_targets, 3),
94
+ rot.reshape(n_cand, n_targets, 3, 3))
95
+
96
+ def residual(meas_pos, meas_rot, target_pos, target_rot):
97
+ return _pose_residual(meas_pos, meas_rot, target_pos, target_rot, row_mask,
98
+ tolerance, jnp)
99
+
100
+ def linearize(bases, q, target_pos, target_rot, dt):
101
+ jac, pos, rot = chain(q)
102
+ (meas_pos, meas_rot, world_pos, world_rot, base_rot,
103
+ base_pos) = _place_on_base(pos, rot, bases, base_frame, jnp)
104
+ err = residual(meas_pos, meas_rot, target_pos, target_rot)
105
+ base_jac, arm_jac = _residual_jacobians(
106
+ err, jac, world_pos, world_rot, base_rot, base_pos,
107
+ base_frame, row_mask, tolerance, dt, jnp)
108
+ return err, base_jac, arm_jac
109
+
110
+ def margin_terms(q, floor):
111
+ return _margin_terms(q, floor, lower, upper, span, bounded,
112
+ margin_weight, jnp)
113
+
114
+ def iterate(state, base_weight, mpos, mrot, mdt):
115
+ bases, q, damping, stalls, done, weight, floor = state
116
+ n_cand = bases.shape[0]
117
+ target_pos = jnp.broadcast_to(static_pos, (n_cand,) + static_pos.shape)
118
+ target_rot = jnp.broadcast_to(static_rot, (n_cand,) + static_rot.shape)
119
+ dt = None
120
+ if has_moving:
121
+ target_pos = target_pos.at[:, moving_idx].set(mpos)
122
+ target_rot = target_rot.at[:, moving_idx].set(mrot)
123
+ dt = jnp.zeros((n_cand, n_targets, 6, 3)).at[
124
+ :, moving_idx].set(mdt)
125
+ err, bj, aj = linearize(bases, q, target_pos, target_rot, dt)
126
+ m_err, m_jac = margin_terms(q, floor)
127
+ cost = _cost(err * weight[..., None], m_err, jnp)
128
+ pos_norm = jnp.linalg.norm(err[..., :3], axis=-1)
129
+ rot_norm = jnp.linalg.norm(err[..., 3:], axis=-1)
130
+ reached = (pos_norm < thre) & (rot_norm < rthre)
131
+ done = done | (jnp.all(reached | (weight == 0), axis=1)
132
+ & ~jnp.any(m_err > 0, axis=(1, 2)))
133
+ done = done | (damping >= 1e4) | (stalls >= 5)
134
+ w = weight[..., None]
135
+ d_base, d_arm = _schur_step(
136
+ _clip_rows(err, max_pos_step, max_rot_step, jnp) * w,
137
+ bj * w[..., None], aj * w[..., None], damping, base_weight,
138
+ m_err, m_jac, jnp)
139
+ new_bases = bases.at[:, :3].add(d_base)
140
+ if lo is not None:
141
+ new_bases = new_bases.at[:, :2].set(
142
+ jnp.clip(new_bases[:, :2], lo, hi))
143
+ new_q = _clip_joints(q + d_arm, lower, upper, unbounded, jnp)
144
+ step = new_bases[:, :3] - bases[:, :3]
145
+ if has_moving:
146
+ # First-order move of the base-following targets.
147
+ new_target_pos = target_pos + jnp.einsum(
148
+ 'knia,ka->kni', dt[..., :3, :], step)
149
+ twist = jnp.einsum('knia,ka->kni', dt[..., 3:, :], step)
150
+ new_target_rot = rodrigues_rotation(
151
+ jnp, twist, jnp.linalg.norm(twist, axis=-1)) @ target_rot
152
+ else:
153
+ new_target_pos, new_target_rot = target_pos, target_rot
154
+ _, pos, rot = chain(new_q)
155
+ mp, mr, _, _, _, _ = _place_on_base(pos, rot, new_bases,
156
+ base_frame, jnp)
157
+ new_err = residual(mp, mr, new_target_pos, new_target_rot)
158
+ new_m_err, _ = margin_terms(new_q, floor)
159
+ new_cost = _cost(new_err * weight[..., None], new_m_err, jnp)
160
+ accept = (new_cost < cost) & ~done
161
+ damping = jnp.where(accept, jnp.maximum(damping * 0.5, 1e-6),
162
+ jnp.minimum(damping * 4.0, 1e4))
163
+ small = cost - new_cost < 1e-3 * jnp.maximum(cost, 1e-12)
164
+ stalls = jnp.where(accept, jnp.where(small, stalls + 1, 0),
165
+ stalls)
166
+ bases = jnp.where(accept[:, None], new_bases, bases)
167
+ q = jnp.where(accept[:, None, None], new_q, q)
168
+ return (bases, q, damping, stalls, done, weight, floor)
169
+
170
+ self._iterate = jax.jit(iterate)
171
+ self._has_moving = has_moving
172
+
173
+ def _moving(self, bases):
174
+ """Host-side poses ``(K, D, 3)``, ``(K, D, 3, 3)`` of the targets
175
+ that follow the base, and their base derivative ``(K, D, 6, 3)``."""
176
+ problem = self.problem
177
+ n_cand = bases.shape[0]
178
+ if not problem.target_fns:
179
+ return (np.zeros((n_cand, 0, 3)), np.zeros((n_cand, 0, 3, 3)),
180
+ np.zeros((n_cand, 0, 6, 3)))
181
+ pos, rot = problem._moving_targets(bases)
182
+ return pos, rot, problem.moving_target_jacobian(bases)
183
+
184
+ def run(self, bases, q, active, stop, base_weight, margin_target):
185
+ """Iterate in place on ``bases`` / ``q``; return the final error."""
186
+ with _enable_x64(self.jax):
187
+ self._run(bases, q, active, stop, base_weight, margin_target)
188
+ return self.problem.residual(bases, q)
189
+
190
+ def _run(self, bases, q, active, stop, base_weight, margin_target):
191
+ n_cand = bases.shape[0]
192
+ floor = (np.zeros(n_cand) if margin_target is None
193
+ else np.asarray(margin_target, dtype=np.float64))
194
+ weight = active.astype(np.float64)
195
+ damping = np.full(n_cand, 1e-2)
196
+ stalls = np.zeros(n_cand, dtype=np.int64)
197
+ done = np.zeros(n_cand, dtype=bool)
198
+ base_weight = self.jax.device_put(
199
+ np.asarray(base_weight, dtype=np.float64))
200
+
201
+ jax = self.jax
202
+ rows = np.arange(n_cand)
203
+ size = _bucket(n_cand)
204
+ state = None
205
+ moving = None
206
+ for _ in range(stop):
207
+ if state is None:
208
+ padded = _pad(rows, size)
209
+ # One transfer for the lot; jnp.asarray per array costs a
210
+ # dispatch each.
211
+ state = jax.device_put((
212
+ bases[padded], q[padded], damping[padded],
213
+ stalls[padded], done[padded] | (padded < 0),
214
+ weight[padded], floor[padded]))
215
+ host_bases = bases[padded].copy()
216
+ host_moving = self._moving(host_bases)
217
+ moving = jax.device_put(host_moving)
218
+ elif self._has_moving:
219
+ # Only rows whose base moved need their targets again; a
220
+ # rejected step leaves the base where it was.
221
+ new_bases = np.asarray(state[0])
222
+ changed = np.any(new_bases != host_bases, axis=1)
223
+ if np.any(changed):
224
+ fresh = self._moving(new_bases[changed])
225
+ for held, new in zip(host_moving, fresh):
226
+ held[changed] = new
227
+ host_bases = new_bases.copy()
228
+ moving = jax.device_put(host_moving)
229
+ state = self._iterate(state, base_weight, *moving)
230
+ live = ~np.asarray(state[4])[:len(rows)]
231
+ if not np.any(live):
232
+ break
233
+ if size > 16 and np.count_nonzero(live) <= size // 16:
234
+ # Shrink the batch: write the rows back and repack the
235
+ # ones still running.
236
+ self._write_back(state, rows, bases, q, damping, stalls,
237
+ done)
238
+ rows = rows[live]
239
+ size = _bucket(len(rows))
240
+ state = None
241
+ if state is not None:
242
+ self._write_back(state, rows, bases, q, damping, stalls, done)
243
+
244
+ @staticmethod
245
+ def _write_back(state, rows, bases, q, damping, stalls, done):
246
+ n = len(rows)
247
+ bases[rows] = np.asarray(state[0])[:n]
248
+ q[rows] = np.asarray(state[1])[:n]
249
+ damping[rows] = np.asarray(state[2])[:n]
250
+ stalls[rows] = np.asarray(state[3])[:n]
251
+ done[rows] = np.asarray(state[4])[:n]
252
+
253
+
254
+ def _bucket(n):
255
+ """Smallest power of sixteen, at least 16, holding ``n`` rows."""
256
+ size = 16
257
+ while size < n:
258
+ size *= 16
259
+ return size
260
+
261
+
262
+ def _pad(rows, size):
263
+ """``rows`` padded to ``size`` with -1, which marks a dummy row.
264
+
265
+ Index -1 picks the last row of the batch, a real row whose copy is
266
+ flagged done and never written back.
267
+ """
268
+ return np.concatenate([rows, np.full(size - len(rows), -1)])