warp-lang 1.4.0__py3-none-win_amd64.whl → 1.4.2__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.

warp/tests/test_print.py CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  import sys
9
9
  import unittest
10
+ from typing import Any
10
11
 
11
12
  import warp as wp
12
13
  from warp.tests.unittest_utils import *
@@ -126,6 +127,139 @@ def test_print_boolean(test, device):
126
127
  test.assertRegex(s, rf"True{os.linesep}False{os.linesep}")
127
128
 
128
129
 
130
+ @wp.kernel
131
+ def generic_print_kernel(x: Any):
132
+ print(x)
133
+
134
+
135
+ @wp.struct
136
+ class SimpleStruct:
137
+ x: float
138
+ y: float
139
+
140
+
141
+ generic_print_types = [*wp.types.scalar_types]
142
+ for scalar_type in wp.types.scalar_types:
143
+ generic_print_types.append(wp.types.vector(2, scalar_type))
144
+ generic_print_types.append(wp.types.vector(3, scalar_type))
145
+ generic_print_types.append(wp.types.vector(4, scalar_type))
146
+ generic_print_types.append(wp.types.matrix((2, 2), scalar_type))
147
+ generic_print_types.append(wp.types.matrix((3, 3), scalar_type))
148
+ generic_print_types.append(wp.types.matrix((4, 4), scalar_type))
149
+ generic_print_types.append(wp.bool)
150
+ generic_print_types.append(SimpleStruct)
151
+ generic_print_types.append(wp.array(dtype=float))
152
+
153
+ for T in generic_print_types:
154
+ wp.overload(generic_print_kernel, [T])
155
+
156
+
157
+ def test_print_adjoint(test, device):
158
+ for scalar_type in wp.types.scalar_types:
159
+ # scalar
160
+ capture = StdOutCapture()
161
+ capture.begin()
162
+ wp.launch(
163
+ generic_print_kernel,
164
+ dim=1,
165
+ inputs=[scalar_type(17)],
166
+ adj_inputs=[scalar_type(42)],
167
+ adjoint=True,
168
+ device=device,
169
+ )
170
+ wp.synchronize_device(device)
171
+ s = capture.end()
172
+
173
+ # We skip the win32 comparison for now since the capture sometimes is an empty string
174
+ if sys.platform != "win32":
175
+ test.assertRegex(s, rf"17{os.linesep}adj: 42{os.linesep}")
176
+
177
+ for dim in (2, 3, 4):
178
+ # vector
179
+ vec_type = wp.types.vector(dim, scalar_type)
180
+ vec_data = np.arange(vec_type._length_, dtype=wp.dtype_to_numpy(scalar_type))
181
+ v = vec_type(vec_data)
182
+ adj_v = vec_type(vec_data[::-1])
183
+
184
+ capture = StdOutCapture()
185
+ capture.begin()
186
+ wp.launch(generic_print_kernel, dim=1, inputs=[v], adj_inputs=[adj_v], adjoint=True, device=device)
187
+ wp.synchronize_device(device)
188
+ s = capture.end()
189
+
190
+ # We skip the win32 comparison for now since the capture sometimes is an empty string
191
+ if sys.platform != "win32":
192
+ expected_forward = " ".join(str(int(x)) for x in v) + " "
193
+ expected_adjoint = " ".join(str(int(x)) for x in adj_v)
194
+ test.assertRegex(s, rf"{expected_forward}{os.linesep}adj: {expected_adjoint}{os.linesep}")
195
+
196
+ # matrix
197
+ mat_type = wp.types.matrix((dim, dim), scalar_type)
198
+ mat_data = np.arange(mat_type._length_, dtype=wp.dtype_to_numpy(scalar_type))
199
+ m = mat_type(mat_data)
200
+ adj_m = mat_type(mat_data[::-1])
201
+
202
+ capture = StdOutCapture()
203
+ capture.begin()
204
+ wp.launch(generic_print_kernel, dim=1, inputs=[m], adj_inputs=[adj_m], adjoint=True, device=device)
205
+ wp.synchronize_device(device)
206
+ s = capture.end()
207
+
208
+ # We skip the win32 comparison for now since the capture sometimes is an empty string
209
+ if sys.platform != "win32":
210
+ expected_forward = ""
211
+ expected_adjoint = ""
212
+ for row in range(dim):
213
+ if row == 0:
214
+ adj_prefix = "adj: "
215
+ else:
216
+ adj_prefix = " "
217
+ expected_forward += " ".join(str(int(x)) for x in m[row]) + f" {os.linesep}"
218
+ expected_adjoint += adj_prefix + " ".join(str(int(x)) for x in adj_m[row]) + f"{os.linesep}"
219
+ test.assertRegex(s, rf"{expected_forward}{expected_adjoint}")
220
+
221
+ # Booleans
222
+ capture = StdOutCapture()
223
+ capture.begin()
224
+ wp.launch(generic_print_kernel, dim=1, inputs=[True], adj_inputs=[False], adjoint=True, device=device)
225
+ wp.synchronize_device(device)
226
+ s = capture.end()
227
+
228
+ # We skip the win32 comparison for now since the capture sometimes is an empty string
229
+ if sys.platform != "win32":
230
+ test.assertRegex(s, rf"True{os.linesep}adj: False{os.linesep}")
231
+
232
+ # structs, not printable yet
233
+ capture = StdOutCapture()
234
+ capture.begin()
235
+ wp.launch(
236
+ generic_print_kernel, dim=1, inputs=[SimpleStruct()], adj_inputs=[SimpleStruct()], adjoint=True, device=device
237
+ )
238
+ wp.synchronize_device(device)
239
+ s = capture.end()
240
+
241
+ # We skip the win32 comparison for now since the capture sometimes is an empty string
242
+ if sys.platform != "win32":
243
+ test.assertRegex(
244
+ s, rf"<type without print implementation>{os.linesep}adj: <type without print implementation>{os.linesep}"
245
+ )
246
+
247
+ # arrays, not printable
248
+ capture = StdOutCapture()
249
+ capture.begin()
250
+ a = wp.ones(10, dtype=float, device=device)
251
+ adj_a = wp.zeros(10, dtype=float, device=device)
252
+ wp.launch(generic_print_kernel, dim=1, inputs=[a], adj_inputs=[adj_a], adjoint=True, device=device)
253
+ wp.synchronize_device(device)
254
+ s = capture.end()
255
+
256
+ # We skip the win32 comparison for now since the capture sometimes is an empty string
257
+ if sys.platform != "win32":
258
+ test.assertRegex(
259
+ s, rf"<type without print implementation>{os.linesep}adj: <type without print implementation>{os.linesep}"
260
+ )
261
+
262
+
129
263
  class TestPrint(unittest.TestCase):
