test_vectorization.py 7.13 KB
Newer Older
1
2
import numpy as np
import sympy as sp
Martin Bauer's avatar
Martin Bauer committed
3

4
5
6
import pystencils as ps
from pystencils.backends.simd_instruction_sets import get_supported_instruction_sets
from pystencils.cpu.vectorization import vectorize
7
from pystencils.fast_approximation import insert_fast_sqrts, insert_fast_divisions
8
9
from pystencils.transformations import replace_inner_stride_with_one

Markus Holzer's avatar
Markus Holzer committed
10
11
12
13
14
supported_instruction_sets = get_supported_instruction_sets()
if supported_instruction_sets:
    instruction_set = supported_instruction_sets[-1]
else:
    instruction_set = None
15
16
17
18
19
20
21
22
23
24
25
26

def test_vector_type_propagation():
    a, b, c, d, e = sp.symbols("a b c d e")
    arr = np.ones((2 ** 2 + 2, 2 ** 3 + 2))
    arr *= 10.0

    f, g = ps.fields(f=arr, g=arr)
    update_rule = [ps.Assignment(a, f[1, 0]),
                   ps.Assignment(b, a),
                   ps.Assignment(g[0, 0], b + 3 + f[0, 1])]

    ast = ps.create_kernel(update_rule)
Markus Holzer's avatar
Markus Holzer committed
27
    vectorize(ast, instruction_set=instruction_set)
28
29
30
31
32
33
34

    func = ast.compile()
    dst = np.zeros_like(arr)
    func(g=dst, f=arr)
    np.testing.assert_equal(dst[1:-1, 1:-1], 2 * 10.0 + 3)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def test_inplace_update():
    shape = (9, 9, 3)
    arr = np.ones(shape, order='f')

    @ps.kernel
    def update_rule(s):
        f = ps.fields("f(3) : [2D]", f=arr)
        s.tmp0 @= f(0)
        s.tmp1 @= f(1)
        s.tmp2 @= f(2)
        f0, f1, f2 = f(0), f(1), f(2)
        f0 @= 2 * s.tmp0
        f1 @= 2 * s.tmp0
        f2 @= 2 * s.tmp0

Markus Holzer's avatar
Markus Holzer committed
50
    ast = ps.create_kernel(update_rule, cpu_vectorize_info={'instruction_set': instruction_set})
51
52
53
54
    kernel = ast.compile()
    kernel(f=arr)
    np.testing.assert_equal(arr, 2)

55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def test_vectorization_fixed_size():
    configurations = []
    # Fixed size - multiple of four
    arr = np.ones((20 + 2, 24 + 2)) * 5.0
    f, g = ps.fields(f=arr, g=arr)
    configurations.append((arr, f, g))
    # Fixed size - no multiple of four
    arr = np.ones((21 + 2, 25 + 2)) * 5.0
    f, g = ps.fields(f=arr, g=arr)
    configurations.append((arr, f, g))
    # Fixed size - different remainder
    arr = np.ones((23 + 2, 17 + 2)) * 5.0
    f, g = ps.fields(f=arr, g=arr)
    configurations.append((arr, f, g))

    for arr, f, g in configurations:
        update_rule = [ps.Assignment(g[0, 0], f[0, 0] + f[-1, 0] + f[1, 0] + f[0, 1] + f[0, -1] + 42.0)]

        ast = ps.create_kernel(update_rule)
Markus Holzer's avatar
Markus Holzer committed
75
        vectorize(ast, instruction_set=instruction_set)
76
77
78
79
80
81
82
83
84
85
86
87
88

        func = ast.compile()
        dst = np.zeros_like(arr)
        func(g=dst, f=arr)
        np.testing.assert_equal(dst[1:-1, 1:-1], 5 * 5.0 + 42.0)


def test_vectorization_variable_size():
    f, g = ps.fields("f, g : double[2D]")
    update_rule = [ps.Assignment(g[0, 0], f[0, 0] + f[-1, 0] + f[1, 0] + f[0, 1] + f[0, -1] + 42.0)]
    ast = ps.create_kernel(update_rule)

    replace_inner_stride_with_one(ast)
Markus Holzer's avatar
Markus Holzer committed
89
    vectorize(ast, instruction_set=instruction_set)
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    func = ast.compile()

    arr = np.ones((23 + 2, 17 + 2)) * 5.0
    dst = np.zeros_like(arr)

    func(g=dst, f=arr)
    np.testing.assert_equal(dst[1:-1, 1:-1], 5 * 5.0 + 42.0)


def test_piecewise1():
    a, b, c, d, e = sp.symbols("a b c d e")
    arr = np.ones((2 ** 3 + 2, 2 ** 4 + 2)) * 5.0

    f, g = ps.fields(f=arr, g=arr)
    update_rule = [ps.Assignment(a, f[1, 0]),
                   ps.Assignment(b, a),
                   ps.Assignment(c, f[0, 0] > 0.0),
                   ps.Assignment(g[0, 0], sp.Piecewise((b + 3 + f[0, 1], c), (0.0, True)))]

    ast = ps.create_kernel(update_rule)
Markus Holzer's avatar
Markus Holzer committed
110
    vectorize(ast, instruction_set=instruction_set)
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    func = ast.compile()
    dst = np.zeros_like(arr)
    func(g=dst, f=arr)
    np.testing.assert_equal(dst[1:-1, 1:-1], 5 + 3 + 5.0)


def test_piecewise2():
    arr = np.zeros((20, 20))

    @ps.kernel
    def test_kernel(s):
        f, g = ps.fields(f=arr, g=arr)

        s.condition @= f[0, 0] > 1
        s.result    @= 0.0 if s.condition else 1.0
        g[0, 0]     @= s.result

    ast = ps.create_kernel(test_kernel)
