warp-lang 1.8.1__py3-none-win_amd64.whl → 1.9.1__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 (141) hide show
  1. warp/__init__.py +282 -103
  2. warp/__init__.pyi +1904 -114
  3. warp/bin/warp-clang.dll +0 -0
  4. warp/bin/warp.dll +0 -0
  5. warp/build.py +93 -30
  6. warp/build_dll.py +331 -101
  7. warp/builtins.py +1244 -160
  8. warp/codegen.py +317 -206
  9. warp/config.py +1 -1
  10. warp/context.py +1465 -789
  11. warp/examples/core/example_marching_cubes.py +1 -0
  12. warp/examples/core/example_render_opengl.py +100 -3
  13. warp/examples/fem/example_apic_fluid.py +98 -52
  14. warp/examples/fem/example_convection_diffusion_dg.py +25 -4
  15. warp/examples/fem/example_diffusion_mgpu.py +8 -3
  16. warp/examples/fem/utils.py +68 -22
  17. warp/examples/interop/example_jax_kernel.py +2 -1
  18. warp/fabric.py +1 -1
  19. warp/fem/cache.py +27 -19
  20. warp/fem/domain.py +2 -2
  21. warp/fem/field/nodal_field.py +2 -2
  22. warp/fem/field/virtual.py +264 -166
  23. warp/fem/geometry/geometry.py +5 -5
  24. warp/fem/integrate.py +129 -51
  25. warp/fem/space/restriction.py +4 -0
  26. warp/fem/space/shape/tet_shape_function.py +3 -10
  27. warp/jax_experimental/custom_call.py +25 -2
  28. warp/jax_experimental/ffi.py +22 -1
  29. warp/jax_experimental/xla_ffi.py +16 -7
  30. warp/marching_cubes.py +708 -0
  31. warp/native/array.h +99 -4
  32. warp/native/builtin.h +86 -9
  33. warp/native/bvh.cpp +64 -28
  34. warp/native/bvh.cu +58 -58
  35. warp/native/bvh.h +2 -2
  36. warp/native/clang/clang.cpp +7 -7
  37. warp/native/coloring.cpp +8 -2
  38. warp/native/crt.cpp +2 -2
  39. warp/native/crt.h +3 -5
  40. warp/native/cuda_util.cpp +41 -10
  41. warp/native/cuda_util.h +10 -4
  42. warp/native/exports.h +1842 -1908
  43. warp/native/fabric.h +2 -1
  44. warp/native/hashgrid.cpp +37 -37
  45. warp/native/hashgrid.cu +2 -2
  46. warp/native/initializer_array.h +1 -1
  47. warp/native/intersect.h +2 -2
  48. warp/native/mat.h +1910 -116
  49. warp/native/mathdx.cpp +43 -43
  50. warp/native/mesh.cpp +24 -24
  51. warp/native/mesh.cu +26 -26
  52. warp/native/mesh.h +4 -2
  53. warp/native/nanovdb/GridHandle.h +179 -12
  54. warp/native/nanovdb/HostBuffer.h +8 -7
  55. warp/native/nanovdb/NanoVDB.h +517 -895
  56. warp/native/nanovdb/NodeManager.h +323 -0
  57. warp/native/nanovdb/PNanoVDB.h +2 -2
  58. warp/native/quat.h +331 -14
  59. warp/native/range.h +7 -1
  60. warp/native/reduce.cpp +10 -10
  61. warp/native/reduce.cu +13 -14
  62. warp/native/runlength_encode.cpp +2 -2
  63. warp/native/runlength_encode.cu +5 -5
  64. warp/native/scan.cpp +3 -3
  65. warp/native/scan.cu +4 -4
  66. warp/native/sort.cpp +10 -10
  67. warp/native/sort.cu +40 -31
  68. warp/native/sort.h +2 -0
  69. warp/native/sparse.cpp +8 -8
  70. warp/native/sparse.cu +13 -13
  71. warp/native/spatial.h +366 -17
  72. warp/native/temp_buffer.h +2 -2
  73. warp/native/tile.h +471 -82
  74. warp/native/vec.h +328 -14
  75. warp/native/volume.cpp +54 -54
  76. warp/native/volume.cu +1 -1
  77. warp/native/volume.h +2 -1
  78. warp/native/volume_builder.cu +30 -37
  79. warp/native/warp.cpp +150 -149
  80. warp/native/warp.cu +377 -216
  81. warp/native/warp.h +227 -226
  82. warp/optim/linear.py +736 -271
  83. warp/render/imgui_manager.py +289 -0
  84. warp/render/render_opengl.py +99 -18
  85. warp/render/render_usd.py +1 -0
  86. warp/sim/graph_coloring.py +2 -2
  87. warp/sparse.py +558 -175
  88. warp/tests/aux_test_module_aot.py +7 -0
  89. warp/tests/cuda/test_async.py +3 -3
  90. warp/tests/cuda/test_conditional_captures.py +101 -0
  91. warp/tests/geometry/test_hash_grid.py +38 -0
  92. warp/tests/geometry/test_marching_cubes.py +233 -12
  93. warp/tests/interop/test_jax.py +608 -28
  94. warp/tests/sim/test_coloring.py +6 -6
  95. warp/tests/test_array.py +58 -5
  96. warp/tests/test_codegen.py +4 -3
  97. warp/tests/test_context.py +8 -15
  98. warp/tests/test_enum.py +136 -0
  99. warp/tests/test_examples.py +2 -2
  100. warp/tests/test_fem.py +49 -6
  101. warp/tests/test_fixedarray.py +229 -0
  102. warp/tests/test_func.py +18 -15
  103. warp/tests/test_future_annotations.py +7 -5
  104. warp/tests/test_linear_solvers.py +30 -0
  105. warp/tests/test_map.py +15 -1
  106. warp/tests/test_mat.py +1518 -378
  107. warp/tests/test_mat_assign_copy.py +178 -0
  108. warp/tests/test_mat_constructors.py +574 -0
  109. warp/tests/test_module_aot.py +287 -0
  110. warp/tests/test_print.py +69 -0
  111. warp/tests/test_quat.py +140 -34
  112. warp/tests/test_quat_assign_copy.py +145 -0
  113. warp/tests/test_reload.py +2 -1
  114. warp/tests/test_sparse.py +71 -0
  115. warp/tests/test_spatial.py +140 -34
  116. warp/tests/test_spatial_assign_copy.py +160 -0
  117. warp/tests/test_struct.py +43 -3
  118. warp/tests/test_tuple.py +96 -0
  119. warp/tests/test_types.py +61 -20
  120. warp/tests/test_vec.py +179 -34
  121. warp/tests/test_vec_assign_copy.py +143 -0
  122. warp/tests/tile/test_tile.py +245 -18
  123. warp/tests/tile/test_tile_cholesky.py +605 -0
  124. warp/tests/tile/test_tile_load.py +169 -0
  125. warp/tests/tile/test_tile_mathdx.py +2 -558
  126. warp/tests/tile/test_tile_matmul.py +1 -1
  127. warp/tests/tile/test_tile_mlp.py +1 -1
  128. warp/tests/tile/test_tile_shared_memory.py +5 -5
  129. warp/tests/unittest_suites.py +6 -0
  130. warp/tests/walkthrough_debug.py +1 -1
  131. warp/thirdparty/unittest_parallel.py +108 -9
  132. warp/types.py +571 -267
  133. warp/utils.py +68 -86
  134. {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/METADATA +29 -69
  135. {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/RECORD +138 -128
  136. warp/native/marching.cpp +0 -19
  137. warp/native/marching.cu +0 -514
  138. warp/native/marching.h +0 -19
  139. {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/WHEEL +0 -0
  140. {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/licenses/LICENSE.md +0 -0
  141. {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/top_level.txt +0 -0
warp/tests/test_tuple.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import sys
16
17
  import unittest
17
18
  from typing import Any, Tuple
18
19
 
@@ -208,6 +209,92 @@ def test_loop_variadic_ellipsis():
208
209
  wp.expect_eq(res, 22)
209
210
 
210
211
 
212
+ # Test for Python 3.10 tuple type compatibility issue
213
+ # Only define these functions on Python 3.9+ where lowercase tuple is supported
214
+ if sys.version_info >= (3, 9):
215
+
216
+ @wp.func
217
+ def complex_tuple_function(scale: float, offset: wp.vec3) -> tuple[float, wp.vec3f, wp.vec3f]:
218
+ """
219
+ Function that returns a complex tuple with mixed types.
220
+ This specifically tests the tuple[float, wp.vec3f, wp.vec3f] case
221
+ that was problematic on Python 3.10.
222
+ """
223
+ # Create some computed values
224
+ scaled_value = scale * 2.5
225
+ position = wp.vec3f(offset.x + 1.0, offset.y + 2.0, offset.z + 3.0)
226
+ velocity = wp.vec3f(scale * 0.1, scale * 0.2, scale * 0.3)
227
+
228
+ return (scaled_value, position, velocity)
229
+
230
+ @wp.func
231
+ def mixed_types_tuple_function() -> tuple[wp.vec3f, wp.vec3f, float, wp.mat33f]:
232
+ """
233
+ Function returning mixed types in a tuple.
234
+ Tests tuple[vec3f, vec3f, float, mat33f] type annotation.
235
+ """
236
+ return (
237
+ wp.vec3f(1.0, 2.0, 3.0),
238
+ wp.vec3f(4.0, 5.0, 6.0),
239
+ 42.0,
240
+ wp.mat33f(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0),
241
+ )
242
+
243
+ @wp.func
244
+ def homogeneous_tuple_function() -> tuple[wp.vec3f, wp.vec3f, wp.vec3f]:
245
+ """
246
+ Function returning fixed-size homogeneous tuple.
247
+ Tests tuple[wp.vec3f, wp.vec3f, wp.vec3f] type annotation.
248
+ """
249
+ return (wp.vec3f(1.0, 2.0, 3.0), wp.vec3f(4.0, 5.0, 6.0), wp.vec3f(7.0, 8.0, 9.0))
250
+
251
+ @wp.kernel
252
+ def test_complex_tuple_functions():
253
+ """
254
+ Kernel that tests complex tuple return types that were problematic on Python 3.10.
255
+ """
256
+ # Test the main problematic case: tuple[float, wp.vec3f, wp.vec3f]
257
+ result1 = complex_tuple_function(4.0, wp.vec3(10.0, 20.0, 30.0))
258
+
259
+ # Unpack and verify
260
+ scale_result, pos_result, vel_result = result1
261
+ wp.expect_near(scale_result, 10.0) # 4.0 * 2.5
262
+ wp.expect_eq(pos_result, wp.vec3f(11.0, 22.0, 33.0))
263
+ wp.expect_eq(vel_result, wp.vec3f(0.4, 0.8, 1.2))
264
+
265
+ # Test access by index
266
+ wp.expect_near(result1[0], 10.0)
267
+ wp.expect_eq(result1[1], wp.vec3f(11.0, 22.0, 33.0))
268
+ wp.expect_eq(result1[2], wp.vec3f(0.4, 0.8, 1.2))
269
+
270
+ # Test more complex tuple: tuple[vec3f, vec3f, float, mat33f]
271
+ mixed_result = mixed_types_tuple_function()
272
+ result_pos, result_vel, result_energy, result_transform = mixed_result
273
+
274
+ # Verify known values
275
+ wp.expect_eq(result_pos, wp.vec3f(1.0, 2.0, 3.0))
276
+ wp.expect_eq(result_vel, wp.vec3f(4.0, 5.0, 6.0))
277
+ wp.expect_eq(result_energy, 42.0)
278
+
279
+ # Verify transform matrix is identity
280
+ wp.expect_eq(result_transform[0, 0], 1.0)
281
+ wp.expect_eq(result_transform[1, 1], 1.0)
282
+ wp.expect_eq(result_transform[2, 2], 1.0)
283
+
284
+ # Test fixed-size homogeneous tuple: tuple[wp.vec3f, wp.vec3f, wp.vec3f]
285
+ homo_result = homogeneous_tuple_function()
286
+ wp.expect_eq(len(homo_result), 3)
287
+ wp.expect_eq(homo_result[0], wp.vec3f(1.0, 2.0, 3.0))
288
+ wp.expect_eq(homo_result[1], wp.vec3f(4.0, 5.0, 6.0))
289
+ wp.expect_eq(homo_result[2], wp.vec3f(7.0, 8.0, 9.0))
290
+
291
+ # Test unpacking
292
+ vec1, vec2, vec3 = homo_result
293
+ wp.expect_eq(vec1, wp.vec3f(1.0, 2.0, 3.0))
294
+ wp.expect_eq(vec2, wp.vec3f(4.0, 5.0, 6.0))
295
+ wp.expect_eq(vec3, wp.vec3f(7.0, 8.0, 9.0))
296
+
297
+
211
298
  devices = get_test_devices()
212
299
 
213
300
 
@@ -258,6 +345,15 @@ add_kernel_test(
258
345
  dim=1,
259
346
  devices=devices,
260
347
  )
348
+ # Only register the test for lowercase tuple syntax on Python 3.9+
349
+ if sys.version_info >= (3, 9):
350
+ add_kernel_test(
351
+ TestTuple,
352
+ name="test_complex_tuple_functions",
353
+ kernel=test_complex_tuple_functions,
354
+ dim=1,
355
+ devices=devices,
356
+ )
261
357
 
262
358
 
263
359
  if __name__ == "__main__":
warp/tests/test_types.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import sys
16
17
  import unittest
17
18
 
18
19
  from warp.tests.unittest_utils import *
@@ -267,11 +268,6 @@ class TestTypes(unittest.TestCase):
267
268
  with self.assertRaisesRegex(TypeError, r"Expected to assign a `int32` value but got `str` instead"):
268
269
  v1[0] = "123.0"
269
270
 
270
- with self.assertRaisesRegex(
271
- TypeError, r"Expected to assign a slice from a sequence of values but got `int` instead"
272
- ):
273
- v1[:] = 123
274
-
275
271
  with self.assertRaisesRegex(
276
272
  TypeError, r"Expected to assign a slice from a sequence of `int32` values but got `vec3i` instead"
277
273
  ):
@@ -483,26 +479,11 @@ class TestTypes(unittest.TestCase):
483
479
  with self.assertRaisesRegex(TypeError, r"Expected to assign a `float16` value but got `str` instead"):
484
480
  m[0][0] = "123.0"
485
481
 
486
- with self.assertRaisesRegex(
487
- TypeError, r"Expected to assign a slice from a sequence of values but got `int` instead"
488
- ):
489
- m[0] = 123
490
-
491
482
  with self.assertRaisesRegex(
492
483
  TypeError, r"Expected to assign a slice from a sequence of `float16` values but got `mat22h` instead"
493
484
  ):
494
485
  m[0] = (m,)
495
486
 
496
- with self.assertRaisesRegex(
497
- KeyError, r"Slices are not supported when indexing matrices using the `m\[start:end\]` notation"
498
- ):
499
- m[:] = 123
500
-
501
- with self.assertRaisesRegex(
502
- KeyError, r"Slices are not supported when indexing matrices using the `m\[i, j\]` notation"
503
- ):
504
- m[0, :1] = (123,)
505
-
506
487
  with self.assertRaisesRegex(ValueError, r"Can only assign sequence of same size"):
507
488
  m[0][:1] = (1, 2)
508
489
 
@@ -547,6 +528,66 @@ class TestTypes(unittest.TestCase):
547
528
  test_conversions(wp.uint64, np.uint64)
548
529
  test_conversions(wp.bool, np.bool_)
549
530
 
531
+ # Only define this test method on Python 3.9+ where lowercase tuple is supported
532
+ if sys.version_info >= (3, 9):
533
+
534
+ def test_tuple_type_code_generation(self):
535
+ """Test that tuple type annotations generate correct type codes, especially on Python 3.10."""
536
+ import sys
537
+ import types
538
+ from typing import get_origin
539
+
540
+ # Test basic tuple types
541
+ tuple_float_float = tuple[float, float]
542
+ result = wp.types.get_type_code(tuple_float_float)
543
+ self.assertEqual(result, "tpl2f4f4", "tuple[float, float] should generate 'tpl2f4f4'")
544
+
545
+ # Test tuple with Warp vector types - the problematic case from Python 3.10
546
+ tuple_mixed = tuple[float, wp.vec3f, wp.vec3f]
547
+ result = wp.types.get_type_code(tuple_mixed)
548
+ self.assertEqual(result, "tpl3f4v3f4v3f4", "tuple[float, vec3f, vec3f] should generate 'tpl3f4v3f4v3f4'")
549
+
550
+ # Test homogeneous tuple with ellipsis
551
+ tuple_homogeneous = tuple[wp.vec3f, ...]
552
+ result = wp.types.get_type_code(tuple_homogeneous)
553
+ self.assertEqual(result, "tpl2v3f4?", "tuple[vec3f, ...] should generate 'tpl2v3f4?'")
554
+
555
+ # Test single element tuple
556
+ tuple_single = tuple[wp.int32]
557
+ result = wp.types.get_type_code(tuple_single)
558
+ self.assertEqual(result, "tpl1i4", "tuple[int32] should generate 'tpl1i4'")
559
+
560
+ # Test tuple with multiple Warp types
561
+ tuple_multi_warp = tuple[wp.vec3f, wp.mat33f, wp.quatf]
562
+ result = wp.types.get_type_code(tuple_multi_warp)
563
+ self.assertEqual(
564
+ result, "tpl3v3f4m33f4qf4", "tuple[vec3f, mat33f, quatf] should generate 'tpl3v3f4m33f4qf4'"
565
+ )
566
+
567
+ # Verify the fix works on Python 3.9-3.10 specifically
568
+ if sys.version_info < (3, 11) and hasattr(types, "GenericAlias"):
569
+ # On Python 3.9-3.10, tuple[...] creates types.GenericAlias
570
+ self.assertIsInstance(
571
+ tuple_mixed, types.GenericAlias, "On Python 3.9-3.10, tuple[...] should create types.GenericAlias"
572
+ )
573
+ self.assertIs(tuple_mixed.__origin__, tuple, "GenericAlias origin should be tuple")
574
+
575
+ # Verify our fix catches this case
576
+ self.assertEqual(get_origin(tuple_mixed), tuple, "get_origin should return tuple")
577
+ elif sys.version_info >= (3, 11):
578
+ # On Python 3.11+, the existing code path should handle it
579
+ self.assertEqual(get_origin(tuple_mixed), tuple, "get_origin should return tuple on Python 3.11+")
580
+
581
+ # Test that the fix doesn't break existing functionality
582
+ # Test with built-in Python types
583
+ tuple_builtin = tuple[int, str, bool]
584
+ try:
585
+ # This might fail because str and bool aren't Warp types, but it shouldn't crash
586
+ wp.types.get_type_code(tuple_builtin)
587
+ except TypeError as e:
588
+ # Expected to fail for non-Warp types, but should be a clean TypeError
589
+ self.assertIn("Unrecognized type", str(e))
590
+
550
591
 
551
592
  for dtype in wp.types.int_types:
552
593
  add_function_test(TestTypes, f"test_integers_{dtype.__name__}", test_integers, devices=devices, dtype=dtype)
warp/tests/test_vec.py CHANGED
@@ -922,39 +922,6 @@ def test_vec_assign(test, device):
922
922
  run(vec_assign_attribute)
923
923
 
924
924
 
925
- def test_vec_assign_copy(test, device):
926
- saved_enable_vector_component_overwrites_setting = wp.config.enable_vector_component_overwrites
927
- try:
928
- wp.config.enable_vector_component_overwrites = True
929
-
930
- @wp.kernel(module="unique")
931
- def vec_assign_overwrite(x: wp.array(dtype=wp.vec3), y: wp.array(dtype=wp.vec3)):
932
- tid = wp.tid()
933
-
934
- a = wp.vec3()
935
- b = x[tid]
936
- a = b
937
- a[1] = 3.0
938
-
939
- y[tid] = a
940
-
941
- x = wp.ones(1, dtype=wp.vec3, device=device, requires_grad=True)
942
- y = wp.zeros(1, dtype=wp.vec3, device=device, requires_grad=True)
943
-
944
- tape = wp.Tape()
945
- with tape:
946
- wp.launch(vec_assign_overwrite, dim=1, inputs=[x, y], device=device)
947
-
948
- y.grad = wp.ones_like(y, requires_grad=False)
949
- tape.backward()
950
-
951
- assert_np_equal(y.numpy(), np.array([[1.0, 3.0, 1.0]], dtype=float))
952
- assert_np_equal(x.grad.numpy(), np.array([[1.0, 0.0, 1.0]], dtype=float))
953
-
954
- finally:
955
- wp.config.enable_vector_component_overwrites = saved_enable_vector_component_overwrites_setting
956
-
957
-
958
925
  @wp.kernel
959
926
  def vec_array_extract_subscript(x: wp.array2d(dtype=wp.vec3), y: wp.array2d(dtype=float)):
960
927
  i, j = wp.tid()
@@ -1189,6 +1156,181 @@ def test_scalar_vec_div(test, device):
1189
1156
  assert_np_equal(x.grad.numpy(), np.array(((-1.0, -0.25, -0.0625),), dtype=float))
1190
1157
 
1191
1158
 
1159
+ def test_vec_indexing_assign(test, device):
1160
+ @wp.func
1161
+ def fn():
1162
+ v = wp.vec4(1.0, 2.0, 3.0, 4.0)
1163
+
1164
+ v[0] = 123.0
1165
+ v[1] *= 2.0
1166
+
1167
+ wp.expect_eq(v[0], 123.0)
1168
+ wp.expect_eq(v[1], 4.0)
1169
+ wp.expect_eq(v[2], 3.0)
1170
+ wp.expect_eq(v[3], 4.0)
1171
+
1172
+ v[-1] = 123.0
1173
+ v[-2] *= 2.0
1174
+
1175
+ wp.expect_eq(v[-1], 123.0)
1176
+ wp.expect_eq(v[-2], 6.0)
1177
+ wp.expect_eq(v[-3], 4.0)
1178
+ wp.expect_eq(v[-4], 123.0)
1179
+
1180
+ @wp.kernel(module="unique")
1181
+ def kernel():
1182
+ fn()
1183
+
1184
+ wp.launch(kernel, 1, device=device)
1185
+ wp.synchronize()
1186
+ fn()
1187
+
1188
+
1189
+ def test_vec_slicing_assign(test, device):
1190
+ vec0 = wp.vec(0, float)
1191
+ vec1 = wp.vec(1, float)
1192
+ vec2 = wp.vec(2, float)
1193
+ vec3 = wp.vec(3, float)
1194
+ vec4 = wp.vec(4, float)
1195
+
1196
+ @wp.func
1197
+ def fn():
1198
+ v = wp.vec4(1.0, 2.0, 3.0, 4.0)
1199
+
1200
+ wp.expect_eq(v[:] == vec4(1.0, 2.0, 3.0, 4.0), True)
1201
+ wp.expect_eq(v[-123:123] == vec4(1.0, 2.0, 3.0, 4.0), True)
1202
+ wp.expect_eq(v[123:] == vec0(), True)
1203
+ wp.expect_eq(v[:-123] == vec0(), True)
1204
+ wp.expect_eq(v[::123] == vec1(1.0), True)
1205
+
1206
+ wp.expect_eq(v[1:] == vec3(2.0, 3.0, 4.0), True)
1207
+ wp.expect_eq(v[-2:] == vec2(3.0, 4.0), True)
1208
+ wp.expect_eq(v[:2] == vec2(1.0, 2.0), True)
1209
+ wp.expect_eq(v[:-1] == vec3(1.0, 2.0, 3.0), True)
1210
+ wp.expect_eq(v[::2] == vec2(1.0, 3.0), True)
1211
+ wp.expect_eq(v[1::2] == vec2(2.0, 4.0), True)
1212
+ wp.expect_eq(v[::-1] == vec4(4.0, 3.0, 2.0, 1.0), True)
1213
+ wp.expect_eq(v[::-2] == vec2(4.0, 2.0), True)
1214
+ wp.expect_eq(v[1::-2] == vec1(2.0), True)
1215
+
1216
+ v[1:] = vec3(5.0, 6.0, 7.0)
1217
+ wp.expect_eq(v == wp.vec4(1.0, 5.0, 6.0, 7.0), True)
1218
+
1219
+ v[-2:] = vec2(8.0, 9.0)
1220
+ wp.expect_eq(v == wp.vec4(1.0, 5.0, 8.0, 9.0), True)
1221
+
1222
+ v[:2] = vec2(10.0, 11.0)
1223
+ wp.expect_eq(v == wp.vec4(10.0, 11.0, 8.0, 9.0), True)
1224
+
1225
+ v[:-1] = vec3(12.0, 13.0, 14.0)
1226
+ wp.expect_eq(v == wp.vec4(12.0, 13.0, 14.0, 9.0), True)
1227
+
1228
+ v[::2] = vec2(15.0, 16.0)
1229
+ wp.expect_eq(v == wp.vec4(15.0, 13.0, 16.0, 9.0), True)
1230
+
1231
+ v[1::2] = vec2(17.0, 18.0)
1232
+ wp.expect_eq(v == wp.vec4(15.0, 17.0, 16.0, 18.0), True)
1233
+
1234
+ v[::-1] = vec4(19.0, 20.0, 21.0, 22.0)
1235
+ wp.expect_eq(v == wp.vec4(22.0, 21.0, 20.0, 19.0), True)
1236
+
1237
+ v[::-2] = vec2(23.0, 24.0)
1238
+ wp.expect_eq(v == wp.vec4(22.0, 24.0, 20.0, 23.0), True)
1239
+
1240
+ v[1::-2] = vec1(25.0)
1241
+ wp.expect_eq(v == wp.vec4(22.0, 25.0, 20.0, 23.0), True)
1242
+
1243
+ v[1:] += vec3(26.0, 27.0, 28.0)
1244
+ wp.expect_eq(v == wp.vec4(22.0, 51.0, 47.0, 51.0), True)
1245
+
1246
+ v[:-1] -= vec3(29.0, 30.0, 31.0)
1247
+ wp.expect_eq(v == wp.vec4(-7.0, 21.0, 16.0, 51.0), True)
1248
+
1249
+ v[:] %= vec4(32.0, 33.0, 34.0, 35.0)
1250
+ wp.expect_eq(v == wp.vec4(-7.0, 21.0, 16.0, 16.0), True)
1251
+
1252
+ @wp.kernel(module="unique")
1253
+ def kernel():
1254
+ fn()
1255
+
1256
+ wp.launch(kernel, 1, device=device)
1257
+ wp.synchronize()
1258
+ fn()
1259
+
1260
+
1261
+ def test_vec_assign_inplace_errors(test, device):
1262
+ @wp.kernel
1263
+ def kernel_1():
1264
+ v = wp.vec4(1.0, 2.0, 3.0, 4.0)
1265
+ v[1:] = wp.vec3d(wp.float64(5.0), wp.float64(6.0), wp.float64(7.0))
1266
+
1267
+ with test.assertRaisesRegex(
1268
+ ValueError,
1269
+ r"The provided vector is expected to be of length 3 with dtype float32.$",
1270
+ ):
1271
+ wp.launch(kernel_1, dim=1, device=device)
1272
+
1273
+ @wp.kernel
1274
+ def kernel_2():
1275
+ v = wp.vec4(1.0, 2.0, 3.0, 4.0)
1276
+ v[1:] = wp.float64(5.0)
1277
+
1278
+ with test.assertRaisesRegex(
1279
+ ValueError,
1280
+ r"The provided value is expected to be a vector of length 3, with dtype float32.$",
1281
+ ):
1282
+ wp.launch(kernel_2, dim=1, device=device)
1283
+
1284
+ @wp.kernel
1285
+ def kernel_3():
1286
+ v = wp.vec4(1.0, 2.0, 3.0, 4.0)
1287
+ v[1:] = wp.mat22(5.0, 6.0, 7.0, 8.0)
1288
+
1289
+ with test.assertRaisesRegex(
1290
+ ValueError,
1291
+ r"The provided value is expected to be a vector of length 3, with dtype float32.$",
1292
+ ):
1293
+ wp.launch(kernel_3, dim=1, device=device)
1294
+
1295
+ @wp.kernel
1296
+ def kernel_4():
1297
+ v = wp.vec4(1.0, 2.0, 3.0, 4.0)
1298
+ v[1:] = wp.vec2(5.0, 6.0)
1299
+
1300
+ with test.assertRaisesRegex(
1301
+ ValueError,
1302
+ r"The length of the provided vector \(2\) isn't compatible with the given slice \(expected 3\).$",
1303
+ ):
1304
+ wp.launch(kernel_4, dim=1, device=device)
1305
+
1306
+
1307
+ def test_vec_slicing_assign_backward(test, device):
1308
+ @wp.kernel(module="unique")
1309
+ def kernel(arr_x: wp.array(dtype=wp.vec2), arr_y: wp.array(dtype=wp.vec4)):
1310
+ i = wp.tid()
1311
+
1312
+ y = arr_y[i]
1313
+
1314
+ y[:2] = arr_x[i]
1315
+ y[1:-1] += arr_x[i][:2]
1316
+ y[3:1:-1] -= arr_x[i][0:]
1317
+
1318
+ arr_y[i] = y
1319
+
1320
+ x = wp.ones(1, dtype=wp.vec2, requires_grad=True, device=device)
1321
+ y = wp.zeros(1, dtype=wp.vec4, requires_grad=True, device=device)
1322
+
1323
+ tape = wp.Tape()
1324
+ with tape:
1325
+ wp.launch(kernel, 1, inputs=(x,), outputs=(y,), device=device)
1326
+
1327
+ y.grad = wp.ones_like(y)
1328
+ tape.backward()
1329
+
1330
+ assert_np_equal(y.numpy(), np.array(((1.0, 2.0, 0.0, -1.0),), dtype=float))
1331
+ assert_np_equal(x.grad.numpy(), np.array(((1.0, 1.0),), dtype=float))
1332
+
1333
+
1192
1334
  devices = get_test_devices()
1193
1335
 
1194
1336
 
@@ -1248,7 +1390,6 @@ add_function_test(TestVec, "test_length_mismatch", test_length_mismatch, devices
1248
1390
  add_function_test(TestVec, "test_vector_len", test_vector_len, devices=devices)
1249
1391
  add_function_test(TestVec, "test_vec_extract", test_vec_extract, devices=devices)
1250
1392
  add_function_test(TestVec, "test_vec_assign", test_vec_assign, devices=devices)
1251
- add_function_test(TestVec, "test_vec_assign_copy", test_vec_assign_copy, devices=devices)
1252
1393
  add_function_test(TestVec, "test_vec_array_extract", test_vec_array_extract, devices=devices)
1253
1394
  add_function_test(TestVec, "test_vec_array_assign", test_vec_array_assign, devices=devices)
1254
1395
  add_function_test(TestVec, "test_vec_add_inplace", test_vec_add_inplace, devices=devices)
@@ -1256,6 +1397,10 @@ add_function_test(TestVec, "test_vec_sub_inplace", test_vec_sub_inplace, devices
1256
1397
  add_function_test(TestVec, "test_vec_array_add_inplace", test_vec_array_add_inplace, devices=devices)
1257
1398
  add_function_test(TestVec, "test_vec_array_sub_inplace", test_vec_array_sub_inplace, devices=devices)
1258
1399
  add_function_test(TestVec, "test_scalar_vec_div", test_scalar_vec_div, devices=devices)
1400
+ add_function_test(TestVec, "test_vec_indexing_assign", test_vec_indexing_assign, devices=devices)
1401
+ add_function_test(TestVec, "test_vec_slicing_assign", test_vec_slicing_assign, devices=devices)
1402
+ add_function_test(TestVec, "test_vec_assign_inplace_errors", test_vec_assign_inplace_errors, devices=devices)
1403
+ add_function_test(TestVec, "test_vec_slicing_assign_backward", test_vec_slicing_assign_backward, devices=devices)
1259
1404
 
1260
1405
 
1261
1406
  if __name__ == "__main__":
@@ -0,0 +1,143 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import unittest
17
+
18
+ import numpy as np
19
+
20
+ import warp as wp
21
+ from warp.tests.unittest_utils import *
22
+
23
+
24
+ def setUpModule():
25
+ wp.config.enable_vector_component_overwrites = True
26
+
27
+
28
+ def tearDownModule():
29
+ wp.config.enable_vector_component_overwrites = False
30
+
31
+
32
+ @wp.kernel
33
+ def vec_assign_subscript(x: wp.array(dtype=float), y: wp.array(dtype=wp.vec3)):
34
+ i = wp.tid()
35
+
36
+ a = wp.vec3()
37
+ a[0] = 1.0 * x[i]
38
+ a[1] = 2.0 * x[i]
39
+ a[2] = 3.0 * x[i]
40
+ y[i] = a
41
+
42
+
43
+ @wp.kernel
44
+ def vec_assign_attribute(x: wp.array(dtype=float), y: wp.array(dtype=wp.vec3)):
45
+ i = wp.tid()
46
+
47
+ a = wp.vec3()
48
+ a.x = 1.0 * x[i]
49
+ a.y = 2.0 * x[i]
50
+ a.z = 3.0 * x[i]
51
+ y[i] = a
52
+
53
+
54
+ def test_vec_assign(test, device):
55
+ def run(kernel):
56
+ x = wp.ones(1, dtype=float, requires_grad=True, device=device)
57
+ y = wp.zeros(1, dtype=wp.vec3, requires_grad=True, device=device)
58
+
59
+ tape = wp.Tape()
60
+ with tape:
61
+ wp.launch(kernel, 1, inputs=[x], outputs=[y], device=device)
62
+
63
+ y.grad = wp.ones_like(y)
64
+ tape.backward()
65
+
66
+ assert_np_equal(y.numpy(), np.array([[1.0, 2.0, 3.0]], dtype=float))
67
+ assert_np_equal(x.grad.numpy(), np.array([6.0], dtype=float))
68
+
69
+ run(vec_assign_subscript)
70
+ run(vec_assign_attribute)
71
+
72
+
73
+ def test_vec_assign_copy(test, device):
74
+ @wp.kernel(module="unique")
75
+ def vec_assign_overwrite(x: wp.array(dtype=wp.vec3), y: wp.array(dtype=wp.vec3)):
76
+ tid = wp.tid()
77
+
78
+ a = wp.vec3()
79
+ b = x[tid]
80
+ a = b
81
+ a[1] = 3.0
82
+
83
+ y[tid] = a
84
+
85
+ x = wp.ones(1, dtype=wp.vec3, device=device, requires_grad=True)
86
+ y = wp.zeros(1, dtype=wp.vec3, device=device, requires_grad=True)
87
+
88
+ tape = wp.Tape()
89
+ with tape:
90
+ wp.launch(vec_assign_overwrite, dim=1, inputs=[x, y], device=device)
91
+
92
+ y.grad = wp.ones_like(y, requires_grad=False)
93
+ tape.backward()
94
+
95
+ assert_np_equal(y.numpy(), np.array([[1.0, 3.0, 1.0]], dtype=float))
96
+ assert_np_equal(x.grad.numpy(), np.array([[1.0, 0.0, 1.0]], dtype=float))
97
+
98
+
99
+ def test_vec_slicing_assign_backward(test, device):
100
+ @wp.kernel(module="unique")
101
+ def kernel(arr_x: wp.array(dtype=wp.vec2), arr_y: wp.array(dtype=wp.vec4)):
102
+ i = wp.tid()
103
+
104
+ x = arr_x[i]
105
+ y = arr_y[i]
106
+
107
+ y[:2] = x
108
+ y[1:-1] += x[:2]
109
+ y[3:1:-1] -= x[0:]
110
+
111
+ arr_y[i] = y
112
+
113
+ x = wp.ones(1, dtype=wp.vec2, requires_grad=True, device=device)
114
+ y = wp.zeros(1, dtype=wp.vec4, requires_grad=True, device=device)
115
+
116
+ tape = wp.Tape()
117
+ with tape:
118
+ wp.launch(kernel, 1, inputs=(x,), outputs=(y,), device=device)
119
+
120
+ y.grad = wp.ones_like(y)
121
+ tape.backward()
122
+
123
+ assert_np_equal(y.numpy(), np.array(((1.0, 2.0, 0.0, -1.0),), dtype=float))
124
+ assert_np_equal(x.grad.numpy(), np.array(((1.0, 1.0),), dtype=float))
125
+
126
+
127
+ devices = get_test_devices()
128
+
129
+
130
+ class TestVecAssignCopy(unittest.TestCase):
131
+ pass
132
+
133
+
134
+ add_function_test(TestVecAssignCopy, "test_vec_assign", test_vec_assign, devices=devices)
135
+ add_function_test(TestVecAssignCopy, "test_vec_assign_copy", test_vec_assign_copy, devices=devices)
136
+ add_function_test(
137
+ TestVecAssignCopy, "test_vec_slicing_assign_backward", test_vec_slicing_assign_backward, devices=devices
138
+ )
139
+
140
+
141
+ if __name__ == "__main__":
142
+ wp.clear_kernel_cache()
143
+ unittest.main(verbosity=2, failfast=True)