Skip to content
Snippets Groups Projects
test_types.py 7.57 KiB
Newer Older
Markus Holzer's avatar
Markus Holzer committed
import pytest

import pystencils.config
Markus Holzer's avatar
Markus Holzer committed

import pystencils as ps
Markus Holzer's avatar
Markus Holzer committed
from pystencils.typing import TypedSymbol, get_type_of_expression, VectorType, collate_types, \
    typed_symbols, CastFunc, PointerArithmeticFunc, PointerType, result_type, BasicType


def test_result_type():
    i = np.dtype('int32')
    l = np.dtype('int64')
    ui = np.dtype('uint32')
    ul = np.dtype('uint64')
    f = np.dtype('float32')
    d = np.dtype('float64')
    b = np.dtype('bool')

    assert result_type(i, l) == l
    assert result_type(l, i) == l
    assert result_type(ui, i) == i
    assert result_type(ui, l) == l
    assert result_type(ul, i) == i
    assert result_type(ul, l) == l
    assert result_type(d, f) == d
    assert result_type(f, d) == d
    assert result_type(i, f) == f
    assert result_type(l, f) == f
    assert result_type(ui, f) == f
    assert result_type(ul, f) == f
    assert result_type(i, d) == d
    assert result_type(l, d) == d
    assert result_type(ui, d) == d
    assert result_type(ul, d) == d
    assert result_type(b, i) == i
    assert result_type(b, l) == l
    assert result_type(b, ui) == ui
    assert result_type(b, ul) == ul
    assert result_type(b, f) == f
    assert result_type(b, d) == d


@pytest.mark.parametrize('dtype', ('float64', 'float32', 'int64', 'int32', 'uint32', 'uint64'))
def test_simple_add(dtype):
    constant = 1.0
    if dtype[0] in 'ui':
        constant = 1
    f = ps.fields(f"f: {dtype}[1D]")
    d = TypedSymbol("d", dtype)

    test_arr = np.array([constant], dtype=dtype)

    ur = ps.Assignment(f[0], f[0] + d)

    ast = ps.create_kernel(ur)
    code = ps.get_code_str(ast)
    kernel = ast.compile()
    kernel(f=test_arr, d=constant)

    assert test_arr[0] == constant+constant


@pytest.mark.parametrize('dtype1', ('float64', 'float32', 'int64', 'int32', 'uint32', 'uint64'))
@pytest.mark.parametrize('dtype2', ('float64', 'float32', 'int64', 'int32', 'uint32', 'uint64'))
def test_mixed_add(dtype1, dtype2):

    constant = 1
    f = ps.fields(f"f: {dtype1}[1D]")
    g = ps.fields(f"g: {dtype2}[1D]")
Markus Holzer's avatar
Markus Holzer committed
    test_f = np.array([constant], dtype=dtype1)
    test_g = np.array([constant], dtype=dtype2)
Markus Holzer's avatar
Markus Holzer committed
    ur = ps.Assignment(f[0], f[0] + g[0])
Markus Holzer's avatar
Markus Holzer committed
    # TODO Markus: check for the logging if colate_types(dtype1, dtype2) != dtype1
    ast = ps.create_kernel(ur)
    code = ps.get_code_str(ast)
    kernel = ast.compile()
    kernel(f=test_f, g=test_g)
Markus Holzer's avatar
Markus Holzer committed
    assert test_f[0] == constant+constant
Markus Holzer's avatar
Markus Holzer committed

def test_collation():
Markus Holzer's avatar
Markus Holzer committed
    double_type = BasicType('float64')
    float_type = BasicType('float32')
    double4_type = VectorType(double_type, 4)
    float4_type = VectorType(float_type, 4)
    assert collate_types([double_type, float_type]) == double_type
    assert collate_types([double4_type, float_type]) == double4_type
    assert collate_types([double4_type, float4_type]) == double4_type
Markus Holzer's avatar
Markus Holzer committed
def test_vector_type():
Markus Holzer's avatar
Markus Holzer committed
    double_type = BasicType('float64')
    float_type = BasicType('float32')
Markus Holzer's avatar
Markus Holzer committed
    double4_type = VectorType(double_type, 4)
    float4_type = VectorType(float_type, 4)

    assert double4_type.item_size == 4
    assert float4_type.item_size == 4

Markus Holzer's avatar
Markus Holzer committed
    double4_type2 = VectorType(double_type, 4)
    assert double4_type == double4_type2
    assert double4_type != 4
    assert double4_type != float4_type
Markus Holzer's avatar
Markus Holzer committed


def test_pointer_type():
Markus Holzer's avatar
Markus Holzer committed
    double_type = BasicType('float64')
    float_type = BasicType('float32')
Markus Holzer's avatar
Markus Holzer committed
    double4_type = PointerType(double_type, restrict=True)
    float4_type = PointerType(float_type, restrict=False)

    assert double4_type.item_size == 1
    assert float4_type.item_size == 1

    assert not double4_type == 4

    assert not double4_type.alias
    assert float4_type.alias


def test_dtype_of_constants():
    # Some come constants are neither of type Integer,Float,Rational and don't have args
    # >>> isinstance(pi, Integer)
    # False
    # >>> isinstance(pi, Float)
    # False
    # >>> isinstance(pi, Rational)
    # False
    # >>> pi.args
    # ()
    get_type_of_expression(sp.pi)
    x = ps.fields('x:  float32[3d]')

    assert x.shape[0].is_nonnegative
    assert (2 * x.shape[0]).is_nonnegative
    assert (2 * x.shape[0]).is_integer
