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,242 @@
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
+ import unittest
9
+
10
+ import warp as wp
11
+ from warp.tests.unittest_utils import *
12
+
13
+
14
+ @wp.kernel
15
+ def expect_ones(a: wp.array(dtype=int)):
16
+ i = wp.tid()
17
+
18
+ assert a[i] == 1
19
+
20
+
21
+ @wp.kernel
22
+ def expect_ones_with_msg(a: wp.array(dtype=int)):
23
+ i = wp.tid()
24
+
25
+ assert a[i] == 1, "Array element must be 1"
26
+
27
+
28
+ @wp.kernel
29
+ def expect_ones_compound(a: wp.array(dtype=int)):
30
+ i = wp.tid()
31
+
32
+ assert a[i] > 0 and a[i] < 2
33
+
34
+
35
+ @wp.func
36
+ def expect_ones_function(value: int):
37
+ assert value == 1, "Array element must be 1"
38
+
39
+
40
+ @wp.kernel
41
+ def expect_ones_call_function(a: wp.array(dtype=int)):
42
+ i = wp.tid()
43
+ expect_ones_function(a[i])
44
+
45
+
46
+ class TestAssertRelease(unittest.TestCase):
47
+ """Assert test cases that are to be run with Warp in release mode."""
48
+
49
+ @classmethod
50
+ def setUpClass(cls):
51
+ cls._saved_mode = wp.get_module_options()["mode"]
52
+ cls._saved_cache_kernels = wp.config.cache_kernels
53
+
54
+ wp.config.mode = "release"
55
+ wp.config.cache_kernels = False
56
+
57
+ @classmethod
58
+ def tearDownClass(cls):
59
+ wp.set_module_options({"mode": cls._saved_mode})
60
+ wp.config.cache_kernels = cls._saved_cache_kernels
61
+
62
+ def test_basic_assert_false_condition(self):
63
+ with wp.ScopedDevice("cpu"):
64
+ wp.load_module(device=wp.get_device())
65
+
66
+ input_array = wp.zeros(1, dtype=int)
67
+
68
+ capture = StdErrCapture()
69
+ capture.begin()
70
+
71
+ wp.launch(expect_ones, input_array.shape, inputs=[input_array])
72
+
73
+ output = capture.end()
74
+
75
+ self.assertEqual(output, "", f"Kernel should not print anything to stderr, got {output}")
76
+
77
+ def test_basic_assert_with_msg(self):
78
+ with wp.ScopedDevice("cpu"):
79
+ wp.load_module(device=wp.get_device())
80
+
81
+ input_array = wp.zeros(1, dtype=int)
82
+
83
+ capture = StdErrCapture()
84
+ capture.begin()
85
+
86
+ wp.launch(expect_ones_with_msg, input_array.shape, inputs=[input_array])
87
+
88
+ output = capture.end()
89
+
90
+ self.assertEqual(output, "", f"Kernel should not print anything to stderr, got {output}")
91
+
92
+ def test_compound_assert_false_condition(self):
93
+ with wp.ScopedDevice("cpu"):
94
+ wp.load_module(device=wp.get_device())
95
+
96
+ input_array = wp.full(1, value=3, dtype=int)
97
+
98
+ capture = StdErrCapture()
99
+ capture.begin()
100
+
101
+ wp.launch(expect_ones_compound, input_array.shape, inputs=[input_array])
102
+
103
+ output = capture.end()
104
+
105
+ self.assertEqual(output, "", f"Kernel should not print anything to stderr, got {output}")
106
+
107
+ def test_basic_assert_false_condition_function(self):
108
+ with wp.ScopedDevice("cpu"):
109
+ wp.load_module(device=wp.get_device())
110
+
111
+ input_array = wp.full(1, value=3, dtype=int)
112
+
113
+ capture = StdErrCapture()
114
+ capture.begin()
115
+
116
+ wp.launch(expect_ones_call_function, input_array.shape, inputs=[input_array])
117
+
118
+ output = capture.end()
119
+
120
+ self.assertEqual(output, "", f"Kernel should not print anything to stderr, got {output}")
121
+
122
+
123
+ # NOTE: Failed assertions on CUDA devices leaves the CUDA context in an unrecoverable state,
124
+ # so we currently do not test them.
125
+ class TestAssertDebug(unittest.TestCase):
126
+ """Assert test cases that are to be run with Warp in debug mode."""
127
+
128
+ @classmethod
129
+ def setUpClass(cls):
130
+ cls._saved_mode = wp.get_module_options()["mode"]
131
+ cls._saved_cache_kernels = wp.config.cache_kernels
132
+
133
+ wp.set_module_options({"mode": "debug"})
134
+ wp.config.cache_kernels = False
135
+
136
+ @classmethod
137
+ def tearDownClass(cls):
138
+ wp.set_module_options({"mode": cls._saved_mode})
139
+ wp.config.cache_kernels = cls._saved_cache_kernels
140
+
141
+ def test_basic_assert_false_condition(self):
142
+ with wp.ScopedDevice("cpu"):
143
+ wp.load_module(device=wp.get_device())
144
+
145
+ input_array = wp.zeros(1, dtype=int)
146
+
147
+ capture = StdErrCapture()
148
+ capture.begin()
149
+
150
+ wp.launch(expect_ones, input_array.shape, inputs=[input_array])
151
+
152
+ output = capture.end()
153
+
154
+ # Older Windows C runtimes have a bug where stdout sometimes does not get properly flushed.
155
+ if output != "" or sys.platform != "win32":
156
+ self.assertRegex(output, r"Assertion failed: .*assert a\[i\] == 1")
157
+
158
+ def test_basic_assert_true_condition(self):
159
+ with wp.ScopedDevice("cpu"):
160
+ wp.load_module(device=wp.get_device())
161
+
162
+ input_array = wp.ones(1, dtype=int)
163
+
164
+ capture = StdErrCapture()
165
+ capture.begin()
166
+
167
+ wp.launch(expect_ones, input_array.shape, inputs=[input_array])
168
+
169
+ output = capture.end()
170
+
171
+ self.assertEqual(output, "", f"Kernel should not print anything to stderr, got {output}")
172
+
173
+ def test_basic_assert_with_msg(self):
174
+ with wp.ScopedDevice("cpu"):
175
+ wp.load_module(device=wp.get_device())
176
+
177
+ input_array = wp.zeros(1, dtype=int)
178
+
179
+ capture = StdErrCapture()
180
+ capture.begin()
181
+
182
+ wp.launch(expect_ones_with_msg, input_array.shape, inputs=[input_array])
183
+
184
+ output = capture.end()
185
+
186
+ # Older Windows C runtimes have a bug where stdout sometimes does not get properly flushed.
187
+ if output != "" or sys.platform != "win32":
188
+ self.assertRegex(output, r"Assertion failed: .*assert a\[i\] == 1.*Array element must be 1")
189
+
190
+ def test_compound_assert_true_condition(self):
191
+ with wp.ScopedDevice("cpu"):
192
+ wp.load_module(device=wp.get_device())
193
+
194
+ input_array = wp.ones(1, dtype=int)
195
+
196
+ capture = StdErrCapture()
197
+ capture.begin()
198
+
199
+ wp.launch(expect_ones_compound, input_array.shape, inputs=[input_array])
200
+
201
+ output = capture.end()
202
+
203
+ self.assertEqual(output, "", f"Kernel should not print anything to stderr, got {output}")
204
+
205
+ def test_compound_assert_false_condition(self):
206
+ with wp.ScopedDevice("cpu"):
207
+ wp.load_module(device=wp.get_device())
208
+
209
+ input_array = wp.full(1, value=3, dtype=int)
210
+
211
+ capture = StdErrCapture()
212
+ capture.begin()
213
+
214
+ wp.launch(expect_ones_compound, input_array.shape, inputs=[input_array])
215
+
216
+ output = capture.end()
217
+
218
+ # Older Windows C runtimes have a bug where stdout sometimes does not get properly flushed.
219
+ if output != "" or sys.platform != "win32":
220
+ self.assertRegex(output, r"Assertion failed: .*assert a\[i\] > 0 and a\[i\] < 2")
221
+
222
+ def test_basic_assert_false_condition_function(self):
223
+ with wp.ScopedDevice("cpu"):
224
+ wp.load_module(device=wp.get_device())
225
+
226
+ input_array = wp.full(1, value=3, dtype=int)
227
+
228
+ capture = StdErrCapture()
229
+ capture.begin()
230
+
231
+ wp.launch(expect_ones_call_function, input_array.shape, inputs=[input_array])
232
+
233
+ output = capture.end()
234
+
235
+ # Older Windows C runtimes have a bug where stdout sometimes does not get properly flushed.
236
+ if output != "" or sys.platform != "win32":
237
+ self.assertRegex(output, r"Assertion failed: .*assert value == 1.*Array element must be 1")
238
+
239
+
240
+ if __name__ == "__main__":
241
+ wp.clear_kernel_cache()
242
+ unittest.main(verbosity=2)
@@ -396,48 +396,29 @@ def test_unresolved_symbol(test, device):
396
396
 
