Skip to content
Snippets Groups Projects
test_conditional_vec.py 4.76 KiB
Newer Older
import sympy as sp
Michael Kuron's avatar
Michael Kuron committed
import pytest

import pystencils as ps
Jan Hönig's avatar
Jan Hönig committed
from pystencils.astnodes import Block, Conditional, SympyAssignment
from pystencils.backends.simd_instruction_sets import get_supported_instruction_sets, get_vector_instruction_set
Jan Hönig's avatar
Jan Hönig committed
from pystencils.enums import Target
from pystencils.cpu.vectorization import vec_all, vec_any
Jan Hönig's avatar
Jan Hönig committed
from pystencils.node_collection import NodeCollection
supported_instruction_sets = get_supported_instruction_sets() if get_supported_instruction_sets() else []
@pytest.mark.parametrize('instruction_set', supported_instruction_sets)
Markus Holzer's avatar
Markus Holzer committed
@pytest.mark.parametrize('dtype', ('float32', 'float64'))
def test_vec_any(instruction_set, dtype):
Michael Kuron's avatar
Michael Kuron committed
    if instruction_set in ['sve', 'sme', 'rvv']:
Michael Kuron's avatar
Michael Kuron committed
        width = 4  # we don't know the actual value
    else:
        width = get_vector_instruction_set(dtype, instruction_set)['width']
Markus Holzer's avatar
Markus Holzer committed
    data_arr = np.zeros((4 * width, 4 * width), dtype=dtype)
Jan Hönig's avatar
Jan Hönig committed
    data_arr[3:9, 1:3 * width - 1] = 1.0
    data = ps.fields(f"data: {dtype}[2D]", data=data_arr)
Jan Hönig's avatar
Jan Hönig committed
        SympyAssignment(sp.Symbol("t1"), vec_any(data.center() > 0.0)),
        Conditional(vec_any(data.center() > 0.0), Block([SympyAssignment(data.center(), 2.0)]))
Jan Hönig's avatar
Jan Hönig committed

    assignmets = NodeCollection(c)
    ast = ps.create_kernel(assignments=assignmets, target=ps.Target.CPU,
Markus Holzer's avatar
Markus Holzer committed
                           cpu_vectorize_info={'instruction_set': instruction_set})
    kernel = ast.compile()
    kernel(data=data_arr)
Michael Kuron's avatar
Michael Kuron committed
    if instruction_set in ['sve', 'sme', 'rvv']:
Michael Kuron's avatar
Michael Kuron committed
        # we only know that the first value has changed
Jan Hönig's avatar
Jan Hönig committed
        np.testing.assert_equal(data_arr[3:9, :3 * width - 1], 2.0)
Michael Kuron's avatar
Michael Kuron committed
    else:
Jan Hönig's avatar
Jan Hönig committed
        np.testing.assert_equal(data_arr[3:9, :3 * width], 2.0)
@pytest.mark.parametrize('instruction_set', supported_instruction_sets)
Markus Holzer's avatar
Markus Holzer committed
@pytest.mark.parametrize('dtype', ('float32', 'float64'))
def test_vec_all(instruction_set, dtype):
Michael Kuron's avatar
Michael Kuron committed
    if instruction_set in ['sve', 'sme', 'rvv']:
Michael Kuron's avatar
Michael Kuron committed
        width = 1000  # we don't know the actual value, need something guaranteed larger than vector
    else:
        width = get_vector_instruction_set(dtype, instruction_set)['width']
Markus Holzer's avatar
Markus Holzer committed
    data_arr = np.zeros((4 * width, 4 * width), dtype=dtype)
Jan Hönig's avatar
Jan Hönig committed
    data_arr[3:9, 1:3 * width - 1] = 1.0
    data = ps.fields(f"data: {dtype}[2D]", data=data_arr)
Jan Hönig's avatar
Jan Hönig committed
    c = [Conditional(vec_all(data.center() > 0.0), Block([SympyAssignment(data.center(), 2.0)]))]
    assignmets = NodeCollection(c)
    ast = ps.create_kernel(assignmets, target=Target.CPU,
                           cpu_vectorize_info={'instruction_set': instruction_set})
    kernel = ast.compile()
    kernel(data=data_arr)
Michael Kuron's avatar
Michael Kuron committed
    if instruction_set in ['sve', 'sme', 'rvv']:
Michael Kuron's avatar
Michael Kuron committed
        # we only know that some values in the middle have been replaced
        assert np.all(data_arr[3:9, :2] <= 1.0)
        assert np.any(data_arr[3:9, 2:] == 2.0)
    else:
        np.testing.assert_equal(data_arr[3:9, :1], 0.0)
        np.testing.assert_equal(data_arr[3:9, 1:width], 1.0)
Jan Hönig's avatar
Jan Hönig committed
        np.testing.assert_equal(data_arr[3:9, width:2 * width], 2.0)
        np.testing.assert_equal(data_arr[3:9, 2 * width:3 * width - 1], 1.0)
        np.testing.assert_equal(data_arr[3:9, 3 * width - 1:], 0.0)
@pytest.mark.skipif(not supported_instruction_sets, reason='cannot detect CPU instruction set')
def test_boolean_before_loop():
    t1, t2 = sp.symbols('t1, t2')
    f_arr = np.ones((10, 10))
    g_arr = np.zeros_like(f_arr)
    f, g = ps.fields("f, g : double[2D]", f=f_arr, g=g_arr)

    a = [
        ps.Assignment(t1, t2 > 0),
        ps.Assignment(g[0, 0],
                      sp.Piecewise((f[0, 0], t1), (42, True)))
    ]
    ast = ps.create_kernel(a, cpu_vectorize_info={'instruction_set': supported_instruction_sets[-1]})
    kernel = ast.compile()
    kernel(f=f_arr, g=g_arr, t2=1.0)
Jan Hönig's avatar
Jan Hönig committed
    # print(g)
    np.testing.assert_array_equal(g_arr, 1.0)
    kernel(f=f_arr, g=g_arr, t2=-1.0)
    np.testing.assert_array_equal(g_arr, 42.0)


@pytest.mark.parametrize('instruction_set', supported_instruction_sets)
Jan Hönig's avatar
Jan Hönig committed
@pytest.mark.parametrize('dtype', ('float32', 'float64'))
def test_vec_maskstore(instruction_set, dtype):
Markus Holzer's avatar
Markus Holzer committed
    data_arr = np.zeros((16, 16), dtype=dtype)
Michael Kuron's avatar
Michael Kuron committed
    data_arr[3:-3, 3:-3] = 1.0
    data = ps.fields(f"data: {dtype}[2D]", data=data_arr)

Jan Hönig's avatar
Jan Hönig committed
    c = [Conditional(data.center() < 1.0, Block([SympyAssignment(data.center(), 2.0)]))]

    assignmets = NodeCollection(c)
Jan Hönig's avatar
Jan Hönig committed
    config = ps.CreateKernelConfig(cpu_vectorize_info={'instruction_set': instruction_set}, default_number_float=dtype)
    ast = ps.create_kernel(assignmets, config=config)
    print(ps.get_code_str(ast))
Michael Kuron's avatar
Michael Kuron committed
    np.testing.assert_equal(data_arr[:3, :], 2.0)
    np.testing.assert_equal(data_arr[-3:, :], 2.0)
    np.testing.assert_equal(data_arr[:, :3], 2.0)
    np.testing.assert_equal(data_arr[:, -3:], 2.0)
    np.testing.assert_equal(data_arr[3:-3, 3:-3], 1.0)