import numpy as np import pytest import sympy as sp from pystencils import Assignment, Field, create_kernel, fields def test_size_check(): """Kernel with two fixed-sized fields creating with same size but calling with wrong size""" src = np.zeros((20, 21, 9)) dst = np.zeros_like(src) sym_src = Field.create_from_numpy_array("src", src, index_dimensions=1) sym_dst = Field.create_from_numpy_array("dst", dst, index_dimensions=1) update_rule = Assignment(sym_dst(0), sym_src[-1, 1](1) + sym_src[1, -1](2)) ast = create_kernel([update_rule]) func = ast.compile() # change size of src field new_shape = [a - 7 for a in src.shape] src = np.zeros(new_shape) dst = np.zeros(new_shape) with pytest.raises(ValueError) as e: func(src=src, dst=dst) assert 'Wrong shape' in str(e.value) def test_fixed_size_mismatch_check(): """Create kernel with two differently sized but constant fields """ src = np.zeros((20, 21, 9)) dst = np.zeros((21, 21, 9)) sym_src = Field.create_from_numpy_array("src", src, index_dimensions=1) sym_dst = Field.create_from_numpy_array("dst", dst, index_dimensions=1) update_rule = Assignment(sym_dst(0), sym_src[-1, 1](1) + sym_src[1, -1](2)) with pytest.raises(ValueError) as e: create_kernel([update_rule]) assert 'Differently sized field accesses' in str(e.value) def test_fixed_and_variable_field_check(): """Create kernel with two variable sized fields - calling them with different sizes""" src = np.zeros((20, 21, 9)) sym_src = Field.create_from_numpy_array("src", src, index_dimensions=1) sym_dst = Field.create_generic("dst", spatial_dimensions=2, index_dimensions=1) update_rule = Assignment(sym_dst(0), sym_src[-1, 1](1) + sym_src[1, -1](2)) with pytest.raises(ValueError) as e: create_kernel(update_rule) assert 'Mixing fixed-shaped and variable-shape fields' in str(e.value) def test_two_variable_shaped_fields(): src = np.zeros((20, 21, 9)) dst = np.zeros((22, 21, 9)) sym_src = Field.create_generic("src", spatial_dimensions=2, index_dimensions=1) sym_dst = Field.create_generic("dst", spatial_dimensions=2, index_dimensions=1) update_rule = Assignment(sym_dst(0), sym_src[-1, 1](1) + sym_src[1, -1](2)) ast = create_kernel([update_rule]) func = ast.compile() with pytest.raises(TypeError) as e: func(src=src, dst=dst) assert 'must have same' in str(e.value) def test_ssa_checks(): f, g = fields("f, g : double[2D]") a, b, c = sp.symbols("a b c") with pytest.raises(ValueError) as e: create_kernel([Assignment(c, f[0, 1]), Assignment(c, f[1, 0]), Assignment(g[0, 0], c)]) assert 'Assignments not in SSA form' in str(e.value) with pytest.raises(ValueError) as e: create_kernel([Assignment(c, a + 3), Assignment(a, 42), Assignment(g[0, 0], c)]) assert 'Symbol a is written, after it has been read' in str(e.value) with pytest.raises(ValueError) as e: create_kernel([Assignment(c, c + 1), Assignment(g[0, 0], c)]) assert 'Symbol c is written, after it has been read' in str(e.value) def test_loop_independence_checks(): f, g = fields("f, g : double[2D]") v = fields("v(2) : double[2D]") with pytest.raises(ValueError) as e: create_kernel([Assignment(g[0, 1], f[0, 1]), Assignment(g[0, 0], f[1, 0])]) assert 'Field g is written at two different locations' in str(e.value) # This is allowed - because only one element of g is accessed create_kernel([Assignment(g[0, 2], f[0, 1]), Assignment(g[0, 2], 2 * g[0, 2])]) create_kernel([Assignment(v[0, 2](1), f[0, 1]), Assignment(v[0, 1](0), 4), Assignment(v[0, 2](1), 2 * v[0, 2](1))]) with pytest.raises(ValueError) as e: create_kernel([Assignment(g[0, 1], 3), Assignment(f[0, 1], 2 * g[0, 2])]) assert 'Field g is read at (0, 2) and written at (0, 1)' in str(e.value)