397
397
 
398
398
  def test_error_global_var(test, device):
399
- arr = wp.array(
400
- (1.0, 2.0, 3.0),
401
- dtype=float,
402
- device=device,
403
- )
399
+ arr = wp.array((1.0, 2.0, 3.0), dtype=float, device=device)
404
400
 
405
- def kernel_1_fn(
406
- out: wp.array(dtype=float),
407
- ):
401
+ def kernel_1_fn(out: wp.array(dtype=float)):
408
402
  out[0] = arr[0]
409
403
 
410
- def kernel_2_fn(
411
- out: wp.array(dtype=float),
412
- ):
404
+ def kernel_2_fn(out: wp.array(dtype=float)):
413
405
  out[0] = arr
414
406
 
415
- def kernel_3_fn(
416
- out: wp.array(dtype=float),
417
- ):
407
+ def kernel_3_fn(out: wp.array(dtype=float)):
418
408
  out[0] = wp.lower_bound(arr, 2.0)
419
409
 
420
410
  out = wp.empty_like(arr)
421
411
 
422
412
  kernel = wp.Kernel(func=kernel_1_fn)
423
- with test.assertRaisesRegex(
424
- TypeError,
425
- r"Invalid external reference type: <class 'warp.types.array'>",
426
- ):
413
+ with test.assertRaisesRegex(TypeError, r"Invalid external reference type: <class 'warp.types.array'>"):
427
414
  wp.launch(kernel, dim=out.shape, inputs=(), outputs=(out,), device=device)