Markus Holzer's avatar
Markus Holzer committed
129
    vectorize(ast, instruction_set=instruction_set)
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    func = ast.compile()
    func(f=arr, g=arr)
    np.testing.assert_equal(arr, np.ones_like(arr))


def test_piecewise3():
    arr = np.zeros((22, 22))

    @ps.kernel
    def test_kernel(s):
        f, g = ps.fields(f=arr, g=arr)
        s.b     @= f[0, 1]
        g[0, 0] @= 1.0 / (s.b + s.k) if f[0, 0] > 0.0 else 1.0

    ast = ps.create_kernel(test_kernel)
Markus Holzer's avatar
Markus Holzer committed
145
    vectorize(ast, instruction_set=instruction_set)
146
147
148
149
150
151
152
    ast.compile()


def test_logical_operators():
    arr = np.zeros((22, 22))

    @ps.kernel
153
    def kernel_and(s):
154
155
156
157
        f, g = ps.fields(f=arr, g=arr)
        s.c @= sp.And(f[0, 1] < 0.0, f[1, 0] < 0.0)
        g[0, 0] @= sp.Piecewise([1.0 / f[1, 0], s.c], [1.0, True])

158
    ast = ps.create_kernel(kernel_and)
Markus Holzer's avatar
Markus Holzer committed
159
    vectorize(ast, instruction_set=instruction_set)
160
161
162
163
164
165
166
167
168
    ast.compile()

    @ps.kernel
    def kernel_or(s):
        f, g = ps.fields(f=arr, g=arr)
        s.c @= sp.Or(f[0, 1] < 0.0, f[1, 0] < 0.0)
        g[0, 0] @= sp.Piecewise([1.0 / f[1, 0], s.c], [1.0, True])

    ast = ps.create_kernel(kernel_or)
Markus Holzer's avatar
Markus Holzer committed
169
    vectorize(ast, instruction_set=instruction_set)
170
171
172
173
174
175
176
177
178
    ast.compile()

    @ps.kernel
    def kernel_equal(s):
        f, g = ps.fields(f=arr, g=arr)
        s.c @= sp.Eq(f[0, 1], 2.0)
        g[0, 0] @= sp.Piecewise([1.0 / f[1, 0], s.c], [1.0, True])

    ast = ps.create_kernel(kernel_equal)
Markus Holzer's avatar
Markus Holzer committed
179
    vectorize(ast, instruction_set=instruction_set)
180
181
182
183
184
185
    ast.compile()


def test_hardware_query():
    instruction_sets = get_supported_instruction_sets()
    assert 'sse' in instruction_sets
186
187
188
189
190
191
192
193
194
195
196
197
198
199


def test_vectorised_pow():
    arr = np.zeros((24, 24))
    f, g = ps.fields(f=arr, g=arr)

    as1 = ps.Assignment(g[0, 0], sp.Pow(f[0, 0], 2))
    as2 = ps.Assignment(g[0, 0], sp.Pow(f[0, 0], 0.5))
    as3 = ps.Assignment(g[0, 0], sp.Pow(f[0, 0], -0.5))
    as4 = ps.Assignment(g[0, 0], sp.Pow(f[0, 0], 4))
    as5 = ps.Assignment(g[0, 0], sp.Pow(f[0, 0], -4))
    as6 = ps.Assignment(g[0, 0], sp.Pow(f[0, 0], -1))

    ast = ps.create_kernel(as1)
Markus Holzer's avatar
Markus Holzer committed
200
    vectorize(ast, instruction_set=instruction_set)
201
202
203
    ast.compile()

    ast = ps.create_kernel(as2)
Markus Holzer's avatar
Markus Holzer committed
204
    vectorize(ast, instruction_set=instruction_set)
205
206
207
    ast.compile()

    ast = ps.create_kernel(as3)
Markus Holzer's avatar
Markus Holzer committed
208
    vectorize(ast, instruction_set=instruction_set)
209
210
211
    ast.compile()

    ast = ps.create_kernel(as4)
Markus Holzer's avatar
Markus Holzer committed
212
    vectorize(ast, instruction_set=instruction_set)
213
214
215
    ast.compile()

    ast = ps.create_kernel(as5)
Markus Holzer's avatar
Markus Holzer committed
216
    vectorize(ast, instruction_set=instruction_set)
217
218
219
    ast.compile()

    ast = ps.create_kernel(as6)
Markus Holzer's avatar
Markus Holzer committed
220
    vectorize(ast, instruction_set=instruction_set)
221
222
223
224
225
226
227
228
229
230
    ast.compile()


def test_vectorised_fast_approximations():
    arr = np.zeros((24, 24))
    f, g = ps.fields(f=arr, g=arr)

    expr = sp.sqrt(f[0, 0] + f[1, 0])
    assignment = ps.Assignment(g[0, 0], insert_fast_sqrts(expr))
    ast = ps.create_kernel(assignment)
Markus Holzer's avatar
Markus Holzer committed
231
    vectorize(ast, instruction_set=instruction_set)
232
233
234
235
236
    ast.compile()

    expr = f[0, 0] / f[1, 0]
    assignment = ps.Assignment(g[0, 0], insert_fast_divisions(expr))
    ast = ps.create_kernel(assignment)
Markus Holzer's avatar
Markus Holzer committed
237
    vectorize(ast, instruction_set=instruction_set)
238
239
240
241
    ast.compile()

    assignment = ps.Assignment(sp.Symbol("tmp"), 3 / sp.sqrt(f[0, 0] + f[1, 0]))
    ast = ps.create_kernel(insert_fast_sqrts(assignment))
Markus Holzer's avatar
Markus Holzer committed
242
    vectorize(ast, instruction_set=instruction_set)
243
    ast.compile()