warp-lang 1.5.1__py3-none-win_amd64.whl → 1.6.0__py3-none-win_amd64.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.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (123) hide show
  1. warp/__init__.py +5 -0
  2. warp/autograd.py +414 -191
  3. warp/bin/warp-clang.dll +0 -0
  4. warp/bin/warp.dll +0 -0
  5. warp/build.py +40 -12
  6. warp/build_dll.py +13 -6
  7. warp/builtins.py +1076 -480
  8. warp/codegen.py +240 -119
  9. warp/config.py +1 -1
  10. warp/context.py +298 -84
  11. warp/examples/assets/square_cloth.usd +0 -0
  12. warp/examples/benchmarks/benchmark_gemm.py +27 -18
  13. warp/examples/benchmarks/benchmark_interop_paddle.py +3 -3
  14. warp/examples/benchmarks/benchmark_interop_torch.py +3 -3
  15. warp/examples/core/example_torch.py +18 -34
  16. warp/examples/fem/example_apic_fluid.py +1 -0
  17. warp/examples/fem/example_mixed_elasticity.py +1 -1
  18. warp/examples/optim/example_bounce.py +1 -1
  19. warp/examples/optim/example_cloth_throw.py +1 -1
  20. warp/examples/optim/example_diffray.py +4 -15
  21. warp/examples/optim/example_drone.py +1 -1
  22. warp/examples/optim/example_softbody_properties.py +392 -0
  23. warp/examples/optim/example_trajectory.py +1 -3
  24. warp/examples/optim/example_walker.py +5 -0
  25. warp/examples/sim/example_cartpole.py +0 -2
  26. warp/examples/sim/example_cloth_self_contact.py +260 -0
  27. warp/examples/sim/example_granular_collision_sdf.py +4 -5
  28. warp/examples/sim/example_jacobian_ik.py +0 -2
  29. warp/examples/sim/example_quadruped.py +5 -2
  30. warp/examples/tile/example_tile_cholesky.py +79 -0
  31. warp/examples/tile/example_tile_convolution.py +2 -2
  32. warp/examples/tile/example_tile_fft.py +2 -2
  33. warp/examples/tile/example_tile_filtering.py +3 -3
  34. warp/examples/tile/example_tile_matmul.py +4 -4
  35. warp/examples/tile/example_tile_mlp.py +12 -12
  36. warp/examples/tile/example_tile_nbody.py +180 -0
  37. warp/examples/tile/example_tile_walker.py +319 -0
  38. warp/math.py +147 -0
  39. warp/native/array.h +12 -0
  40. warp/native/builtin.h +0 -1
  41. warp/native/bvh.cpp +149 -70
  42. warp/native/bvh.cu +287 -68
  43. warp/native/bvh.h +195 -85
  44. warp/native/clang/clang.cpp +5 -1
  45. warp/native/cuda_util.cpp +35 -0
  46. warp/native/cuda_util.h +5 -0
  47. warp/native/exports.h +40 -40
  48. warp/native/intersect.h +17 -0
  49. warp/native/mat.h +41 -0
  50. warp/native/mathdx.cpp +19 -0
  51. warp/native/mesh.cpp +25 -8
  52. warp/native/mesh.cu +153 -101
  53. warp/native/mesh.h +482 -403
  54. warp/native/quat.h +40 -0
  55. warp/native/solid_angle.h +7 -0
  56. warp/native/sort.cpp +85 -0
  57. warp/native/sort.cu +34 -0
  58. warp/native/sort.h +3 -1
  59. warp/native/spatial.h +11 -0
  60. warp/native/tile.h +1185 -664
  61. warp/native/tile_reduce.h +8 -6
  62. warp/native/vec.h +41 -0
  63. warp/native/warp.cpp +8 -1
  64. warp/native/warp.cu +263 -40
  65. warp/native/warp.h +19 -5
  66. warp/optim/linear.py +22 -4
  67. warp/render/render_opengl.py +124 -59
  68. warp/sim/__init__.py +6 -1
  69. warp/sim/collide.py +270 -26
  70. warp/sim/integrator_euler.py +25 -7
  71. warp/sim/integrator_featherstone.py +154 -35
  72. warp/sim/integrator_vbd.py +842 -40
  73. warp/sim/model.py +111 -53
  74. warp/stubs.py +248 -115
  75. warp/tape.py +28 -30
  76. warp/tests/aux_test_module_unload.py +15 -0
  77. warp/tests/{test_sim_grad.py → flaky_test_sim_grad.py} +104 -63
  78. warp/tests/test_array.py +74 -0
  79. warp/tests/test_assert.py +242 -0
  80. warp/tests/test_codegen.py +14 -61
  81. warp/tests/test_collision.py +2 -2
  82. warp/tests/test_examples.py +9 -0
  83. warp/tests/test_grad_debug.py +87 -2
  84. warp/tests/test_hash_grid.py +1 -1
  85. warp/tests/test_ipc.py +116 -0
  86. warp/tests/test_mat.py +138 -167
  87. warp/tests/test_math.py +47 -1
  88. warp/tests/test_matmul.py +11 -7
  89. warp/tests/test_matmul_lite.py +4 -4
  90. warp/tests/test_mesh.py +84 -60
  91. warp/tests/test_mesh_query_aabb.py +165 -0
  92. warp/tests/test_mesh_query_point.py +328 -286
  93. warp/tests/test_mesh_query_ray.py +134 -121
  94. warp/tests/test_mlp.py +2 -2
  95. warp/tests/test_operators.py +43 -0
  96. warp/tests/test_overwrite.py +2 -2
  97. warp/tests/test_quat.py +77 -0
  98. warp/tests/test_reload.py +29 -0
  99. warp/tests/test_sim_grad_bounce_linear.py +204 -0
  100. warp/tests/test_static.py +16 -0
  101. warp/tests/test_tape.py +25 -0
  102. warp/tests/test_tile.py +134 -191
  103. warp/tests/test_tile_load.py +356 -0
  104. warp/tests/test_tile_mathdx.py +61 -8
  105. warp/tests/test_tile_mlp.py +17 -17
  106. warp/tests/test_tile_reduce.py +24 -18
  107. warp/tests/test_tile_shared_memory.py +66 -17
  108. warp/tests/test_tile_view.py +165 -0
  109. warp/tests/test_torch.py +35 -0
  110. warp/tests/test_utils.py +36 -24
  111. warp/tests/test_vec.py +110 -0
  112. warp/tests/unittest_suites.py +29 -4
  113. warp/tests/unittest_utils.py +30 -11
  114. warp/thirdparty/unittest_parallel.py +2 -2
  115. warp/types.py +409 -99
  116. warp/utils.py +9 -5
  117. {warp_lang-1.5.1.dist-info → warp_lang-1.6.0.dist-info}/METADATA +68 -44
  118. {warp_lang-1.5.1.dist-info → warp_lang-1.6.0.dist-info}/RECORD +121 -110
  119. {warp_lang-1.5.1.dist-info → warp_lang-1.6.0.dist-info}/WHEEL +1 -1
  120. warp/examples/benchmarks/benchmark_tile.py +0 -179
  121. warp/native/tile_gemm.h +0 -341
  122. {warp_lang-1.5.1.dist-info → warp_lang-1.6.0.dist-info}/LICENSE.md +0 -0
  123. {warp_lang-1.5.1.dist-info → warp_lang-1.6.0.dist-info}/top_level.txt +0 -0