130
264
  pass
131
265
 
@@ -134,6 +268,7 @@ devices = get_test_devices()
134
268
  add_function_test(TestPrint, "test_print", test_print, devices=devices, check_output=False)
135
269
  add_function_test(TestPrint, "test_print_numeric", test_print_numeric, devices=devices, check_output=False)
136
270
  add_function_test(TestPrint, "test_print_boolean", test_print_boolean, devices=devices, check_output=False)
271
+ add_function_test(TestPrint, "test_print_adjoint", test_print_adjoint, devices=devices, check_output=False)
137
272
 
138
273
 
139
274
  if __name__ == "__main__":
warp/tests/test_static.py CHANGED
@@ -5,6 +5,8 @@
5
5
  # distribution of this software and related documentation without an express
6
6
  # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
7
 
8
+ import importlib
9
+ import tempfile
8
10
  import unittest
9
11
  from typing import Dict, List
10
12
 
@@ -17,6 +19,23 @@ from warp.tests.unittest_utils import *
17
19
  global_variable = 3
18
20
 
19
21
 
22
+ def load_code_as_module(code, name):
23
+ file, file_path = tempfile.mkstemp(suffix=".py")
24
+
25
+ try:
26
+ with os.fdopen(file, "w") as f:
27
+ f.write(code)
28
+
29
+ spec = importlib.util.spec_from_file_location(name, file_path)
30
+ module = importlib.util.module_from_spec(spec)
31
+ spec.loader.exec_module(module)
32
+ finally:
33
+ os.remove(file_path)
34
+
35
+ # return Warp module
36
+ return wp.get_module(module.__name__)
37
+
38
+
20
39
  @wp.func
