blob: 8c1ed6796a3a1c20724afacdc8f79c99db003291 [file] [log] [blame]
Fredrik Svedberg1575b942020-08-18 13:19:18 +02001# Copyright (C) 2020 Arm Limited or its affiliates. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
4#
5# Licensed under the Apache License, Version 2.0 (the License); you may
6# not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an AS IS BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16# Description:
17# Unit tests for fixed point math
18import numpy as np
19import pytest
20
21from ethosu.vela import fp_math
Louis Verhaardd7911c42020-08-25 13:36:41 +020022from ethosu.vela import scaling
Fredrik Svedberg1575b942020-08-18 13:19:18 +020023from ethosu.vela.softmax import SoftMax
24
25# Turn off black formatting for EXP_LUT to keep it compact
26# fmt: off
27
28EXP_LUT = [
29 0x000011c9, 0x000012b8, 0x000013b4, 0x000014bd, 0x000015d4, 0x000016fa, 0x0000182f, 0x00001975,
30 0x00001acb, 0x00001c34, 0x00001daf, 0x00001f3f, 0x000020e3, 0x0000229e, 0x00002470, 0x0000265a,
31 0x0000285e, 0x00002a7d, 0x00002cb9, 0x00002f13, 0x0000318c, 0x00003427, 0x000036e5, 0x000039c8,
32 0x00003cd1, 0x00004004, 0x00004361, 0x000046ec, 0x00004aa6, 0x00004e93, 0x000052b4, 0x0000570d,
33 0x00005ba1, 0x00006072, 0x00006583, 0x00006ada, 0x00007077, 0x00007661, 0x00007c9a, 0x00008327,
34 0x00008a0c, 0x0000914d, 0x000098f1, 0x0000a0fb, 0x0000a971, 0x0000b259, 0x0000bbb9, 0x0000c597,
35 0x0000cffa, 0x0000dae9, 0x0000e66b, 0x0000f288, 0x0000ff48, 0x00010cb3, 0x00011ad3, 0x000129b1,
36 0x00013957, 0x000149d0, 0x00015b26, 0x00016d65, 0x0001809b, 0x000194d2, 0x0001aa1a, 0x0001c080,
37 0x0001d814, 0x0001f0e4, 0x00020b03, 0x00022681, 0x00024371, 0x000261e7, 0x000281f7, 0x0002a3b5,
38 0x0002c73b, 0x0002ec9e, 0x000313f8, 0x00033d64, 0x000368fd, 0x000396e1, 0x0003c72e, 0x0003fa05,
39 0x00042f89, 0x000467dd, 0x0004a326, 0x0004e18e, 0x0005233d, 0x00056861, 0x0005b126, 0x0005fdbf,
40 0x00064e5f, 0x0006a33c, 0x0006fc8e, 0x00075a93, 0x0007bd89, 0x000825b3, 0x00089356, 0x000906bd,
41 0x00098035, 0x000a000f, 0x000a86a2, 0x000b1447, 0x000ba95f, 0x000c464e, 0x000ceb7c, 0x000d9959,
42 0x000e505a, 0x000f10f9, 0x000fdbb9, 0x0010b120, 0x001191c0, 0x00127e2f, 0x0013770b, 0x00147cfc,
43 0x001590b2, 0x0016b2e7, 0x0017e45d, 0x001925e1, 0x001a784c, 0x001bdc81, 0x001d536f, 0x001ede14,
44 0x00207d77, 0x002232af, 0x0023fee4, 0x0025e349, 0x0027e125, 0x0029f9ce, 0x002c2ead, 0x002e813e,
45 0x0030f30f, 0x003385c7, 0x00363b1f, 0x003914e9, 0x003c1510, 0x003f3d97, 0x004290a1, 0x00461066,
46 0x0049bf41, 0x004d9fad, 0x0051b444, 0x0055ffc3, 0x005a850f, 0x005f4730, 0x0064495a, 0x00698eeb,
47 0x006f1b6c, 0x0074f299, 0x007b185f, 0x008190de, 0x00886074, 0x008f8bae, 0x00971762, 0x009f08a2,
48 0x00a764c2, 0x00b03164, 0x00b9746e, 0x00c3341b, 0x00cd76fa, 0x00d843ed, 0x00e3a23b, 0x00ef9983,
49 0x00fc31d2, 0x010973a0, 0x011767d1, 0x012617cf, 0x01358d70, 0x0145d31c, 0x0156f3c1, 0x0168fadf,
50 0x017bf4a0, 0x018fedb6, 0x01a4f394, 0x01bb145a, 0x01d25ee1, 0x01eae2e5, 0x0204b0c8, 0x021fd9ed,
51 0x023c7091, 0x025a87f9, 0x027a343d, 0x029b8ac5, 0x02bea1ee, 0x02e3914d, 0x030a71c2, 0x03335d4e,
52 0x035e6f8d, 0x038bc56a, 0x03bb7d57, 0x03edb77c, 0x04229573, 0x045a3ae4, 0x0494cd29, 0x04d2739e,
53 0x051357c7, 0x0557a519, 0x059f8997, 0x05eb358d, 0x063adbcc, 0x068eb1ff, 0x06e6f049, 0x0743d21b,
54 0x07a595d9, 0x080c7d29, 0x0878cd66, 0x08eacf1a, 0x0962cf07, 0x09e11dcc, 0x0a661032, 0x0af1ffea,
55 0x0b854a9a, 0x0c20536f, 0x0cc3828e, 0x0d6f4584, 0x0e241040, 0x0ee25bb0, 0x0faaa7f2, 0x107d7b9e,
56 0x115b64be, 0x1244f787, 0x133ad1c6, 0x143d9885, 0x154df999, 0x166cac7a, 0x179a70d5, 0x18d81262,
57 0x1a266657, 0x1b864d4c, 0x1cf8b43e, 0x1e7e9316, 0x2018f0b9, 0x21c8e0b1, 0x238f851d, 0x256e1046,
58 0x2765c287, 0x2977ef55, 0x2ba5fab4, 0x2df15b8a, 0x305b9d83, 0x32e65ea3, 0x35935539, 0x38644d75,
59 0x3b5b2b74, 0x3e79eea7, 0x41c2addc, 0x45379f60, 0x48db159c, 0x4caf81fa, 0x50b7797f, 0x54f5af2b,
60 0x596cfe46, 0x5e2066e8, 0x631310c8, 0x684852d8, 0x6dc3a909, 0x7388c43d, 0x799b84b7, 0x7fffffff,
61]
62# fmt: on
63
64
65def test_saturating_rounding_mul():
66 i32info = np.iinfo(np.int32)
67 shift = 22
68 multiplier = 1760306048
69 assert fp_math.saturating_rounding_mul(i32info.min, i32info.min) == i32info.max
70 assert fp_math.saturating_rounding_mul(-255 * 1 << shift, multiplier) == -876714926
71 assert fp_math.saturating_rounding_mul(-128 * 1 << shift, multiplier) == -440076512
72 assert fp_math.saturating_rounding_mul(0, multiplier) == 0
73 assert fp_math.saturating_rounding_mul(128 * 1 << shift, multiplier) == 440076512
74 assert fp_math.saturating_rounding_mul(255 * 1 << shift, multiplier) == 876714926
75
76
77def test_shift_left():
78 i32info = np.iinfo(np.int32)
79 assert fp_math.shift_left(np.int32(1), i32info.bits) == i32info.max
80 assert fp_math.shift_left(np.int32(-1), i32info.bits) == i32info.min
81 assert fp_math.shift_left(np.int32(1), i32info.bits - 2) == (i32info.max + 1) / 2
82 assert fp_math.shift_left(np.int32(-1), i32info.bits - 2) == i32info.min // 2
83
84
85def test_rounding_divide_by_pot():
86 assert fp_math.rounding_divide_by_pot(1024, 4) == 64
87 assert fp_math.rounding_divide_by_pot(1031, 4) == 64
88 assert fp_math.rounding_divide_by_pot(1032, 4) == 65
89 assert fp_math.rounding_divide_by_pot(1047, 4) == 65
90 assert fp_math.rounding_divide_by_pot(1048, 4) == 66
91 assert fp_math.rounding_divide_by_pot(1056, 4) == 66
92 assert fp_math.rounding_divide_by_pot(-1024, 4) == -64
93 assert fp_math.rounding_divide_by_pot(-1031, 4) == -64
94 assert fp_math.rounding_divide_by_pot(-1032, 4) == -65
95 assert fp_math.rounding_divide_by_pot(-1047, 4) == -65
96 assert fp_math.rounding_divide_by_pot(-1048, 4) == -66
97 assert fp_math.rounding_divide_by_pot(-1056, 4) == -66
98
99
100def test_saturating_rounding_multiply_by_pot():
101 i32info = np.iinfo(np.int32)
102 assert fp_math.saturating_rounding_multiply_by_pot(4, np.int32(1025)) == 16400
103 assert fp_math.saturating_rounding_multiply_by_pot(5, np.int32(67108865)) == i32info.max
104 assert fp_math.saturating_rounding_multiply_by_pot(5, np.int32(-67108865)) == i32info.min
105
106
107def test_rescale():
108 assert fp_math.rescale(5, 0, np.int32(1025)) == 32800
109 assert fp_math.rescale(3, 0, np.int32(1025)) == 8200
110 assert fp_math.rescale(5, 1, np.int32(1025)) == 16400
111 assert fp_math.rescale(3, 1, np.int32(1025)) == 4100
112 with pytest.raises(AssertionError):
113 fp_math.rescale(1, 3, np.int32(1024))
114
115
116def test_exp():
117 sm = SoftMax(None)
118 for (expected, actual) in zip(EXP_LUT, sm.generate_exp_table(1.0, np.float32(0.05123165))):
119 assert actual == expected
Louis Verhaardd7911c42020-08-25 13:36:41 +0200120
121
122multiply_test_data = [
123 (0, 0, 0),
124 (0, 0.7, 0),
125 (0, 55.8, 0),
126 (6, 0.3, 2),
127 (200, 0, 0),
128 (1, 1, 1),
129 (1, 0.1, 0),
130 (1, 3.49, 3),
131 (1, 3.51, 4),
132 (27, 1, 27),
133 (13, 0.9, 12),
134 (3, 21.2, 64),
135 (1000, 2000, 2000000),
136 (32767, 32767, 32767 * 32767), # extreme values
137]
138
139
140@pytest.mark.parametrize("x, factor, expected", multiply_test_data)
141def test_multiply_by_quantized_multiplier(x, factor, expected):
142 scale, shift = scaling.quantise_scale(factor)
143 assert fp_math.multiply_by_quantized_multiplier(x, scale, shift) == expected
144 assert fp_math.multiply_by_quantized_multiplier(-x, scale, shift) == -expected
145 assert fp_math.multiply_by_quantized_multiplier(x, -scale, shift) == -expected
146 assert fp_math.multiply_by_quantized_multiplier(-x, -scale, shift) == expected
147
148
149def test_multiply_by_quantized_multiplier_int16_limits():
150 # Tests min/max limits of foreseen practical usage of multiply_by_quantized_multiplier
151 # for the purpose of calculating LUTs
152 for x in [-32768, 32767]:
153 for y in [-32768, 32767]:
154 scale, shift = scaling.quantise_scale(y)
155 assert fp_math.multiply_by_quantized_multiplier(x, scale, shift) == x * y