warp/tape.py CHANGED
@@ -43,7 +43,6 @@ class Tape:
43
43
 
44
44
  def __init__(self):
45
45
  self.gradients = {}
46
- self.const_gradients = set()
47
46
  self.launches = []
48
47
  self.scopes = []
49
48
 
@@ -106,7 +105,6 @@ class Tape:
106
105
  else:
107
106
  # ensure we can capture this backward pass in a CUDA graph
108
107
  a.grad.assign(g)
109
- self.const_gradients.add(a)
110
108
 
111
109
  # run launches backwards
112
110
  for launch in reversed(self.launches):
@@ -115,13 +113,13 @@ class Tape:
115
113
 
116
114
  else:
117
115
  # kernel option takes precedence over module option
118
- kernel_enable_backward = launch[0].options.get("enable_backward")
119
- if kernel_enable_backward is False:
116
+ enable_backward = launch[0].options.get("enable_backward")
117
+ if enable_backward is False:
120
118
  msg = f"Running the tape backwards may produce incorrect gradients because recorded kernel {launch[0].key} is configured with the option 'enable_backward=False'."
121
119
  wp.utils.warn(msg)
122
- elif kernel_enable_backward is None:
123
- module_enable_backward = launch[0].module.options.get("enable_backward")
124
- if module_enable_backward is False:
120
+ elif enable_backward is None:
121
+ enable_backward = launch[0].module.options.get("enable_backward")
122
+ if enable_backward is False:
125
123
  msg = f"Running the tape backwards may produce incorrect gradients because recorded kernel {launch[0].key} is defined in a module with the option 'enable_backward=False' set."
