warp-lang 1.7.0__py3-none-macosx_10_13_universal2.whl → 1.7.2__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 (59) hide show
  1. warp/autograd.py +12 -2
  2. warp/bin/libwarp.dylib +0 -0
  3. warp/build.py +1 -1
  4. warp/builtins.py +103 -66
  5. warp/codegen.py +48 -27
  6. warp/config.py +1 -1
  7. warp/context.py +112 -49
  8. warp/examples/benchmarks/benchmark_cloth.py +1 -1
  9. warp/examples/distributed/example_jacobi_mpi.py +507 -0
  10. warp/fem/cache.py +1 -1
  11. warp/fem/field/field.py +11 -1
  12. warp/fem/field/nodal_field.py +36 -22
  13. warp/fem/geometry/adaptive_nanogrid.py +7 -3
  14. warp/fem/geometry/trimesh.py +4 -12
  15. warp/jax_experimental/custom_call.py +14 -2
  16. warp/jax_experimental/ffi.py +100 -67
  17. warp/native/builtin.h +91 -65
  18. warp/native/svd.h +59 -49
  19. warp/native/tile.h +55 -26
  20. warp/native/volume.cpp +2 -2
  21. warp/native/volume_builder.cu +33 -22
  22. warp/native/warp.cu +1 -1
  23. warp/render/render_opengl.py +41 -34
  24. warp/render/render_usd.py +96 -6
  25. warp/sim/collide.py +11 -9
  26. warp/sim/inertia.py +189 -156
  27. warp/sim/integrator_euler.py +3 -0
  28. warp/sim/integrator_xpbd.py +3 -0
  29. warp/sim/model.py +56 -31
  30. warp/sim/render.py +4 -0
  31. warp/sparse.py +1 -1
  32. warp/stubs.py +73 -25
  33. warp/tests/assets/torus.usda +1 -1
  34. warp/tests/cuda/test_streams.py +1 -1
  35. warp/tests/sim/test_collision.py +237 -206
  36. warp/tests/sim/test_inertia.py +161 -0
  37. warp/tests/sim/test_model.py +5 -3
  38. warp/tests/sim/{flaky_test_sim_grad.py → test_sim_grad.py} +1 -4
  39. warp/tests/sim/test_xpbd.py +399 -0
  40. warp/tests/test_array.py +8 -7
  41. warp/tests/test_atomic.py +181 -2
  42. warp/tests/test_builtins_resolution.py +38 -38
  43. warp/tests/test_codegen.py +24 -3
  44. warp/tests/test_examples.py +16 -6
  45. warp/tests/test_fem.py +93 -14
  46. warp/tests/test_func.py +1 -1
  47. warp/tests/test_mat.py +416 -119
  48. warp/tests/test_quat.py +321 -137
  49. warp/tests/test_struct.py +116 -0
  50. warp/tests/test_vec.py +320 -174
  51. warp/tests/tile/test_tile.py +27 -0
  52. warp/tests/tile/test_tile_load.py +124 -0
  53. warp/tests/unittest_suites.py +2 -5
  54. warp/types.py +107 -9
  55. {warp_lang-1.7.0.dist-info → warp_lang-1.7.2.dist-info}/METADATA +41 -19
  56. {warp_lang-1.7.0.dist-info → warp_lang-1.7.2.dist-info}/RECORD +59 -56
  57. {warp_lang-1.7.0.dist-info → warp_lang-1.7.2.dist-info}/WHEEL +1 -1
  58. {warp_lang-1.7.0.dist-info → warp_lang-1.7.2.dist-info}/licenses/LICENSE.md +0 -26
  59. {warp_lang-1.7.0.dist-info → warp_lang-1.7.2.dist-info}/top_level.txt +0 -0
warp/context.py CHANGED
@@ -457,6 +457,24 @@ class Function:
457
457
  return f"<Function {self.key}({inputs_str})>"
458
458
 
459
459
 