21
40
  def static_global_variable_func():
22
41
  static_var = warp.static(global_variable + 2)
@@ -234,7 +253,7 @@ def test_function_variable(test, device):
234
253
  results[0] = wp.static(func)(3, 2) # noqa: B023
235
254
 
236
255
  results = wp.zeros(1, dtype=int, device=device)
237
- # note that the kernel has to be recompiled everytime the value of func changes
256
+ # note that the kernel has to be recompiled every time the value of func changes
238
257
  wp.launch(function_variable_kernel, 1, [results], device=device)
239
258
  assert_np_equal(results.numpy(), np.array([func(3, 2)], dtype=int))
240
259
 
@@ -383,6 +402,140 @@ def test_static_if_else_elif(test, device):
383
402
  assert_np_equal(counts["else"], 0)
384
403
 
385
404
 
405
+ static_builtin_constant_template = """
406
+ import warp as wp
407
+
408
+ # Python builtin literal like 17, 42.0, or True
409
+ C = {value}
410
+
411
+ @wp.kernel
412
+ def k():
413
+ print(wp.static(C))
414
+ """
415
+
416
+ static_warp_constant_template = """
417
+ import warp as wp
418
+
419
+ # Warp scalar value like wp.uint8(17)
420
+ C = wp.{dtype}({value})
421
+
422
+ @wp.kernel
423
+ def k():
424
+ print(wp.static(C))
425
+ """
426
+
427
+ static_struct_constant_template = """
428
+ import warp as wp
429
+
430
+ @wp.struct
431
+ class SimpleStruct:
432
+ x: float
433
+
434
+ C = SimpleStruct()
435
+ C.x = {value}
436
+
437
+ @wp.kernel
438
+ def k():
439
+ print(wp.static(C))
440
+ """
441
+
442
+ static_func_template = """
443
+ import warp as wp
444
+
445
+ @wp.func
446
+ def f():
447
+ # modify the function to verify hashing
448
+ return {value}
449
+
450
+ @wp.kernel
451
+ def k():
452
+ print(wp.static(f)())
453
+ """
454
+
455
+
456
+ def test_static_constant_hash(test, _):
457
+ # Python literals
458
+ # (type, value1, value2)
459
+ literals = [
460
+ (int, 17, 42),
461
+ (float, 17.5, 42.5),
462
+ (bool, True, False),
463
+ ]
464
+
465
+ for builtin_type, value1, value2 in literals:
466
+ type_name = builtin_type.__name__
467
+ with test.subTest(msg=f"{type_name}"):
468
+ source1 = static_builtin_constant_template.format(value=value1)
469
+ source2 = static_builtin_constant_template.format(value=value2)
470
+ source3 = static_builtin_constant_template.format(value=value1)
471
+
472
+ module1 = load_code_as_module(source1, f"aux_static_constant_builtin_{type_name}_1")
473
+ module2 = load_code_as_module(source2, f"aux_static_constant_builtin_{type_name}_2")
474
+ module3 = load_code_as_module(source3, f"aux_static_constant_builtin_{type_name}_3")
475
+
476
+ hash1 = module1.hash_module()
477
+ hash2 = module2.hash_module()
478
+ hash3 = module3.hash_module()
479
+
480
+ test.assertNotEqual(hash1, hash2)
481
+ test.assertEqual(hash1, hash3)
482
+
483
+ # Warp types (scalars, vectors, matrices)
484
+ for warp_type in [*wp.types.scalar_types, *wp.types.vector_types]:
485
+ type_name = warp_type.__name__
486
+ with test.subTest(msg=f"wp.{type_name}"):
487
+ value1 = ", ".join([str(17)] * warp_type._length_)
488
+ value2 = ", ".join([str(42)] * warp_type._length_)
489
+ source1 = static_warp_constant_template.format(dtype=type_name, value=value1)
490
+ source2 = static_warp_constant_template.format(dtype=type_name, value=value2)
491
+ source3 = static_warp_constant_template.format(dtype=type_name, value=value1)
492
+
493
+ module1 = load_code_as_module(source1, f"aux_static_constant_wp_{type_name}_1")
494
+ module2 = load_code_as_module(source2, f"aux_static_constant_wp_{type_name}_2")
495
+ module3 = load_code_as_module(source3, f"aux_static_constant_wp_{type_name}_3")
496
+
497
+ hash1 = module1.hash_module()
498
+ hash2 = module2.hash_module()
499
+ hash3 = module3.hash_module()
500
+
501
+ test.assertNotEqual(hash1, hash2)
502
+ test.assertEqual(hash1, hash3)
503
+
504
+ # structs
505
+ with test.subTest(msg="struct"):
506
+ source1 = static_struct_constant_template.format(value=17)
507
+ source2 = static_struct_constant_template.format(value=42)
508
+ source3 = static_struct_constant_template.format(value=17)
509
+
510
+ module1 = load_code_as_module(source1, "aux_static_constant_struct_1")
511
+ module2 = load_code_as_module(source2, "aux_static_constant_struct_2")
512
+ module3 = load_code_as_module(source3, "aux_static_constant_struct_3")
513
+
514
+ hash1 = module1.hash_module()
515
+ hash2 = module2.hash_module()
516
+ hash3 = module3.hash_module()
517
+
518
+ test.assertNotEqual(hash1, hash2)
519
+ test.assertEqual(hash1, hash3)
520
+
521
+
522
+ def test_static_function_hash(test, _):
523
+ source1 = static_func_template.format(value=17)
524
+ source2 = static_func_template.format(value=42)
525
+ source3 = static_func_template.format(value=17)
526
+
527
+ module1 = load_code_as_module(source1, "aux_static_func1")
528
+ module2 = load_code_as_module(source2, "aux_static_func2")
529
+ module3 = load_code_as_module(source3, "aux_static_func3")
530
+
531
+ hash1 = module1.hash_module()
532
+ hash2 = module2.hash_module()
533
+ hash3 = module3.hash_module()
534
+
535
+ test.assertNotEqual(hash1, hash2)
536
+ test.assertEqual(hash1, hash3)
537
+
538
+
386
539
  devices = get_test_devices()