126
124
  wp.utils.warn(msg)
127
125
 
@@ -144,18 +142,19 @@ class Tape:
144
142
  for a in outputs:
145
143
  adj_outputs.append(self.get_adjoint(a))
146
144
 
147
- wp.launch(
148
- kernel=kernel,
149
- dim=dim,
150
- inputs=inputs,
151
- outputs=outputs,
152
- adj_inputs=adj_inputs,
153
- adj_outputs=adj_outputs,
154
- device=device,
155
- adjoint=True,
156
- max_blocks=max_blocks,
157
- block_dim=block_dim,
158
- )
145
+ if enable_backward:
146
+ wp.launch(
147
+ kernel=kernel,
148
+ dim=dim,
149
+ inputs=inputs,
150
+ outputs=outputs,
151
+ adj_inputs=adj_inputs,
152
+ adj_outputs=adj_outputs,
153
+ device=device,
154
+ adjoint=True,
155
+ max_blocks=max_blocks,
156
+ block_dim=block_dim,
157
+ )
159
158
 
160
159
  # record a kernel launch on the tape
161
160
  def record_launch(self, kernel, dim, max_blocks, inputs, outputs, device, block_dim=0, metadata=None):
@@ -222,9 +221,9 @@ class Tape:
222
221
  # returns the adjoint of a kernel parameter
223
222
  def get_adjoint(self, a):
224
223
  if not wp.types.is_array(a) and not isinstance(a, wp.codegen.StructInstance):
225
- # if input is a simple type (e.g.: float, vec3, etc) then
226
- # no gradient needed (we only return gradients through arrays and structs)
227
- return a
224
+ # if input is a simple type (e.g.: float, vec3, etc) or a non-Warp array,
225
+ # then no gradient needed (we only return gradients through Warp arrays and structs)
226
+ return None
228
227
 
229
228
  elif wp.types.is_array(a) and a.grad:
230
229
  # keep track of all gradients used by the tape (for zeroing)
@@ -267,13 +266,12 @@ class Tape:
267
266
  Zero out all gradients recorded on the tape.
268
267
  """
269
268
  for a, g in self.gradients.items():
270
- if a not in self.const_gradients:
271
- if isinstance(a, wp.codegen.StructInstance):
272
- for name in g._cls.vars:
273
- if isinstance(g._cls.vars[name].type, wp.array) and g._cls.vars[name].requires_grad:
274
- getattr(g, name).zero_()
275
- else:
276
- g.zero_()
269
+ if isinstance(a, wp.codegen.StructInstance):
270
+ for name in g._cls.vars:
271
+ if isinstance(g._cls.vars[name].type, wp.array) and g._cls.vars[name].requires_grad:
272
+ getattr(g, name).zero_()
273
+ else:
274
+ g.zero_()
277
275
 
278
276
  def _reset_array_read_flags(self):
279
277
  """
