warp-lang 1.8.0__py3-none-macosx_10_13_universal2.whl → 1.9.0__py3-none-macosx_10_13_universal2.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 (153) hide show
  1. warp/__init__.py +282 -103
  2. warp/__init__.pyi +482 -110
  3. warp/bin/libwarp-clang.dylib +0 -0
  4. warp/bin/libwarp.dylib +0 -0
  5. warp/build.py +93 -30
  6. warp/build_dll.py +48 -63
  7. warp/builtins.py +955 -137
  8. warp/codegen.py +327 -209
  9. warp/config.py +1 -1
  10. warp/context.py +1363 -800
  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_callable.py +34 -4
  18. warp/examples/interop/example_jax_kernel.py +27 -1
  19. warp/fabric.py +1 -1
  20. warp/fem/cache.py +27 -19
  21. warp/fem/domain.py +2 -2
  22. warp/fem/field/nodal_field.py +2 -2
  23. warp/fem/field/virtual.py +266 -166
  24. warp/fem/geometry/geometry.py +5 -5
  25. warp/fem/integrate.py +200 -91
  26. warp/fem/space/restriction.py +4 -0
  27. warp/fem/space/shape/tet_shape_function.py +3 -10
  28. warp/jax_experimental/custom_call.py +1 -1
  29. warp/jax_experimental/ffi.py +203 -54
  30. warp/marching_cubes.py +708 -0
  31. warp/native/array.h +103 -8
  32. warp/native/builtin.h +90 -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 +13 -3
  38. warp/native/crt.cpp +2 -2
  39. warp/native/crt.h +3 -5
  40. warp/native/cuda_util.cpp +42 -11
  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 +4 -4
  48. warp/native/mat.h +1913 -119
  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 +5 -3
  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 +337 -16
  59. warp/native/rand.h +7 -7
  60. warp/native/range.h +7 -1
  61. warp/native/reduce.cpp +10 -10
  62. warp/native/reduce.cu +13 -14
  63. warp/native/runlength_encode.cpp +2 -2
  64. warp/native/runlength_encode.cu +5 -5
  65. warp/native/scan.cpp +3 -3
  66. warp/native/scan.cu +4 -4
  67. warp/native/sort.cpp +10 -10
  68. warp/native/sort.cu +22 -22
  69. warp/native/sparse.cpp +8 -8
  70. warp/native/sparse.cu +14 -14
  71. warp/native/spatial.h +366 -17
  72. warp/native/svd.h +23 -8
  73. warp/native/temp_buffer.h +2 -2
  74. warp/native/tile.h +303 -70
  75. warp/native/tile_radix_sort.h +5 -1
  76. warp/native/tile_reduce.h +16 -25
  77. warp/native/tuple.h +2 -2
  78. warp/native/vec.h +385 -18
  79. warp/native/volume.cpp +54 -54
  80. warp/native/volume.cu +1 -1
  81. warp/native/volume.h +2 -1
  82. warp/native/volume_builder.cu +30 -37
  83. warp/native/warp.cpp +150 -149
  84. warp/native/warp.cu +337 -193
  85. warp/native/warp.h +227 -226
  86. warp/optim/linear.py +736 -271
  87. warp/render/imgui_manager.py +289 -0
  88. warp/render/render_opengl.py +137 -57
  89. warp/render/render_usd.py +0 -1
  90. warp/sim/collide.py +1 -2
  91. warp/sim/graph_coloring.py +2 -2
  92. warp/sim/integrator_vbd.py +10 -2
  93. warp/sparse.py +559 -176
  94. warp/tape.py +2 -0
  95. warp/tests/aux_test_module_aot.py +7 -0
  96. warp/tests/cuda/test_async.py +3 -3
  97. warp/tests/cuda/test_conditional_captures.py +101 -0
  98. warp/tests/geometry/test_marching_cubes.py +233 -12
  99. warp/tests/sim/test_cloth.py +89 -6
  100. warp/tests/sim/test_coloring.py +82 -7
  101. warp/tests/test_array.py +56 -5
  102. warp/tests/test_assert.py +53 -0
  103. warp/tests/test_atomic_cas.py +127 -114
  104. warp/tests/test_codegen.py +3 -2
  105. warp/tests/test_context.py +8 -15
  106. warp/tests/test_enum.py +136 -0
  107. warp/tests/test_examples.py +2 -2
  108. warp/tests/test_fem.py +45 -2
  109. warp/tests/test_fixedarray.py +229 -0
  110. warp/tests/test_func.py +18 -15
  111. warp/tests/test_future_annotations.py +7 -5
  112. warp/tests/test_linear_solvers.py +30 -0
  113. warp/tests/test_map.py +1 -1
  114. warp/tests/test_mat.py +1540 -378
  115. warp/tests/test_mat_assign_copy.py +178 -0
  116. warp/tests/test_mat_constructors.py +574 -0
  117. warp/tests/test_module_aot.py +287 -0
  118. warp/tests/test_print.py +69 -0
  119. warp/tests/test_quat.py +162 -34
  120. warp/tests/test_quat_assign_copy.py +145 -0
  121. warp/tests/test_reload.py +2 -1
  122. warp/tests/test_sparse.py +103 -0
  123. warp/tests/test_spatial.py +140 -34
  124. warp/tests/test_spatial_assign_copy.py +160 -0
  125. warp/tests/test_static.py +48 -0
  126. warp/tests/test_struct.py +43 -3
  127. warp/tests/test_tape.py +38 -0
  128. warp/tests/test_types.py +0 -20
  129. warp/tests/test_vec.py +216 -441
  130. warp/tests/test_vec_assign_copy.py +143 -0
  131. warp/tests/test_vec_constructors.py +325 -0
  132. warp/tests/tile/test_tile.py +206 -152
  133. warp/tests/tile/test_tile_cholesky.py +605 -0
  134. warp/tests/tile/test_tile_load.py +169 -0
  135. warp/tests/tile/test_tile_mathdx.py +2 -558
  136. warp/tests/tile/test_tile_matmul.py +179 -0
  137. warp/tests/tile/test_tile_mlp.py +1 -1
  138. warp/tests/tile/test_tile_reduce.py +100 -11
  139. warp/tests/tile/test_tile_shared_memory.py +16 -16
  140. warp/tests/tile/test_tile_sort.py +59 -55
  141. warp/tests/unittest_suites.py +16 -0
  142. warp/tests/walkthrough_debug.py +1 -1
  143. warp/thirdparty/unittest_parallel.py +108 -9
  144. warp/types.py +554 -264
  145. warp/utils.py +68 -86
  146. {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/METADATA +28 -65
  147. {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/RECORD +150 -138
  148. warp/native/marching.cpp +0 -19
  149. warp/native/marching.cu +0 -514
  150. warp/native/marching.h +0 -19
  151. {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/WHEEL +0 -0
  152. {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/licenses/LICENSE.md +0 -0
  153. {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,145 @@
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 quat_assign_subscript(x: wp.array(dtype=float), y: wp.array(dtype=wp.quat)):
34
+ i = wp.tid()
35
+
36
+ a = wp.quat()
37
+ a[0] = 1.0 * x[i]
38
+ a[1] = 2.0 * x[i]
39
+ a[2] = 3.0 * x[i]
40
+ a[3] = 4.0 * x[i]
41
+ y[i] = a
42
+
43
+
44
+ @wp.kernel
45
+ def quat_assign_attribute(x: wp.array(dtype=float), y: wp.array(dtype=wp.quat)):
46
+ i = wp.tid()
47
+
48
+ a = wp.quat()
49
+ a.x = 1.0 * x[i]
50
+ a.y = 2.0 * x[i]
51
+ a.z = 3.0 * x[i]
52
+ a.w = 4.0 * x[i]
53
+ y[i] = a
54
+
55
+
56
+ def test_quat_assign(test, device):
57
+ def run(kernel):
58
+ x = wp.ones(1, dtype=float, requires_grad=True, device=device)
59
+ y = wp.zeros(1, dtype=wp.quat, requires_grad=True, device=device)
60
+
61
+ tape = wp.Tape()
62
+ with tape:
63
+ wp.launch(kernel, 1, inputs=[x], outputs=[y], device=device)
64
+
65
+ y.grad = wp.ones_like(y)
66
+ tape.backward()
67
+
68
+ assert_np_equal(y.numpy(), np.array([[1.0, 2.0, 3.0, 4.0]], dtype=float))
69
+ assert_np_equal(x.grad.numpy(), np.array([10.0], dtype=float))
70
+
71
+ run(quat_assign_subscript)
72
+ run(quat_assign_attribute)
73
+
74
+
75
+ def test_quat_assign_copy(test, device):
76
+ @wp.kernel(module="unique")
77
+ def quat_assign_overwrite(x: wp.array(dtype=wp.quat), y: wp.array(dtype=wp.quat)):
78
+ tid = wp.tid()
79
+
80
+ a = wp.quat()
81
+ b = x[tid]
82
+ a = b
83
+ a[1] = 3.0
84
+
85
+ y[tid] = a
86
+
87
+ x = wp.ones(1, dtype=wp.quat, device=device, requires_grad=True)
88
+ y = wp.zeros(1, dtype=wp.quat, device=device, requires_grad=True)
89
+
90
+ tape = wp.Tape()
91
+ with tape:
92
+ wp.launch(quat_assign_overwrite, dim=1, inputs=[x, y], device=device)
93
+
94
+ y.grad = wp.ones_like(y, requires_grad=False)
95
+ tape.backward()
96
+
97
+ assert_np_equal(y.numpy(), np.array([[1.0, 3.0, 1.0, 1.0]], dtype=float))
98
+ assert_np_equal(x.grad.numpy(), np.array([[1.0, 0.0, 1.0, 1.0]], dtype=float))
99
+
100
+
101
+ def test_quat_slicing_assign_backward(test, device):
102
+ @wp.kernel(module="unique")
103
+ def kernel(arr_x: wp.array(dtype=wp.vec2), arr_y: wp.array(dtype=wp.quat)):
104
+ i = wp.tid()
105
+
106
+ x = arr_x[i]
107
+ y = arr_y[i]
108
+
109
+ y[:2] = x
110
+ y[1:-1] += x[:2]
111
+ y[3:1:-1] -= x[0:]
112
+
113
+ arr_y[i] = y
114
+
115
+ x = wp.ones(1, dtype=wp.vec2, requires_grad=True, device=device)
116
+ y = wp.zeros(1, dtype=wp.quat, requires_grad=True, device=device)
117
+
118
+ tape = wp.Tape()
119
+ with tape:
120
+ wp.launch(kernel, 1, inputs=(x,), outputs=(y,), device=device)
121
+
122
+ y.grad = wp.ones_like(y)
123
+ tape.backward()
124
+
125
+ assert_np_equal(y.numpy(), np.array(((1.0, 2.0, 0.0, -1.0),), dtype=float))
126
+ assert_np_equal(x.grad.numpy(), np.array(((1.0, 1.0),), dtype=float))
127
+
128
+
129
+ devices = get_test_devices()
130
+
131
+
132
+ class TestQuatAssignCopy(unittest.TestCase):
133
+ pass
134
+
135
+
136
+ add_function_test(TestQuatAssignCopy, "test_quat_assign", test_quat_assign, devices=devices)
137
+ add_function_test(TestQuatAssignCopy, "test_quat_assign_copy", test_quat_assign_copy, devices=devices)
138
+ add_function_test(
139
+ TestQuatAssignCopy, "test_quat_slicing_assign_backward", test_quat_slicing_assign_backward, devices=devices
140
+ )
141
+
142
+
143
+ if __name__ == "__main__":
144
+ wp.clear_kernel_cache()
145
+ unittest.main(verbosity=2)
warp/tests/test_reload.py CHANGED
@@ -35,7 +35,8 @@ def reload_module(module):
35
35
  # Clearing the .pyc file associated with a module is a necessary workaround
36
36
  # for `importlib.reload` to work as expected when run from within Kit.
37
37
  cache_file = importlib.util.cache_from_source(module.__file__)
38
- os.remove(cache_file)
38
+ if os.path.exists(cache_file):
39
+ os.remove(cache_file)
39
40
  importlib.reload(module)
40
41
 
41
42
 
warp/tests/test_sparse.py CHANGED
@@ -140,6 +140,32 @@ def test_bsr_from_triplets(test, device):
140
140
  bsr_set_from_triplets(bsr, rows, cols, vals)
141
141
 
142
142
 
143
+ def test_bsr_from_triplets_prune_numerical_zeros(test, device):
144
+ rows = wp.array([1, 0, 2, 3], dtype=int)
145
+ cols = wp.array([0, 1, 2, 3], dtype=int)
146
+ vals = wp.zeros(len(rows), dtype=float)
147
+
148
+ A = bsr_from_triplets(
149
+ rows_of_blocks=12, # Number of rows of blocks
150
+ cols_of_blocks=12, # Number of columns of blocks
151
+ rows=rows, # Row indices
152
+ columns=cols, # Column indices
153
+ values=vals, # Block values
154
+ prune_numerical_zeros=False,
155
+ )
156
+ assert A.nnz_sync() == 4
157
+
158
+ A = bsr_from_triplets(
159
+ rows_of_blocks=12, # Number of rows of blocks
160
+ cols_of_blocks=12, # Number of columns of blocks
161
+ rows=rows, # Row indices
162
+ columns=cols, # Column indices
163
+ values=vals, # Block values
164
+ prune_numerical_zeros=True,
165
+ )
166
+ assert A.nnz_sync() == 0
167
+
168
+
143
169
  def test_bsr_from_triplets_gradient(test, device):
144
170
  rng = np.random.default_rng(123)
145
171
 
@@ -542,6 +568,7 @@ def make_test_bsr_mv(block_shape, scalar_type):
542
568
  work_buffer = wp.empty_like(y)
543
569
  for alpha, beta in zip(alphas, betas):
544
570
  ref = alpha * _bsr_to_dense(A) @ x.numpy().flatten() + beta * y.numpy().flatten()
571
+
545
572
  if beta == 0.0:
546
573
  y = A @ x
547
574
  else:
@@ -578,7 +605,67 @@ def make_test_bsr_mv(block_shape, scalar_type):
578
605
  return test_bsr_mv
579
606
 
580
607
 
608
+ def make_test_bsr_multiply_deep(block_shape, scalar_type):
609
+ def test_bsr_multiply_deep(test, device):
610
+ """Test BSR matrix multiplication with deep matrices (many columns > 256)"""
611
+ rng = np.random.default_rng(123)
612
+
613
+ # Generate a dense matrix with few rows and many columns (> 256)
614
+ nrow = (4 + block_shape[0] - 1) // block_shape[0]
615
+ ncol = (600 + block_shape[1] - 1) // block_shape[1]
616
+
617
+ # Create a dense "sparse" matrix
618
+ values = rng.random(size=(nrow * ncol, block_shape[0], block_shape[1]))
619
+ rows, cols = np.meshgrid(np.arange(nrow), np.arange(ncol))
620
+
621
+ # Convert to warp arrays
622
+ rows = wp.array(rows.flatten(), dtype=int, device=device)
623
+ cols = wp.array(cols.flatten(), dtype=int, device=device)
624
+ vals = wp.array(values, dtype=scalar_type, device=device)
625
+
626
+ # Convert to BSR using bsr_from_triplets
627
+ A = bsr_from_triplets(nrow, ncol, rows, cols, vals)
628
+
629
+ # Get dense representation for numpy reference
630
+ A_dense = _bsr_to_dense(A)
631
+
632
+ # Multiply with itself transpose using bsr_mm
633
+ # A @ A.T should result in a nrow x nrow matrix
634
+ At = bsr_transposed(A)
635
+
636
+ result = bsr_mm(A, At)
637
+
638
+ # Check that the result is correct against numpy reference
639
+ result_dense = _bsr_to_dense(result)
640
+ ref_dense = A_dense @ A_dense.T
641
+
642
+ assert_np_equal(result_dense, ref_dense, 0.0001)
643
+
644
+ # Additional test: multiply A.T @ A (should be ncol x ncol)
645
+ result2 = bsr_mm(At, A)
646
+ result2_dense = _bsr_to_dense(result2)
647
+ ref2_dense = A_dense.T @ A_dense
648
+
649
+ assert_np_equal(result2_dense, ref2_dense, 0.0001)
650
+
651
+ # Test matrix vector products
652
+ x = wp.array(rng.random(size=A.shape[1]), dtype=A.scalar_type, device=device)
653
+ y = wp.array(rng.random(size=A.shape[0]), dtype=A.scalar_type, device=device)
654
+ bsr_mv(A, x, y)
655
+ res = y.numpy().flatten()
656
+ ref = A_dense @ x.numpy().flatten()
657
+ assert_np_equal(res, ref, 0.0001 * block_shape[1])
658
+
659
+ bsr_mv(A, y, x, transpose=True)
660
+ res = x.numpy().flatten()
661
+ ref = A_dense.T @ y.numpy().flatten()
662
+ assert_np_equal(res, ref, 0.0001 * block_shape[1])
663
+
664
+ return test_bsr_multiply_deep
665
+
666
+
581
667
  devices = get_test_devices()
668
+ cuda_test_devices = get_selected_cuda_test_devices()
582
669
 
583
670
 
584
671
  class TestSparse(unittest.TestCase):
@@ -604,6 +691,12 @@ class TestSparse(unittest.TestCase):
604
691
 
605
692
  add_function_test(TestSparse, "test_csr_from_triplets", test_csr_from_triplets, devices=devices)
606
693
  add_function_test(TestSparse, "test_bsr_from_triplets", test_bsr_from_triplets, devices=devices)
694
+ add_function_test(
695
+ TestSparse,
696
+ "test_bsr_from_triplets_prune_numerical_zeros",
697
+ test_bsr_from_triplets_prune_numerical_zeros,
698
+ devices=devices,
699
+ )
607
700
  add_function_test(TestSparse, "test_bsr_get_diag", test_bsr_get_set_diag, devices=devices)
608
701
  add_function_test(TestSparse, "test_bsr_split_merge", test_bsr_split_merge, devices=devices)
609
702
  add_function_test(TestSparse, "test_bsr_assign_masked", test_bsr_assign_masked, devices=devices)
@@ -621,6 +714,16 @@ add_function_test(TestSparse, "test_csr_mm", make_test_bsr_mm((1, 1), wp.float32
621
714
  add_function_test(TestSparse, "test_bsr_mm_1_3", make_test_bsr_mm((1, 3), wp.float32), devices=devices)
622
715
  add_function_test(TestSparse, "test_bsr_mm_3_3", make_test_bsr_mm((3, 3), wp.float64), devices=devices)
623
716
 
717
+ add_function_test(
718
+ TestSparse, "test_bsr_multiply_deep_2_2", make_test_bsr_multiply_deep((2, 2), wp.float64), devices=devices
719
+ )
720
+ add_function_test(
721
+ TestSparse,
722
+ "test_bsr_multiply_deep_30_30",
723
+ make_test_bsr_multiply_deep((30, 30), wp.float32),
724
+ devices=cuda_test_devices,
725
+ )
726
+
624
727
  add_function_test(TestSparse, "test_csr_mv", make_test_bsr_mv((1, 1), wp.float32), devices=devices)
625
728
  add_function_test(TestSparse, "test_bsr_mv_1_3", make_test_bsr_mv((1, 3), wp.float32), devices=devices)
626
729
  add_function_test(TestSparse, "test_bsr_mv_3_3", make_test_bsr_mv((3, 3), wp.float64), devices=devices)
@@ -2217,39 +2217,6 @@ def test_transform_assign(test, device):
2217
2217
  assert_np_equal(y.grad.numpy(), np.array([[1.0, 1.0, 1.0, 1.0]], dtype=float))
2218
2218
 
2219
2219
 
2220
- def test_transform_assign_copy(test, device):
2221
- saved_enable_vector_component_overwrites_setting = wp.config.enable_vector_component_overwrites
2222
- try:
2223
- wp.config.enable_vector_component_overwrites = True
2224
-
2225
- @wp.kernel
2226
- def transform_assign_overwrite(x: wp.array(dtype=wp.transform), y: wp.array(dtype=wp.transform)):
2227
- tid = wp.tid()
2228
-
2229
- a = wp.transform()
2230
- b = x[tid]
2231
- a = b
2232
- a[1] = 3.0
2233
-
2234
- y[tid] = a
2235
-
2236
- x = wp.ones(1, dtype=wp.transform, device=device, requires_grad=True)
2237
- y = wp.zeros(1, dtype=wp.transform, device=device, requires_grad=True)
2238
-
2239
- tape = wp.Tape()
2240
- with tape:
2241
- wp.launch(transform_assign_overwrite, dim=1, inputs=[x, y], device=device)
2242
-
2243
- y.grad = wp.ones_like(y, requires_grad=False)
2244
- tape.backward()
2245
-
2246
- assert_np_equal(y.numpy(), np.array([[1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=float))
2247
- assert_np_equal(x.grad.numpy(), np.array([[1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=float))
2248
-
2249
- finally:
2250
- wp.config.enable_vector_component_overwrites = saved_enable_vector_component_overwrites_setting
2251
-
2252
-
2253
2220
  @wp.kernel
2254
2221
  def transform_array_extract_subscript(x: wp.array2d(dtype=wp.transform), y: wp.array2d(dtype=float)):
2255
2222
  i, j = wp.tid()
@@ -2510,6 +2477,141 @@ def test_transform_array_sub_inplace(test, device):
2510
2477
  assert_np_equal(x.grad.numpy(), np.array([[-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0]], dtype=float))
2511
2478
 
2512
2479
 
2480
+ def test_transform_indexing_assign(test, device):
2481
+ @wp.func
2482
+ def fn():
2483
+ t = wp.transform(p=wp.vec3(1.0, 2.0, 3.0), q=wp.quat(4.0, 5.0, 6.0, 7.0))
2484
+
2485
+ t[0] = 123.0
2486
+ t[3] *= 2.0
2487
+
2488
+ wp.expect_eq(t[0], 123.0)
2489
+ wp.expect_eq(t[1], 2.0)
2490
+ wp.expect_eq(t[2], 3.0)
2491
+ wp.expect_eq(t[3], 8.0)
2492
+ wp.expect_eq(t[4], 5.0)
2493
+ wp.expect_eq(t[5], 6.0)
2494
+ wp.expect_eq(t[6], 7.0)
2495
+
2496
+ t[-1] = 123.0
2497
+ t[-5] *= 2.0
2498
+
2499
+ wp.expect_eq(t[0], 123.0)
2500
+ wp.expect_eq(t[1], 2.0)
2501
+ wp.expect_eq(t[2], 6.0)
2502
+ wp.expect_eq(t[3], 8.0)
2503
+ wp.expect_eq(t[4], 5.0)
2504
+ wp.expect_eq(t[5], 6.0)
2505
+ wp.expect_eq(t[6], 123.0)
2506
+
2507
+ @wp.kernel(module="unique")
2508
+ def kernel():
2509
+ fn()
2510
+
2511
+ wp.launch(kernel, 1, device=device)
2512
+ wp.synchronize()
2513
+ fn()
2514
+
2515
+
2516
+ def test_transform_slicing_assign(test, device):
2517
+ vec0 = wp.vec(0, float)
2518
+ vec1 = wp.vec(1, float)
2519
+ vec2 = wp.vec(2, float)
2520
+ vec3 = wp.vec(3, float)
2521
+ vec4 = wp.vec(4, float)
2522
+ vec5 = wp.vec(5, float)
2523
+ vec6 = wp.vec(6, float)
2524
+ vec7 = wp.vec(7, float)
2525
+
2526
+ @wp.func
2527
+ def fn():
2528
+ t = wp.transform(p=wp.vec3(1.0, 2.0, 3.0), q=wp.quat(4.0, 5.0, 6.0, 7.0))
2529
+
2530
+ wp.expect_eq(t[:] == vec7(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0), True)
2531
+ wp.expect_eq(t[-123:123] == vec7(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0), True)
2532
+ wp.expect_eq(t[123:] == vec0(), True)
2533
+ wp.expect_eq(t[:-123] == vec0(), True)
2534
+ wp.expect_eq(t[::123] == vec1(1.0), True)
2535
+
2536
+ wp.expect_eq(t[1:] == vec6(2.0, 3.0, 4.0, 5.0, 6.0, 7.0), True)
2537
+ wp.expect_eq(t[-2:] == vec2(6.0, 7.0), True)
2538
+ wp.expect_eq(t[:2] == vec2(1.0, 2.0), True)
2539
+ wp.expect_eq(t[:-1] == vec6(1.0, 2.0, 3.0, 4.0, 5.0, 6.0), True)
2540
+ wp.expect_eq(t[::2] == vec4(1.0, 3.0, 5.0, 7.0), True)
2541
+ wp.expect_eq(t[1::2] == vec3(2.0, 4.0, 6.0), True)
2542
+ wp.expect_eq(t[::-1] == vec7(7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0), True)
2543
+ wp.expect_eq(t[::-2] == vec4(7.0, 5.0, 3.0, 1.0), True)
2544
+ wp.expect_eq(t[1::-2] == vec1(2.0), True)
2545
+
2546
+ t[1:] = vec6(8.0, 9.0, 10.0, 11.0, 12.0, 13.0)
2547
+ wp.expect_eq(t == wp.transform(p=wp.vec3(1.0, 8.0, 9.0), q=wp.quat(10.0, 11.0, 12.0, 13.0)), True)
2548
+
2549
+ t[-2:] = vec2(14.0, 15.0)
2550
+ wp.expect_eq(t == wp.transform(p=wp.vec3(1.0, 8.0, 9.0), q=wp.quat(10.0, 11.0, 14.0, 15.0)), True)
2551
+
2552
+ t[:2] = vec2(16.0, 17.0)
2553
+ wp.expect_eq(t == wp.transform(p=wp.vec3(16.0, 17.0, 9.0), q=wp.quat(10.0, 11.0, 14.0, 15.0)), True)
2554
+
2555
+ t[:-1] = vec6(18.0, 19.0, 20.0, 21.0, 22.0, 23.0)
2556
+ wp.expect_eq(t == wp.transform(p=wp.vec3(18.0, 19.0, 20.0), q=wp.quat(21.0, 22.0, 23.0, 15.0)), True)
2557
+
2558
+ t[::2] = vec4(24.0, 25.0, 26.0, 27.0)
2559
+ wp.expect_eq(t == wp.transform(p=wp.vec3(24.0, 19.0, 25.0), q=wp.quat(21.0, 26.0, 23.0, 27.0)), True)
2560
+
2561
+ t[1::2] = vec3(28.0, 29.0, 30.0)
2562
+ wp.expect_eq(t == wp.transform(p=wp.vec3(24.0, 28.0, 25.0), q=wp.quat(29.0, 26.0, 30.0, 27.0)), True)
2563
+
2564
+ t[::-1] = vec7(31.0, 32.0, 33.0, 34.0, 35.0, 36.0, 37.0)
2565
+ wp.expect_eq(t == wp.transform(p=wp.vec3(37.0, 36.0, 35.0), q=wp.quat(34.0, 33.0, 32.0, 31.0)), True)
2566
+
2567
+ t[::-2] = vec4(38.0, 39.0, 40.0, 41.0)
2568
+ wp.expect_eq(t == wp.transform(p=wp.vec3(41.0, 36.0, 40.0), q=wp.quat(34.0, 39.0, 32.0, 38.0)), True)
2569
+
2570
+ t[1::-2] = vec1(42.0)
2571
+ wp.expect_eq(t == wp.transform(p=wp.vec3(41.0, 42.0, 40.0), q=wp.quat(34.0, 39.0, 32.0, 38.0)), True)
2572
+
2573
+ t[1:] += vec6(43.0, 44.0, 45.0, 46.0, 47.0, 48.0)
2574
+ wp.expect_eq(t == wp.transform(p=wp.vec3(41.0, 85.0, 84.0), q=wp.quat(79.0, 85.0, 79.0, 86.0)), True)
2575
+
2576
+ t[:-1] -= vec6(49.0, 50.0, 51.0, 52.0, 53.0, 54.0)
2577
+ wp.expect_eq(t == wp.transform(p=wp.vec3(-8.0, 35.0, 33.0), q=wp.quat(27.0, 32.0, 25.0, 86.0)), True)
2578
+
2579
+ @wp.kernel(module="unique")
2580
+ def kernel():
2581
+ fn()
2582
+
2583
+ wp.launch(kernel, 1, device=device)
2584
+ wp.synchronize()
2585
+ fn()
2586
+
2587
+
2588
+ def test_transform_slicing_assign_backward(test, device):
2589
+ @wp.kernel(module="unique")
2590
+ def kernel(arr_x: wp.array(dtype=wp.vec2), arr_y: wp.array(dtype=wp.transform)):
2591
+ i = wp.tid()
2592
+
2593
+ y = arr_y[i]
2594
+
2595
+ y[:2] = arr_x[i]
2596
+ y[1:-4] += arr_x[i][:2]
2597
+ y[3:1:-1] -= arr_x[i][0:]
2598
+
2599
+ arr_y[i] = y
2600
+
2601
+ x = wp.ones(1, dtype=wp.vec2, requires_grad=True, device=device)
2602
+ y = wp.zeros(1, dtype=wp.transform, requires_grad=True, device=device)
2603
+
2604
+ tape = wp.Tape()
2605
+ with tape:
2606
+ wp.launch(kernel, 1, inputs=(x,), outputs=(y,), device=device)
2607
+
2608
+ y.grad = wp.ones_like(y)
2609
+ tape.backward()
2610
+
2611
+ assert_np_equal(y.numpy(), np.array(((1.0, 2.0, 0.0, -1.0, 0.0, 0.0, 0.0),), dtype=float))
2612
+ assert_np_equal(x.grad.numpy(), np.array(((1.0, 1.0),), dtype=float))
2613
+
2614
+
2513
2615
  devices = get_test_devices()
2514
2616
 
2515
2617
 
@@ -2721,13 +2823,17 @@ add_function_test(
2721
2823
  )
2722
2824
  add_function_test(TestSpatial, "test_transform_extract", test_transform_extract, devices=devices)
2723
2825
  add_function_test(TestSpatial, "test_transform_assign", test_transform_assign, devices=devices)
2724
- add_function_test(TestSpatial, "test_transform_assign_copy", test_transform_assign_copy, devices=devices)
2725
2826
  add_function_test(TestSpatial, "test_transform_array_extract", test_transform_array_extract, devices=devices)
2726
2827
  add_function_test(TestSpatial, "test_transform_array_assign", test_transform_array_assign, devices=devices)
2727
2828
  add_function_test(TestSpatial, "test_transform_add_inplace", test_transform_add_inplace, devices=devices)
2728
2829
  add_function_test(TestSpatial, "test_transform_sub_inplace", test_transform_sub_inplace, devices=devices)
2729
2830
  add_function_test(TestSpatial, "test_transform_array_add_inplace", test_transform_array_add_inplace, devices=devices)
2730
2831
  add_function_test(TestSpatial, "test_transform_array_sub_inplace", test_transform_array_sub_inplace, devices=devices)
2832
+ add_function_test(TestSpatial, "test_transform_indexing_assign", test_transform_indexing_assign, devices=devices)
2833
+ add_function_test(TestSpatial, "test_transform_slicing_assign", test_transform_slicing_assign, devices=devices)
2834
+ add_function_test(
2835
+ TestSpatial, "test_transform_slicing_assign_backward", test_transform_slicing_assign_backward, devices=devices
2836
+ )
2731
2837
 
2732
2838
 
2733
2839
  if __name__ == "__main__":
@@ -0,0 +1,160 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2023 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 transform_assign_subscript(x: wp.array(dtype=float), y: wp.array(dtype=wp.transform)):
34
+ i = wp.tid()
35
+
36
+ a = wp.transform()
37
+ a[0] = 1.0 * x[i]
38
+ a[1] = 2.0 * x[i]
39
+ a[2] = 3.0 * x[i]
40
+ a[3] = 4.0 * x[i]
41
+ a[4] = 5.0 * x[i]
42
+ a[5] = 6.0 * x[i]
43
+ a[6] = 7.0 * x[i]
44
+ y[i] = a
45
+
46
+
47
+ @wp.kernel
48
+ def transform_assign_attribute(x: wp.array(dtype=wp.vec3), y: wp.array(dtype=wp.quat), z: wp.array(dtype=wp.transform)):
49
+ i = wp.tid()
50
+
51
+ a = wp.transform()
52
+ a.p = x[i]
53
+ a.q = y[i]
54
+ z[i] = a
55
+
56
+
57
+ def test_transform_assign(test, device):
58
+ x = wp.ones(1, dtype=float, requires_grad=True, device=device)
59
+ y = wp.zeros(1, dtype=wp.transform, requires_grad=True, device=device)
60
+
61
+ tape = wp.Tape()
62
+ with tape:
63
+ wp.launch(transform_assign_subscript, 1, inputs=[x], outputs=[y], device=device)
64
+
65
+ y.grad = wp.ones_like(y)
66
+ tape.backward()
67
+
68
+ assert_np_equal(y.numpy(), np.array([[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]], dtype=float))
69
+ assert_np_equal(x.grad.numpy(), np.array([28.0], dtype=float))
70
+
71
+ x = wp.ones(1, dtype=wp.vec3, requires_grad=True, device=device)
72
+ y = wp.ones(1, dtype=wp.quat, requires_grad=True, device=device)
73
+ z = wp.zeros(1, dtype=wp.transform, requires_grad=True, device=device)
74
+
75
+ tape = wp.Tape()
76
+ with tape:
77
+ wp.launch(transform_assign_attribute, 1, inputs=[x, y], outputs=[z], device=device)
78
+
79
+ z.grad = wp.ones_like(z)
80
+ tape.backward()
81
+
82
+ assert_np_equal(z.numpy(), np.array([[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=float))
83
+ assert_np_equal(x.grad.numpy(), np.array([[1.0, 1.0, 1.0]], dtype=float))
84
+ assert_np_equal(y.grad.numpy(), np.array([[1.0, 1.0, 1.0, 1.0]], dtype=float))
85
+
86
+
87
+ def test_transform_assign_copy(test, device):
88
+ @wp.kernel(module="unique")
89
+ def transform_assign_overwrite(x: wp.array(dtype=wp.transform), y: wp.array(dtype=wp.transform)):
90
+ tid = wp.tid()
91
+
92
+ a = wp.transform()
93
+ b = x[tid]
94
+ a = b
95
+ a[1] = 3.0
96
+
97
+ y[tid] = a
98
+
99
+ x = wp.ones(1, dtype=wp.transform, device=device, requires_grad=True)
100
+ y = wp.zeros(1, dtype=wp.transform, device=device, requires_grad=True)
101
+
102
+ tape = wp.Tape()
103
+ with tape:
104
+ wp.launch(transform_assign_overwrite, dim=1, inputs=[x, y], device=device)
105
+
106
+ y.grad = wp.ones_like(y, requires_grad=False)
107
+ tape.backward()
108
+
109
+ assert_np_equal(y.numpy(), np.array([[1.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=float))
110
+ assert_np_equal(x.grad.numpy(), np.array([[1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0]], dtype=float))
111
+
112
+
113
+ def test_transform_slicing_assign_backward(test, device):
114
+ @wp.kernel(module="unique")
115
+ def kernel(arr_x: wp.array(dtype=wp.vec2), arr_y: wp.array(dtype=wp.transform)):
116
+ i = wp.tid()
117
+
118
+ x = arr_x[i]
119
+ y = arr_y[i]
120
+
121
+ y[:2] = x
122
+ y[1:-4] += x[:2]
123
+ y[3:1:-1] -= x[0:]
124
+
125
+ arr_y[i] = y
126
+
127
+ x = wp.ones(1, dtype=wp.vec2, requires_grad=True, device=device)
128
+ y = wp.zeros(1, dtype=wp.transform, requires_grad=True, device=device)
129
+
130
+ tape = wp.Tape()
131
+ with tape:
132
+ wp.launch(kernel, 1, inputs=(x,), outputs=(y,), device=device)
133
+
134
+ y.grad = wp.ones_like(y)
135
+ tape.backward()
136
+
137
+ assert_np_equal(y.numpy(), np.array(((1.0, 2.0, 0.0, -1.0, 0.0, 0.0, 0.0),), dtype=float))
138
+ assert_np_equal(x.grad.numpy(), np.array(((1.0, 1.0),), dtype=float))
139
+
140
+
141
+ devices = get_test_devices()
142
+
143
+
144
+ class TestSpatialAssignCopy(unittest.TestCase):
145
+ pass
146
+
147
+
148
+ add_function_test(TestSpatialAssignCopy, "test_transform_assign", test_transform_assign, devices=devices)
149
+ add_function_test(TestSpatialAssignCopy, "test_transform_assign_copy", test_transform_assign_copy, devices=devices)
150
+ add_function_test(
151
+ TestSpatialAssignCopy,
152
+ "test_transform_slicing_assign_backward",
153
+ test_transform_slicing_assign_backward,
154
+ devices=devices,
155
+ )
156
+
157
+
158
+ if __name__ == "__main__":
159
+ wp.clear_kernel_cache()
160
+ unittest.main(verbosity=2)