warp-lang 1.5.0__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 (132) 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 +1124 -497
  8. warp/codegen.py +261 -136
  9. warp/config.py +1 -1
  10. warp/context.py +357 -119
  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.py +3 -1
  27. warp/examples/sim/example_cloth_self_contact.py +260 -0
  28. warp/examples/sim/example_granular_collision_sdf.py +4 -5
  29. warp/examples/sim/example_jacobian_ik.py +0 -2
  30. warp/examples/sim/example_quadruped.py +5 -2
  31. warp/examples/tile/example_tile_cholesky.py +79 -0
  32. warp/examples/tile/example_tile_convolution.py +2 -2
  33. warp/examples/tile/example_tile_fft.py +2 -2
  34. warp/examples/tile/example_tile_filtering.py +3 -3
  35. warp/examples/tile/example_tile_matmul.py +4 -4
  36. warp/examples/tile/example_tile_mlp.py +12 -12
  37. warp/examples/tile/example_tile_nbody.py +180 -0
  38. warp/examples/tile/example_tile_walker.py +319 -0
  39. warp/fem/geometry/geometry.py +0 -2
  40. warp/math.py +147 -0
  41. warp/native/array.h +12 -0
  42. warp/native/builtin.h +0 -1
  43. warp/native/bvh.cpp +149 -70
  44. warp/native/bvh.cu +287 -68
  45. warp/native/bvh.h +195 -85
  46. warp/native/clang/clang.cpp +5 -1
  47. warp/native/coloring.cpp +5 -1
  48. warp/native/cuda_util.cpp +91 -53
  49. warp/native/cuda_util.h +5 -0
  50. warp/native/exports.h +40 -40
  51. warp/native/intersect.h +17 -0
  52. warp/native/mat.h +41 -0
  53. warp/native/mathdx.cpp +19 -0
  54. warp/native/mesh.cpp +25 -8
  55. warp/native/mesh.cu +153 -101
  56. warp/native/mesh.h +482 -403
  57. warp/native/quat.h +40 -0
  58. warp/native/solid_angle.h +7 -0
  59. warp/native/sort.cpp +85 -0
  60. warp/native/sort.cu +34 -0
  61. warp/native/sort.h +3 -1
  62. warp/native/spatial.h +11 -0
  63. warp/native/tile.h +1187 -669
  64. warp/native/tile_reduce.h +8 -6
  65. warp/native/vec.h +41 -0
  66. warp/native/warp.cpp +8 -1
  67. warp/native/warp.cu +263 -40
  68. warp/native/warp.h +19 -5
  69. warp/optim/linear.py +22 -4
  70. warp/render/render_opengl.py +130 -64
  71. warp/sim/__init__.py +6 -1
  72. warp/sim/collide.py +270 -26
  73. warp/sim/import_urdf.py +8 -8
  74. warp/sim/integrator_euler.py +25 -7
  75. warp/sim/integrator_featherstone.py +154 -35
  76. warp/sim/integrator_vbd.py +842 -40
  77. warp/sim/model.py +134 -72
  78. warp/sparse.py +1 -1
  79. warp/stubs.py +265 -132
  80. warp/tape.py +28 -30
  81. warp/tests/aux_test_module_unload.py +15 -0
  82. warp/tests/{test_sim_grad.py → flaky_test_sim_grad.py} +104 -63
  83. warp/tests/test_array.py +74 -0
  84. warp/tests/test_assert.py +242 -0
  85. warp/tests/test_codegen.py +14 -61
  86. warp/tests/test_collision.py +2 -2
  87. warp/tests/test_coloring.py +12 -2
  88. warp/tests/test_examples.py +12 -1
  89. warp/tests/test_func.py +21 -4
  90. warp/tests/test_grad_debug.py +87 -2
  91. warp/tests/test_hash_grid.py +1 -1
  92. warp/tests/test_ipc.py +116 -0
  93. warp/tests/test_lerp.py +13 -87
  94. warp/tests/test_mat.py +138 -167
  95. warp/tests/test_math.py +47 -1
  96. warp/tests/test_matmul.py +17 -16
  97. warp/tests/test_matmul_lite.py +10 -15
  98. warp/tests/test_mesh.py +84 -60
  99. warp/tests/test_mesh_query_aabb.py +165 -0
  100. warp/tests/test_mesh_query_point.py +328 -286
  101. warp/tests/test_mesh_query_ray.py +134 -121
  102. warp/tests/test_mlp.py +2 -2
  103. warp/tests/test_operators.py +43 -0
  104. warp/tests/test_overwrite.py +47 -2
  105. warp/tests/test_quat.py +77 -0
  106. warp/tests/test_reload.py +29 -0
  107. warp/tests/test_sim_grad_bounce_linear.py +204 -0
  108. warp/tests/test_smoothstep.py +17 -83
  109. warp/tests/test_static.py +19 -3
  110. warp/tests/test_tape.py +25 -0
  111. warp/tests/test_tile.py +178 -191
  112. warp/tests/test_tile_load.py +356 -0
  113. warp/tests/test_tile_mathdx.py +61 -8
  114. warp/tests/test_tile_mlp.py +17 -17
  115. warp/tests/test_tile_reduce.py +24 -18
  116. warp/tests/test_tile_shared_memory.py +66 -17
  117. warp/tests/test_tile_view.py +165 -0
  118. warp/tests/test_torch.py +35 -0
  119. warp/tests/test_utils.py +36 -24
  120. warp/tests/test_vec.py +110 -0
  121. warp/tests/unittest_suites.py +29 -4
  122. warp/tests/unittest_utils.py +30 -13
  123. warp/thirdparty/unittest_parallel.py +2 -2
  124. warp/types.py +411 -101
  125. warp/utils.py +10 -7
  126. {warp_lang-1.5.0.dist-info → warp_lang-1.6.0.dist-info}/METADATA +92 -69
  127. {warp_lang-1.5.0.dist-info → warp_lang-1.6.0.dist-info}/RECORD +130 -119
  128. {warp_lang-1.5.0.dist-info → warp_lang-1.6.0.dist-info}/WHEEL +1 -1
  129. warp/examples/benchmarks/benchmark_tile.py +0 -179
  130. warp/native/tile_gemm.h +0 -341
  131. {warp_lang-1.5.0.dist-info → warp_lang-1.6.0.dist-info}/LICENSE.md +0 -0
  132. {warp_lang-1.5.0.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
 
@@ -11,7 +11,12 @@ import numpy as np
11
11
  import warp as wp
12
12
  import warp.examples
13
13
  import warp.sim
14
- from warp.sim.graph_coloring import ColoringAlgorithm, construct_trimesh_graph_edges, validate_graph_coloring
14
+ from warp.sim.graph_coloring import (
15
+ ColoringAlgorithm,
16
+ construct_trimesh_graph_edges,
17
+ convert_to_color_groups,
18
+ validate_graph_coloring,
19
+ )
15
20
  from warp.tests.unittest_utils import *
16
21
 
17
22
 
@@ -120,7 +125,7 @@ def test_coloring_trimesh(test, device):
120
125
  ColoringAlgorithm.MCS.value,
121
126
  particle_colors.__ctype__(),
122
127
  )
