jaxsim 0.4.3.dev282__py3-none-any.whl → 0.4.3.dev298__py3-none-any.whl

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.
jaxsim/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.4.3.dev282'
16
- __version_tuple__ = version_tuple = (0, 4, 3, 'dev282')
15
+ __version__ = version = '0.4.3.dev298'
16
+ __version_tuple__ = version_tuple = (0, 4, 3, 'dev298')
jaxsim/api/contact.py CHANGED
@@ -243,9 +243,7 @@ def in_contact(
243
243
  A boolean vector indicating whether the links are in contact with the terrain.
244
244
  """
245
245
 
246
- link_names = link_names if link_names is not None else model.link_names()
247
-
248
- if set(link_names).difference(model.link_names()):
246
+ if link_names is not None and set(link_names).difference(model.link_names()):
249
247
  raise ValueError("One or more link names are not part of the model")
250
248
 
251
249
  W_p_Ci = collidable_point_positions(model=model, data=data)
@@ -256,13 +254,19 @@ def in_contact(
256
254
 
257
255
  below_terrain = W_p_Ci[:, 2] <= terrain_height
258
256
 
257
+ link_idxs = (
258
+ js.link.names_to_idxs(link_names=link_names, model=model)
259
+ if link_names is not None
260
+ else jnp.arange(model.number_of_links())
261
+ )
262
+
259
263
  links_in_contact = jax.vmap(
260
264
  lambda link_index: jnp.where(
261
265
  jnp.array(model.kin_dyn_parameters.contact_parameters.body) == link_index,
262
266
  below_terrain,
263
267
  jnp.zeros_like(below_terrain, dtype=bool),
264
268
  ).any()
265
- )(js.link.names_to_idxs(link_names=link_names, model=model))
269
+ )(link_idxs)
266
270
 
267
271
  return links_in_contact
268
272
 
jaxsim/api/data.py CHANGED
@@ -292,11 +292,13 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
292
292
  msg = "The data object is not compatible with the provided model"
293
293
  raise ValueError(msg)
294
294
 
295
- joint_names = joint_names if joint_names is not None else model.joint_names()
296
-
297
- return self.state.physics_model.joint_positions[
295
+ joint_idxs = (
298
296
  js.joint.names_to_idxs(joint_names=joint_names, model=model)
299
- ]
297
+ if joint_names is not None
298
+ else jnp.arange(model.number_of_joints())
299
+ )
300
+
301
+ return self.state.physics_model.joint_positions[joint_idxs]
300
302
 
301
303
  @functools.partial(jax.jit, static_argnames=["joint_names"])
302
304
  def joint_velocities(
@@ -337,11 +339,13 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
337
339
  msg = "The data object is not compatible with the provided model"
338
340
  raise ValueError(msg)
339
341
 
340
- joint_names = joint_names if joint_names is not None else model.joint_names()
341
-
342
- return self.state.physics_model.joint_velocities[
342
+ joint_idxs = (
343
343
  js.joint.names_to_idxs(joint_names=joint_names, model=model)
344
- ]
344
+ if joint_names is not None
345
+ else jnp.arange(model.number_of_joints())
346
+ )
347
+
348
+ return self.state.physics_model.joint_velocities[joint_idxs]
345
349
 
346
350
  @jax.jit
347
351
  def base_position(self) -> jtp.Vector:
@@ -374,10 +378,8 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
374
378
  # we introduce a Baumgarte stabilization to let the quaternion converge to
375
379
  # a unit quaternion. In this case, it is not guaranteed that the quaternion
376
380
  # stored in the state is a unit quaternion.
377
- W_Q_B = jax.lax.select(
378
- pred=jnp.allclose(jnp.linalg.norm(W_Q_B), 1.0, atol=1e-6, rtol=0.0),
379
- on_true=W_Q_B,
380
- on_false=W_Q_B / jnp.linalg.norm(W_Q_B),
381
+ W_Q_B = jnp.where(
382
+ jnp.allclose(W_Q_B.dot(W_Q_B), 1.0), W_Q_B, W_Q_B / jnp.linalg.norm(W_Q_B)
381
383
  )
382
384
 
383
385
  return (W_Q_B if not dcm else jaxsim.math.Quaternion.to_dcm(W_Q_B)).astype(
@@ -502,12 +504,14 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
502
504
  msg = "The data object is not compatible with the provided model"
503
505
  raise ValueError(msg)
504
506
 
505
- joint_names = joint_names if joint_names is not None else model.joint_names()
507
+ joint_idxs = (
508
+ js.joint.names_to_idxs(joint_names=joint_names, model=model)
509
+ if joint_names is not None
510
+ else jnp.arange(model.number_of_joints())
511
+ )
506
512
 
507
513
  return replace(
508
- s=self.state.physics_model.joint_positions.at[
509
- js.joint.names_to_idxs(joint_names=joint_names, model=model)
510
- ].set(positions)
514
+ s=self.state.physics_model.joint_positions.at[joint_idxs].set(positions)
511
515
  )
512
516
 
513
517
  @functools.partial(jax.jit, static_argnames=["joint_names"])
@@ -548,12 +552,14 @@ class JaxSimModelData(common.ModelDataWithVelocityRepresentation):
548
552
  msg = "The data object is not compatible with the provided model"
549
553
  raise ValueError(msg)
550
554
 
551
- joint_names = joint_names if joint_names is not None else model.joint_names()
555
+ joint_idxs = (
556
+ js.joint.names_to_idxs(joint_names=joint_names, model=model)
557
+ if joint_names is not None
558
+ else jnp.arange(model.number_of_joints())
559
+ )
552
560
 
553
561
  return replace(
554
- ṡ=self.state.physics_model.joint_velocities.at[
555
- js.joint.names_to_idxs(joint_names=joint_names, model=model)
556
- ].set(velocities)
562
+ ṡ=self.state.physics_model.joint_velocities.at[joint_idxs].set(velocities)
557
563
  )
558
564
 
559
565
  @jax.jit
jaxsim/api/joint.py CHANGED
@@ -157,13 +157,19 @@ def position_limits(
157
157
  The position limits of the joints.
158
158
  """
159
159
 
160
- joint_names = joint_names if joint_names is not None else model.joint_names()
160
+ joint_idxs = (
161
+ names_to_idxs(joint_names=joint_names, model=model)
162
+ if joint_names is not None
163
+ else jnp.arange(model.number_of_joints())
164
+ )
161
165
 
162
- if len(joint_names) == 0:
166
+ if len(joint_idxs) == 0:
163
167
  return jnp.empty(0).astype(float), jnp.empty(0).astype(float)
164
168
 
165
- joint_idxs = names_to_idxs(joint_names=joint_names, model=model)
166
- return jax.vmap(lambda i: position_limit(model=model, joint_index=i))(joint_idxs)
169
+ s_min = model.kin_dyn_parameters.joint_parameters.position_limits_min[joint_idxs]
170
+ s_max = model.kin_dyn_parameters.joint_parameters.position_limits_max[joint_idxs]
171
+
172
+ return s_min.astype(float), s_max.astype(float)
167
173
 
168
174
 
169
175
  # ======================
@@ -203,7 +209,11 @@ def random_joint_positions(
203
209
  # Get the joint indices.
204
210
  # Note that it will trigger an exception if the given `joint_names` are not valid.
205
211
  joint_names = joint_names if joint_names is not None else model.joint_names()
206
- joint_indices = names_to_idxs(model=model, joint_names=joint_names)
212
+ joint_indices = (
213
+ names_to_idxs(model=model, joint_names=joint_names)
214
+ if joint_names is not None
215
+ else jnp.arange(model.number_of_joints())
216
+ )
207
217
 
208
218
  from jaxsim.parsers.descriptions.joint import JointType
209
219
 
@@ -398,9 +398,7 @@ class KynDynParameters(JaxsimDataclass):
398
398
  λ_H_pre = jnp.vstack(
399
399
  [
400
400
  jnp.eye(4)[jnp.newaxis],
401
- jax.vmap(
402
- lambda i: self.joint_model.parent_H_predecessor(joint_index=i)
403
- )(jnp.arange(1, 1 + self.number_of_joints())),
401
+ self.joint_model.λ_H_pre[1 : 1 + self.number_of_joints()],
404
402
  ]
405
403
  )
406
404
 
jaxsim/api/link.py CHANGED
@@ -423,156 +423,9 @@ def jacobian_derivative(
423
423
  output_vel_repr if output_vel_repr is not None else data.velocity_representation
424
424
  )
425
425
 
426
- # Compute the derivative of the doubly-left free-floating full jacobian.
427
- B_J̇_full_WX_B, B_H_L = jaxsim.rbda.jacobian_derivative_full_doubly_left(
428
- model=model,
429
- joint_positions=data.joint_positions(),
430
- joint_velocities=data.joint_velocities(),
431
- )
432
-
433
- # Compute the actual doubly-left free-floating jacobian derivative of the link
434
- # by zeroing the columns not in the path π_B(L) using the boolean κ(i).
435
- κb = model.kin_dyn_parameters.support_body_array_bool[link_index]
436
- B_J̇_WL_B = jnp.hstack([jnp.ones(5), κb]) * B_J̇_full_WX_B
437
-
438
- # =====================================================
439
- # Compute quantities to adjust the input representation
440
- # =====================================================
441
-
442
- In = jnp.eye(model.dofs())
443
- On = jnp.zeros(shape=(model.dofs(), model.dofs()))
444
-
445
- match data.velocity_representation:
446
-
447
- case VelRepr.Inertial:
448
-
449
- W_H_B = data.base_transform()
450
- B_X_W = jaxsim.math.Adjoint.from_transform(transform=W_H_B, inverse=True)
451
-
452
- with data.switch_velocity_representation(VelRepr.Inertial):
453
- W_v_WB = data.base_velocity()
454
- B_Ẋ_W = -B_X_W @ jaxsim.math.Cross.vx(W_v_WB)
455
-
456
- # Compute the operator to change the representation of ν, and its
457
- # time derivative.
458
- T = jax.scipy.linalg.block_diag(B_X_W, In)
459
- Ṫ = jax.scipy.linalg.block_diag(B_Ẋ_W, On)
460
-
461
- case VelRepr.Body:
462
-
463
- B_X_B = jaxsim.math.Adjoint.from_rotation_and_translation(
464
- translation=jnp.zeros(3), rotation=jnp.eye(3)
465
- )
466
-
467
- B_Ẋ_B = jnp.zeros(shape=(6, 6))
468
-
469
- # Compute the operator to change the representation of ν, and its
470
- # time derivative.
471
- T = jax.scipy.linalg.block_diag(B_X_B, In)
472
- Ṫ = jax.scipy.linalg.block_diag(B_Ẋ_B, On)
473
-
474
- case VelRepr.Mixed:
475
-
476
- BW_H_B = data.base_transform().at[0:3, 3].set(jnp.zeros(3))
477
- B_X_BW = jaxsim.math.Adjoint.from_transform(transform=BW_H_B, inverse=True)
478
-
479
- with data.switch_velocity_representation(VelRepr.Mixed):
480
- BW_v_WB = data.base_velocity()
481
- BW_v_W_BW = BW_v_WB.at[3:6].set(jnp.zeros(3))
482
-
483
- BW_v_BW_B = BW_v_WB - BW_v_W_BW
484
- B_Ẋ_BW = -B_X_BW @ jaxsim.math.Cross.vx(BW_v_BW_B)
485
-
486
- # Compute the operator to change the representation of ν, and its
487
- # time derivative.
488
- T = jax.scipy.linalg.block_diag(B_X_BW, In)
489
- Ṫ = jax.scipy.linalg.block_diag(B_Ẋ_BW, On)
490
-
491
- case _:
492
- raise ValueError(data.velocity_representation)
493
-
494
- # ======================================================
495
- # Compute quantities to adjust the output representation
496
- # ======================================================
497
-
498
- match output_vel_repr:
499
-
500
- case VelRepr.Inertial:
501
-
502
- W_H_B = data.base_transform()
503
- O_X_B = W_X_B = jaxsim.math.Adjoint.from_transform(transform=W_H_B)
504
-
505
- with data.switch_velocity_representation(VelRepr.Body):
506
- B_v_WB = data.base_velocity()
507
-
508
- O_Ẋ_B = W_Ẋ_B = W_X_B @ jaxsim.math.Cross.vx(B_v_WB) # noqa: F841
509
-
510
- case VelRepr.Body:
511
-
512
- O_X_B = L_X_B = jaxsim.math.Adjoint.from_transform(
513
- transform=B_H_L[link_index, :, :], inverse=True
514
- )
515
-
516
- B_X_L = jaxsim.math.Adjoint.inverse(adjoint=L_X_B)
517
-
518
- with data.switch_velocity_representation(VelRepr.Body):
519
- B_v_WB = data.base_velocity()
520
- L_v_WL = js.link.velocity(model=model, data=data, link_index=link_index)
521
-
522
- O_Ẋ_B = L_Ẋ_B = -L_X_B @ jaxsim.math.Cross.vx( # noqa: F841
523
- B_X_L @ L_v_WL - B_v_WB
524
- )
525
-
526
- case VelRepr.Mixed:
527
-
528
- W_H_B = data.base_transform()
529
- W_H_L = W_H_B @ B_H_L[link_index, :, :]
530
- LW_H_L = W_H_L.at[0:3, 3].set(jnp.zeros(3))
531
- LW_H_B = LW_H_L @ jaxsim.math.Transform.inverse(B_H_L[link_index, :, :])
532
-
533
- O_X_B = LW_X_B = jaxsim.math.Adjoint.from_transform(transform=LW_H_B)
534
-
535
- B_X_LW = jaxsim.math.Adjoint.inverse(adjoint=LW_X_B)
536
-
537
- with data.switch_velocity_representation(VelRepr.Body):
538
- B_v_WB = data.base_velocity()
539
-
540
- with data.switch_velocity_representation(VelRepr.Mixed):
541
- LW_v_WL = js.link.velocity(
542
- model=model, data=data, link_index=link_index
543
- )
544
- LW_v_W_LW = LW_v_WL.at[3:6].set(jnp.zeros(3))
545
-
546
- LW_v_LW_L = LW_v_WL - LW_v_W_LW
547
- LW_v_B_LW = LW_v_WL - LW_X_B @ B_v_WB - LW_v_LW_L
548
-
549
- O_Ẋ_B = LW_Ẋ_B = -LW_X_B @ jaxsim.math.Cross.vx( # noqa: F841
550
- B_X_LW @ LW_v_B_LW
551
- )
552
- case _:
553
- raise ValueError(output_vel_repr)
554
-
555
- # =============================================================
556
- # Express the Jacobian derivative in the target representations
557
- # =============================================================
558
-
559
- # The derivative of the equation to change the input and output representations
560
- # of the Jacobian derivative needs the computation of the plain link Jacobian.
561
- # Compute here the full Jacobian of the model...
562
- B_J_full_WL_B, _ = jaxsim.rbda.jacobian_full_doubly_left(
563
- model=model,
564
- joint_positions=data.joint_positions(),
565
- )
566
-
567
- # ... and extract the link Jacobian using the boolean support body array.
568
- B_J_WL_B = jnp.hstack([jnp.ones(5), κb]) * B_J_full_WL_B
569
-
570
- # Sum all the components that form the Jacobian derivative in the target
571
- # input/output velocity representations.
572
- O_J̇_WL_I = jnp.zeros(shape=(6, 6 + model.dofs()))
573
- O_J̇_WL_I += O_Ẋ_B @ B_J_WL_B @ T
574
- O_J̇_WL_I += O_X_B @ B_J̇_WL_B @ T
575
- O_J̇_WL_I += O_X_B @ B_J_WL_B @ Ṫ
426
+ O_J̇_WL_I = js.model.generalized_free_floating_jacobian_derivative(
427
+ model=model, data=data, output_vel_repr=output_vel_repr
428
+ )[link_index]
576
429
 
577
430
  return O_J̇_WL_I
578
431
 
jaxsim/api/model.py CHANGED
@@ -700,14 +700,173 @@ def generalized_free_floating_jacobian_derivative(
700
700
  output_vel_repr if output_vel_repr is not None else data.velocity_representation
701
701
  )
702
702
 
703
- O_J̇_WL_I = jax.vmap(
704
- lambda model, data, link_idxs, output_vel_repr: js.link.jacobian_derivative(
705
- model, data, link_index=link_idxs, output_vel_repr=output_vel_repr
706
- ),
707
- in_axes=(None, None, 0, None),
708
- )(model, data, jnp.arange(model.number_of_links()), output_vel_repr)
703
+ # Compute the derivative of the doubly-left free-floating full jacobian.
704
+ B_J̇_full_WX_B, B_H_L = jaxsim.rbda.jacobian_derivative_full_doubly_left(
705
+ model=model,
706
+ joint_positions=data.joint_positions(),
707
+ joint_velocities=data.joint_velocities(),
708
+ )
709
+
710
+ # The derivative of the equation to change the input and output representations
711
+ # of the Jacobian derivative needs the computation of the plain link Jacobian.
712
+ B_J_full_WL_B, _ = jaxsim.rbda.jacobian_full_doubly_left(
713
+ model=model,
714
+ joint_positions=data.joint_positions(),
715
+ )
716
+
717
+ # Compute the actual doubly-left free-floating jacobian derivative of the link
718
+ # by zeroing the columns not in the path π_B(L) using the boolean κ(i).
719
+ κb = model.kin_dyn_parameters.support_body_array_bool
720
+
721
+ # Compute the base transform.
722
+ W_H_B = data.base_transform()
723
+
724
+ @functools.partial(jax.vmap, in_axes=(0, None, None, 0))
725
+ def _compute_row(
726
+ B_H_L: jtp.Matrix,
727
+ B_J_full_WL_B: jtp.Matrix,
728
+ W_H_B: jtp.Matrix,
729
+ κb: jtp.Matrix,
730
+ ) -> jtp.Matrix:
731
+
732
+ # =====================================================
733
+ # Compute quantities to adjust the input representation
734
+ # =====================================================
735
+
736
+ In = jnp.eye(model.dofs())
737
+ On = jnp.zeros(shape=(model.dofs(), model.dofs()))
738
+
739
+ # Extract the link quantities using the boolean support body array.
740
+ B_J̇_WL_B = jnp.hstack([jnp.ones(5), κb]) * B_J̇_full_WX_B
741
+ B_J_WL_B = jnp.hstack([jnp.ones(5), κb]) * B_J_full_WL_B
742
+
743
+ match data.velocity_representation:
709
744
 
710
- return O_J̇_WL_I
745
+ case VelRepr.Inertial:
746
+
747
+ B_X_W = jaxsim.math.Adjoint.from_transform(
748
+ transform=W_H_B, inverse=True
749
+ )
750
+
751
+ W_v_WB = data.base_velocity()
752
+ B_Ẋ_W = -B_X_W @ jaxsim.math.Cross.vx(W_v_WB)
753
+
754
+ # Compute the operator to change the representation of ν, and its
755
+ # time derivative.
756
+ T = jax.scipy.linalg.block_diag(B_X_W, In)
757
+ Ṫ = jax.scipy.linalg.block_diag(B_Ẋ_W, On)
758
+
759
+ case VelRepr.Body:
760
+
761
+ B_X_B = jaxsim.math.Adjoint.from_rotation_and_translation(
762
+ translation=jnp.zeros(3), rotation=jnp.eye(3)
763
+ )
764
+
765
+ B_Ẋ_B = jnp.zeros(shape=(6, 6))
766
+
767
+ # Compute the operator to change the representation of ν, and its
768
+ # time derivative.
769
+ T = jax.scipy.linalg.block_diag(B_X_B, In)
770
+ Ṫ = jax.scipy.linalg.block_diag(B_Ẋ_B, On)
771
+
772
+ case VelRepr.Mixed:
773
+
774
+ BW_H_B = W_H_B.at[0:3, 3].set(jnp.zeros(3))
775
+ B_X_BW = jaxsim.math.Adjoint.from_transform(
776
+ transform=BW_H_B, inverse=True
777
+ )
778
+
779
+ BW_v_WB = data.base_velocity()
780
+ BW_v_W_BW = BW_v_WB.at[3:6].set(jnp.zeros(3))
781
+
782
+ BW_v_BW_B = BW_v_WB - BW_v_W_BW
783
+ B_Ẋ_BW = -B_X_BW @ jaxsim.math.Cross.vx(BW_v_BW_B)
784
+
785
+ # Compute the operator to change the representation of ν, and its
786
+ # time derivative.
787
+ T = jax.scipy.linalg.block_diag(B_X_BW, In)
788
+ Ṫ = jax.scipy.linalg.block_diag(B_Ẋ_BW, On)
789
+
790
+ case _:
791
+ raise ValueError(data.velocity_representation)
792
+
793
+ # ======================================================
794
+ # Compute quantities to adjust the output representation
795
+ # ======================================================
796
+
797
+ match output_vel_repr:
798
+
799
+ case VelRepr.Inertial:
800
+
801
+ O_X_B = W_X_B = jaxsim.math.Adjoint.from_transform(transform=W_H_B)
802
+
803
+ with data.switch_velocity_representation(VelRepr.Body):
804
+ B_v_WB = data.base_velocity()
805
+
806
+ O_Ẋ_B = W_Ẋ_B = W_X_B @ jaxsim.math.Cross.vx(B_v_WB) # noqa: F841
807
+
808
+ case VelRepr.Body:
809
+
810
+ O_X_B = L_X_B = jaxsim.math.Adjoint.from_transform(
811
+ transform=B_H_L, inverse=True
812
+ )
813
+
814
+ B_X_L = jaxsim.math.Adjoint.inverse(adjoint=L_X_B)
815
+
816
+ with data.switch_velocity_representation(VelRepr.Body):
817
+ B_v_WB = data.base_velocity()
818
+ L_v_WL = L_X_B @ B_J_WL_B @ data.generalized_velocity()
819
+
820
+ O_Ẋ_B = L_Ẋ_B = -L_X_B @ jaxsim.math.Cross.vx( # noqa: F841
821
+ B_X_L @ L_v_WL - B_v_WB
822
+ )
823
+
824
+ case VelRepr.Mixed:
825
+
826
+ W_H_L = W_H_B @ B_H_L
827
+ LW_H_L = W_H_L.at[0:3, 3].set(jnp.zeros(3))
828
+ LW_H_B = LW_H_L @ jaxsim.math.Transform.inverse(B_H_L)
829
+
830
+ O_X_B = LW_X_B = jaxsim.math.Adjoint.from_transform(transform=LW_H_B)
831
+
832
+ B_X_LW = jaxsim.math.Adjoint.inverse(adjoint=LW_X_B)
833
+
834
+ with data.switch_velocity_representation(VelRepr.Body):
835
+ B_v_WB = data.base_velocity()
836
+
837
+ with data.switch_velocity_representation(VelRepr.Mixed):
838
+ BW_H_B = W_H_B.at[0:3, 3].set(jnp.zeros(3))
839
+ B_X_BW = Adjoint.from_transform(transform=BW_H_B, inverse=True)
840
+ LW_v_WL = LW_X_B @ (
841
+ B_J_WL_B
842
+ @ jax.scipy.linalg.block_diag(B_X_BW, jnp.eye(model.dofs()))
843
+ @ data.generalized_velocity()
844
+ )
845
+ LW_v_W_LW = LW_v_WL.at[3:6].set(jnp.zeros(3))
846
+
847
+ LW_v_LW_L = LW_v_WL - LW_v_W_LW
848
+ LW_v_B_LW = LW_v_WL - LW_X_B @ B_v_WB - LW_v_LW_L
849
+
850
+ O_Ẋ_B = LW_Ẋ_B = -LW_X_B @ jaxsim.math.Cross.vx( # noqa: F841
851
+ B_X_LW @ LW_v_B_LW
852
+ )
853
+ case _:
854
+ raise ValueError(output_vel_repr)
855
+
856
+ # =============================================================
857
+ # Express the Jacobian derivative in the target representations
858
+ # =============================================================
859
+
860
+ # Sum all the components that form the Jacobian derivative in the target
861
+ # input/output velocity representations.
862
+ O_J̇_WL_I = jnp.zeros(shape=(6, 6 + model.dofs()))
863
+ O_J̇_WL_I += O_Ẋ_B @ B_J_WL_B @ T
864
+ O_J̇_WL_I += O_X_B @ B_J̇_WL_B @ T
865
+ O_J̇_WL_I += O_X_B @ B_J_WL_B @ Ṫ
866
+
867
+ return O_J̇_WL_I
868
+
869
+ return _compute_row(B_H_L, B_J_full_WL_B, W_H_B, κb)
711
870
 
712
871
 
713
872
  @functools.partial(jax.jit, static_argnames=["prefer_aba"])
@@ -1064,11 +1223,7 @@ def free_floating_coriolis_matrix(
1064
1223
  L_J_WL_B = generalized_free_floating_jacobian(model=model, data=data)
1065
1224
 
1066
1225
  # Doubly-left free-floating Jacobian derivative.
1067
- L_J̇_WL_B = jax.vmap(
1068
- lambda link_index: js.link.jacobian_derivative(
1069
- model=model, data=data, link_index=link_index
1070
- )
1071
- )(jnp.arange(model.number_of_links()))
1226
+ L_J̇_WL_B = generalized_free_floating_jacobian_derivative(model=model, data=data)
1072
1227
 
1073
1228
  L_M_L = link_spatial_inertia_matrices(model=model)
1074
1229
 
jaxsim/api/references.py CHANGED
@@ -193,8 +193,11 @@ class JaxSimModelReferences(js.common.ModelDataWithVelocityRepresentation):
193
193
  return self.input.physics_model.f_ext
194
194
 
195
195
  # If we have the model, we can extract the link names, if not provided.
196
- link_names = link_names if link_names is not None else model.link_names()
197
- link_idxs = js.link.names_to_idxs(link_names=link_names, model=model)
196
+ link_idxs = (
197
+ js.link.names_to_idxs(link_names=link_names, model=model)
198
+ if link_names is not None
199
+ else jnp.arange(model.number_of_links())
200
+ )
198
201
 
199
202
  # In inertial-fixed representation, we already have the link forces.
200
203
  if self.velocity_representation is VelRepr.Inertial:
@@ -267,8 +270,11 @@ class JaxSimModelReferences(js.common.ModelDataWithVelocityRepresentation):
267
270
  msg = "The actuation object is not compatible with the provided model"
268
271
  raise ValueError(msg)
269
272
 
270
- joint_names = joint_names if joint_names is not None else model.joint_names()
271
- joint_idxs = js.joint.names_to_idxs(joint_names=joint_names, model=model)
273
+ joint_idxs = (
274
+ js.joint.names_to_idxs(joint_names=joint_names, model=model)
275
+ if joint_names is not None
276
+ else jnp.arange(model.number_of_joints())
277
+ )
272
278
 
273
279
  return jnp.atleast_1d(
274
280
  self.input.physics_model.tau[joint_idxs].squeeze()
@@ -318,8 +324,11 @@ class JaxSimModelReferences(js.common.ModelDataWithVelocityRepresentation):
318
324
  msg = "The references object is not compatible with the provided model"
319
325
  raise ValueError(msg)
320
326
 
321
- joint_names = joint_names if joint_names is not None else model.joint_names()
322
- joint_idxs = js.joint.names_to_idxs(joint_names=joint_names, model=model)
327
+ joint_idxs = (
328
+ js.joint.names_to_idxs(joint_names=joint_names, model=model)
329
+ if joint_names is not None
330
+ else jnp.arange(model.number_of_joints())
331
+ )
323
332
 
324
333
  return replace(forces=self.input.physics_model.tau.at[joint_idxs].set(forces))
325
334
 
@@ -388,18 +397,16 @@ class JaxSimModelReferences(js.common.ModelDataWithVelocityRepresentation):
388
397
 
389
398
  return replace(forces=W_f0_L + W_f_L)
390
399
 
391
- # If we have the model, we can extract the link names if not provided.
392
- link_names = link_names if link_names is not None else model.link_names()
393
-
394
- # Make sure that the link names are a tuple if they are provided by the user.
395
- link_names = (link_names,) if isinstance(link_names, str) else link_names
396
-
397
- if len(link_names) != f_L.shape[0]:
400
+ if link_names is not None and len(link_names) != f_L.shape[0]:
398
401
  msg = "The number of link names ({}) must match the number of forces ({})"
399
402
  raise ValueError(msg.format(len(link_names), f_L.shape[0]))
400
403
 
401
404
  # Extract the link indices.
402
- link_idxs = js.link.names_to_idxs(link_names=link_names, model=model)
405
+ link_idxs = (
406
+ js.link.names_to_idxs(link_names=link_names, model=model)
407
+ if link_names is not None
408
+ else jnp.arange(model.number_of_links())
409
+ )
403
410
 
404
411
  # Compute the bias depending on whether we either set or add the link forces.
405
412
  W_f0_L = (
@@ -480,22 +487,21 @@ class JaxSimModelReferences(js.common.ModelDataWithVelocityRepresentation):
480
487
 
481
488
  f_F = jnp.atleast_2d(forces).astype(float)
482
489
 
483
- # If we have the model, we can extract the frame names if not provided.
484
- frame_names = frame_names if frame_names is not None else model.frame_names()
485
-
486
- # Make sure that the frame names are a tuple if they are provided by the user.
487
- frame_names = (frame_names,) if isinstance(frame_names, str) else frame_names
488
-
489
490
  if len(frame_names) != f_F.shape[0]:
490
491
  msg = "The number of frame names ({}) must match the number of forces ({})"
491
492
  raise ValueError(msg.format(len(frame_names), f_F.shape[0]))
492
493
 
493
494
  # Extract the frame indices.
494
- frame_idxs = js.frame.names_to_idxs(frame_names=frame_names, model=model)
495
- parent_link_idxs = jax.vmap(js.frame.idx_of_parent_link, in_axes=(None,))(
496
- model, frame_index=frame_idxs
495
+ frame_idxs = (
496
+ js.frame.names_to_idxs(frame_names=frame_names, model=model)
497
+ if frame_names is not None
498
+ else jnp.arange(len(model.frame_names()))
497
499
  )
498
500
 
501
+ parent_link_idxs = jnp.array(model.kin_dyn_parameters.frame_parameters.body)[
502
+ frame_idxs - model.number_of_links()
503
+ ]
504
+
499
505
  exceptions.raise_value_error_if(
500
506
  condition=jnp.logical_not(data.valid(model=model)),
501
507
  msg="The provided data is not valid for the model",
@@ -319,9 +319,8 @@ class ExplicitRungeKutta(Integrator[PyTreeType, PyTreeType], Generic[PyTreeType]
319
319
  f = lambda x, t: self.dynamics(x=x, t=t, **kwargs)
320
320
 
321
321
  # Initialize the carry of the for loop with the stacked kᵢ vectors.
322
- carry0 = jax.tree.map(
323
- lambda l: jnp.repeat(jnp.zeros_like(l)[jnp.newaxis, ...], c.size, axis=0),
324
- x0,
322
+ carry0 = jax.tree_map(
323
+ lambda l: jnp.zeros((c.size, *l.shape), dtype=l.dtype), x0
325
324
  )
326
325
 
327
326
  # Closure on metadata to either evaluate the dynamics at the initial state
jaxsim/math/adjoint.py CHANGED
@@ -137,11 +137,12 @@ class Adjoint:
137
137
  jtp.Matrix: The inverse adjoint matrix.
138
138
  """
139
139
  A_X_B = adjoint
140
- A_H_B = Adjoint.to_transform(adjoint=A_X_B)
141
140
 
142
- A_R_B = A_H_B[0:3, 0:3]
143
- A_o_B = A_H_B[0:3, 3]
141
+ A_R_B = A_X_B[0:3, 0:3]
144
142
 
145
- return Adjoint.from_rotation_and_translation(
146
- rotation=A_R_B, translation=A_o_B, inverse=True
143
+ return jnp.vstack(
144
+ [
145
+ jnp.block([A_R_B.T, -A_R_B.T @ A_X_B[0:3, 3:6] @ A_R_B.T]),
146
+ jnp.block([jnp.zeros(shape=(3, 3)), A_R_B.T]),
147
+ ]
147
148
  )
@@ -113,7 +113,7 @@ def extract_model_data(
113
113
  links = [
114
114
  descriptions.LinkDescription(
115
115
  name=l.name,
116
- mass=jnp.float32(l.inertial.mass),
116
+ mass=float(l.inertial.mass),
117
117
  inertia=utils.from_sdf_inertial(inertial=l.inertial),
118
118
  pose=l.pose.transform() if l.pose is not None else np.eye(4),
119
119
  )
@@ -437,29 +437,25 @@ class RigidContacts(ContactModel):
437
437
  def _compute_ineq_constraint_matrix(
438
438
  inactive_collidable_points: jtp.Vector, mu: jtp.FloatLike
439
439
  ) -> jtp.Matrix:
440
-
441
- def compute_G_single_point(mu: float, c: float) -> jtp.Matrix:
442
- """
443
- Compute the inequality constraint matrix for a single collidable point
444
- Rows 0-3: enforce the friction pyramid constraint,
445
- Row 4: last one is for the non negativity of the vertical force
446
- Row 5: contact complementarity condition
447
- """
448
- G_single_point = jnp.array(
449
- [
450
- [1, 0, -mu],
451
- [0, 1, -mu],
452
- [-1, 0, -mu],
453
- [0, -1, -mu],
454
- [0, 0, -1],
455
- [0, 0, c],
456
- ]
457
- )
458
- return G_single_point
459
-
460
- G = jax.vmap(compute_G_single_point, in_axes=(None, 0))(
461
- mu, inactive_collidable_points
440
+ """
441
+ Compute the inequality constraint matrix for a single collidable point
442
+ Rows 0-3: enforce the friction pyramid constraint,
443
+ Row 4: last one is for the non negativity of the vertical force
444
+ Row 5: contact complementarity condition
445
+ """
446
+ G_single_point = jnp.array(
447
+ [
448
+ [1, 0, -mu],
449
+ [0, 1, -mu],
450
+ [-1, 0, -mu],
451
+ [0, -1, -mu],
452
+ [0, 0, -1],
453
+ [0, 0, 0],
454
+ ]
462
455
  )
456
+ G = jnp.tile(G_single_point, (len(inactive_collidable_points), 1, 1))
457
+ G = G.at[:, 5, 2].set(inactive_collidable_points)
458
+
463
459
  G = jax.scipy.linalg.block_diag(*G)
464
460
  return G
465
461
 
@@ -498,28 +494,8 @@ class RigidContacts(ContactModel):
498
494
  D: jtp.FloatLike,
499
495
  ) -> jtp.Array:
500
496
 
501
- def baumgarte_stabilization_of_single_point(
502
- inactive: jtp.BoolLike,
503
- δ: jtp.FloatLike,
504
- δ_dot: jtp.FloatLike,
505
- n: jtp.ArrayLike,
506
- k_baumgarte: jtp.FloatLike,
507
- d_baumgarte: jtp.FloatLike,
508
- ) -> jtp.Array:
509
-
510
- baumgarte_term = jax.lax.cond(
511
- inactive,
512
- lambda δ, δ_dot, n, K, D: jnp.zeros(3),
513
- # This is equivalent to: K*(pT - p)⋅n̂ + D*(0 - v)⋅n̂,
514
- # where pT is the point on the terrain surface vertical to p.
515
- lambda δ, δ_dot, n, K, D: (K * δ + D * δ_dot) * n,
516
- *(δ, δ_dot, n, k_baumgarte, d_baumgarte),
517
- )
518
-
519
- return baumgarte_term
520
-
521
- baumgarte_term = jax.vmap(
522
- baumgarte_stabilization_of_single_point, in_axes=(0, 0, 0, 0, None, None)
523
- )(inactive_collidable_points, δ, δ_dot, n, K, D)
524
-
525
- return baumgarte_term
497
+ return jnp.where(
498
+ inactive_collidable_points[:, jnp.newaxis],
499
+ jnp.zeros_like(n),
500
+ (K * δ + D * δ_dot)[:, jnp.newaxis] * n,
501
+ )
@@ -407,10 +407,12 @@ class ViscoElasticContacts(common.ContactModel):
407
407
  # Compute the contact point dynamics
408
408
  # ==================================
409
409
 
410
- p_t0 = js.contact.collidable_point_positions(model, data)[indices, :]
411
- v_t0 = js.contact.collidable_point_velocities(model, data)[indices, :]
410
+ p_t0, v_t0 = js.contact.collidable_point_kinematics(model, data)
412
411
  m_t0 = data.state.extended["tangential_deformation"][indices, :]
413
412
 
413
+ p_t0 = p_t0[indices, :]
414
+ v_t0 = v_t0[indices, :]
415
+
414
416
  # Compute the linearized contact dynamics.
415
417
  # Note that it linearizes the (non-linear) contact model at (p, v, m)[t0].
416
418
  A, b, A_sc, b_sc = ViscoElasticContacts._contact_points_dynamics(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaxsim
3
- Version: 0.4.3.dev282
3
+ Version: 0.4.3.dev298
4
4
  Summary: A differentiable physics engine and multibody dynamics library for control and robot learning.
5
5
  Author-email: Diego Ferigo <dgferigo@gmail.com>
6
6
  Maintainer-email: Diego Ferigo <dgferigo@gmail.com>, Filippo Luca Ferretti <filippo.ferretti@iit.it>
@@ -1,27 +1,27 @@
1
1
  jaxsim/__init__.py,sha256=opgtbhhd1kDsHI4H1vOd3loMPDRi884yQ3tohfFGfNc,3382
2
- jaxsim/_version.py,sha256=8Lzzuj01bYiR6tHmTBRLQW2sSRCWlBO6B-razI_HdjU,428
2
+ jaxsim/_version.py,sha256=Pwqoke-57lWzujPjc0ocPWyiVHY0CgqE-ALFKL9bumE,428
3
3
  jaxsim/exceptions.py,sha256=vSoScaRD4nvh6jltgK9Ry5pKnE0O5hb4_yI_pk_fvR8,2175
4
4
  jaxsim/logging.py,sha256=STI-D_upXZYX-ZezLrlJJ0UlD5YspST0vZ_DcIwkzO4,1553
5
5
  jaxsim/typing.py,sha256=2HXy9hgazPXjofi1vLQ09ZubPtgVmg80U9NKmZ6NYiI,761
6
6
  jaxsim/api/__init__.py,sha256=8eV22t2S3UwNyCg8karPetG1dmX1VDBXkyv28_FwNQA,210
7
7
  jaxsim/api/com.py,sha256=m-p3EJDhpnMTlXKplfbZE_aH9NqX_VyLlAE3vUhc6l4,13642
8
8
  jaxsim/api/common.py,sha256=SNgxq42r6eF_-aPszvOjUYkGwXOzz4hKmhDwEUkscFQ,6650
9
- jaxsim/api/contact.py,sha256=iiQc8vdlJ60Vl-ki4ieP7TW6MJhJfWREYpcVyyEWT0M,24034
10
- jaxsim/api/data.py,sha256=gQX6hfEaw0ooJYvpr5f8UvEJwqhtflEK_NHWn9XgTZY,28935
9
+ jaxsim/api/contact.py,sha256=EM2pCPpFgbk0sjWBWZFYweRHfDNPa2jfnOZP6qjg-XY,24108
10
+ jaxsim/api/data.py,sha256=ThRpoBlbdwf1N3xs8SWrY5d8RbfdYRwFcmkdIPgtee4,29004
11
11
  jaxsim/api/frame.py,sha256=yPSgNygHkvWlln4wShNt7vZm_fFobVEm7phsklNNyH8,12922
12
- jaxsim/api/joint.py,sha256=iz7kHLLXMjlDOjKN0T6tcutWCnpnFAOA2IEE9GuxlQI,7304
13
- jaxsim/api/kin_dyn_parameters.py,sha256=kbDN5n9uj8CamVJXk1U5oYLbxyjaWDIeUG0V68DCEFs,29578
14
- jaxsim/api/link.py,sha256=LAA6ZMQXkWomXeptURBtc7z3_xDZ2BBnBMhVrohh0bE,18621
15
- jaxsim/api/model.py,sha256=dpQZDT0BodMfK1wmpG-STFh-rFsJStobQ1fhrWILK9o,73410
12
+ jaxsim/api/joint.py,sha256=Vl9VJs66_es88zjBBXqPzKkA3oAktV-DNiTkXwxOSsI,7562
13
+ jaxsim/api/kin_dyn_parameters.py,sha256=fRB7LPGTIwqunJGSq5YfMwSuy2yM_c5gZbsjN1K19Jw,29482
14
+ jaxsim/api/link.py,sha256=au47jV7bNdH2itvZ4qngKZyLi0UTIKzqVjjKosnlMsU,12858
15
+ jaxsim/api/model.py,sha256=ynzI2Us2XNVgcz_rasxVjE5575MC04YINsAxNP-B5sU,79472
16
16
  jaxsim/api/ode.py,sha256=_t18avoCJngQk6eMFTGpaeahbpchQP20qJnUOCPkz8s,15360
17
17
  jaxsim/api/ode_data.py,sha256=1SD-x-lYk_YSEnVpxTLd69uOKC0mFUj44ZqpSmEDOxw,20190
18
- jaxsim/api/references.py,sha256=fW77LitZ8DYgT6ZmUInJfm5luBV1mTcqcNRiC_i79og,20862
18
+ jaxsim/api/references.py,sha256=crPzgUCDHkTKUuXQcj9ygFAI0pewIx-fTPEsU8fBiU4,20555
19
19
  jaxsim/integrators/__init__.py,sha256=hxvOD-VK_mmd6v31wtC-nb28AYve1gLuZCNLV9wS-Kg,103
20
- jaxsim/integrators/common.py,sha256=_FZs7E0EazERGA3K0tGC1baUrs8sBDzYTf2U2mFYh9s,18329
20
+ jaxsim/integrators/common.py,sha256=8Y3PGVOydPBJrqYtH33rtng48T12ySWfXTk-ED_2wao,18297
21
21
  jaxsim/integrators/fixed_step.py,sha256=KpjRd6hHtapxDoo6D1kyDrVDSHnke2TepI5grFH7_bM,2693
22
22
  jaxsim/integrators/variable_step.py,sha256=hGYKG3Sq3QITgzIePmCVCrrirwagqsKnB3aYifAcKR4,22848
23
23
  jaxsim/math/__init__.py,sha256=8oPITEoGwgRcOeG8KxtqxPQ8b5uku1HNRMokpCoi9Tc,352
24
- jaxsim/math/adjoint.py,sha256=o1FCipkGwPtMbN2gFNIyUV8ADF3TX5fxElpTEXK0bIs,4377
24
+ jaxsim/math/adjoint.py,sha256=V7r5VrTCKPLEL5gavNSx9U7xSsrb11a5e4gWqJ2MuRo,4375
25
25
  jaxsim/math/cross.py,sha256=U7yEx_l75mSy5g6O-jsjBztApvxC3WaV4MpkS5tThu4,1330
26
26
  jaxsim/math/inertia.py,sha256=01hz6wMFreN2jBA0rVoBS1YMVh77KvwuzXSOpI3pxNk,1614
27
27
  jaxsim/math/joint_model.py,sha256=EzAveaG5B6ZnCFNUzN30KEQUVesd83lfWXJarYR-kUw,9989
@@ -43,7 +43,7 @@ jaxsim/parsers/descriptions/joint.py,sha256=VSb6C0FBBKMqwrHBKfc-Bbn4rl_J0RzUxMQl
43
43
  jaxsim/parsers/descriptions/link.py,sha256=Eh0W5qL7_Uw0GV-BkNKXhm9Q2dRTfIWCX5D-87zQkxA,3711
44
44
  jaxsim/parsers/descriptions/model.py,sha256=I2Vsbv8Josl4Le7b5rIvhqA2k9Bbv5JxMqwytayxds0,9833
45
45
  jaxsim/parsers/rod/__init__.py,sha256=G2vqlLajBLUc4gyzXwsEI2Wsi4TMOIF9bLDFeT6KrGU,92
46
- jaxsim/parsers/rod/parser.py,sha256=P3QFPdI2NBxL4TALcPhL6Exij9-Q9W716Aps2cb8s2I,14041
46
+ jaxsim/parsers/rod/parser.py,sha256=UAL6vkAab2y6PgIv3tAL8UodNbq-mmNBuBotxHJOSVU,14035
47
47
  jaxsim/parsers/rod/utils.py,sha256=5DsF3OeePZGidOJ5GiFSZx-51uIdnFvMW9EK6SgOW6Q,5698
48
48
  jaxsim/rbda/__init__.py,sha256=kmy4G9aMkrqPNGdLSaSV3k15dpF52vBEUQXDFDuKIxU,337
49
49
  jaxsim/rbda/aba.py,sha256=w7ciyxB0IsmueatT0C7PcBQEl9dyiH9oqJgIi3xeTUE,8983
@@ -56,17 +56,17 @@ jaxsim/rbda/utils.py,sha256=eeT21Y4DiiyhrdF0lUE_VvRuwru5-rR7yOlOlWzCCWE,5381
56
56
  jaxsim/rbda/contacts/__init__.py,sha256=L5MM-2pv76YPGzxExdz2EErgGBATuAjYnNHlq5QOySs,503
57
57
  jaxsim/rbda/contacts/common.py,sha256=ELASrMnkFuUZBRDPKu-HO7ymUukK3r-VZw9TjqOSZgM,11174
58
58
  jaxsim/rbda/contacts/relaxed_rigid.py,sha256=6EWTkHjixSv-9pBl7aO_abOxHrneUQKF6uUyt5Vbbuc,20512
59
- jaxsim/rbda/contacts/rigid.py,sha256=I_FrJv4rK9Lzj4i0EMaZHxOGyrPT_XuQUg6ZUzvp4y8,17943
59
+ jaxsim/rbda/contacts/rigid.py,sha256=q9hXH2FpqAAf4UVt_BPUQ5DrLgitEARIu4j3kKr3Wpg,17005
60
60
  jaxsim/rbda/contacts/soft.py,sha256=wqwnsg0abWn64pYG7je08fsBwdgyJdd2k7dAG0Sx0_k,16432
61
- jaxsim/rbda/contacts/visco_elastic.py,sha256=S1GsYZQa8vMS1EtGmS7_Ql07h2AhJEmO67iShkGWmIU,41443
61
+ jaxsim/rbda/contacts/visco_elastic.py,sha256=vQkfMuqQ3Qu8nbDTPY4jWBZjV3U7qtoRK1Aya3O3oFA,41424
62
62
  jaxsim/terrain/__init__.py,sha256=f7lVX-iNpH_wkkjef9Qpjh19TTAUOQw76EiLYJDVizc,78
63
63
  jaxsim/terrain/terrain.py,sha256=K91HEzPqTSyNrc_j1KfAAEF_5oDeuk_-jnnZGrcMEcY,5015
64
64
  jaxsim/utils/__init__.py,sha256=Y5zyoRevl3EMVQadhZ4EtSwTEkDt2vcnFoRhPJjKTZ0,215
65
65
  jaxsim/utils/jaxsim_dataclass.py,sha256=TGmTQV2Lq7Q-2nLoAEaeNtkPa_qj0IKkdBm4COj46Os,11312
66
66
  jaxsim/utils/tracing.py,sha256=KDMoyVPlu2NJvFkhtZwq5AkqMMgajt3munvJom-vEjQ,650
67
67
  jaxsim/utils/wrappers.py,sha256=Fh82ZcaFi5fUnByyFLnmumaobsu1hJIvFdopUVzJ1ps,4052
68
- jaxsim-0.4.3.dev282.dist-info/LICENSE,sha256=eaYdFmdeMbiIoIiPzEK0MjP1S9wtFXjXNR5er49uLR0,1546
69
- jaxsim-0.4.3.dev282.dist-info/METADATA,sha256=Llp_WIbsROSnrBpSMJUdFnAOOkLDobo5f87CO8xvOuA,17276
70
- jaxsim-0.4.3.dev282.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
71
- jaxsim-0.4.3.dev282.dist-info/top_level.txt,sha256=LxGMA8FLtXjQ6oI7N5gd_R_oSUHxpXxUEOfT1xS_ni0,7
72
- jaxsim-0.4.3.dev282.dist-info/RECORD,,
68
+ jaxsim-0.4.3.dev298.dist-info/LICENSE,sha256=eaYdFmdeMbiIoIiPzEK0MjP1S9wtFXjXNR5er49uLR0,1546
69
+ jaxsim-0.4.3.dev298.dist-info/METADATA,sha256=2QuLbV-zLRmC7baPpENbJ9CXPiOoYuEzZEmpovjyQtw,17276
70
+ jaxsim-0.4.3.dev298.dist-info/WHEEL,sha256=a7TGlA-5DaHMRrarXjVbQagU3Man_dCnGIWMJr5kRWo,91
71
+ jaxsim-0.4.3.dev298.dist-info/top_level.txt,sha256=LxGMA8FLtXjQ6oI7N5gd_R_oSUHxpXxUEOfT1xS_ni0,7
72
+ jaxsim-0.4.3.dev298.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5