Markus Holzer's avatar
Markus Holzer committed
    assert (TypedSymbol('a', BasicType('uint64'))).is_nonnegative
    assert (TypedSymbol('a', BasicType('uint64'))).is_positive is None
    assert (TypedSymbol('a', BasicType('uint64')) + 1).is_positive
Markus Holzer's avatar
Markus Holzer committed
@pytest.mark.parametrize('dtype', ('float64', 'float32'))
def test_sqrt_of_integer(dtype):
    """Regression test for bug where sqrt(3) was classified as integer"""
Markus Holzer's avatar
Markus Holzer committed
    f = ps.fields(f'f: {dtype}[1D]')
    tmp = sp.symbols('tmp')

    assignments = [ps.Assignment(tmp, sp.sqrt(3)),
                   ps.Assignment(f[0], tmp)]
Markus Holzer's avatar
Markus Holzer committed
    arr = np.array([1], dtype=dtype)
    config = pystencils.config.CreateKernelConfig(data_type=dtype, default_number_float=dtype)
Markus Holzer's avatar
Markus Holzer committed
    ast = ps.create_kernel(assignments, config=config)
    kernel = ast.compile()
    kernel(f=arr)
    assert 1.7 < arr[0] < 1.8
Markus Holzer's avatar
Markus Holzer committed
    code = ps.get_code_str(ast)
    constant = '1.7320508075688772f'
    if dtype == 'float32':
        assert constant in code
    else:
        assert constant not in code
Markus Holzer's avatar
Markus Holzer committed
@pytest.mark.parametrize('dtype', ('float64', 'float32'))
def test_integer_comparision(dtype):
    f = ps.fields(f"f: {dtype}[2D]")
    d = TypedSymbol("dir", "int64")
Markus Holzer's avatar
Markus Holzer committed

    ur = ps.Assignment(f[0, 0], sp.Piecewise((0, sp.Equality(d, 1)), (f[0, 0], True)))

    ast = ps.create_kernel(ur)
    code = ps.get_code_str(ast)

Markus Holzer's avatar
Markus Holzer committed
    # There should be an explicit cast for the integer zero to the type of the field on the rhs
    if dtype == 'float64':
        t = "_data_f[_stride_f_0*ctr_0 + _stride_f_1*ctr_1] = " \
            "((((dir) == (1))) ? (0.0): (_data_f[_stride_f_0*ctr_0 + _stride_f_1*ctr_1]));"
Markus Holzer's avatar
Markus Holzer committed
    else:
        t = "_data_f[_stride_f_0*ctr_0 + _stride_f_1*ctr_1] = " \
            "((((dir) == (1))) ? (0.0f): (_data_f[_stride_f_0*ctr_0 + _stride_f_1*ctr_1]));"
Markus Holzer's avatar
Markus Holzer committed
    assert t in code
Markus Holzer's avatar
Markus Holzer committed
def test_typed_symbols_dtype():
Markus Holzer's avatar
Markus Holzer committed
    assert typed_symbols(("s", "f"), np.uint) == typed_symbols("s, f", np.uint)
    t_symbols = typed_symbols(("s", "f"), np.uint)
    s = t_symbols[0]

    assert t_symbols[0] == TypedSymbol("s", np.uint)
    assert s.dtype.is_uint()

Markus Holzer's avatar
Markus Holzer committed
    assert typed_symbols("s", np.float64).dtype.c_name == 'double'
    assert typed_symbols("s", np.float32).dtype.c_name == 'float'
Markus Holzer's avatar
Markus Holzer committed

    assert TypedSymbol("s", np.uint).canonical == TypedSymbol("s", np.uint)
    assert TypedSymbol("s", np.uint).reversed == TypedSymbol("s", np.uint)


def test_cast_func():
Markus Holzer's avatar
Markus Holzer committed
    assert CastFunc(TypedSymbol("s", np.uint), np.int64).canonical == TypedSymbol("s", np.uint).canonical
Markus Holzer's avatar
Markus Holzer committed
    a = CastFunc(5, np.uint)
Markus Holzer's avatar
Markus Holzer committed
    assert a.is_negative is False
    assert a.is_nonnegative


def test_pointer_arithmetic_func():
Markus Holzer's avatar
Markus Holzer committed
    assert PointerArithmeticFunc(TypedSymbol("s", np.uint), 1).canonical == TypedSymbol("s", np.uint).canonical


def test_division():
    f = ps.fields('f(10): float32[2D]')
    m, tau = sp.symbols("m, tau")

    up = [ps.Assignment(tau, 1 / (0.5 + (3.0 * m))),
          ps.Assignment(f.center, tau)]
    config = pystencils.config.CreateKernelConfig(data_type='float32', default_number_float='float32')
    ast = ps.create_kernel(up, config=config)
    code = ps.get_code_str(ast)

    assert "((1.0f) / (m*3.0f + 0.5f))" in code


def test_pow():
    f = ps.fields('f(10): float32[2D]')
    m, tau = sp.symbols("m, tau")

    up = [ps.Assignment(tau, m ** 1.5),
          ps.Assignment(f.center, tau)]

    config = pystencils.config.CreateKernelConfig(data_type="float32", default_number_float='float32')
    ast = ps.create_kernel(up, config=config)
    code = ps.get_code_str(ast)

    assert "1.5f" in code