387
540
 
388
541
 
@@ -406,6 +559,9 @@ add_function_test(
406
559
  add_function_test(TestStatic, "test_static_for_loop", test_static_for_loop, devices=devices)
407
560
  add_function_test(TestStatic, "test_static_if_else_elif", test_static_if_else_elif, devices=devices)
408
561
 
562
+ add_function_test(TestStatic, "test_static_constant_hash", test_static_constant_hash, devices=None)
563
+ add_function_test(TestStatic, "test_static_function_hash", test_static_function_hash, devices=None)
564
+
409
565
 
410
566
  if __name__ == "__main__":
411
567
  wp.clear_kernel_cache()
@@ -170,6 +170,7 @@ def default_suite(test_loader: unittest.TestLoader = unittest.defaultTestLoader)
170
170
  from warp.tests.test_sparse import TestSparse
171
171
  from warp.tests.test_spatial import TestSpatial
172
172
  from warp.tests.test_special_values import TestSpecialValues
173
+ from warp.tests.test_static import TestStatic
173
174
  from warp.tests.test_streams import TestStreams
174
175
  from warp.tests.test_struct import TestStruct
175
176
  from warp.tests.test_tape import TestTape
@@ -269,6 +270,7 @@ def default_suite(test_loader: unittest.TestLoader = unittest.defaultTestLoader)
269
270
  TestSparse,
270
271
  TestSpatial,
271
272
  TestSpecialValues,
273
+ TestStatic,
272
274
  TestStreams,
273
275
  TestStruct,
274
276
  TestTape,
@@ -329,6 +331,7 @@ def kit_suite(test_loader: unittest.TestLoader = unittest.defaultTestLoader):
329
331
  from warp.tests.test_rounding import TestRounding
330
332
  from warp.tests.test_runlength_encode import TestRunlengthEncode
331
333
  from warp.tests.test_sparse import TestSparse
334
+ from warp.tests.test_static import TestStatic
332
335
  from warp.tests.test_streams import TestStreams
333
336
  from warp.tests.test_tape import TestTape
334
337
  from warp.tests.test_transient_module import TestTransientModule
@@ -374,6 +377,7 @@ def kit_suite(test_loader: unittest.TestLoader = unittest.defaultTestLoader):
374
377
  TestRounding,
375
378
  TestRunlengthEncode,
376
379
  TestSparse,
380
+ TestStatic,
377
381
  TestStreams,
378
382
  TestTape,
379
383
  TestTransientModule,
warp/types.py CHANGED
@@ -1488,7 +1488,7 @@ def types_equal(a, b, match_generic=False):
1488
1488
 
1489
1489
  return True
1490
1490
 
1491
- if is_array(a) and type(a) is type(b):
1491
+ if is_array(a) and type(a) is type(b) and types_equal(a.dtype, b.dtype, match_generic=match_generic):
1492
1492
  return True
1493
1493
 
1494
1494
  # match NewStructInstance and Struct dtype
@@ -2261,13 +2261,22 @@ class array(Array):
2261
2261
  self._requires_grad = False
2262
2262
  else:
2263
2263
  # make sure the given gradient array is compatible
2264
- if (
2265
- grad.dtype != self.dtype
2266
- or grad.shape != self.shape
2267
- or grad.strides != self.strides
2268
- or grad.device != self.device
2269
- ):
2270
- raise ValueError("The given gradient array is incompatible")
2264
+ if grad.dtype != self.dtype:
2265
+ raise ValueError(
2266
+ f"The given gradient array is incompatible: expected dtype {self.dtype}, got {grad.dtype}"
2267
+ )
2268
+ if grad.shape != self.shape:
2269
+ raise ValueError(
2270
+ f"The given gradient array is incompatible: expected shape {self.shape}, got {grad.shape}"
2271
+ )
2272
+ if grad.device != self.device:
2273
+ raise ValueError(
2274
+ f"The given gradient array is incompatible: expected device {self.device}, got {grad.device}"
2275
+ )
2276
+ if grad.strides != self.strides:
2277
+ raise ValueError(
2278
+ f"The given gradient array is incompatible: expected strides {self.strides}, got {grad.strides}"
2279
+ )
2271
2280
  self._grad = grad
2272
2281
  self._requires_grad = True
2273
2282
 
@@ -3465,7 +3474,7 @@ class Volume:
3465
3474
  )