428
415
 
429
416
  kernel = wp.Kernel(func=kernel_2_fn)
430
- with test.assertRaisesRegex(
431
- TypeError,
432
- r"Invalid external reference type: <class 'warp.types.array'>",
433
- ):
417
+ with test.assertRaisesRegex(TypeError, r"Invalid external reference type: <class 'warp.types.array'>"):
434
418
  wp.launch(kernel, dim=out.shape, inputs=(), outputs=(out,), device=device)
435
419
 
436
420
  kernel = wp.Kernel(func=kernel_3_fn)
437
- with test.assertRaisesRegex(
438
- TypeError,
439
- r"Invalid external reference type: <class 'warp.types.array'>",
440
- ):
421
+ with test.assertRaisesRegex(TypeError, r"Invalid external reference type: <class 'warp.types.array'>"):
441
422
  wp.launch(kernel, dim=out.shape, inputs=(), outputs=(out,), device=device)
442
423
 
443
424
 
@@ -469,16 +450,12 @@ def test_error_collection_construct(test, device):
469
450
  wp.launch(kernel, dim=1, device=device)
470
451
 
471
452
  kernel = wp.Kernel(func=kernel_3_fn)
472
- with test.assertRaisesRegex(
473
- RuntimeError,
474
- r"Construct `ast.Dict` not supported in kernels.",
475
- ):
453
+ with test.assertRaisesRegex(RuntimeError, r"Construct `ast.Dict` not supported in kernels."):
476
454
  wp.launch(kernel, dim=1, device=device)