460
+ def get_builtin_type(return_type: type) -> type:
461
+ # The return_type might just be vector_t(length=3,dtype=wp.float32), so we've got to match that
462
+ # in the list of hard coded types so it knows it's returning one of them:
463
+ if hasattr(return_type, "_wp_generic_type_hint_"):
464
+ return_type_match = tuple(
465
+ x
466
+ for x in generic_vtypes
467
+ if x._wp_generic_type_hint_ == return_type._wp_generic_type_hint_
468
+ and x._wp_type_params_ == return_type._wp_type_params_
469
+ )
470
+ if not return_type_match:
471
+ raise RuntimeError("No match")
472
+
473
+ return return_type_match[0]
474
+
475
+ return return_type
476
+
477
+
460
478
  def call_builtin(func: Function, *params: Any) -> Tuple[bool, Any]:
461
479
  uses_non_warp_array_type = False
462
480
 
@@ -769,6 +787,12 @@ class Kernel:
769
787
 
770
788
  return f"{self.key}_{hash_suffix}"
771
789
 
790
+ def __call__(self, *args, **kwargs):
791
+ # we implement this function only to ensure Kernel is a callable object
792
+ # so that we can document Warp kernels in the same way as Python functions
793
+ # annotated by @wp.kernel (see functools.update_wrapper())
794
+ raise NotImplementedError("Kernel.__call__() is not implemented, please use wp.launch() instead")
795
+
772
796
 
773
797
  # ----------------------
774
798
 