3466
3475
 
3467
3476
  def feature_array(self, feature_index: int, dtype=None) -> array:
3468
- """Returns one the the grid's feature data arrays as a Warp array
3477
+ """Returns one the grid's feature data arrays as a Warp array
3469
3478
 
3470
3479
  Args:
3471
3480
  feature_index: Index of the supplemental data array in the grid
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: warp-lang
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: A Python framework for high-performance simulation and graphics programming
5
5
  Author-email: NVIDIA Corporation <mmacklin@nvidia.com>
6
6
  License: NVIDIA Software License
@@ -77,9 +77,9 @@ the `pip install` command, e.g.
77
77
 
78
78
  | Platform | Install Command |
79
79
  | --------------- | ----------------------------------------------------------------------------------------------------------------------------- |
80
- | Linux aarch64 | `pip install https://github.com/NVIDIA/warp/releases/download/v1.4.0/warp_lang-1.4.0+cu11-py3-none-manylinux2014_aarch64.whl` |
81
- | Linux x86-64 | `pip install https://github.com/NVIDIA/warp/releases/download/v1.4.0/warp_lang-1.4.0+cu11-py3-none-manylinux2014_x86_64.whl` |
82
- | Windows x86-64 | `pip install https://github.com/NVIDIA/warp/releases/download/v1.4.0/warp_lang-1.4.0+cu11-py3-none-win_amd64.whl` |
80
+ | Linux aarch64 | `pip install https://github.com/NVIDIA/warp/releases/download/v1.4.2/warp_lang-1.4.2+cu11-py3-none-manylinux2014_aarch64.whl` |
81
+ | Linux x86-64 | `pip install https://github.com/NVIDIA/warp/releases/download/v1.4.2/warp_lang-1.4.2+cu11-py3-none-manylinux2014_x86_64.whl` |
82
+ | Windows x86-64 | `pip install https://github.com/NVIDIA/warp/releases/download/v1.4.2/warp_lang-1.4.2+cu11-py3-none-win_amd64.whl` |
83
83
 
84
84
  The `--force-reinstall` option may need to be used to overwrite a previous installation.
85
85