warp-lang 1.5.1__py3-none-manylinux2014_x86_64.whl → 1.6.0__py3-none-manylinux2014_x86_64.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.so +0 -0
  4. warp/bin/warp.so +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
@@ -0,0 +1,204 @@
1
+ # Copyright (c) 2025 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
+ import numpy as np
9
+
10
+ import warp as wp
11
+ import warp.optim
12
+ import warp.sim
13
+ import warp.sim.render
14
+ from warp.tests.unittest_utils import *
15
+
16
+
17
+ @wp.kernel
18
+ def update_trajectory_kernel(
19
+ trajectory: wp.array(dtype=wp.vec3),
20
+ q: wp.array(dtype=wp.transform),
21
+ time_step: wp.int32,
22
+ q_idx: wp.int32,
23
+ ):
24
+ trajectory[time_step] = wp.transform_get_translation(q[q_idx])
25
+
26
+
27
+ @wp.kernel
28
+ def trajectory_loss_kernel(
29
+ trajectory: wp.array(dtype=wp.vec3f),
30
+ target_trajectory: wp.array(dtype=wp.vec3f),
31
+ loss: wp.array(dtype=wp.float32),
32
+ ):
33
+ tid = wp.tid()
34
+ diff = trajectory[tid] - target_trajectory[tid]
35
+ distance_loss = wp.dot(diff, diff)
36
+ wp.atomic_add(loss, 0, distance_loss)
37
+
38
+
39
+ class BallBounceLinearTest:
40
+ def __init__(self, gravity=True, rendering=False):
41
+ # Ball bouncing scenario inspired by https://github.com/NVIDIA/warp/issues/349
42
+ self.fps = 30
43
+ self.num_frames = 60
44
+ self.sim_substeps = 20 # XXX need to use enough substeps to achieve smooth gradients
45
+ self.frame_dt = 1.0 / self.fps
46
+ self.sim_dt = self.frame_dt / self.sim_substeps
47
+ self.sim_duration = self.num_frames * self.frame_dt
48
+ self.sim_steps = int(self.sim_duration // self.sim_dt)
49
+
50
+ self.target_force_linear = 100.0
51
+
52
+ if gravity:
53
+ builder = wp.sim.ModelBuilder(up_vector=wp.vec3(0, 0, 1))
54
+ else:
55
+ builder = wp.sim.ModelBuilder(gravity=0.0, up_vector=wp.vec3(0, 0, 1))
56
+
57
+ b = builder.add_body(origin=wp.transform((0.5, 0.0, 1.0), wp.quat_identity()), name="ball")
58
+ builder.add_shape_sphere(
59
+ body=b, radius=0.1, density=100.0, ke=2000.0, kd=10.0, kf=200.0, mu=0.2, thickness=0.01
60
+ )
61
+ builder.set_ground_plane(ke=10, kd=10, kf=0.0, mu=0.2)
62
+ self.model = builder.finalize(requires_grad=True)
63
+
64
+ self.time = np.linspace(0, self.sim_duration, self.sim_steps)
65
+
66
+ self.integrator = wp.sim.SemiImplicitIntegrator()
67
+ if rendering:
68
+ self.renderer = wp.sim.render.SimRendererOpenGL(self.model, "ball_bounce_linear")
69
+ else:
70
+ self.renderer = None
71
+
72
+ self.loss = wp.array([0], dtype=wp.float32, requires_grad=True)
73
+ self.states = [self.model.state() for _ in range(self.sim_steps + 1)]
74
+ self.target_states = [self.model.state() for _ in range(self.sim_steps + 1)]
75
+
76
+ self.target_force = wp.array([0.0, 0.0, 0.0, 0.0, self.target_force_linear, 0.0], dtype=wp.spatial_vectorf)
77
+
78
+ self.trajectory = wp.empty(len(self.time), dtype=wp.vec3, requires_grad=True)
79
+ self.target_trajectory = wp.empty(len(self.time), dtype=wp.vec3)
80
+
81
+ def _reset(self):
82
+ self.loss = wp.array([0], dtype=wp.float32, requires_grad=True)
83
+
84
+ def generate_target_trajectory(self):
85
+ for i in range(self.sim_steps):
86
+ curr_state = self.target_states[i]
87
+ next_state = self.target_states[i + 1]
88
+ curr_state.clear_forces()
89
+ if i == 0:
90
+ wp.copy(curr_state.body_f, self.target_force, dest_offset=0, src_offset=0, count=1)
91
+ wp.sim.collide(self.model, curr_state)
92
+ self.integrator.simulate(self.model, curr_state, next_state, self.sim_dt)
93
+ wp.launch(kernel=update_trajectory_kernel, dim=1, inputs=[self.target_trajectory, curr_state.body_q, i, 0])
94
+
95
+ def forward(self, force: wp.array):
96
+ for i in range(self.sim_steps):
97
+ curr_state = self.states[i]
98
+ next_state = self.states[i + 1]
99
+ curr_state.clear_forces()
100
+ if i == 0:
101
+ wp.copy(curr_state.body_f, force, dest_offset=0, src_offset=0, count=1)
102
+ wp.sim.collide(self.model, curr_state)
103
+ self.integrator.simulate(self.model, curr_state, next_state, self.sim_dt)
104
+ wp.launch(kernel=update_trajectory_kernel, dim=1, inputs=[self.trajectory, curr_state.body_q, i, 0])
105
+
106
+ if self.renderer:
107
+ self.renderer.begin_frame(self.time[i])
108
+ self.renderer.render(curr_state)
109
+ self.renderer.end_frame()
110
+
111
+ def step(self, force: wp.array):
112
+ self.tape = wp.Tape()
113
+ self._reset()
114
+ with self.tape:
115
+ self.forward(force)
116
+ wp.launch(
117
+ kernel=trajectory_loss_kernel,
118
+ dim=len(self.trajectory),
119
+ inputs=[self.trajectory, self.target_trajectory, self.loss],
120
+ )
121
+ self.tape.backward(self.loss)
122
+ force_grad = force.grad.numpy()[0, 4]
123
+ self.tape.zero()
124
+
125
+ return self.loss.numpy()[0], force_grad
126
+
127
+ def evaluate(self, num_samples, plot_results=False):
128
+ forces = np.linspace(0, self.target_force_linear * 2, num_samples)
129
+ losses = np.zeros_like(forces)
130
+ grads = np.zeros_like(forces)
131
+
132
+ for i, fx in enumerate(forces):
133
+ force = wp.array([[0.0, 0.0, 0.0, 0.0, fx, 0.0]], dtype=wp.spatial_vectorf, requires_grad=True)
134
+ losses[i], grads[i] = self.step(force)
135
+ if plot_results:
136
+ print(f"Iteration {i + 1}/{num_samples}")
137
+ print(f"Force: {fx:.2f}, Loss: {losses[i]:.6f}, Grad: {grads[i]:.6f}")
138
+
139
+ assert np.isfinite(losses[i])
140
+ assert np.isfinite(grads[i])
141
+ if i > 0:
142
+ assert grads[i] >= grads[i - 1]
143
+
144
+ if plot_results:
145
+ import matplotlib.pyplot as plt
146
+
147
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
148
+
149
+ # Plot the loss curve
150
+ ax1.plot(forces, losses, label="Loss")
151
+ ax1.set_xlabel("Force")
152
+ ax1.set_ylabel("Loss")
153
+ ax1.set_title("Loss vs Force")
154
+ ax1.legend()
155
+
156
+ # Make sure the grads are not too large
157
+ grads = np.clip(grads, -1e4, 1e4)
158
+
159
+ # Plot the gradient curve
160
+ ax2.plot(forces, grads, label="Gradient", color="orange")
161
+ ax2.set_xlabel("Force")
162
+ ax2.set_ylabel("Gradient")
163
+ ax2.set_title("Gradient vs Force")
164
+ ax2.legend()
165
+
166
+ plt.suptitle("Loss and Gradient vs Force")
167
+ plt.tight_layout(rect=[0, 0, 1, 0.95])
168
+ plt.show()
169
+
170
+ return losses, grads
171
+
172
+
173
+ def test_sim_grad_bounce_linear(test, device):
174
+ with wp.ScopedDevice(device):
175
+ model = BallBounceLinearTest()
176
+ model.generate_target_trajectory()
177
+
178
+ num_samples = 20
179
+ losses, grads = model.evaluate(num_samples=num_samples)
180
+ # gradients must approximate linear behavior with zero crossing in the middle
181
+ test.assertTrue(np.abs(grads[1:] - grads[:-1]).max() < 1.1)
182
+ test.assertTrue(np.all(grads[: num_samples // 2] <= 0.0))
183
+ test.assertTrue(np.all(grads[num_samples // 2 :] >= 0.0))
184
+ # losses must follow a parabolic behavior
185
+ test.assertTrue(np.allclose(losses[: num_samples // 2], losses[num_samples // 2 :][::-1], atol=1.0))
186
+ diffs = losses[1:] - losses[:-1]
187
+ test.assertTrue(np.all(diffs[: num_samples // 2 - 1] <= 0.0))
188
+ test.assertTrue(np.all(diffs[num_samples // 2 - 1 :] >= 0.0))
189
+ # second derivative must be constant positive
190
+ diffs2 = diffs[1:] - diffs[:-1]
191
+ test.assertTrue(np.allclose(diffs2, diffs2[0], atol=1e-2))
192
+ test.assertTrue(np.all(diffs2 >= 0.0))
193
+
194
+
195
+ class TestSimGradBounceLinear(unittest.TestCase):
196
+ pass
197
+
198
+
199
+ devices = get_test_devices("basic")
200
+ add_function_test(TestSimGradBounceLinear, "test_sim_grad_bounce_linear", test_sim_grad_bounce_linear, devices=devices)
201
+
202
+ if __name__ == "__main__":
203
+ wp.clear_kernel_cache()
204
+ unittest.main(verbosity=2, failfast=True)
warp/tests/test_static.py CHANGED
@@ -536,6 +536,21 @@ def test_static_function_hash(test, _):
536
536
  test.assertEqual(hash1, hash3)
537
537
 
538
538
 
539
+ @wp.kernel
540
+ def static_len_query_kernel(v1: wp.vec2):
541
+ v2 = wp.vec3()
542
+ m = wp.identity(n=wp.static(len(v1) + len(v2) + 1), dtype=float)
543
+ wp.expect_eq(wp.ddot(m, m), 6.0)
544
+
545
+ t = wp.transform_identity(float)
546
+ wp.expect_eq(wp.static(len(t)), 7)
547
+
548
+
549
+ def test_static_len_query(test, _):
550
+ v1 = wp.vec2()
551
+ wp.launch(static_len_query_kernel, 1, inputs=(v1,))
552
+
553
+
539
554
  devices = get_test_devices()
540
555
 
541
556
 
@@ -561,6 +576,7 @@ add_function_test(TestStatic, "test_static_if_else_elif", test_static_if_else_el
561
576
 
562
577
  add_function_test(TestStatic, "test_static_constant_hash", test_static_constant_hash, devices=None)
563
578
  add_function_test(TestStatic, "test_static_function_hash", test_static_function_hash, devices=None)
579
+ add_function_test(TestStatic, "test_static_len_query", test_static_len_query, devices=None)
564
580
 
565
581
 
566
582
  if __name__ == "__main__":
warp/tests/test_tape.py CHANGED
@@ -125,6 +125,30 @@ def test_tape_dot_product(test, device):
125
125
  assert_np_equal(tape.gradients[y].numpy(), x.numpy())
126
126
 
127
127
 
128
+ @wp.kernel
129
+ def assign_chain_kernel(x: wp.array(dtype=float), y: wp.array(dtype=float), z: wp.array(dtype=float)):
130
+ tid = wp.tid()
131
+ y[tid] = x[tid]
132
+ z[tid] = y[tid]
133
+
134
+
135
+ def test_tape_zero_multiple_outputs(test, device):
136
+ x = wp.array(np.arange(3), dtype=float, device=device, requires_grad=True)
137
+ y = wp.zeros_like(x)
138
+ z = wp.zeros_like(x)
139
+
140
+ tape = wp.Tape()
141
+ with tape:
142
+ wp.launch(assign_chain_kernel, dim=3, inputs=[x, y, z], device=device)
143
+
144
+ tape.backward(grads={y: wp.ones_like(x)})
145
+ assert_np_equal(x.grad.numpy(), np.ones(3, dtype=float))
146
+ tape.zero()
147
+
148
+ tape.backward(grads={z: wp.ones_like(x)})
149
+ assert_np_equal(x.grad.numpy(), np.ones(3, dtype=float))
150
+
151
+
128
152
  def test_tape_visualize(test, device):
129
153
  dim = 8
130
154
  tape = wp.Tape()
@@ -163,6 +187,7 @@ class TestTape(unittest.TestCase):
163
187
  add_function_test(TestTape, "test_tape_mul_constant", test_tape_mul_constant, devices=devices)
164
188
  add_function_test(TestTape, "test_tape_mul_variable", test_tape_mul_variable, devices=devices)
165
189
  add_function_test(TestTape, "test_tape_dot_product", test_tape_dot_product, devices=devices)
190
+ add_function_test(TestTape, "test_tape_zero_multiple_outputs", test_tape_zero_multiple_outputs, devices=devices)
166
191
  add_function_test(TestTape, "test_tape_visualize", test_tape_visualize, devices=devices)
167
192
 
168
193