1 /*
2  * Copyright (c) 2021 Stephanos Ioannidis <root@stephanos.io>
3  * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/ztest.h>
9 #include <zephyr/kernel.h>
10 #include <stdlib.h>
11 #include <arm_math.h>
12 #include "../../common/test_common.h"
13 
14 #include "unary_q31.pat"
15 
16 #define SNR_ERROR_THRESH	((float32_t)100)
17 #define ABS_ERROR_THRESH_Q31	((q31_t)2)
18 #define ABS_ERROR_THRESH_Q63	((q63_t)(1 << 16))
19 
20 #define NUM_MATRICES		(ARRAY_SIZE(in_dims) / 2)
21 #define MAX_MATRIX_DIM		(40)
22 
23 #define OP2_ADD			(0)
24 #define OP2_SUB			(1)
25 #define OP1_SCALE		(0)
26 #define OP1_TRANS		(1)
27 #define OP2V_VEC_MULT		(0)
28 #define OP1C_CMPLX_TRANS	(0)
29 
test_op2(int op,const q31_t * ref,size_t length)30 static void test_op2(int op, const q31_t *ref, size_t length)
31 {
32 	size_t index;
33 	uint16_t *dims = (uint16_t *)in_dims;
34 	q31_t *tmp1, *tmp2, *output;
35 	uint16_t rows, columns;
36 	arm_status status;
37 
38 	arm_matrix_instance_q31 mat_in1;
39 	arm_matrix_instance_q31 mat_in2;
40 	arm_matrix_instance_q31 mat_out;
41 
42 	/* Allocate buffers */
43 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(q31_t));
44 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
45 
46 	tmp2 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(q31_t));
47 	zassert_not_null(tmp2, ASSERT_MSG_BUFFER_ALLOC_FAILED);
48 
49 	output = malloc(length * sizeof(q31_t));
50 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
51 
52 	/* Initialise contexts */
53 	mat_in1.pData = tmp1;
54 	mat_in2.pData = tmp2;
55 	mat_out.pData = output;
56 
57 	/* Iterate matrices */
58 	for (index = 0; index < NUM_MATRICES; index++) {
59 		rows = *dims++;
60 		columns = *dims++;
61 
62 		/* Initialise matrix dimensions */
63 		mat_in1.numRows = mat_in2.numRows = mat_out.numRows = rows;
64 		mat_in1.numCols = mat_in2.numCols = mat_out.numCols = columns;
65 
66 		/* Load matrix data */
67 		memcpy(mat_in1.pData, in_com1, rows * columns * sizeof(q31_t));
68 		memcpy(mat_in2.pData, in_com2, rows * columns * sizeof(q31_t));
69 
70 		/* Run test function */
71 		switch (op) {
72 		case OP2_ADD:
73 			status = arm_mat_add_q31(&mat_in1, &mat_in2,
74 						 &mat_out);
75 			break;
76 		case OP2_SUB:
77 			status = arm_mat_sub_q31(&mat_in1, &mat_in2,
78 						 &mat_out);
79 			break;
80 		default:
81 			zassert_unreachable("invalid operation");
82 		}
83 
84 		/* Validate status */
85 		zassert_equal(status, ARM_MATH_SUCCESS,
86 			      ASSERT_MSG_INCORRECT_COMP_RESULT);
87 
88 		/* Increment output pointer */
89 		mat_out.pData += (rows * columns);
90 	}
91 
92 	/* Validate output */
93 	zassert_true(
94 		test_snr_error_q31(length, output, ref, SNR_ERROR_THRESH),
95 		ASSERT_MSG_SNR_LIMIT_EXCEED);
96 
97 	zassert_true(
98 		test_near_equal_q31(length, output, ref, ABS_ERROR_THRESH_Q31),
99 		ASSERT_MSG_ABS_ERROR_LIMIT_EXCEED);
100 
101 	/* Free buffers */
102 	free(tmp1);
103 	free(tmp2);
104 	free(output);
105 }
106 
107 DEFINE_TEST_VARIANT3(matrix_unary_q31,
108 	op2, arm_mat_add_q31, OP2_ADD,
109 	ref_add, ARRAY_SIZE(ref_add));
110 DEFINE_TEST_VARIANT3(matrix_unary_q31,
111 	op2, arm_mat_sub_q31, OP2_SUB,
112 	ref_sub, ARRAY_SIZE(ref_sub));
113 
test_op1(int op,const q31_t * ref,size_t length,bool transpose)114 static void test_op1(int op, const q31_t *ref, size_t length, bool transpose)
115 {
116 	size_t index;
117 	uint16_t *dims = (uint16_t *)in_dims;
118 	q31_t *tmp1, *output;
119 	uint16_t rows, columns;
120 	arm_status status;
121 
122 	arm_matrix_instance_q31 mat_in1;
123 	arm_matrix_instance_q31 mat_out;
124 
125 	/* Allocate buffers */
126 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(q31_t));
127 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
128 
129 	output = malloc(length * sizeof(q31_t));
130 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
131 
132 	/* Initialise contexts */
133 	mat_in1.pData = tmp1;
134 	mat_out.pData = output;
135 
136 	/* Iterate matrices */
137 	for (index = 0; index < NUM_MATRICES; index++) {
138 		rows = *dims++;
139 		columns = *dims++;
140 
141 		/* Initialise matrix dimensions */
142 		mat_in1.numRows = rows;
143 		mat_in1.numCols = columns;
144 		mat_out.numRows = transpose ? columns : rows;
145 		mat_out.numCols = transpose ? rows : columns;
146 
147 		/* Load matrix data */
148 		memcpy(mat_in1.pData, in_com1, rows * columns * sizeof(q31_t));
149 
150 		/* Run test function */
151 		switch (op) {
152 		case OP1_SCALE:
153 			status = arm_mat_scale_q31(&mat_in1, 0x40000000, 0,
154 						   &mat_out);
155 			break;
156 		case OP1_TRANS:
157 			status = arm_mat_trans_q31(&mat_in1, &mat_out);
158 			break;
159 		default:
160 			zassert_unreachable("invalid operation");
161 		}
162 
163 		/* Validate status */
164 		zassert_equal(status, ARM_MATH_SUCCESS,
165 			      ASSERT_MSG_INCORRECT_COMP_RESULT);
166 
167 		/* Increment output pointer */
168 		mat_out.pData += (rows * columns);
169 	}
170 
171 	/* Validate output */
172 	zassert_true(
173 		test_snr_error_q31(length, output, ref, SNR_ERROR_THRESH),
174 		ASSERT_MSG_SNR_LIMIT_EXCEED);
175 
176 	zassert_true(
177 		test_near_equal_q31(length, output, ref, ABS_ERROR_THRESH_Q31),
178 		ASSERT_MSG_ABS_ERROR_LIMIT_EXCEED);
179 
180 	/* Free buffers */
181 	free(tmp1);
182 	free(output);
183 }
184 
185 DEFINE_TEST_VARIANT4(matrix_unary_q31,
186 	op1, arm_mat_scale_q31, OP1_SCALE,
187 	ref_scale, ARRAY_SIZE(ref_scale), false);
188 DEFINE_TEST_VARIANT4(matrix_unary_q31,
189 	op1, arm_mat_trans_q31, OP1_TRANS,
190 	ref_trans, ARRAY_SIZE(ref_trans), true);
191 
test_op2v(int op,const q31_t * ref,size_t length)192 static void test_op2v(int op, const q31_t *ref, size_t length)
193 {
194 	size_t index;
195 	const uint16_t *dims = in_dims;
196 	q31_t *tmp1, *vec, *output_buf, *output;
197 	uint16_t rows, internal;
198 
199 	arm_matrix_instance_q31 mat_in1;
200 
201 	/* Allocate buffers */
202 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(q31_t));
203 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
204 
205 	vec = malloc(2 * MAX_MATRIX_DIM * sizeof(q31_t));
206 	zassert_not_null(vec, ASSERT_MSG_BUFFER_ALLOC_FAILED);
207 
208 	output_buf = malloc(length * sizeof(q31_t));
209 	zassert_not_null(output_buf, ASSERT_MSG_BUFFER_ALLOC_FAILED);
210 
211 	/* Initialise contexts */
212 	mat_in1.pData = tmp1;
213 	output = output_buf;
214 
215 	/* Iterate matrices */
216 	for (index = 0; index < NUM_MATRICES; index++) {
217 		rows = *dims++;
218 		internal = *dims++;
219 
220 		/* Initialise matrix dimensions */
221 		mat_in1.numRows = rows;
222 		mat_in1.numCols = internal;
223 
224 		/* Load matrix data */
225 		memcpy(mat_in1.pData, in_com1,
226 		       2 * rows * internal * sizeof(q31_t));
227 		memcpy(vec, in_vec1, 2 * internal * sizeof(q31_t));
228 
229 		/* Run test function */
230 		switch (op) {
231 		case OP2V_VEC_MULT:
232 			arm_mat_vec_mult_q31(&mat_in1, vec, output);
233 			break;
234 		default:
235 			zassert_unreachable("invalid operation");
236 		}
237 
238 		/* Increment output pointer */
239 		output += rows;
240 	}
241 
242 	/* Validate output */
243 	zassert_true(
244 		test_snr_error_q31(length, output_buf, ref, SNR_ERROR_THRESH),
245 		ASSERT_MSG_SNR_LIMIT_EXCEED);
246 
247 	zassert_true(
248 		test_near_equal_q31(length, output_buf, ref, ABS_ERROR_THRESH_Q31),
249 		ASSERT_MSG_ABS_ERROR_LIMIT_EXCEED);
250 
251 	/* Free buffers */
252 	free(tmp1);
253 	free(vec);
254 	free(output_buf);
255 }
256 
257 DEFINE_TEST_VARIANT3(matrix_unary_q31,
258 	op2v, arm_mat_vec_mult_q31, OP2V_VEC_MULT,
259 	ref_vec_mult, ARRAY_SIZE(ref_vec_mult));
260 
test_op1c(int op,const q31_t * ref,size_t length,bool transpose)261 static void test_op1c(int op, const q31_t *ref, size_t length, bool transpose)
262 {
263 	size_t index;
264 	const uint16_t *dims = in_dims;
265 	q31_t *tmp1, *output;
266 	uint16_t rows, columns;
267 	arm_status status;
268 
269 	arm_matrix_instance_q31 mat_in1;
270 	arm_matrix_instance_q31 mat_out;
271 
272 	/* Allocate buffers */
273 	tmp1 = malloc(2 * MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(q31_t));
274 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
275 
276 	output = malloc(2 * length * sizeof(q31_t));
277 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
278 
279 	/* Initialise contexts */
280 	mat_in1.pData = tmp1;
281 	mat_out.pData = output;
282 
283 	/* Iterate matrices */
284 	for (index = 0; index < NUM_MATRICES; index++) {
285 		rows = *dims++;
286 		columns = *dims++;
287 
288 		/* Initialise matrix dimensions */
289 		mat_in1.numRows = rows;
290 		mat_in1.numCols = columns;
291 		mat_out.numRows = transpose ? columns : rows;
292 		mat_out.numCols = transpose ? rows : columns;
293 
294 		/* Load matrix data */
295 		memcpy(mat_in1.pData,
296 		       in_cmplx1, 2 * rows * columns * sizeof(q31_t));
297 
298 		/* Run test function */
299 		switch (op) {
300 		case OP1C_CMPLX_TRANS:
301 			status = arm_mat_cmplx_trans_q31(&mat_in1, &mat_out);
302 			break;
303 		default:
304 			zassert_unreachable("invalid operation");
305 		}
306 
307 		/* Validate status */
308 		zassert_equal(status, ARM_MATH_SUCCESS,
309 			      ASSERT_MSG_INCORRECT_COMP_RESULT);
310 
311 		/* Increment output pointer */
312 		mat_out.pData += 2 * (rows * columns);
313 	}
314 
315 	/* Validate output */
316 	zassert_true(
317 		test_snr_error_q31(2 * length, output, ref, SNR_ERROR_THRESH),
318 		ASSERT_MSG_SNR_LIMIT_EXCEED);
319 
320 	zassert_true(
321 		test_near_equal_q31(2 * length, output, ref, ABS_ERROR_THRESH_Q31),
322 		ASSERT_MSG_ABS_ERROR_LIMIT_EXCEED);
323 
324 	/* Free buffers */
325 	free(tmp1);
326 	free(output);
327 }
328 
329 DEFINE_TEST_VARIANT4(matrix_unary_q31,
330 	op1c, arm_mat_cmplx_trans_q31, OP1C_CMPLX_TRANS,
331 	ref_cmplx_trans, ARRAY_SIZE(ref_cmplx_trans) / 2, true);
332 
333 ZTEST_SUITE(matrix_unary_q31, NULL, NULL, NULL, NULL, NULL);
334