477
455
 
478
456
  kernel = wp.Kernel(func=kernel_4_fn)
479
457
  with test.assertRaisesRegex(
480
- RuntimeError,
481
- r"Tuple constructs are not supported in kernels. Use vectors like `wp.vec3\(\)` instead.",
458
+ RuntimeError, r"Tuple constructs are not supported in kernels. Use vectors like `wp.vec3\(\)` instead."
482
459
  ):
483
460
  wp.launch(kernel, dim=1, device=device)
484
461
 
@@ -491,10 +468,7 @@ def test_error_unmatched_arguments(test, device):
491
468
  x = wp.dot(wp.vec2(1.0, 2.0), wp.vec2h(wp.float16(1.0), wp.float16(2.0)))
492
469
 
493
470
  kernel = wp.Kernel(func=kernel_1_fn)
494
- with test.assertRaisesRegex(
495
- RuntimeError,
496
- r"Input types must be the same, got \['int32', 'float32'\]",
497
- ):
471
+ with test.assertRaisesRegex(RuntimeError, r"Input types must be the same, got \['int32', 'float32'\]"):
498
472
  wp.launch(kernel, dim=1, device=device)
499
473
 
500
474
  kernel = wp.Kernel(func=kernel_2_fn)
@@ -704,12 +678,7 @@ add_kernel_test(
704
678
  TestCodeGen, name="test_dynamic_for_rename", kernel=test_dynamic_for_rename, inputs=[10], dim=1, devices=devices
705
679
  )
706
680
  add_kernel_test(
707
- TestCodeGen,
708
- name="test_dynamic_for_inplace",
709
- kernel=test_dynamic_for_inplace,
710
- inputs=[10],
711
- dim=1,
712
- devices=devices,
681
+ TestCodeGen, name="test_dynamic_for_inplace", kernel=test_dynamic_for_inplace, inputs=[10], dim=1, devices=devices
713
682
  )
714
683
  add_kernel_test(TestCodeGen, name="test_reassign", kernel=test_reassign, dim=1, devices=devices)
