warp-lang 1.0.1__py3-none-manylinux2014_aarch64.whl → 1.1.0__py3-none-manylinux2014_aarch64.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/__init__.py +108 -97
- warp/__init__.pyi +1 -1
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +115 -113
- warp/build_dll.py +383 -375
- warp/builtins.py +3425 -3354
- warp/codegen.py +2878 -2792
- warp/config.py +40 -36
- warp/constants.py +45 -45
- warp/context.py +5194 -5102
- warp/dlpack.py +442 -442
- warp/examples/__init__.py +16 -16
- warp/examples/assets/bear.usd +0 -0
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/assets/cartpole.urdf +110 -110
- warp/examples/assets/crazyflie.usd +0 -0
- warp/examples/assets/cube.usd +0 -0
- warp/examples/assets/nv_ant.xml +92 -92
- warp/examples/assets/nv_humanoid.xml +183 -183
- warp/examples/assets/quadruped.urdf +267 -267
- warp/examples/assets/rocks.nvdb +0 -0
- warp/examples/assets/rocks.usd +0 -0
- warp/examples/assets/sphere.usd +0 -0
- warp/examples/benchmarks/benchmark_api.py +383 -383
- warp/examples/benchmarks/benchmark_cloth.py +278 -279
- warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -88
- warp/examples/benchmarks/benchmark_cloth_jax.py +97 -100
- warp/examples/benchmarks/benchmark_cloth_numba.py +146 -142
- warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -77
- warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -86
- warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -112
- warp/examples/benchmarks/benchmark_cloth_warp.py +146 -146
- warp/examples/benchmarks/benchmark_launches.py +295 -295
- warp/examples/browse.py +29 -28
- warp/examples/core/example_dem.py +234 -221
- warp/examples/core/example_fluid.py +293 -267
- warp/examples/core/example_graph_capture.py +144 -129
- warp/examples/core/example_marching_cubes.py +188 -176
- warp/examples/core/example_mesh.py +174 -154
- warp/examples/core/example_mesh_intersect.py +205 -193
- warp/examples/core/example_nvdb.py +176 -169
- warp/examples/core/example_raycast.py +105 -89
- warp/examples/core/example_raymarch.py +199 -178
- warp/examples/core/example_render_opengl.py +185 -141
- warp/examples/core/example_sph.py +405 -389
- warp/examples/core/example_torch.py +222 -181
- warp/examples/core/example_wave.py +263 -249
- warp/examples/fem/bsr_utils.py +378 -380
- warp/examples/fem/example_apic_fluid.py +407 -391
- warp/examples/fem/example_convection_diffusion.py +182 -168
- warp/examples/fem/example_convection_diffusion_dg.py +219 -209
- warp/examples/fem/example_convection_diffusion_dg0.py +204 -194
- warp/examples/fem/example_deformed_geometry.py +177 -159
- warp/examples/fem/example_diffusion.py +201 -173
- warp/examples/fem/example_diffusion_3d.py +177 -152
- warp/examples/fem/example_diffusion_mgpu.py +221 -214
- warp/examples/fem/example_mixed_elasticity.py +244 -222
- warp/examples/fem/example_navier_stokes.py +259 -243
- warp/examples/fem/example_stokes.py +220 -192
- warp/examples/fem/example_stokes_transfer.py +265 -249
- warp/examples/fem/mesh_utils.py +133 -109
- warp/examples/fem/plot_utils.py +292 -287
- warp/examples/optim/example_bounce.py +260 -248
- warp/examples/optim/example_cloth_throw.py +222 -210
- warp/examples/optim/example_diffray.py +566 -535
- warp/examples/optim/example_drone.py +864 -835
- warp/examples/optim/example_inverse_kinematics.py +176 -169
- warp/examples/optim/example_inverse_kinematics_torch.py +185 -170
- warp/examples/optim/example_spring_cage.py +239 -234
- warp/examples/optim/example_trajectory.py +223 -201
- warp/examples/optim/example_walker.py +306 -292
- warp/examples/sim/example_cartpole.py +139 -128
- warp/examples/sim/example_cloth.py +196 -184
- warp/examples/sim/example_granular.py +124 -113
- warp/examples/sim/example_granular_collision_sdf.py +197 -185
- warp/examples/sim/example_jacobian_ik.py +236 -213
- warp/examples/sim/example_particle_chain.py +118 -106
- warp/examples/sim/example_quadruped.py +193 -179
- warp/examples/sim/example_rigid_chain.py +197 -189
- warp/examples/sim/example_rigid_contact.py +189 -176
- warp/examples/sim/example_rigid_force.py +127 -126
- warp/examples/sim/example_rigid_gyroscopic.py +109 -97
- warp/examples/sim/example_rigid_soft_contact.py +134 -124
- warp/examples/sim/example_soft_body.py +190 -178
- warp/fabric.py +337 -335
- warp/fem/__init__.py +60 -27
- warp/fem/cache.py +401 -388
- warp/fem/dirichlet.py +178 -179
- warp/fem/domain.py +262 -263
- warp/fem/field/__init__.py +100 -101
- warp/fem/field/field.py +148 -149
- warp/fem/field/nodal_field.py +298 -299
- warp/fem/field/restriction.py +22 -21
- warp/fem/field/test.py +180 -181
- warp/fem/field/trial.py +183 -183
- warp/fem/geometry/__init__.py +15 -19
- warp/fem/geometry/closest_point.py +69 -70
- warp/fem/geometry/deformed_geometry.py +270 -271
- warp/fem/geometry/element.py +744 -744
- warp/fem/geometry/geometry.py +184 -186
- warp/fem/geometry/grid_2d.py +380 -373
- warp/fem/geometry/grid_3d.py +441 -435
- warp/fem/geometry/hexmesh.py +953 -953
- warp/fem/geometry/partition.py +374 -376
- warp/fem/geometry/quadmesh_2d.py +532 -532
- warp/fem/geometry/tetmesh.py +840 -840
- warp/fem/geometry/trimesh_2d.py +577 -577
- warp/fem/integrate.py +1630 -1615
- warp/fem/operator.py +190 -191
- warp/fem/polynomial.py +214 -213
- warp/fem/quadrature/__init__.py +2 -2
- warp/fem/quadrature/pic_quadrature.py +243 -245
- warp/fem/quadrature/quadrature.py +295 -294
- warp/fem/space/__init__.py +294 -292
- warp/fem/space/basis_space.py +488 -489
- warp/fem/space/collocated_function_space.py +100 -105
- warp/fem/space/dof_mapper.py +236 -236
- warp/fem/space/function_space.py +148 -145
- warp/fem/space/grid_2d_function_space.py +267 -267
- warp/fem/space/grid_3d_function_space.py +305 -306
- warp/fem/space/hexmesh_function_space.py +350 -352
- warp/fem/space/partition.py +350 -350
- warp/fem/space/quadmesh_2d_function_space.py +368 -369
- warp/fem/space/restriction.py +158 -160
- warp/fem/space/shape/__init__.py +13 -15
- warp/fem/space/shape/cube_shape_function.py +738 -738
- warp/fem/space/shape/shape_function.py +102 -103
- warp/fem/space/shape/square_shape_function.py +611 -611
- warp/fem/space/shape/tet_shape_function.py +565 -567
- warp/fem/space/shape/triangle_shape_function.py +429 -429
- warp/fem/space/tetmesh_function_space.py +294 -292
- warp/fem/space/topology.py +297 -295
- warp/fem/space/trimesh_2d_function_space.py +223 -221
- warp/fem/types.py +77 -77
- warp/fem/utils.py +495 -495
- warp/jax.py +166 -141
- warp/jax_experimental.py +341 -339
- warp/native/array.h +1072 -1025
- warp/native/builtin.h +1560 -1560
- warp/native/bvh.cpp +398 -398
- warp/native/bvh.cu +525 -525
- warp/native/bvh.h +429 -429
- warp/native/clang/clang.cpp +495 -464
- warp/native/crt.cpp +31 -31
- warp/native/crt.h +334 -334
- warp/native/cuda_crt.h +1049 -1049
- warp/native/cuda_util.cpp +549 -540
- warp/native/cuda_util.h +288 -203
- warp/native/cutlass_gemm.cpp +34 -34
- warp/native/cutlass_gemm.cu +372 -372
- warp/native/error.cpp +66 -66
- warp/native/error.h +27 -27
- warp/native/fabric.h +228 -228
- warp/native/hashgrid.cpp +301 -278
- warp/native/hashgrid.cu +78 -77
- warp/native/hashgrid.h +227 -227
- warp/native/initializer_array.h +32 -32
- warp/native/intersect.h +1204 -1204
- warp/native/intersect_adj.h +365 -365
- warp/native/intersect_tri.h +322 -322
- warp/native/marching.cpp +2 -2
- warp/native/marching.cu +497 -497
- warp/native/marching.h +2 -2
- warp/native/mat.h +1498 -1498
- warp/native/matnn.h +333 -333
- warp/native/mesh.cpp +203 -203
- warp/native/mesh.cu +293 -293
- warp/native/mesh.h +1887 -1887
- warp/native/nanovdb/NanoVDB.h +4782 -4782
- warp/native/nanovdb/PNanoVDB.h +2553 -2553
- warp/native/nanovdb/PNanoVDBWrite.h +294 -294
- warp/native/noise.h +850 -850
- warp/native/quat.h +1084 -1084
- warp/native/rand.h +299 -299
- warp/native/range.h +108 -108
- warp/native/reduce.cpp +156 -156
- warp/native/reduce.cu +348 -348
- warp/native/runlength_encode.cpp +61 -61
- warp/native/runlength_encode.cu +46 -46
- warp/native/scan.cpp +30 -30
- warp/native/scan.cu +36 -36
- warp/native/scan.h +7 -7
- warp/native/solid_angle.h +442 -442
- warp/native/sort.cpp +94 -94
- warp/native/sort.cu +97 -97
- warp/native/sort.h +14 -14
- warp/native/sparse.cpp +337 -337
- warp/native/sparse.cu +544 -544
- warp/native/spatial.h +630 -630
- warp/native/svd.h +562 -562
- warp/native/temp_buffer.h +30 -30
- warp/native/vec.h +1132 -1132
- warp/native/volume.cpp +297 -297
- warp/native/volume.cu +32 -32
- warp/native/volume.h +538 -538
- warp/native/volume_builder.cu +425 -425
- warp/native/volume_builder.h +19 -19
- warp/native/warp.cpp +1057 -1052
- warp/native/warp.cu +2943 -2828
- warp/native/warp.h +313 -305
- warp/optim/__init__.py +9 -9
- warp/optim/adam.py +120 -120
- warp/optim/linear.py +1104 -939
- warp/optim/sgd.py +104 -92
- warp/render/__init__.py +10 -10
- warp/render/render_opengl.py +3217 -3204
- warp/render/render_usd.py +768 -749
- warp/render/utils.py +152 -150
- warp/sim/__init__.py +52 -59
- warp/sim/articulation.py +685 -685
- warp/sim/collide.py +1594 -1590
- warp/sim/import_mjcf.py +489 -481
- warp/sim/import_snu.py +220 -221
- warp/sim/import_urdf.py +536 -516
- warp/sim/import_usd.py +887 -881
- warp/sim/inertia.py +316 -317
- warp/sim/integrator.py +234 -233
- warp/sim/integrator_euler.py +1956 -1956
- warp/sim/integrator_featherstone.py +1910 -1991
- warp/sim/integrator_xpbd.py +3294 -3312
- warp/sim/model.py +4473 -4314
- warp/sim/particles.py +113 -112
- warp/sim/render.py +417 -403
- warp/sim/utils.py +413 -410
- warp/sparse.py +1227 -1227
- warp/stubs.py +2109 -2469
- warp/tape.py +1162 -225
- warp/tests/__init__.py +1 -1
- warp/tests/__main__.py +4 -4
- warp/tests/assets/torus.usda +105 -105
- warp/tests/aux_test_class_kernel.py +26 -26
- warp/tests/aux_test_compile_consts_dummy.py +10 -10
- warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -21
- warp/tests/aux_test_dependent.py +22 -22
- warp/tests/aux_test_grad_customs.py +23 -23
- warp/tests/aux_test_reference.py +11 -11
- warp/tests/aux_test_reference_reference.py +10 -10
- warp/tests/aux_test_square.py +17 -17
- warp/tests/aux_test_unresolved_func.py +14 -14
- warp/tests/aux_test_unresolved_symbol.py +14 -14
- warp/tests/disabled_kinematics.py +239 -239
- warp/tests/run_coverage_serial.py +31 -31
- warp/tests/test_adam.py +157 -157
- warp/tests/test_arithmetic.py +1124 -1124
- warp/tests/test_array.py +2417 -2326
- warp/tests/test_array_reduce.py +150 -150
- warp/tests/test_async.py +668 -656
- warp/tests/test_atomic.py +141 -141
- warp/tests/test_bool.py +204 -149
- warp/tests/test_builtins_resolution.py +1292 -1292
- warp/tests/test_bvh.py +164 -171
- warp/tests/test_closest_point_edge_edge.py +228 -228
- warp/tests/test_codegen.py +566 -553
- warp/tests/test_compile_consts.py +97 -101
- warp/tests/test_conditional.py +246 -246
- warp/tests/test_copy.py +232 -215
- warp/tests/test_ctypes.py +632 -632
- warp/tests/test_dense.py +67 -67
- warp/tests/test_devices.py +91 -98
- warp/tests/test_dlpack.py +530 -529
- warp/tests/test_examples.py +400 -378
- warp/tests/test_fabricarray.py +955 -955
- warp/tests/test_fast_math.py +62 -54
- warp/tests/test_fem.py +1277 -1278
- warp/tests/test_fp16.py +130 -130
- warp/tests/test_func.py +338 -337
- warp/tests/test_generics.py +571 -571
- warp/tests/test_grad.py +746 -640
- warp/tests/test_grad_customs.py +333 -336
- warp/tests/test_hash_grid.py +210 -164
- warp/tests/test_import.py +39 -39
- warp/tests/test_indexedarray.py +1134 -1134
- warp/tests/test_intersect.py +67 -67
- warp/tests/test_jax.py +307 -307
- warp/tests/test_large.py +167 -164
- warp/tests/test_launch.py +354 -354
- warp/tests/test_lerp.py +261 -261
- warp/tests/test_linear_solvers.py +191 -171
- warp/tests/test_lvalue.py +421 -493
- warp/tests/test_marching_cubes.py +65 -65
- warp/tests/test_mat.py +1801 -1827
- warp/tests/test_mat_lite.py +115 -115
- warp/tests/test_mat_scalar_ops.py +2907 -2889
- warp/tests/test_math.py +126 -193
- warp/tests/test_matmul.py +500 -499
- warp/tests/test_matmul_lite.py +410 -410
- warp/tests/test_mempool.py +188 -190
- warp/tests/test_mesh.py +284 -324
- warp/tests/test_mesh_query_aabb.py +228 -241
- warp/tests/test_mesh_query_point.py +692 -702
- warp/tests/test_mesh_query_ray.py +292 -303
- warp/tests/test_mlp.py +276 -276
- warp/tests/test_model.py +110 -110
- warp/tests/test_modules_lite.py +39 -39
- warp/tests/test_multigpu.py +163 -163
- warp/tests/test_noise.py +248 -248
- warp/tests/test_operators.py +250 -250
- warp/tests/test_options.py +123 -125
- warp/tests/test_peer.py +133 -137
- warp/tests/test_pinned.py +78 -78
- warp/tests/test_print.py +54 -54
- warp/tests/test_quat.py +2086 -2086
- warp/tests/test_rand.py +288 -288
- warp/tests/test_reload.py +217 -217
- warp/tests/test_rounding.py +179 -179
- warp/tests/test_runlength_encode.py +190 -190
- warp/tests/test_sim_grad.py +243 -0
- warp/tests/test_sim_kinematics.py +91 -97
- warp/tests/test_smoothstep.py +168 -168
- warp/tests/test_snippet.py +305 -266
- warp/tests/test_sparse.py +468 -460
- warp/tests/test_spatial.py +2148 -2148
- warp/tests/test_streams.py +486 -473
- warp/tests/test_struct.py +710 -675
- warp/tests/test_tape.py +173 -148
- warp/tests/test_torch.py +743 -743
- warp/tests/test_transient_module.py +87 -87
- warp/tests/test_types.py +556 -659
- warp/tests/test_utils.py +490 -499
- warp/tests/test_vec.py +1264 -1268
- warp/tests/test_vec_lite.py +73 -73
- warp/tests/test_vec_scalar_ops.py +2099 -2099
- warp/tests/test_verify_fp.py +94 -94
- warp/tests/test_volume.py +737 -736
- warp/tests/test_volume_write.py +255 -265
- warp/tests/unittest_serial.py +37 -37
- warp/tests/unittest_suites.py +363 -359
- warp/tests/unittest_utils.py +603 -578
- warp/tests/unused_test_misc.py +71 -71
- warp/tests/walkthrough_debug.py +85 -85
- warp/thirdparty/appdirs.py +598 -598
- warp/thirdparty/dlpack.py +143 -143
- warp/thirdparty/unittest_parallel.py +566 -561
- warp/torch.py +321 -295
- warp/types.py +4504 -4450
- warp/utils.py +1008 -821
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/LICENSE.md +126 -126
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/METADATA +338 -400
- warp_lang-1.1.0.dist-info/RECORD +352 -0
- warp/examples/assets/cube.usda +0 -42
- warp/examples/assets/sphere.usda +0 -56
- warp/examples/assets/torus.usda +0 -105
- warp_lang-1.0.1.dist-info/RECORD +0 -352
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/WHEEL +0 -0
- {warp_lang-1.0.1.dist-info → warp_lang-1.1.0.dist-info}/top_level.txt +0 -0
warp/tests/test_utils.py
CHANGED
|
@@ -1,499 +1,490 @@
|
|
|
1
|
-
# Copyright (c) 2023 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 contextlib
|
|
9
|
-
import inspect
|
|
10
|
-
import io
|
|
11
|
-
import unittest
|
|
12
|
-
|
|
13
|
-
from warp.tests.unittest_utils import *
|
|
14
|
-
|
|
15
|
-
wp.init()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def test_array_scan(test, device):
|
|
19
|
-
rng = np.random.default_rng(123)
|
|
20
|
-
|
|
21
|
-
for dtype in (int, float):
|
|
22
|
-
if dtype == int:
|
|
23
|
-
values = rng.integers(-1e6, high=1e6, size=100000, dtype=dtype)
|
|
24
|
-
else:
|
|
25
|
-
values = rng.uniform(low=-1e6, high=1e6, size=100000)
|
|
26
|
-
|
|
27
|
-
expected = np.cumsum(values)
|
|
28
|
-
|
|
29
|
-
values = wp.array(values, dtype=dtype, device=device)
|
|
30
|
-
result_inc = wp.zeros_like(values)
|
|
31
|
-
result_exc = wp.zeros_like(values)
|
|
32
|
-
|
|
33
|
-
wp.utils.array_scan(values, result_inc, True)
|
|
34
|
-
wp.utils.array_scan(values, result_exc, False)
|
|
35
|
-
|
|
36
|
-
tolerance = 0 if dtype == int else 1e-3
|
|
37
|
-
|
|
38
|
-
result_inc = result_inc.numpy().squeeze()
|
|
39
|
-
result_exc = result_exc.numpy().squeeze()
|
|
40
|
-
error_inc = np.max(np.abs(result_inc - expected)) / abs(expected[-1])
|
|
41
|
-
error_exc = max(np.max(np.abs(result_exc[1:] - expected[:-1])), abs(result_exc[0])) / abs(expected[-2])
|
|
42
|
-
|
|
43
|
-
test.assertTrue(error_inc <= tolerance)
|
|
44
|
-
test.assertTrue(error_exc <= tolerance)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def test_array_scan_empty(test, device):
|
|
48
|
-
values = wp.array((), dtype=int, device=device)
|
|
49
|
-
result = wp.array((), dtype=int, device=device)
|
|
50
|
-
wp.utils.array_scan(values, result)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def test_array_scan_error_sizes_mismatch(test, device):
|
|
54
|
-
values = wp.zeros(123, dtype=int, device=device)
|
|
55
|
-
result = wp.zeros(234, dtype=int, device=device)
|
|
56
|
-
with test.assertRaisesRegex(
|
|
57
|
-
RuntimeError,
|
|
58
|
-
r"Array storage sizes do not match$",
|
|
59
|
-
):
|
|
60
|
-
wp.utils.array_scan(values, result, True)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def test_array_scan_error_dtypes_mismatch(test, device):
|
|
64
|
-
values = wp.zeros(123, dtype=int, device=device)
|
|
65
|
-
result = wp.zeros(123, dtype=float, device=device)
|
|
66
|
-
with test.assertRaisesRegex(
|
|
67
|
-
RuntimeError,
|
|
68
|
-
r"Array data types do not match$",
|
|
69
|
-
):
|
|
70
|
-
wp.utils.array_scan(values, result, True)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def test_array_scan_error_unsupported_dtype(test, device):
|
|
74
|
-
values = wp.zeros(123, dtype=wp.vec3, device=device)
|
|
75
|
-
result = wp.zeros(123, dtype=wp.vec3, device=device)
|
|
76
|
-
with test.assertRaisesRegex(
|
|
77
|
-
RuntimeError,
|
|
78
|
-
r"Unsupported data type$",
|
|
79
|
-
):
|
|
80
|
-
wp.utils.array_scan(values, result, True)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def test_radix_sort_pairs(test, device):
|
|
84
|
-
keys = wp.array((7, 2, 8, 4, 1, 6, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0), dtype=int, device=device)
|
|
85
|
-
values = wp.array((1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0), dtype=int, device=device)
|
|
86
|
-
wp.utils.radix_sort_pairs(keys, values, 8)
|
|
87
|
-
assert_np_equal(keys.numpy()[:8], np.array((1, 2, 3, 4, 5, 6, 7, 8)))
|
|
88
|
-
assert_np_equal(values.numpy()[:8], np.array((5, 2, 8, 4, 7, 6, 1, 3)))
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def test_radix_sort_pairs_empty(test, device):
|
|
92
|
-
keys = wp.array((), dtype=int, device=device)
|
|
93
|
-
values = wp.array((), dtype=int, device=device)
|
|
94
|
-
wp.utils.radix_sort_pairs(keys, values, 0)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def test_radix_sort_pairs_error_insufficient_storage(test, device):
|
|
98
|
-
keys = wp.array((1, 2, 3), dtype=int, device=device)
|
|
99
|
-
values = wp.array((1, 2, 3), dtype=int, device=device)
|
|
100
|
-
with test.assertRaisesRegex(
|
|
101
|
-
RuntimeError,
|
|
102
|
-
r"Array storage must be large enough to contain 2\*count elements$",
|
|
103
|
-
):
|
|
104
|
-
wp.utils.radix_sort_pairs(keys, values, 3)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def test_radix_sort_pairs_error_unsupported_dtype(test, device):
|
|
108
|
-
keys = wp.array((1.0, 2.0, 3.0), dtype=float, device=device)
|
|
109
|
-
values = wp.array((1.0, 2.0, 3.0), dtype=float, device=device)
|
|
110
|
-
with test.assertRaisesRegex(
|
|
111
|
-
RuntimeError,
|
|
112
|
-
r"Unsupported data type$",
|
|
113
|
-
):
|
|
114
|
-
wp.utils.radix_sort_pairs(keys, values, 1)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def test_array_sum(test, device):
|
|
118
|
-
for dtype in (wp.float32, wp.float64):
|
|
119
|
-
with test.subTest(dtype=dtype):
|
|
120
|
-
values = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
121
|
-
test.assertEqual(wp.utils.array_sum(values), 6.0)
|
|
122
|
-
|
|
123
|
-
values = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
124
|
-
result = wp.empty(shape=(1,), dtype=dtype, device=device)
|
|
125
|
-
wp.utils.array_sum(values, out=result)
|
|
126
|
-
test.assertEqual(result.numpy()[0], 6.0)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def test_array_sum_error_out_dtype_mismatch(test, device):
|
|
130
|
-
values = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
131
|
-
result = wp.empty(shape=(1,), dtype=wp.float64, device=device)
|
|
132
|
-
with test.assertRaisesRegex(
|
|
133
|
-
RuntimeError,
|
|
134
|
-
r"out array should have type float32$",
|
|
135
|
-
):
|
|
136
|
-
wp.utils.array_sum(values, out=result)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def test_array_sum_error_out_shape_mismatch(test, device):
|
|
140
|
-
values = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
141
|
-
result = wp.empty(shape=(2,), dtype=wp.float32, device=device)
|
|
142
|
-
with test.assertRaisesRegex(
|
|
143
|
-
RuntimeError,
|
|
144
|
-
r"out array should have shape \(1,\)$",
|
|
145
|
-
):
|
|
146
|
-
wp.utils.array_sum(values, out=result)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
def test_array_sum_error_unsupported_dtype(test, device):
|
|
150
|
-
values = wp.array((1, 2, 3), dtype=int, device=device)
|
|
151
|
-
with test.assertRaisesRegex(
|
|
152
|
-
RuntimeError,
|
|
153
|
-
r"Unsupported data type$",
|
|
154
|
-
):
|
|
155
|
-
wp.utils.array_sum(values)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def test_array_inner(test, device):
|
|
159
|
-
for dtype in (wp.float32, wp.float64):
|
|
160
|
-
a = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
161
|
-
b = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
162
|
-
test.assertEqual(wp.utils.array_inner(a, b), 14.0)
|
|
163
|
-
|
|
164
|
-
a = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
165
|
-
b = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
166
|
-
result = wp.empty(shape=(1,), dtype=dtype, device=device)
|
|
167
|
-
wp.utils.array_inner(a, b, out=result)
|
|
168
|
-
test.assertEqual(result.numpy()[0], 14.0)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def test_array_inner_error_sizes_mismatch(test, device):
|
|
172
|
-
a = wp.array((1.0, 2.0), dtype=wp.float32, device=device)
|
|
173
|
-
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
174
|
-
with test.assertRaisesRegex(
|
|
175
|
-
RuntimeError,
|
|
176
|
-
r"Array storage sizes do not match$",
|
|
177
|
-
):
|
|
178
|
-
wp.utils.array_inner(a, b)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def test_array_inner_error_dtypes_mismatch(test, device):
|
|
182
|
-
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
183
|
-
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float64, device=device)
|
|
184
|
-
with test.assertRaisesRegex(
|
|
185
|
-
RuntimeError,
|
|
186
|
-
r"Array data types do not match$",
|
|
187
|
-
):
|
|
188
|
-
wp.utils.array_inner(a, b)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def test_array_inner_error_out_dtype_mismatch(test, device):
|
|
192
|
-
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
193
|
-
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
194
|
-
result = wp.empty(shape=(1,), dtype=wp.float64, device=device)
|
|
195
|
-
with test.assertRaisesRegex(
|
|
196
|
-
RuntimeError,
|
|
197
|
-
r"out array should have type float32$",
|
|
198
|
-
):
|
|
199
|
-
wp.utils.array_inner(a, b, result)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def test_array_inner_error_out_shape_mismatch(test, device):
|
|
203
|
-
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
204
|
-
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
205
|
-
result = wp.empty(shape=(2,), dtype=wp.float32, device=device)
|
|
206
|
-
with test.assertRaisesRegex(
|
|
207
|
-
RuntimeError,
|
|
208
|
-
r"out array should have shape \(1,\)$",
|
|
209
|
-
):
|
|
210
|
-
wp.utils.array_inner(a, b, result)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def test_array_inner_error_unsupported_dtype(test, device):
|
|
214
|
-
a = wp.array((1, 2, 3), dtype=int, device=device)
|
|
215
|
-
b = wp.array((1, 2, 3), dtype=int, device=device)
|
|
216
|
-
with test.assertRaisesRegex(
|
|
217
|
-
RuntimeError,
|
|
218
|
-
r"Unsupported data type$",
|
|
219
|
-
):
|
|
220
|
-
wp.utils.array_inner(a, b)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def test_array_cast(test, device):
|
|
224
|
-
values = wp.array((1, 2, 3), dtype=int, device=device)
|
|
225
|
-
result = wp.empty(3, dtype=float, device=device)
|
|
226
|
-
wp.utils.array_cast(values, result)
|
|
227
|
-
test.assertEqual(result.dtype, wp.float32)
|
|
228
|
-
test.assertEqual(result.shape, (3,))
|
|
229
|
-
assert_np_equal(result.numpy(), np.array((1.0, 2.0, 3.0), dtype=float))
|
|
230
|
-
|
|
231
|
-
values = wp.array((1, 2, 3, 4), dtype=int, device=device)
|
|
232
|
-
result = wp.empty((2, 2), dtype=float, device=device)
|
|
233
|
-
wp.utils.array_cast(values, result)
|
|
234
|
-
test.assertEqual(result.dtype, wp.float32)
|
|
235
|
-
test.assertEqual(result.shape, (2, 2))
|
|
236
|
-
assert_np_equal(result.numpy(), np.array(((1.0, 2.0), (3.0, 4.0)), dtype=float))
|
|
237
|
-
|
|
238
|
-
values = wp.array(((1, 2), (3, 4)), dtype=wp.vec2, device=device)
|
|
239
|
-
result = wp.zeros(2, dtype=float, device=device)
|
|
240
|
-
wp.utils.array_cast(values, result, count=1)
|
|
241
|
-
test.assertEqual(result.dtype, wp.float32)
|
|
242
|
-
test.assertEqual(result.shape, (2,))
|
|
243
|
-
assert_np_equal(result.numpy(), np.array((1.0, 2.0), dtype=float))
|
|
244
|
-
|
|
245
|
-
values = wp.array(((1, 2), (3, 4)), dtype=int, device=device)
|
|
246
|
-
result = wp.zeros((2, 2), dtype=int, device=device)
|
|
247
|
-
wp.utils.array_cast(values, result)
|
|
248
|
-
test.assertEqual(result.dtype, wp.int32)
|
|
249
|
-
test.assertEqual(result.shape, (2, 2))
|
|
250
|
-
assert_np_equal(result.numpy(), np.array(((1, 2), (3, 4)), dtype=int))
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def test_array_cast_error_unsupported_partial_cast(test, device):
|
|
254
|
-
values = wp.array(((1, 2), (3, 4)), dtype=int, device=device)
|
|
255
|
-
result = wp.zeros((2, 2), dtype=float, device=device)
|
|
256
|
-
with test.assertRaisesRegex(
|
|
257
|
-
RuntimeError,
|
|
258
|
-
r"Partial cast is not supported for arrays with more than one dimension$",
|
|
259
|
-
):
|
|
260
|
-
wp.utils.array_cast(values, result, count=1)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
devices = get_test_devices()
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
class TestUtils(unittest.TestCase):
|
|
267
|
-
def test_warn(self):
|
|
268
|
-
# Multiple warnings get printed out each time.
|
|
269
|
-
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
270
|
-
wp.utils.warn("hello, world!")
|
|
271
|
-
wp.utils.warn("hello, world!")
|
|
272
|
-
|
|
273
|
-
expected =
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
)
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
self.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
def
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
(
|
|
397
|
-
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
(0,
|
|
404
|
-
(0, 2
|
|
405
|
-
(
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
add_function_test(
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
"
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
add_function_test(
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
add_function_test(
|
|
474
|
-
TestUtils, "
|
|
475
|
-
)
|
|
476
|
-
add_function_test(
|
|
477
|
-
TestUtils, "
|
|
478
|
-
)
|
|
479
|
-
add_function_test(
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
"test_array_cast_error_unsupported_partial_cast",
|
|
492
|
-
test_array_cast_error_unsupported_partial_cast,
|
|
493
|
-
devices=devices,
|
|
494
|
-
)
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if __name__ == "__main__":
|
|
498
|
-
wp.build.clear_kernel_cache()
|
|
499
|
-
unittest.main(verbosity=2)
|
|
1
|
+
# Copyright (c) 2023 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 contextlib
|
|
9
|
+
import inspect
|
|
10
|
+
import io
|
|
11
|
+
import unittest
|
|
12
|
+
|
|
13
|
+
from warp.tests.unittest_utils import *
|
|
14
|
+
|
|
15
|
+
wp.init()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_array_scan(test, device):
|
|
19
|
+
rng = np.random.default_rng(123)
|
|
20
|
+
|
|
21
|
+
for dtype in (int, float):
|
|
22
|
+
if dtype == int:
|
|
23
|
+
values = rng.integers(-1e6, high=1e6, size=100000, dtype=dtype)
|
|
24
|
+
else:
|
|
25
|
+
values = rng.uniform(low=-1e6, high=1e6, size=100000)
|
|
26
|
+
|
|
27
|
+
expected = np.cumsum(values)
|
|
28
|
+
|
|
29
|
+
values = wp.array(values, dtype=dtype, device=device)
|
|
30
|
+
result_inc = wp.zeros_like(values)
|
|
31
|
+
result_exc = wp.zeros_like(values)
|
|
32
|
+
|
|
33
|
+
wp.utils.array_scan(values, result_inc, True)
|
|
34
|
+
wp.utils.array_scan(values, result_exc, False)
|
|
35
|
+
|
|
36
|
+
tolerance = 0 if dtype == int else 1e-3
|
|
37
|
+
|
|
38
|
+
result_inc = result_inc.numpy().squeeze()
|
|
39
|
+
result_exc = result_exc.numpy().squeeze()
|
|
40
|
+
error_inc = np.max(np.abs(result_inc - expected)) / abs(expected[-1])
|
|
41
|
+
error_exc = max(np.max(np.abs(result_exc[1:] - expected[:-1])), abs(result_exc[0])) / abs(expected[-2])
|
|
42
|
+
|
|
43
|
+
test.assertTrue(error_inc <= tolerance)
|
|
44
|
+
test.assertTrue(error_exc <= tolerance)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_array_scan_empty(test, device):
|
|
48
|
+
values = wp.array((), dtype=int, device=device)
|
|
49
|
+
result = wp.array((), dtype=int, device=device)
|
|
50
|
+
wp.utils.array_scan(values, result)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_array_scan_error_sizes_mismatch(test, device):
|
|
54
|
+
values = wp.zeros(123, dtype=int, device=device)
|
|
55
|
+
result = wp.zeros(234, dtype=int, device=device)
|
|
56
|
+
with test.assertRaisesRegex(
|
|
57
|
+
RuntimeError,
|
|
58
|
+
r"Array storage sizes do not match$",
|
|
59
|
+
):
|
|
60
|
+
wp.utils.array_scan(values, result, True)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_array_scan_error_dtypes_mismatch(test, device):
|
|
64
|
+
values = wp.zeros(123, dtype=int, device=device)
|
|
65
|
+
result = wp.zeros(123, dtype=float, device=device)
|
|
66
|
+
with test.assertRaisesRegex(
|
|
67
|
+
RuntimeError,
|
|
68
|
+
r"Array data types do not match$",
|
|
69
|
+
):
|
|
70
|
+
wp.utils.array_scan(values, result, True)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_array_scan_error_unsupported_dtype(test, device):
|
|
74
|
+
values = wp.zeros(123, dtype=wp.vec3, device=device)
|
|
75
|
+
result = wp.zeros(123, dtype=wp.vec3, device=device)
|
|
76
|
+
with test.assertRaisesRegex(
|
|
77
|
+
RuntimeError,
|
|
78
|
+
r"Unsupported data type$",
|
|
79
|
+
):
|
|
80
|
+
wp.utils.array_scan(values, result, True)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_radix_sort_pairs(test, device):
|
|
84
|
+
keys = wp.array((7, 2, 8, 4, 1, 6, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0), dtype=int, device=device)
|
|
85
|
+
values = wp.array((1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0), dtype=int, device=device)
|
|
86
|
+
wp.utils.radix_sort_pairs(keys, values, 8)
|
|
87
|
+
assert_np_equal(keys.numpy()[:8], np.array((1, 2, 3, 4, 5, 6, 7, 8)))
|
|
88
|
+
assert_np_equal(values.numpy()[:8], np.array((5, 2, 8, 4, 7, 6, 1, 3)))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_radix_sort_pairs_empty(test, device):
|
|
92
|
+
keys = wp.array((), dtype=int, device=device)
|
|
93
|
+
values = wp.array((), dtype=int, device=device)
|
|
94
|
+
wp.utils.radix_sort_pairs(keys, values, 0)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_radix_sort_pairs_error_insufficient_storage(test, device):
|
|
98
|
+
keys = wp.array((1, 2, 3), dtype=int, device=device)
|
|
99
|
+
values = wp.array((1, 2, 3), dtype=int, device=device)
|
|
100
|
+
with test.assertRaisesRegex(
|
|
101
|
+
RuntimeError,
|
|
102
|
+
r"Array storage must be large enough to contain 2\*count elements$",
|
|
103
|
+
):
|
|
104
|
+
wp.utils.radix_sort_pairs(keys, values, 3)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_radix_sort_pairs_error_unsupported_dtype(test, device):
|
|
108
|
+
keys = wp.array((1.0, 2.0, 3.0), dtype=float, device=device)
|
|
109
|
+
values = wp.array((1.0, 2.0, 3.0), dtype=float, device=device)
|
|
110
|
+
with test.assertRaisesRegex(
|
|
111
|
+
RuntimeError,
|
|
112
|
+
r"Unsupported data type$",
|
|
113
|
+
):
|
|
114
|
+
wp.utils.radix_sort_pairs(keys, values, 1)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_array_sum(test, device):
|
|
118
|
+
for dtype in (wp.float32, wp.float64):
|
|
119
|
+
with test.subTest(dtype=dtype):
|
|
120
|
+
values = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
121
|
+
test.assertEqual(wp.utils.array_sum(values), 6.0)
|
|
122
|
+
|
|
123
|
+
values = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
124
|
+
result = wp.empty(shape=(1,), dtype=dtype, device=device)
|
|
125
|
+
wp.utils.array_sum(values, out=result)
|
|
126
|
+
test.assertEqual(result.numpy()[0], 6.0)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def test_array_sum_error_out_dtype_mismatch(test, device):
|
|
130
|
+
values = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
131
|
+
result = wp.empty(shape=(1,), dtype=wp.float64, device=device)
|
|
132
|
+
with test.assertRaisesRegex(
|
|
133
|
+
RuntimeError,
|
|
134
|
+
r"out array should have type float32$",
|
|
135
|
+
):
|
|
136
|
+
wp.utils.array_sum(values, out=result)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_array_sum_error_out_shape_mismatch(test, device):
|
|
140
|
+
values = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
141
|
+
result = wp.empty(shape=(2,), dtype=wp.float32, device=device)
|
|
142
|
+
with test.assertRaisesRegex(
|
|
143
|
+
RuntimeError,
|
|
144
|
+
r"out array should have shape \(1,\)$",
|
|
145
|
+
):
|
|
146
|
+
wp.utils.array_sum(values, out=result)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_array_sum_error_unsupported_dtype(test, device):
|
|
150
|
+
values = wp.array((1, 2, 3), dtype=int, device=device)
|
|
151
|
+
with test.assertRaisesRegex(
|
|
152
|
+
RuntimeError,
|
|
153
|
+
r"Unsupported data type$",
|
|
154
|
+
):
|
|
155
|
+
wp.utils.array_sum(values)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_array_inner(test, device):
|
|
159
|
+
for dtype in (wp.float32, wp.float64):
|
|
160
|
+
a = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
161
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
162
|
+
test.assertEqual(wp.utils.array_inner(a, b), 14.0)
|
|
163
|
+
|
|
164
|
+
a = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
165
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=dtype, device=device)
|
|
166
|
+
result = wp.empty(shape=(1,), dtype=dtype, device=device)
|
|
167
|
+
wp.utils.array_inner(a, b, out=result)
|
|
168
|
+
test.assertEqual(result.numpy()[0], 14.0)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_array_inner_error_sizes_mismatch(test, device):
|
|
172
|
+
a = wp.array((1.0, 2.0), dtype=wp.float32, device=device)
|
|
173
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
174
|
+
with test.assertRaisesRegex(
|
|
175
|
+
RuntimeError,
|
|
176
|
+
r"Array storage sizes do not match$",
|
|
177
|
+
):
|
|
178
|
+
wp.utils.array_inner(a, b)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_array_inner_error_dtypes_mismatch(test, device):
|
|
182
|
+
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
183
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float64, device=device)
|
|
184
|
+
with test.assertRaisesRegex(
|
|
185
|
+
RuntimeError,
|
|
186
|
+
r"Array data types do not match$",
|
|
187
|
+
):
|
|
188
|
+
wp.utils.array_inner(a, b)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def test_array_inner_error_out_dtype_mismatch(test, device):
|
|
192
|
+
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
193
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
194
|
+
result = wp.empty(shape=(1,), dtype=wp.float64, device=device)
|
|
195
|
+
with test.assertRaisesRegex(
|
|
196
|
+
RuntimeError,
|
|
197
|
+
r"out array should have type float32$",
|
|
198
|
+
):
|
|
199
|
+
wp.utils.array_inner(a, b, result)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def test_array_inner_error_out_shape_mismatch(test, device):
|
|
203
|
+
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
204
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device=device)
|
|
205
|
+
result = wp.empty(shape=(2,), dtype=wp.float32, device=device)
|
|
206
|
+
with test.assertRaisesRegex(
|
|
207
|
+
RuntimeError,
|
|
208
|
+
r"out array should have shape \(1,\)$",
|
|
209
|
+
):
|
|
210
|
+
wp.utils.array_inner(a, b, result)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def test_array_inner_error_unsupported_dtype(test, device):
|
|
214
|
+
a = wp.array((1, 2, 3), dtype=int, device=device)
|
|
215
|
+
b = wp.array((1, 2, 3), dtype=int, device=device)
|
|
216
|
+
with test.assertRaisesRegex(
|
|
217
|
+
RuntimeError,
|
|
218
|
+
r"Unsupported data type$",
|
|
219
|
+
):
|
|
220
|
+
wp.utils.array_inner(a, b)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def test_array_cast(test, device):
|
|
224
|
+
values = wp.array((1, 2, 3), dtype=int, device=device)
|
|
225
|
+
result = wp.empty(3, dtype=float, device=device)
|
|
226
|
+
wp.utils.array_cast(values, result)
|
|
227
|
+
test.assertEqual(result.dtype, wp.float32)
|
|
228
|
+
test.assertEqual(result.shape, (3,))
|
|
229
|
+
assert_np_equal(result.numpy(), np.array((1.0, 2.0, 3.0), dtype=float))
|
|
230
|
+
|
|
231
|
+
values = wp.array((1, 2, 3, 4), dtype=int, device=device)
|
|
232
|
+
result = wp.empty((2, 2), dtype=float, device=device)
|
|
233
|
+
wp.utils.array_cast(values, result)
|
|
234
|
+
test.assertEqual(result.dtype, wp.float32)
|
|
235
|
+
test.assertEqual(result.shape, (2, 2))
|
|
236
|
+
assert_np_equal(result.numpy(), np.array(((1.0, 2.0), (3.0, 4.0)), dtype=float))
|
|
237
|
+
|
|
238
|
+
values = wp.array(((1, 2), (3, 4)), dtype=wp.vec2, device=device)
|
|
239
|
+
result = wp.zeros(2, dtype=float, device=device)
|
|
240
|
+
wp.utils.array_cast(values, result, count=1)
|
|
241
|
+
test.assertEqual(result.dtype, wp.float32)
|
|
242
|
+
test.assertEqual(result.shape, (2,))
|
|
243
|
+
assert_np_equal(result.numpy(), np.array((1.0, 2.0), dtype=float))
|
|
244
|
+
|
|
245
|
+
values = wp.array(((1, 2), (3, 4)), dtype=int, device=device)
|
|
246
|
+
result = wp.zeros((2, 2), dtype=int, device=device)
|
|
247
|
+
wp.utils.array_cast(values, result)
|
|
248
|
+
test.assertEqual(result.dtype, wp.int32)
|
|
249
|
+
test.assertEqual(result.shape, (2, 2))
|
|
250
|
+
assert_np_equal(result.numpy(), np.array(((1, 2), (3, 4)), dtype=int))
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_array_cast_error_unsupported_partial_cast(test, device):
|
|
254
|
+
values = wp.array(((1, 2), (3, 4)), dtype=int, device=device)
|
|
255
|
+
result = wp.zeros((2, 2), dtype=float, device=device)
|
|
256
|
+
with test.assertRaisesRegex(
|
|
257
|
+
RuntimeError,
|
|
258
|
+
r"Partial cast is not supported for arrays with more than one dimension$",
|
|
259
|
+
):
|
|
260
|
+
wp.utils.array_cast(values, result, count=1)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
devices = get_test_devices()
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class TestUtils(unittest.TestCase):
|
|
267
|
+
def test_warn(self):
|
|
268
|
+
# Multiple warnings get printed out each time.
|
|
269
|
+
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
270
|
+
wp.utils.warn("hello, world!")
|
|
271
|
+
wp.utils.warn("hello, world!")
|
|
272
|
+
|
|
273
|
+
expected = "Warp UserWarning: hello, world!\n" "Warp UserWarning: hello, world!\n"
|
|
274
|
+
|
|
275
|
+
self.assertEqual(f.getvalue(), expected)
|
|
276
|
+
|
|
277
|
+
# Test verbose warnings
|
|
278
|
+
saved_verbosity = wp.config.verbose_warnings
|
|
279
|
+
try:
|
|
280
|
+
wp.config.verbose_warnings = True
|
|
281
|
+
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
282
|
+
frame_info = inspect.getframeinfo(inspect.currentframe())
|
|
283
|
+
wp.utils.warn("hello, world!")
|
|
284
|
+
wp.utils.warn("hello, world!")
|
|
285
|
+
|
|
286
|
+
expected = (
|
|
287
|
+
f"Warp UserWarning: hello, world! ({frame_info.filename}:{frame_info.lineno + 1})\n"
|
|
288
|
+
' wp.utils.warn("hello, world!")\n'
|
|
289
|
+
f"Warp UserWarning: hello, world! ({frame_info.filename}:{frame_info.lineno + 2})\n"
|
|
290
|
+
' wp.utils.warn("hello, world!")\n'
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
self.assertEqual(f.getvalue(), expected)
|
|
294
|
+
|
|
295
|
+
finally:
|
|
296
|
+
# make sure to restore warning verbosity
|
|
297
|
+
wp.config.verbose_warnings = saved_verbosity
|
|
298
|
+
|
|
299
|
+
# Multiple similar deprecation warnings get printed out only once.
|
|
300
|
+
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
301
|
+
wp.utils.warn("hello, world!", category=DeprecationWarning)
|
|
302
|
+
wp.utils.warn("hello, world!", category=DeprecationWarning)
|
|
303
|
+
|
|
304
|
+
expected = "Warp DeprecationWarning: hello, world!\n"
|
|
305
|
+
|
|
306
|
+
self.assertEqual(f.getvalue(), expected)
|
|
307
|
+
|
|
308
|
+
# Multiple different deprecation warnings get printed out each time.
|
|
309
|
+
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
310
|
+
wp.utils.warn("foo", category=DeprecationWarning)
|
|
311
|
+
wp.utils.warn("bar", category=DeprecationWarning)
|
|
312
|
+
|
|
313
|
+
expected = "Warp DeprecationWarning: foo\n" "Warp DeprecationWarning: bar\n"
|
|
314
|
+
|
|
315
|
+
self.assertEqual(f.getvalue(), expected)
|
|
316
|
+
|
|
317
|
+
def test_transform_expand(self):
|
|
318
|
+
t = (1.0, 2.0, 3.0, 4.0, 3.0, 2.0, 1.0)
|
|
319
|
+
self.assertEqual(
|
|
320
|
+
wp.utils.transform_expand(t),
|
|
321
|
+
wp.transformf(p=(1.0, 2.0, 3.0), q=(4.0, 3.0, 2.0, 1.0)),
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
@unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
|
|
325
|
+
def test_array_scan_error_devices_mismatch(self):
|
|
326
|
+
values = wp.zeros(123, dtype=int, device="cpu")
|
|
327
|
+
result = wp.zeros_like(values, device="cuda:0")
|
|
328
|
+
with self.assertRaisesRegex(
|
|
329
|
+
RuntimeError,
|
|
330
|
+
r"Array storage devices do not match$",
|
|
331
|
+
):
|
|
332
|
+
wp.utils.array_scan(values, result, True)
|
|
333
|
+
|
|
334
|
+
@unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
|
|
335
|
+
def test_radix_sort_pairs_error_devices_mismatch(self):
|
|
336
|
+
keys = wp.array((1, 2, 3), dtype=int, device="cpu")
|
|
337
|
+
values = wp.array((1, 2, 3), dtype=int, device="cuda:0")
|
|
338
|
+
with self.assertRaisesRegex(
|
|
339
|
+
RuntimeError,
|
|
340
|
+
r"Array storage devices do not match$",
|
|
341
|
+
):
|
|
342
|
+
wp.utils.radix_sort_pairs(keys, values, 1)
|
|
343
|
+
|
|
344
|
+
@unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
|
|
345
|
+
def test_array_inner_error_out_device_mismatch(self):
|
|
346
|
+
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device="cpu")
|
|
347
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device="cpu")
|
|
348
|
+
result = wp.empty(shape=(1,), dtype=wp.float32, device="cuda:0")
|
|
349
|
+
with self.assertRaisesRegex(
|
|
350
|
+
RuntimeError,
|
|
351
|
+
r"out storage device should match values array$",
|
|
352
|
+
):
|
|
353
|
+
wp.utils.array_inner(a, b, result)
|
|
354
|
+
|
|
355
|
+
@unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
|
|
356
|
+
def test_array_sum_error_out_device_mismatch(self):
|
|
357
|
+
values = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device="cpu")
|
|
358
|
+
result = wp.empty(shape=(1,), dtype=wp.float32, device="cuda:0")
|
|
359
|
+
with self.assertRaisesRegex(
|
|
360
|
+
RuntimeError,
|
|
361
|
+
r"out storage device should match values array$",
|
|
362
|
+
):
|
|
363
|
+
wp.utils.array_sum(values, out=result)
|
|
364
|
+
|
|
365
|
+
@unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
|
|
366
|
+
def test_array_inner_error_devices_mismatch(self):
|
|
367
|
+
a = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device="cpu")
|
|
368
|
+
b = wp.array((1.0, 2.0, 3.0), dtype=wp.float32, device="cuda:0")
|
|
369
|
+
with self.assertRaisesRegex(
|
|
370
|
+
RuntimeError,
|
|
371
|
+
r"Array storage devices do not match$",
|
|
372
|
+
):
|
|
373
|
+
wp.utils.array_inner(a, b)
|
|
374
|
+
|
|
375
|
+
@unittest.skipUnless(wp.is_cuda_available(), "Requires CUDA")
|
|
376
|
+
def test_array_cast_error_devices_mismatch(self):
|
|
377
|
+
values = wp.array((1, 2, 3), dtype=int, device="cpu")
|
|
378
|
+
result = wp.empty(3, dtype=float, device="cuda:0")
|
|
379
|
+
with self.assertRaisesRegex(
|
|
380
|
+
RuntimeError,
|
|
381
|
+
r"Array storage devices do not match$",
|
|
382
|
+
):
|
|
383
|
+
wp.utils.array_cast(values, result)
|
|
384
|
+
|
|
385
|
+
def test_mesh_adjacency(self):
|
|
386
|
+
triangles = (
|
|
387
|
+
(0, 3, 1),
|
|
388
|
+
(0, 2, 3),
|
|
389
|
+
)
|
|
390
|
+
adj = wp.utils.MeshAdjacency(triangles, len(triangles))
|
|
391
|
+
expected_edges = {
|
|
392
|
+
(0, 3): (0, 3, 1, 2, 0, 1),
|
|
393
|
+
(1, 3): (3, 1, 0, -1, 0, -1),
|
|
394
|
+
(0, 1): (1, 0, 3, -1, 0, -1),
|
|
395
|
+
(0, 2): (0, 2, 3, -1, 1, -1),
|
|
396
|
+
(2, 3): (2, 3, 0, -1, 1, -1),
|
|
397
|
+
}
|
|
398
|
+
edges = {k: (e.v0, e.v1, e.o0, e.o1, e.f0, e.f1) for k, e in adj.edges.items()}
|
|
399
|
+
self.assertDictEqual(edges, expected_edges)
|
|
400
|
+
|
|
401
|
+
def test_mesh_adjacency_error_manifold(self):
|
|
402
|
+
triangles = (
|
|
403
|
+
(0, 3, 1),
|
|
404
|
+
(0, 2, 3),
|
|
405
|
+
(3, 0, 1),
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
409
|
+
wp.utils.MeshAdjacency(triangles, len(triangles))
|
|
410
|
+
|
|
411
|
+
self.assertEqual(f.getvalue(), "Detected non-manifold edge\n")
|
|
412
|
+
|
|
413
|
+
def test_scoped_timer(self):
|
|
414
|
+
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
415
|
+
with wp.ScopedTimer("hello"):
|
|
416
|
+
pass
|
|
417
|
+
|
|
418
|
+
self.assertRegex(f.getvalue(), r"^hello took \d+\.\d+ ms$")
|
|
419
|
+
|
|
420
|
+
with contextlib.redirect_stdout(io.StringIO()) as f:
|
|
421
|
+
with wp.ScopedTimer("hello", detailed=True):
|
|
422
|
+
pass
|
|
423
|
+
|
|
424
|
+
self.assertRegex(f.getvalue(), r"^ 4 function calls in \d+\.\d+ seconds")
|
|
425
|
+
self.assertRegex(f.getvalue(), r"hello took \d+\.\d+ ms$")
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
add_function_test(TestUtils, "test_array_scan", test_array_scan, devices=devices)
|
|
429
|
+
add_function_test(TestUtils, "test_array_scan_empty", test_array_scan_empty, devices=devices)
|
|
430
|
+
add_function_test(
|
|
431
|
+
TestUtils, "test_array_scan_error_sizes_mismatch", test_array_scan_error_sizes_mismatch, devices=devices
|
|
432
|
+
)
|
|
433
|
+
add_function_test(
|
|
434
|
+
TestUtils, "test_array_scan_error_dtypes_mismatch", test_array_scan_error_dtypes_mismatch, devices=devices
|
|
435
|
+
)
|
|
436
|
+
add_function_test(
|
|
437
|
+
TestUtils, "test_array_scan_error_unsupported_dtype", test_array_scan_error_unsupported_dtype, devices=devices
|
|
438
|
+
)
|
|
439
|
+
add_function_test(TestUtils, "test_radix_sort_pairs", test_radix_sort_pairs, devices=devices)
|
|
440
|
+
add_function_test(TestUtils, "test_radix_sort_pairs_empty", test_radix_sort_pairs, devices=devices)
|
|
441
|
+
add_function_test(
|
|
442
|
+
TestUtils,
|
|
443
|
+
"test_radix_sort_pairs_error_insufficient_storage",
|
|
444
|
+
test_radix_sort_pairs_error_insufficient_storage,
|
|
445
|
+
devices=devices,
|
|
446
|
+
)
|
|
447
|
+
add_function_test(
|
|
448
|
+
TestUtils,
|
|
449
|
+
"test_radix_sort_pairs_error_unsupported_dtype",
|
|
450
|
+
test_radix_sort_pairs_error_unsupported_dtype,
|
|
451
|
+
devices=devices,
|
|
452
|
+
)
|
|
453
|
+
add_function_test(TestUtils, "test_array_sum", test_array_sum, devices=devices)
|
|
454
|
+
add_function_test(
|
|
455
|
+
TestUtils, "test_array_sum_error_out_dtype_mismatch", test_array_sum_error_out_dtype_mismatch, devices=devices
|
|
456
|
+
)
|
|
457
|
+
add_function_test(
|
|
458
|
+
TestUtils, "test_array_sum_error_out_shape_mismatch", test_array_sum_error_out_shape_mismatch, devices=devices
|
|
459
|
+
)
|
|
460
|
+
add_function_test(
|
|
461
|
+
TestUtils, "test_array_sum_error_unsupported_dtype", test_array_sum_error_unsupported_dtype, devices=devices
|
|
462
|
+
)
|
|
463
|
+
add_function_test(TestUtils, "test_array_inner", test_array_inner, devices=devices)
|
|
464
|
+
add_function_test(
|
|
465
|
+
TestUtils, "test_array_inner_error_sizes_mismatch", test_array_inner_error_sizes_mismatch, devices=devices
|
|
466
|
+
)
|
|
467
|
+
add_function_test(
|
|
468
|
+
TestUtils, "test_array_inner_error_dtypes_mismatch", test_array_inner_error_dtypes_mismatch, devices=devices
|
|
469
|
+
)
|
|
470
|
+
add_function_test(
|
|
471
|
+
TestUtils, "test_array_inner_error_out_dtype_mismatch", test_array_inner_error_out_dtype_mismatch, devices=devices
|
|
472
|
+
)
|
|
473
|
+
add_function_test(
|
|
474
|
+
TestUtils, "test_array_inner_error_out_shape_mismatch", test_array_inner_error_out_shape_mismatch, devices=devices
|
|
475
|
+
)
|
|
476
|
+
add_function_test(
|
|
477
|
+
TestUtils, "test_array_inner_error_unsupported_dtype", test_array_inner_error_unsupported_dtype, devices=devices
|
|
478
|
+
)
|
|
479
|
+
add_function_test(TestUtils, "test_array_cast", test_array_cast, devices=devices)
|
|
480
|
+
add_function_test(
|
|
481
|
+
TestUtils,
|
|
482
|
+
"test_array_cast_error_unsupported_partial_cast",
|
|
483
|
+
test_array_cast_error_unsupported_partial_cast,
|
|
484
|
+
devices=devices,
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
if __name__ == "__main__":
|
|
489
|
+
wp.build.clear_kernel_cache()
|
|
490
|
+
unittest.main(verbosity=2)
|