|
6 | 6 | ####################################################################### |
7 | 7 |
|
8 | 8 |
|
| 9 | +import subprocess |
| 10 | +import sys |
| 11 | + |
9 | 12 | import numpy as np |
10 | 13 | import pytest |
11 | 14 |
|
@@ -113,6 +116,18 @@ def kernel_scalar_start_step(start, step): |
113 | 116 | return start + step * (_i0 * _n1 + _i1) # noqa: F821 # DSL index/shape symbols resolved by miniexpr |
114 | 117 |
|
115 | 118 |
|
| 119 | +@blosc2.dsl_kernel |
| 120 | +def kernel_scalar_start_stop_nitems(start, stop, nitems): |
| 121 | + step = (stop - start) / nitems |
| 122 | + return start + _global_linear_idx * step # noqa: F821 # DSL index/shape symbols resolved by miniexpr |
| 123 | + |
| 124 | + |
| 125 | +@blosc2.dsl_kernel |
| 126 | +def kernel_scalar_start_stop_nitems_float_cast(start, stop, nitems): |
| 127 | + step = (float(stop) - float(start)) / float(nitems) |
| 128 | + return float(start) + _global_linear_idx * step # noqa: F821 # DSL index/shape symbols resolved by miniexpr |
| 129 | + |
| 130 | + |
116 | 131 | @blosc2.dsl_kernel |
117 | 132 | def kernel_fallback_kw_call(x, y): |
118 | 133 | return clip(x + y, a_min=0.5, a_max=2.5) |
@@ -542,6 +557,63 @@ def test_dsl_kernel_two_scalar_params_start_step_linear_ramp(): |
542 | 557 | np.testing.assert_allclose(res[...], expected, rtol=0.0, atol=0.0) |
543 | 558 |
|
544 | 559 |
|
| 560 | +def test_dsl_kernel_three_scalar_params_start_stop_nitems_ramp(): |
| 561 | + shape = (20, 25) |
| 562 | + start = np.float64(1.0) |
| 563 | + stop = np.float64(2.0) |
| 564 | + nitems = np.int64(np.prod(shape)) |
| 565 | + |
| 566 | + expr = blosc2.lazyudf( |
| 567 | + kernel_scalar_start_stop_nitems, (start, stop, nitems), dtype=np.float64, shape=shape |
| 568 | + ) |
| 569 | + res = expr.compute() |
| 570 | + |
| 571 | + step = (stop - start) / nitems |
| 572 | + expected = (start + step * np.arange(np.prod(shape), dtype=np.float64)).reshape(shape) |
| 573 | + np.testing.assert_allclose(res[...], expected, rtol=0.0, atol=0.0) |
| 574 | + |
| 575 | + |
| 576 | +def test_dsl_kernel_float_cast_with_negative_scalar_param(): |
| 577 | + shape = (10, 100) |
| 578 | + start = -10 |
| 579 | + stop = 10 |
| 580 | + nitems = np.int64(np.prod(shape) - 1) |
| 581 | + |
| 582 | + expr = blosc2.lazyudf( |
| 583 | + kernel_scalar_start_stop_nitems_float_cast, (start, stop, nitems), dtype=np.float32, shape=shape |
| 584 | + ) |
| 585 | + res = expr.compute() |
| 586 | + |
| 587 | + expected = np.linspace(start, stop, np.prod(shape), dtype=np.float32).reshape(shape) |
| 588 | + np.testing.assert_allclose(res[...], expected, rtol=1e-6, atol=1e-6) |
| 589 | + |
| 590 | + |
| 591 | +def test_dsl_kernel_float_cast_with_global_linear_idx_no_segfault_subprocess(): |
| 592 | + if blosc2.IS_WASM: |
| 593 | + pytest.skip("subprocess is not supported on emscripten/wasm32") |
| 594 | + |
| 595 | + code = ( |
| 596 | + "import numpy as np\n" |
| 597 | + "import blosc2\n" |
| 598 | + "@blosc2.dsl_kernel\n" |
| 599 | + "def kernel(start, stop, nitems):\n" |
| 600 | + " step = (float(stop) - float(start)) / float(nitems)\n" |
| 601 | + " return float(start) + _global_linear_idx * step # noqa: F821\n" |
| 602 | + "shape = (10, 100)\n" |
| 603 | + "arr = blosc2.lazyudf(kernel, (-10, 10, 999), dtype=np.float32, shape=shape).compute()\n" |
| 604 | + "exp = np.linspace(-10, 10, np.prod(shape), dtype=np.float32).reshape(shape)\n" |
| 605 | + "np.testing.assert_allclose(arr, exp, rtol=1e-6, atol=1e-6)\n" |
| 606 | + "print('ok')\n" |
| 607 | + ) |
| 608 | + result = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True, check=False) |
| 609 | + assert result.returncode == 0, ( |
| 610 | + "subprocess failed (possible segfault/regression in DSL float-cast path):\n" |
| 611 | + f"stdout:\n{result.stdout}\n" |
| 612 | + f"stderr:\n{result.stderr}" |
| 613 | + ) |
| 614 | + assert "ok" in result.stdout |
| 615 | + |
| 616 | + |
545 | 617 | def test_dsl_kernel_miniexpr_failure_raises_even_with_strict_disabled(monkeypatch): |
546 | 618 | import importlib |
547 | 619 |
|
|
0 commit comments