@@ -517,7 +515,7 @@ class GraphvizTapeVisitor(TapeVisitor):
517
515
  node_attrs = f"label=<{label}>"
518
516
  if "caller" in launch_data:
519
517
  caller = launch_data["caller"]
520
- node_attrs += f",tooltip=\"{self.sanitize(caller['file'])}:{caller['lineno']} ({caller['func']})\""
518
+ node_attrs += f',tooltip="{self.sanitize(caller["file"])}:{caller["lineno"]} ({caller["func"]})"'
521
519
 
522
520
  self.graphviz_lines.append(f"{chart_indent}{kernel_launch_id} [{node_attrs}];")
523
521
 
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ """Dummy module used in test_reload.py"""
9
+
10
+ import warp as wp
11
+
12
+
13
+ @wp.kernel
14
+ def k():
15
+ pass
@@ -11,6 +11,7 @@ import numpy as np
11
11
 
12
12
  import warp as wp
13
13
  import warp.sim
14
+ import warp.sim.render
14
15
  from warp.tests.unittest_utils import *
15
16
 
16
17
 
@@ -23,8 +24,7 @@ def evaluate_loss(
23
24
  loss: wp.array(dtype=float),
24
25
  ):
25
26
  tid = wp.tid()
26
- # wp.atomic_add(loss, 0, weighting * (target - joint_q[tid * 2 + 1]) ** 2.0)
27
- d = wp.abs(target - joint_q[tid * 2 + 1])
27
+ d = (target - joint_q[tid * 2 + 1]) ** 2.0
28
28
  wp.atomic_add(loss, 0, weighting * d)
29
29
 
30
30
 