@@ -1068,7 +1092,7 @@ def kernel(
1068
1092
  # decorator to register struct, @struct
1069
1093
  def struct(c: type):
1070
1094
  m = get_module(c.__module__)
1071
- s = warp.codegen.Struct(cls=c, key=warp.codegen.make_full_qualified_name(c), module=m)
1095
+ s = warp.codegen.Struct(key=warp.codegen.make_full_qualified_name(c), cls=c, module=m)
1072
1096
  s = functools.update_wrapper(s, c)
1073
1097
  return s
1074
1098
 
@@ -1439,6 +1463,24 @@ def register_api_function(
1439
1463
  """
1440
1464
  function.group = group
1441
1465
  function.hidden = hidden
1466
+
1467
+ # Update the docstring to mark these functions as being available from kernels and Python's runtime.
1468
+ assert function.__doc__.startswith("\n")
1469
+ leading_space_count = sum(1 for _ in itertools.takewhile(str.isspace, function.__doc__[1:]))
1470
+ assert leading_space_count % 4 == 0
1471
+ indent_level = leading_space_count // 4
1472
+ indent = " "
1473
+ function.__doc__ = (
1474
+ f"\n"
1475
+ f"{indent * indent_level}.. hlist::\n"
1476
+ f"{indent * (indent_level + 1)}:columns: 8\n"
1477
+ f"\n"
1478
+ f"{indent * (indent_level + 1)}* Kernel\n"
1479
+ f"{indent * (indent_level + 1)}* Python\n"
1480
+ f"{indent * (indent_level + 1)}* Differentiable\n"
1481
+ f"{function.__doc__}"
1482
+ )
1483
+
1442
1484
  builtin_functions[function.key] = function
1443
1485
 
1444
1486
 
@@ -6504,12 +6546,46 @@ def type_str(t):
6504
6546
  return t.__name__
6505
6547
 
6506
6548
 
6507
- def print_function(f, file, noentry=False): # pragma: no cover
6549
+ def ctype_ret_str(t):
6550
+ return get_builtin_type(t).__name__
6551
+
6552
+
6553
+ def resolve_exported_function_sig(f):
6554
+ if not f.export or f.generic:
6555
+ return None
6556
+
6557
+ # only export simple types that don't use arrays or templated types
6558
+ if not f.is_simple():
6559
+ return None
6560
+
6561
+ # Runtime arguments that are to be passed to the function, not its template signature.
6562
+ if f.export_func is not None:
6563
+ func_args = f.export_func(f.input_types)
6564
+ else:
6565
+ func_args = f.input_types
6566
+
6567
+ # todo: construct a default value for each of the functions args
6568
+ # so we can generate the return type for overloaded functions
6569
+ return_type = f.value_func(func_args, None)
6570
+
6571
+ try:
6572
+ return_type_str = ctype_ret_str(return_type)
6573
+ except Exception:
6574
+ return None
6575
+
6576
+ if return_type_str.startswith("Tuple"):
6577
+ return None
6578
+
6579
+ return (func_args, return_type)
6580
+
6581
+
6582
+ def print_function(f, file, is_exported, noentry=False): # pragma: no cover
6508
6583
  """Writes a function definition to a file for use in reST documentation
6509
6584
 
6510
6585
  Args:
6511
6586
  f: The function being written
6512
6587
  file: The file object for output
6588
+ is_exported: Whether the function is available in Python's runtime
6513
6589
  noentry: If True, then the :noindex: and :nocontentsentry: directive
6514
6590
  options will be added
6515
6591
 
@@ -6537,11 +6613,21 @@ def print_function(f, file, noentry=False): # pragma: no cover
6537
6613
  print(" :nocontentsentry:", file=file)
6538
6614
  print("", file=file)
6539
6615
 
6616
+ print(" .. hlist::", file=file)
6617
+ print(" :columns: 8", file=file)
6618
+ print("", file=file)
6619
+ print(" * Kernel", file=file)
6620
+
6621
+ if is_exported:
6622
+ print(" * Python", file=file)
6623
+
6624
+ if not f.missing_grad:
6625
+ print(" * Differentiable", file=file)
6626
+
6627
+ print("", file=file)
6628
+
6540
6629
  if f.doc != "":
6541
- if not f.missing_grad:
6542
- print(f" {f.doc}", file=file)
6543
- else:
6544
- print(f" {f.doc} [1]_", file=file)
6630
+ print(f" {f.doc}", file=file)
6545
6631
  print("", file=file)
6546
6632
 
6547
6633
  print(file=file)
@@ -6557,8 +6643,10 @@ def export_functions_rst(file): # pragma: no cover
6557
6643
  ".. functions:\n"
6558
6644
  ".. currentmodule:: warp\n"
6559
6645
  "\n"
6560
- "Kernel Reference\n"
6561
- "================"
6646
+ "Built-Ins Reference\n"
6647
+ "===================\n"
6648
+ "This section lists the Warp types and functions available to use from Warp kernels and optionally also from the Warp Python runtime API.\n"
6649
+ "For a listing of the API that is exclusively intended to be used at the *Python Scope* and run inside the CPython interpreter, see the :doc:`runtime` section.\n"
6562
6650
  )
6563
6651
 
6564
6652
  print(header, file=file)
@@ -6603,9 +6691,12 @@ def export_functions_rst(file): # pragma: no cover
6603
6691
  if hasattr(f, "overloads"):
6604
6692
  # append all overloads to the group
6605
6693
  for o in f.overloads:
6606
- groups[f.group].append(o)
6694
+ sig = resolve_exported_function_sig(f)
6695
+ is_exported = sig is not None
6696
+ groups[f.group].append((o, is_exported))
6607
6697
  else:
6608
- groups[f.group].append(f)
6698
+ is_exported = False
6699
+ groups[f.group].append((f, is_exported))
6609
6700
 
6610
6701
  # Keep track of what function and query types have been written
6611
6702
  written_functions = set()
@@ -6624,7 +6715,7 @@ def export_functions_rst(file): # pragma: no cover
6624
6715
  print(k, file=file)
6625
6716
  print("---------------", file=file)
6626
6717
 
6627
- for f in g:
6718
+ for f, is_exported in g:
6628
6719
  if f.func:
6629
6720
  # f is a Warp function written in Python, we can use autofunction
6630
6721
  print(f".. autofunction:: {f.func.__module__}.{f.key}", file=file)
@@ -6637,15 +6728,11 @@ def export_functions_rst(file): # pragma: no cover
6637
6728
 
6638
6729
  if f.key in written_functions:
6639
6730
  # Add :noindex: + :nocontentsentry: since Sphinx gets confused
6640
- print_function(f, file=file, noentry=True)
6731
+ print_function(f, file, is_exported, noentry=True)
6641
6732
  else:
6642
- if print_function(f, file=file):
6733
+ if print_function(f, file, is_exported):
6643
6734
  written_functions.add(f.key)
6644
6735
 
6645
- # footnotes
6646
- print(".. rubric:: Footnotes", file=file)
6647
- print(".. [1] Function gradients have not been implemented for backpropagation.", file=file)
6648
-
6649
6736
 
6650
6737
  def export_stubs(file): # pragma: no cover
6651
6738
  """Generates stub file for auto-complete of builtin functions"""
@@ -6745,14 +6832,6 @@ def export_builtins(file: io.TextIOBase): # pragma: no cover
6745
6832
  else:
6746
6833
  return t.__name__
6747
6834
 
6748
- def ctype_ret_str(t):
6749
- if isinstance(t, int):
6750
- return "int"
6751
- elif isinstance(t, float):
6752
- return "float"
6753
- else:
6754
- return t.__name__
6755
-
6756
6835
  file.write("namespace wp {\n\n")
6757
6836
  file.write('extern "C" {\n\n')
6758
6837
 
@@ -6760,40 +6839,24 @@ def export_builtins(file: io.TextIOBase): # pragma: no cover
6760
6839
  if not hasattr(g, "overloads"):
6761
6840
  continue
6762
6841
  for f in g.overloads:
6763
- if not f.export or f.generic:
6842
+ sig = resolve_exported_function_sig(f)
6843
+ if sig is None:
6764
6844
  continue
6765
6845
 
6766
- # only export simple types that don't use arrays
6767
- # or templated types
6768
- if not f.is_simple():
6769
- continue
6770
-
6771
- try:
6772
- # todo: construct a default value for each of the functions args
6773
- # so we can generate the return type for overloaded functions
6774
- return_type = ctype_ret_str(f.value_func(None, None))
6775
- except Exception:
6776
- continue
6777
-
6778
- if return_type.startswith("Tuple"):
6779
- continue
6780
-
6781
- # Runtime arguments that are to be passed to the function, not its template signature.
6782
- if f.export_func is not None:
6783
- func_args = f.export_func(f.input_types)
6784
- else:
6785
- func_args = f.input_types
6846
+ func_args, return_type = sig
6786
6847
 
6787
6848
  args = ", ".join(f"{ctype_arg_str(v)} {k}" for k, v in func_args.items())
6788
6849
  params = ", ".join(func_args.keys())
6789
6850
 
6851
+ return_str = ctype_ret_str(return_type)
6852
+
6790
6853
  if args == "":
6791
- file.write(f"WP_API void {f.mangled_name}({return_type}* ret) {{ *ret = wp::{f.key}({params}); }}\n")
6792
- elif return_type == "None":
6854
+ file.write(f"WP_API void {f.mangled_name}({return_str}* ret) {{ *ret = wp::{f.key}({params}); }}\n")
6855
+ elif return_type is None:
6793
6856
  file.write(f"WP_API void {f.mangled_name}({args}) {{ wp::{f.key}({params}); }}\n")
6794
6857
  else:
6795
6858
  file.write(
6796
- f"WP_API void {f.mangled_name}({args}, {return_type}* ret) {{ *ret = wp::{f.key}({params}); }}\n"
6859
+ f"WP_API void {f.mangled_name}({args}, {return_str}* ret) {{ *ret = wp::{f.key}({params}); }}\n"
6797
6860
  )
6798
6861
 
6799
6862
  file.write('\n} // extern "C"\n\n')
@@ -160,7 +160,7 @@ def run_benchmark(mode, dim, timers, render=False):
160
160
  stage = Usd.Stage.CreateNew("benchmark.usd")
161
161
  stage.SetStartTimeCode(0.0)
162
162
  stage.SetEndTimeCode(sim_duration * sim_fps)
163
- stage.SetTimeCodesPerSecond(sim_fps)
163
+ stage.SetFramesPerSecond(sim_fps)
164
164
 
165
165
  grid = UsdGeom.Mesh.Define(stage, "/root")
166
166
  grid.GetPointsAttr().Set(cloth.positions, 0.0)