123
- wp.context.runtime.core.balance_coloring(
128
+ max_min_ratio = wp.context.runtime.core.balance_coloring(
124
129
  model.particle_count,
125
130
  edge_indices_cpu_with_bending.__ctype__(),
126
131
  num_colors_mcs,
@@ -134,6 +139,11 @@ def test_coloring_trimesh(test, device):
134
139
  device="cpu",
135
140
  )
136
141
 
142
+ color_categories_balanced = convert_to_color_groups(num_colors_mcs, particle_colors)
143
+
144
+ color_sizes = np.array([c.shape[0] for c in color_categories_balanced], dtype=np.float32)
145
+ test.assertTrue(np.max(color_sizes) / np.min(color_sizes) <= max_min_ratio)
146
+
137
147
 
138
148
  @unittest.skipUnless(USD_AVAILABLE, "Requires usd-core")
139
149
  def test_combine_coloring(test, device):
@@ -165,7 +165,9 @@ def add_example_test(
165
165
 
166
166
  # with wp.ScopedTimer(f"{name}_{sanitize_identifier(device)}"):
167
167
  # Run the script as a subprocess
168
- result = subprocess.run(command, capture_output=True, text=True, env=env_vars, timeout=test_timeout)
168
+ result = subprocess.run(
169
+ command, capture_output=True, text=True, env=env_vars, timeout=test_timeout, check=False
170
+ )
169
171
 
170
172
  # Check the return code (0 is standard for success)
171
173
  test.assertEqual(
@@ -302,6 +304,15 @@ add_example_test(
302
304
  },
303
305
  test_options_cpu={"train_iters": 1, "num_frames": 30},
304
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
+ )
305
316
 
306
317
 
307
318
  class TestSimExamples(unittest.TestCase):
warp/tests/test_func.py CHANGED
@@ -162,7 +162,7 @@ def user_func_with_defaults(a: int = 123, b: int = 234) -> int:
162
162
 
163
163
 
164
164
  @wp.kernel
165
- def test_user_func_with_defaults():
165
+ def user_func_with_defaults_kernel():
166
166
  a = user_func_with_defaults()
167
167
  wp.expect_eq(a, 357)
168
168
 
@@ -179,6 +179,25 @@ def test_user_func_with_defaults():
179
179
  wp.expect_eq(e, 234)
180
180
 
181
181
 
182
+ def test_user_func_with_defaults(test, device):
183
+ wp.launch(user_func_with_defaults_kernel, dim=1, device=device)
184
+
185
+ a = user_func_with_defaults()
186
+ assert a == 357
187
+
188
+ b = user_func_with_defaults(111)
189
+ assert b == 345
190
+
191
+ c = user_func_with_defaults(111, 222)
192
+ assert c == 333
193
+
194
+ d = user_func_with_defaults(a=111)
195
+ assert d == 345
196
+
197
+ e = user_func_with_defaults(b=111)
198
+ assert e == 234
199
+
200
+
182
201
  @wp.func
183
202
  def user_func_return_multiple_values(a: int, b: float) -> Tuple[int, float]:
184
203
  return a + a, b * b
@@ -406,9 +425,7 @@ add_function_test(TestFunc, func=test_func_closure_capture, name="test_func_clos
406
425
  add_function_test(TestFunc, func=test_multi_valued_func, name="test_multi_valued_func", devices=devices)
407
426
  add_kernel_test(TestFunc, kernel=test_func_defaults, name="test_func_defaults", dim=1, devices=devices)
408
427
  add_kernel_test(TestFunc, kernel=test_builtin_shadowing, name="test_builtin_shadowing", dim=1, devices=devices)
409
- add_kernel_test(
410
- TestFunc, kernel=test_user_func_with_defaults, name="test_user_func_with_defaults", dim=1, devices=devices
411
- )
428
+ add_function_test(TestFunc, func=test_user_func_with_defaults, name="test_user_func_with_defaults", devices=devices)
412
429
  add_kernel_test(
413
430
  TestFunc,
414
431
  kernel=test_user_func_return_multiple_values,
@@ -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)