@@ -34,7 +34,13 @@ def assign_action(action: wp.array(dtype=float), joint_act: wp.array(dtype=float
34
34
  joint_act[2 * tid] = action[tid]
35
35
 
36
36
 
37
- def gradcheck(func, inputs, device, eps=1e-1, tol=1e-2):
37
+ @wp.kernel
38
+ def assign_force(action: wp.array(dtype=float), body_f: wp.array(dtype=wp.spatial_vector)):
39
+ tid = wp.tid()
40
+ body_f[2 * tid] = wp.spatial_vector(0.0, 0.0, 0.0, action[tid], 0.0, 0.0)
41
+
42
+
43
+ def gradcheck(func, inputs, device, eps=1e-1, tol=1e-2, print_grad=False):
38
44
  """
39
45
  Checks that the gradient of the Warp kernel is correct by comparing it to the
40
46
  numerical gradient computed using finite differences.
@@ -46,56 +52,64 @@ def gradcheck(func, inputs, device, eps=1e-1, tol=1e-2):
46
52
  output = func(*wp_xs)
47
53
  return output.numpy()[0]
48
54
 
55
+ # compute analytical gradient
56
+ tape = wp.Tape()
57
+ with tape:
58
+ output = func(*inputs)
59
+
60
+ tape.backward(loss=output)
61
+
49
62
  # compute numerical gradient
50
- numerical_grad = []
51
63
  np_xs = []
52
64
  for i in range(len(inputs)):
53
65
  np_xs.append(inputs[i].numpy().flatten().copy())
54
- numerical_grad.append(np.zeros_like(np_xs[-1]))
55
- inputs[i].requires_grad = True
56
66
 
57
- for i in range(len(np_xs)):
67
+ for i in range(len(inputs)):
68
+ fd_grad = np.zeros_like(np_xs[i])
58
69
  for j in range(len(np_xs[i])):
59
70
  np_xs[i][j] += eps
60
71
  y1 = f(np_xs)
61
72
  np_xs[i][j] -= 2 * eps
62
73
  y2 = f(np_xs)
63
74
  np_xs[i][j] += eps
64
- numerical_grad[i][j] = (y1 - y2) / (2 * eps)
65
-
66
- # compute analytical gradient
67
- tape = wp.Tape()
68
- with tape:
69
- output = func(*inputs)
70
-
71
- tape.backward(loss=output)
72
-
73
- # compare gradients
74
- for i in range(len(inputs)):
75
- grad = tape.gradients[inputs[i]]
76
- assert_np_equal(grad.numpy(), numerical_grad[i], tol=tol)
75
+ fd_grad[j] = (y1 - y2) / (2 * eps)
76
+
77
+ # compare gradients
78
+ ad_grad = tape.gradients[inputs[i]].numpy()
79
+ if print_grad:
80
+ print("grad ad:", ad_grad)
81
+ print("grad fd:", fd_grad)
82
+ assert_np_equal(ad_grad, fd_grad, tol=tol)
77
83
  # ensure the signs match
78
- assert np.allclose(grad.numpy() * numerical_grad[i] > 0, True)
84
+ assert np.allclose(ad_grad * fd_grad > 0, True)
79
85
 
80
86
  tape.zero()
81
87
 
82
88
 
83
- def test_box_pushing_on_rails(test, device, joint_type, integrator_type):
84
- # Two boxes on a rail (prismatic or D6 joint), one is pushed, the other is passive.
89
+ def test_sphere_pushing_on_rails(
90
+ test,
91
+ device,
92
+ joint_type,
93
+ integrator_type,
94
+ apply_force=False,
95
+ static_contacts=True,
96
+ print_grad=False,
97
+ ):
98
+ # Two spheres on a rail (prismatic or D6 joint), one is pushed, the other is passive.
85
99
  # The absolute distance to a target is measured and gradients are compared for
86
100
  # a push that is too far and too close.
87
101
  num_envs = 2
88
- num_steps = 200
89
- sim_substeps = 2
102
+ num_steps = 150
103
+ sim_substeps = 10
90
104
  dt = 1 / 30
91
105
 
92
- target = 5.0
106
+ target = 3.0
93
107
 
94
108
  if integrator_type == 0:
95
- contact_ke = 1e5
96
- contact_kd = 1e3
109
+ contact_ke = 1e3
110
+ contact_kd = 1e1
97
111
  else:
98
- contact_ke = 1e5
112
+ contact_ke = 1e3
99
113
  contact_kd = 1e1
100
114
 
101
115
  complete_builder = wp.sim.ModelBuilder()
@@ -104,16 +118,16 @@ def test_box_pushing_on_rails(test, device, joint_type, integrator_type):
104
118
  complete_builder.default_shape_kd = contact_kd
105
119
 
106
120
  for _ in range(num_envs):
107
- builder = wp.sim.ModelBuilder()
121
+ builder = wp.sim.ModelBuilder(gravity=0.0)
108
122
 
109
123
  builder.default_shape_ke = complete_builder.default_shape_ke
110
124
  builder.default_shape_kd = complete_builder.default_shape_kd
111
125
 
112
126
  b0 = builder.add_body(name="pusher")
113
- builder.add_shape_box(b0, density=1000.0)
127
+ builder.add_shape_sphere(b0, radius=0.4, density=100.0)
114
128
 
115
129
  b1 = builder.add_body(name="passive")
116
- builder.add_shape_box(b1, hx=0.4, hy=0.4, hz=0.4, density=1000.0)
130
+ builder.add_shape_sphere(b1, radius=0.47, density=100.0)
117
131
 
118
132
  if joint_type == 0:
119
133
  builder.add_joint_prismatic(-1, b0)
@@ -122,7 +136,7 @@ def test_box_pushing_on_rails(test, device, joint_type, integrator_type):
122
136
  builder.add_joint_d6(-1, b0, linear_axes=[wp.sim.JointAxis((1.0, 0.0, 0.0))])
123
137
  builder.add_joint_d6(-1, b1, linear_axes=[wp.sim.JointAxis((1.0, 0.0, 0.0))])
124
138
 
125
- builder.joint_q[-2:] = [0.0, 1.0]
139
+ builder.joint_q[-2:] = [0.0, 2.0]
126
140
  complete_builder.add_builder(builder)
127
141
 
128
142
  assert complete_builder.body_count == 2 * num_envs
@@ -135,6 +149,15 @@ def test_box_pushing_on_rails(test, device, joint_type, integrator_type):
135
149
  model.joint_attach_ke = 32000.0 * 16
136
150
  model.joint_attach_kd = 500.0 * 4
137
151
 
152
+ model.shape_geo.scale.requires_grad = False
153
+ model.shape_geo.thickness.requires_grad = False
154
+
155
+ if static_contacts:
156
+ wp.sim.eval_fk(model, model.joint_q, model.joint_qd, None, model)
157
+ model.rigid_contact_margin = 10.0
158
+ state = model.state()
159
+ wp.sim.collide(model, state)
160
+
138
161
  if integrator_type == 0:
139
162
  integrator = wp.sim.FeatherstoneIntegrator(model, update_mass_matrix_every=num_steps * sim_substeps)
140
163
  elif integrator_type == 1:
@@ -143,40 +166,57 @@ def test_box_pushing_on_rails(test, device, joint_type, integrator_type):
143
166
  else:
144
167
  integrator = wp.sim.XPBDIntegrator(iterations=2, rigid_contact_relaxation=1.0)
145
168
 
146
- # renderer = wp.sim.render.SimRenderer(model, "test_sim_grad.usd", scaling=1.0)
169
+ # renderer = wp.sim.render.SimRendererOpenGL(model, "test_sim_grad.usd", scaling=1.0)
147
170
  renderer = None
148
171
  render_time = 0.0
149
172
 
173
+ if renderer:
174
+ renderer.render_sphere("target", pos=wp.vec3(target, 0, 0), rot=wp.quat_identity(), radius=0.1, color=(1, 0, 0))
175
+
150
176
  def rollout(action: wp.array) -> wp.array:
151
177
  nonlocal render_time
152
178
  states = [model.state() for _ in range(num_steps * sim_substeps + 1)]
153
179
 
154
- if not isinstance(integrator, wp.sim.FeatherstoneIntegrator):
155
- # apply initial generalized coordinates
156
- wp.sim.eval_fk(model, model.joint_q, model.joint_qd, None, states[0])
180
+ wp.sim.eval_fk(model, model.joint_q, model.joint_qd, None, states[0])
157
181
 
158
182
  control_active = model.control()
159
183
  control_nop = model.control()
160
184
 
161
- wp.launch(
162
- assign_action,
163
- dim=num_envs,
164
- inputs=[action],
165
- outputs=[control_active.joint_act],
166
- device=model.device,
167
- )
185
+ if not apply_force:
186
+ wp.launch(
187
+ assign_action,
188
+ dim=num_envs,
189
+ inputs=[action],
190
+ outputs=[control_active.joint_act],
191
+ device=model.device,
192
+ )
168
193
 
169
194
  i = 0
170
195
  for step in range(num_steps):
171
- wp.sim.collide(model, states[i])
172
- control = control_active if step < 10 else control_nop
196
+ state = states[i]
197
+ if not static_contacts:
198
+ wp.sim.collide(model, state)
199
+ if apply_force:
200
+ control = control_nop
201
+ else:
202
+ control = control_active if step < 10 else control_nop
173
203
  if renderer:
174
204
  renderer.begin_frame(render_time)
175
- renderer.render(states[i])
205
+ renderer.render(state)
176
206
  renderer.end_frame()
177
207
  render_time += dt
178
208
  for _ in range(sim_substeps):
179
- integrator.simulate(model, states[i], states[i + 1], dt / sim_substeps, control)
209
+ state = states[i]
210
+ next_state = states[i + 1]
211
+ if apply_force and step < 10:
212
+ wp.launch(
213
+ assign_force,
214
+ dim=num_envs,
215
+ inputs=[action],
216
+ outputs=[state.body_f],
217
+ device=model.device,
218
+ )
219
+ integrator.simulate(model, state, next_state, dt / sim_substeps, control)
180
220
  i += 1
181
221
 
182
222
  if not isinstance(integrator, wp.sim.FeatherstoneIntegrator):
@@ -184,39 +224,40 @@ def test_box_pushing_on_rails(test, device, joint_type, integrator_type):
184
224
  wp.sim.eval_ik(model, states[-1], states[-1].joint_q, states[-1].joint_qd)
185
225
 
186
226
  loss = wp.zeros(1, requires_grad=True, device=device)
227
+ weighting = 1.0
187
228
  wp.launch(
188
229
  evaluate_loss,
189
230
  dim=num_envs,
190
- inputs=[states[-1].joint_q, 1.0, target],
231
+ inputs=[states[-1].joint_q, weighting, target],
191
232
  outputs=[loss],
192
233
  device=model.device,
193
234
  )
194
235
 
195
- if renderer:
196
- renderer.save()
236
+ # if renderer:
237
+ # renderer.save()
197
238
 
198
239
  return loss
199
240
 
200
241
  action_too_far = wp.array(
201
- [5000.0 for _ in range(num_envs)],
242
+ [80.0 for _ in range(num_envs)],
202
243
  device=device,
203
244
  dtype=wp.float32,
204
245
  requires_grad=True,
205
246
  )
206
- tol = 1e-2
247
+ tol = 2e-1
207
248
  if isinstance(integrator, wp.sim.XPBDIntegrator):
208
249
  # Euler, XPBD do not yield as accurate gradients, but at least the
209
250
  # signs should match
210
251
  tol = 0.1
211
- gradcheck(rollout, [action_too_far], device=device, eps=0.2, tol=tol)
252
+ gradcheck(rollout, [action_too_far], device=device, eps=0.2, tol=tol, print_grad=print_grad)
212
253
 
213
254
  action_too_close = wp.array(
214
- [1500.0 for _ in range(num_envs)],
255
+ [40.0 for _ in range(num_envs)],
215
256
  device=device,
216
257
  dtype=wp.float32,
217
258
  requires_grad=True,
218
259
  )
219
- gradcheck(rollout, [action_too_close], device=device, eps=0.2, tol=tol)
260
+ gradcheck(rollout, [action_too_close], device=device, eps=0.2, tol=tol, print_grad=print_grad)
220
261
 
221
262
 
222
263
  devices = get_test_devices()
@@ -226,15 +267,15 @@ class TestSimGradients(unittest.TestCase):
226
267
  pass
227
268
 
228
269
 
229
- for int_type, int_name in enumerate(["featherstone", "semiimplicit"]):
230
- for jt_type, jt_name in enumerate(["prismatic", "d6"]):
231
- test_name = f"test_box_pushing_on_rails_{int_name}_{jt_name}"
270
+ for jt_type, jt_name in enumerate(["prismatic", "d6"]):
271
+ test_name = f"test_sphere_pushing_on_rails_{jt_name}"
232
272
 
233
- def test_fn(self, device, jt_type=jt_type, int_type=int_type):
234
- return test_box_pushing_on_rails(self, device, jt_type, int_type)
235
-
236
- add_function_test(TestSimGradients, test_name, test_fn, devices=devices)
273
+ def test_fn(self, device, jt_type=jt_type, int_type=1):
274
+ return test_sphere_pushing_on_rails(
275
+ self, device, jt_type, int_type, apply_force=True, static_contacts=True, print_grad=False
276
+ )
237
277
 
278
+ add_function_test(TestSimGradients, test_name, test_fn, devices=devices)
238
279
 
239
280
  if __name__ == "__main__":
240
281
  wp.clear_kernel_cache()
warp/tests/test_array.py CHANGED
@@ -2766,6 +2766,76 @@ def test_indexing_types(test, device):
2766
2766
  )
2767
2767
 
2768
2768
 
2769
+ def test_alloc_strides(test, device):
2770
+ def test_transposed(shape, dtype):
2771
+ # allocate without specifying strides
2772
+ a1 = wp.zeros(shape, dtype=dtype)
2773
+
2774
+ # allocate with contiguous strides
2775
+ strides = wp.types.strides_from_shape(shape, dtype)
2776
+ a2 = wp.zeros(shape, dtype=dtype, strides=strides)
2777
+
2778
+ # allocate with transposed (reversed) shape/strides
2779
+ rshape = shape[::-1]
2780
+ rstrides = strides[::-1]
2781
+ a3 = wp.zeros(rshape, dtype=dtype, strides=rstrides)
2782
+
2783
+ # ensure that correct capacity was allocated
2784
+ assert a2.capacity == a1.capacity
2785
+ assert a3.capacity == a1.capacity
2786
+
2787
+ with wp.ScopedDevice(device):
2788
+ shapes = [(5, 5), (5, 3), (3, 5), (2, 3, 4), (4, 2, 3), (3, 2, 4)]
2789
+ for shape in shapes:
2790
+ with test.subTest(msg=f"shape={shape}"):
2791
+ test_transposed(shape, wp.int8)
2792
+ test_transposed(shape, wp.float32)
2793
+ test_transposed(shape, wp.vec3)
2794
+
2795
+
2796
+ def test_casting(test, device):
2797
+ idxs = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
2798
+ idxs = wp.array(idxs, device=device).reshape((-1, 3))
2799
+ idxs = wp.array(idxs, shape=idxs.shape[0], dtype=wp.vec3i, device=device)
2800
+ assert idxs.dtype is wp.vec3i
2801
+ assert idxs.shape == (4,)
2802
+ assert idxs.strides == (12,)
2803
+
2804
+
2805
+ @wp.kernel
2806
+ def array_len_kernel(
2807
+ a1: wp.array(dtype=int),
2808
+ a2: wp.array(dtype=float, ndim=3),
2809
+ out: wp.array(dtype=int),
2810
+ ):
2811
+ length = len(a1)
2812
+ wp.expect_eq(len(a1), 123)
2813
+ out[0] = len(a1)
2814
+
2815
+ length = len(a2)
2816
+ wp.expect_eq(len(a2), 2)
2817
+ out[1] = len(a2)
2818
+
2819
+
2820
+ def test_array_len(test, device):
2821
+ a1 = wp.zeros(123, dtype=int, device=device)
2822
+ a2 = wp.zeros((2, 3, 4), dtype=float, device=device)
2823
+ out = wp.empty(2, dtype=int, device=device)
2824
+ wp.launch(
2825
+ array_len_kernel,
2826
+ dim=(1,),
2827
+ inputs=(
2828
+ a1,
2829
+ a2,
2830
+ ),
2831
+ outputs=(out,),
2832
+ device=device,
2833
+ )
2834
+
2835
+ test.assertEqual(out.numpy()[0], 123)
2836
+ test.assertEqual(out.numpy()[1], 2)
2837
+
2838
+
2769
2839
  devices = get_test_devices()
2770
2840
 
2771
2841
 
@@ -2835,6 +2905,10 @@ add_function_test(TestArray, "test_array_from_int32_domain", test_array_from_int
2835
2905
  add_function_test(TestArray, "test_array_from_int64_domain", test_array_from_int64_domain, devices=devices)
2836
2906
  add_function_test(TestArray, "test_indexing_types", test_indexing_types, devices=devices)
2837
2907
 
2908
+ add_function_test(TestArray, "test_alloc_strides", test_alloc_strides, devices=devices)
2909
+ add_function_test(TestArray, "test_casting", test_casting, devices=devices)
2910
+ add_function_test(TestArray, "test_array_len", test_array_len, devices=devices)
2911
+
2838
2912
  try:
2839
2913
  import torch
2840
2914