715
684
  add_kernel_test(
@@ -754,12 +723,7 @@ add_kernel_test(
754
723
  )
755
724
 
756
725
  add_kernel_test(
757
- TestCodeGen,
758
- name="test_range_static_sum",
759
- kernel=test_range_static_sum,
760
- dim=1,
761
- expect=[10, 10, 10],
762
- devices=devices,
726
+ TestCodeGen, name="test_range_static_sum", kernel=test_range_static_sum, dim=1, expect=[10, 10, 10], devices=devices
763
727
  )
764
728
  add_kernel_test(
765
729
  TestCodeGen,
@@ -789,20 +753,9 @@ add_kernel_test(
789
753
  devices=devices,
790
754
  )
791
755
  add_kernel_test(
792
- TestCodeGen,
793
- name="test_range_dynamic_nested",
794
- kernel=test_range_dynamic_nested,
795
- dim=1,
796
- inputs=[4],
797
- devices=devices,
798
- )
799
- add_kernel_test(
800
- TestCodeGen,
801
- name="test_range_expression",
802
- kernel=test_range_expression,
803
- dim=1,
804
- devices=devices,
756
+ TestCodeGen, name="test_range_dynamic_nested", kernel=test_range_dynamic_nested, dim=1, inputs=[4], devices=devices
805
757
  )
758
+ add_kernel_test(TestCodeGen, name="test_range_expression", kernel=test_range_expression, dim=1, devices=devices)
806
759
 
807
760
  add_kernel_test(TestCodeGen, name="test_while_zero", kernel=test_while, dim=1, inputs=[0], devices=devices)
808
761
  add_kernel_test(TestCodeGen, name="test_while_positive", kernel=test_while, dim=1, inputs=[16], devices=devices)
@@ -430,8 +430,8 @@ class Example:
430
430
  def set_points_fixed(self, model, fixed_particles):
431
431
  if len(fixed_particles):
432
432
  flags = model.particle_flags.numpy()
433
- for fixed_v_id in fixed_particles:
434
- flags[fixed_v_id] = wp.uint32(int(flags[fixed_v_id]) & ~int(PARTICLE_FLAG_ACTIVE))
433
+ for fixed_vertex_id in fixed_particles:
434
+ flags[fixed_vertex_id] = wp.uint32(int(flags[fixed_vertex_id]) & ~int(PARTICLE_FLAG_ACTIVE))
435
435
 
436
436
  model.particle_flags = wp.array(flags, device=model.device)
437
437
 
@@ -304,6 +304,15 @@ add_example_test(
304
304
  },
305
305
  test_options_cpu={"train_iters": 1, "num_frames": 30},
306
306
  )
307
+ add_example_test(
308
+ TestOptimExamples,
309
+ name="optim.example_softbody_properties",
310
+ devices=test_devices,
311
+ test_options_cuda={
312
+ "train_iters": 1 if warp.context.runtime.core.is_debug_enabled() else 3,
313
+ },
314
+ test_options_cpu={"train_iters": 1},
315
+ )
307
316
 
308
317
 
309
318
  class TestSimExamples(unittest.TestCase):
@@ -8,7 +8,12 @@
8
8
  import unittest
9
9
 
10
10
  import warp as wp
11
- from warp.autograd import gradcheck, gradcheck_tape, jacobian, jacobian_fd
11
+ from warp.autograd import (
12
+ gradcheck,
13
+ gradcheck_tape,
14
+ jacobian,
15
+ jacobian_fd,
16
+ )
12
17
  from warp.tests.unittest_utils import *
13
18
 
14
19
 
@@ -43,7 +48,7 @@ def vec_length_kernel(a: wp.array(dtype=wp.vec3), out: wp.array(dtype=float)):
43
48
  tid = wp.tid()
44
49
  v = a[tid]
45
50
  # instead of wp.length(v), we use a trivial implementation that
46
- # fails when a division by zero is occurs in the backward pass of sqrt
51
+ # fails when a division by zero occurs in the backward pass of sqrt
47
52
  out[tid] = wp.sqrt(v[0] ** 2.0 + v[1] ** 2.0 + v[2] ** 2.0)
48
53
 
49
54
 
@@ -63,6 +68,16 @@ def wrong_grad_kernel(a: wp.array(dtype=float), out: wp.array(dtype=float)):
63
68
  out[tid] = wrong_grad_func(a[tid])
64
69
 
65
70
 
71
+ @wp.kernel
72
+ def transform_point_kernel(
73
+ transforms: wp.array(dtype=wp.transform),
74
+ points: wp.array(dtype=wp.vec3),
75
+ out: wp.array(dtype=wp.vec3),
76
+ ):
77
+ tid = wp.tid()
78
+ out[tid] = wp.transform_point(transforms[tid], points[tid])
79
+
80
+
66
81
  def test_gradcheck_3d(test, device):
67
82
  a_3d = wp.array([((2.0, 0.0), (1.0, 0.0), (2.0, 0.0))], dtype=float, requires_grad=True, device=device)
68
83
  b_3d = wp.array([((3.0, 0.0), (1.0, 0.0), (2.0, 0.0))], dtype=float, requires_grad=True, device=device)
@@ -229,6 +244,76 @@ def test_gradcheck_tape(test, device):
229
244
  assert passed
230
245
 
231
246
 
247
+ def test_gradcheck_function(test, device):
248
+ def compute_transformed_point_norms(transforms, points):
249
+ tf_points = wp.empty_like(points)
250
+ norms = wp.empty(len(points), dtype=float, requires_grad=points.requires_grad, device=points.device)
251
+
252
+ wp.launch(
253
+ transform_point_kernel,
254
+ dim=len(points),
255
+ inputs=[transforms, points],
256
+ outputs=[tf_points],
257
+ device=device,
258
+ )
259
+ wp.launch(
260
+ vec_length_kernel,
261
+ dim=len(points),
262
+ inputs=[tf_points],
263
+ outputs=[norms],
264
+ device=device,
265
+ )
266
+ return tf_points, norms
267
+
268
+ transforms = wp.array(
269
+ [
270
+ wp.transform(wp.vec3(1.0, 0.6, -2.0), wp.quat_rpy(-0.5, 0.1, 0.8)),
271
+ wp.transform(wp.vec3(0.2, 1.4, -0.4), wp.quat_rpy(0.5, 0.65, -0.3)),
272
+ wp.transform(wp.vec3(0.5, 0.2, 0.0), wp.quat_rpy(-0.5, -0.3, 0.4)),
273
+ ],
274
+ dtype=wp.transform,
275
+ requires_grad=True,
276
+ device=device,
277
+ )
278
+ points = wp.array(
279
+ [
280
+ (1.0, -0.5, 2.0),
281
+ (-0.95, -0.1, 0.0),
282
+ (9.1, 9.7, 3.8),
283
+ ],
284
+ dtype=wp.vec3,
285
+ requires_grad=True,
286
+ device=device,
287
+ )
288
+
289
+ jacs_ad = jacobian(
290
+ kernel_mixed,
291
+ dim=len(points),
292
+ inputs=[transforms, points],
293
+ )
294
+ jacs_fd = jacobian_fd(
295
+ kernel_mixed,
296
+ dim=len(points),
297
+ inputs=[transforms, points],
298
+ eps=1e-4,
299
+ )
300
+
301
+ # manual gradcheck
302
+ for i in range(2):
303
+ for j in range(2):
304
+ assert np.allclose(jacs_ad[(i, j)].numpy(), jacs_fd[(i, j)].numpy(), atol=1e-2, rtol=1e-2)
305
+
306
+ passed = gradcheck(
307
+ kernel_mixed,
308
+ dim=len(points),
309
+ inputs=[transforms, points],
310
+ raise_exception=False,
311
+ show_summary=False,
312
+ )
313
+
314
+ assert passed
315
+
316
+
232
317
  devices = get_test_devices()
233
318
 
234
319
 
@@ -85,7 +85,7 @@ def test_hashgrid_query(test, device):
85
85
 
86
86
  for i in range(num_runs):
87
87
  if print_enabled:
88
- print(f"Run: {i+1}")
88
+ print(f"Run: {i + 1}")
89
89
  print("---------")
90
90
 
91
91
  points = particle_grid(16, 32, 16, (0.0, 0.3, 0.0), cell_radius * 0.25, 0.1)
warp/tests/test_ipc.py ADDED
@@ -0,0 +1,116 @@
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
+ import multiprocessing as mp
9
+ import unittest
10
+
11
+ import warp as wp
12
+ from warp.tests.unittest_utils import *
13
+
14
+
15
+ def test_ipc_get_memory_handle(test, device):
16
+ if device.is_ipc_supported is False:
17
+ test.skipTest(f"IPC is not supported on {device}")
18
+
19
+ with wp.ScopedMempool(device, False):
20
+ test_array = wp.full(10, value=42.0, dtype=wp.float32, device=device)
21
+ ipc_handle = test_array.ipc_handle()
22
+
23
+ test.assertNotEqual(ipc_handle, bytes(64), "IPC memory handle appears to be invalid")
24
+
25
+
26
+ def test_ipc_get_event_handle(test, device):
27
+ if device.is_ipc_supported is False:
28
+ test.skipTest(f"IPC is not supported on {device}")
29
+
30
+ e1 = wp.Event(device, interprocess=True)
31
+
32
+ ipc_handle = e1.ipc_handle()
33
+
34
+ test.assertNotEqual(ipc_handle, bytes(64), "IPC event handle appears to be invalid")
35
+
36
+
37
+ def test_ipc_event_missing_interprocess_flag(test, device):
38
+ if device.is_ipc_supported is False:
39
+ test.skipTest(f"IPC is not supported on {device}")
40
+
41
+ e1 = wp.Event(device, interprocess=False)
42
+
43
+ try:
44
+ capture = StdOutCapture()
45
+ capture.begin()
46
+ ipc_handle = e1.ipc_handle()
47
+ finally:
48
+ output = capture.end()
49
+
50
+ # Older Windows C runtimes have a bug where stdout sometimes does not get properly flushed.
51
+ if sys.platform != "win32":
52
+ test.assertRegex(output, r"Warp UserWarning: IPC event handle appears to be invalid.")
53
+
54
+
55
+ @wp.kernel
56
+ def multiply_by_two(a: wp.array(dtype=wp.float32)):
57
+ i = wp.tid()
58
+ a[i] = 2.0 * a[i]
59
+
60
+
61
+ def child_task(array_handle, dtype, shape, device, event_handle):
62
+ with wp.ScopedDevice(device):
63
+ ipc_array = wp.from_ipc_handle(array_handle, dtype, shape, device=device)
64
+ ipc_event = wp.event_from_ipc_handle(event_handle, device=device)
65
+ stream = wp.get_stream()
66
+ wp.launch(multiply_by_two, ipc_array.shape, inputs=[ipc_array])
67
+ stream.record_event(ipc_event)
68
+ stream.wait_event(ipc_event)
69
+ wp.synchronize_device()
70
+
71
+
72
+ def test_ipc_multiprocess_write(test, device):
73
+ if device.is_ipc_supported is False:
74
+ test.skipTest(f"IPC is not supported on {device}")
75
+
76
+ stream = wp.get_stream(device)
77
+ e1 = wp.Event(device, interprocess=True)
78
+
79
+ with wp.ScopedMempool(device, False):
80
+ test_array = wp.full(1024, value=42.0, dtype=wp.float32, device=device)
81
+ ipc_handle = test_array.ipc_handle()
82
+
83
+ wp.launch(multiply_by_two, test_array.shape, inputs=[test_array], device=device)
84
+
85
+ ctx = mp.get_context("spawn")
86
+
87
+ process = ctx.Process(
88
+ target=child_task, args=(ipc_handle, test_array.dtype, test_array.shape, str(device), e1.ipc_handle())
89
+ )
90
+
91
+ process.start()
92
+ process.join()
93
+
94
+ assert_np_equal(test_array.numpy(), np.full(test_array.shape, 168.0, dtype=np.float32))
95
+
96
+
97
+ cuda_devices = get_cuda_test_devices()
98
+
99
+
100
+ class TestIpc(unittest.TestCase):
101
+ pass
102
+
103
+
104
+ add_function_test(TestIpc, "test_ipc_get_memory_handle", test_ipc_get_memory_handle, devices=cuda_devices)
105
+ add_function_test(TestIpc, "test_ipc_get_event_handle", test_ipc_get_event_handle, devices=cuda_devices)
106
+ add_function_test(
107
+ TestIpc, "test_ipc_event_missing_interprocess_flag", test_ipc_event_missing_interprocess_flag, devices=cuda_devices
108
+ )
109
+ add_function_test(
110
+ TestIpc, "test_ipc_multiprocess_write", test_ipc_multiprocess_write, devices=cuda_devices, check_output=False
111
+ )
112
+
113
+
114
+ if __name__ == "__main__":
115
+ wp.clear_kernel_cache()
116
+ unittest.main(verbosity=2)