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_f64.pat"
15 
16 #define SNR_ERROR_THRESH	((float64_t)120)
17 #define REL_ERROR_THRESH	(1.0e-6)
18 #define ABS_ERROR_THRESH	(1.0e-5)
19 
20 #define SNR_ERROR_THRESH_CHOL	((float64_t)270)
21 #define REL_ERROR_THRESH_CHOL	(1.0e-9)
22 #define ABS_ERROR_THRESH_CHOL	(1.0e-9)
23 
24 #define NUM_MATRICES		(ARRAY_SIZE(in_dims) / 2)
25 #define MAX_MATRIX_DIM		(40)
26 
27 #define OP2_SUB			(1)
28 #define OP1_TRANS		(1)
29 
test_op2(int op,const uint64_t * ref,size_t length)30 static void test_op2(int op, const uint64_t *ref, size_t length)
31 {
32 	size_t index;
33 	uint16_t *dims = (uint16_t *)in_dims;
34 	float64_t *tmp1, *tmp2, *output;
35 	uint16_t rows, columns;
36 	arm_status status;
37 
38 	arm_matrix_instance_f64 mat_in1;
39 	arm_matrix_instance_f64 mat_in2;
40 	arm_matrix_instance_f64 mat_out;
41 
42 	/* Allocate buffers */
43 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
44 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
45 
46 	tmp2 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
47 	zassert_not_null(tmp2, ASSERT_MSG_BUFFER_ALLOC_FAILED);
48 
49 	output = malloc(length * sizeof(float64_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,
68 		       rows * columns * sizeof(float64_t));
69 
70 		memcpy(mat_in2.pData, in_com2,
71 		       rows * columns * sizeof(float64_t));
72 
73 		/* Run test function */
74 		switch (op) {
75 		case OP2_SUB:
76 			status = arm_mat_sub_f64(&mat_in1, &mat_in2,
77 						 &mat_out);
78 			break;
79 		default:
80 			zassert_unreachable("invalid operation");
81 		}
82 
83 		/* Validate status */
84 		zassert_equal(status, ARM_MATH_SUCCESS,
85 			      ASSERT_MSG_INCORRECT_COMP_RESULT);
86 
87 		/* Increment output pointer */
88 		mat_out.pData += (rows * columns);
89 	}
90 
91 	/* Validate output */
92 	zassert_true(
93 		test_snr_error_f64(length, output, (float64_t *)ref,
94 			SNR_ERROR_THRESH),
95 		ASSERT_MSG_SNR_LIMIT_EXCEED);
96 
97 	zassert_true(
98 		test_close_error_f64(length, output, (float64_t *)ref,
99 			ABS_ERROR_THRESH, REL_ERROR_THRESH),
100 		ASSERT_MSG_ERROR_LIMIT_EXCEED);
101 
102 	/* Free buffers */
103 	free(tmp1);
104 	free(tmp2);
105 	free(output);
106 }
107 
108 DEFINE_TEST_VARIANT3(matrix_unary_f64,
109 	op2, arm_mat_sub_f64, OP2_SUB,
110 	ref_sub, ARRAY_SIZE(ref_sub));
111 
test_op1(int op,const uint64_t * ref,size_t length,bool transpose)112 static void test_op1(int op, const uint64_t *ref, size_t length,
113 	bool transpose)
114 {
115 	size_t index;
116 	uint16_t *dims = (uint16_t *)in_dims;
117 	float64_t *tmp1, *output;
118 	uint16_t rows, columns;
119 	arm_status status;
120 
121 	arm_matrix_instance_f64 mat_in1;
122 	arm_matrix_instance_f64 mat_out;
123 
124 	/* Allocate buffers */
125 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
126 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
127 
128 	output = malloc(length * sizeof(float64_t));
129 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
130 
131 	/* Initialise contexts */
132 	mat_in1.pData = tmp1;
133 	mat_out.pData = output;
134 
135 	/* Iterate matrices */
136 	for (index = 0; index < NUM_MATRICES; index++) {
137 		rows = *dims++;
138 		columns = *dims++;
139 
140 		/* Initialise matrix dimensions */
141 		mat_in1.numRows = rows;
142 		mat_in1.numCols = columns;
143 		mat_out.numRows = transpose ? columns : rows;
144 		mat_out.numCols = transpose ? rows : columns;
145 
146 		/* Load matrix data */
147 		memcpy(mat_in1.pData, in_com1,
148 		       rows * columns * sizeof(float64_t));
149 
150 		/* Run test function */
151 		switch (op) {
152 		case OP1_TRANS:
153 			status = arm_mat_trans_f64(&mat_in1, &mat_out);
154 			break;
155 		default:
156 			zassert_unreachable("invalid operation");
157 		}
158 
159 		/* Validate status */
160 		zassert_equal(status, ARM_MATH_SUCCESS,
161 			      ASSERT_MSG_INCORRECT_COMP_RESULT);
162 
163 		/* Increment output pointer */
164 		mat_out.pData += (rows * columns);
165 	}
166 
167 	/* Validate output */
168 	zassert_true(
169 		test_snr_error_f64(length, output, (float64_t *)ref,
170 			SNR_ERROR_THRESH),
171 		ASSERT_MSG_SNR_LIMIT_EXCEED);
172 
173 	zassert_true(
174 		test_close_error_f64(length, output, (float64_t *)ref,
175 			ABS_ERROR_THRESH, REL_ERROR_THRESH),
176 		ASSERT_MSG_ERROR_LIMIT_EXCEED);
177 
178 	/* Free buffers */
179 	free(tmp1);
180 	free(output);
181 }
182 
183 DEFINE_TEST_VARIANT4(matrix_unary_f64,
184 	op1, arm_mat_trans_f64, OP1_TRANS,
185 	ref_trans, ARRAY_SIZE(ref_trans), true);
186 
ZTEST(matrix_unary_f64,test_arm_mat_inverse_f64)187 ZTEST(matrix_unary_f64, test_arm_mat_inverse_f64)
188 {
189 	size_t index;
190 	size_t length = ARRAY_SIZE(ref_inv);
191 	uint16_t *dims = (uint16_t *)in_inv_dims;
192 	float64_t *input, *tmp1, *output;
193 	arm_status status;
194 	uint16_t rows, columns;
195 
196 	arm_matrix_instance_f64 mat_in1;
197 	arm_matrix_instance_f64 mat_out;
198 
199 	/* Allocate buffers */
200 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
201 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
202 
203 	output = malloc(length * sizeof(float64_t));
204 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
205 
206 	/* Initialise contexts */
207 	input = (float64_t *)in_inv;
208 	mat_in1.pData = tmp1;
209 	mat_out.pData = output;
210 
211 	/* Iterate matrices */
212 	for (index = 0; index < ARRAY_SIZE(in_inv_dims); index++) {
213 		rows = columns = *dims++;
214 
215 		/* Initialise matrix dimensions */
216 		mat_in1.numRows = mat_out.numRows = rows;
217 		mat_in1.numCols = mat_out.numCols = columns;
218 
219 		/* Load matrix data */
220 		memcpy(mat_in1.pData, input,
221 		       rows * columns * sizeof(float64_t));
222 
223 		/* Run test function */
224 		status = arm_mat_inverse_f64(&mat_in1, &mat_out);
225 
226 		zassert_equal(status, ARM_MATH_SUCCESS,
227 			ASSERT_MSG_INCORRECT_COMP_RESULT);
228 
229 		/* Increment pointers */
230 		input += (rows * columns);
231 		mat_out.pData += (rows * columns);
232 	}
233 
234 	/* Validate output */
235 	zassert_true(
236 		test_snr_error_f64(length, output, (float64_t *)ref_inv,
237 			SNR_ERROR_THRESH),
238 		ASSERT_MSG_SNR_LIMIT_EXCEED);
239 
240 	zassert_true(
241 		test_close_error_f64(length, output, (float64_t *)ref_inv,
242 			ABS_ERROR_THRESH, REL_ERROR_THRESH),
243 		ASSERT_MSG_ERROR_LIMIT_EXCEED);
244 
245 	/* Free buffers */
246 	free(tmp1);
247 	free(output);
248 }
249 
ZTEST(matrix_unary_f64,test_arm_mat_cholesky_f64)250 ZTEST(matrix_unary_f64, test_arm_mat_cholesky_f64)
251 {
252 	size_t index;
253 	size_t length = ARRAY_SIZE(ref_cholesky_dpo);
254 	const uint16_t *dims = in_cholesky_dpo_dims;
255 	float64_t *input, *tmp1, *output;
256 	uint16_t rows, columns;
257 	arm_status status;
258 
259 	arm_matrix_instance_f64 mat_in1;
260 	arm_matrix_instance_f64 mat_out;
261 
262 	/* Allocate buffers */
263 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
264 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
265 
266 	output = calloc(length, sizeof(float64_t));
267 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
268 
269 	/* Initialise contexts */
270 	input = (float64_t *)in_cholesky_dpo;
271 	mat_in1.pData = tmp1;
272 	mat_out.pData = output;
273 
274 	/* Iterate matrices */
275 	for (index = 0; index < ARRAY_SIZE(in_cholesky_dpo_dims); index++) {
276 		rows = columns = *dims++;
277 
278 		/* Initialise matrix dimensions */
279 		mat_in1.numRows = mat_out.numRows = rows;
280 		mat_in1.numCols = mat_out.numCols = columns;
281 
282 		/* Load matrix data */
283 		memcpy(mat_in1.pData,
284 		       input, rows * columns * sizeof(float64_t));
285 
286 		/* Run test function */
287 		status = arm_mat_cholesky_f64(&mat_in1, &mat_out);
288 
289 		zassert_equal(status, ARM_MATH_SUCCESS,
290 			ASSERT_MSG_INCORRECT_COMP_RESULT);
291 
292 		/* Increment pointers */
293 		input += (rows * columns);
294 		mat_out.pData += (rows * columns);
295 	}
296 
297 	/* Validate output */
298 	zassert_true(
299 		test_snr_error_f64(length, output, (float64_t *)ref_cholesky_dpo,
300 			SNR_ERROR_THRESH_CHOL),
301 		ASSERT_MSG_SNR_LIMIT_EXCEED);
302 
303 	zassert_true(
304 		test_close_error_f64(length, output, (float64_t *)ref_cholesky_dpo,
305 			ABS_ERROR_THRESH_CHOL, REL_ERROR_THRESH_CHOL),
306 		ASSERT_MSG_ERROR_LIMIT_EXCEED);
307 
308 	/* Free buffers */
309 	free(tmp1);
310 	free(output);
311 }
312 
ZTEST(matrix_unary_f64,test_arm_mat_solve_upper_triangular_f64)313 ZTEST(matrix_unary_f64, test_arm_mat_solve_upper_triangular_f64)
314 {
315 	size_t index;
316 	size_t length = ARRAY_SIZE(ref_uptriangular_dpo);
317 	const uint16_t *dims = in_cholesky_dpo_dims;
318 	float64_t *input1, *input2, *tmp1, *tmp2, *output;
319 	uint16_t rows, columns;
320 	arm_status status;
321 
322 	arm_matrix_instance_f64 mat_in1;
323 	arm_matrix_instance_f64 mat_in2;
324 	arm_matrix_instance_f64 mat_out;
325 
326 	/* Allocate buffers */
327 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
328 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
329 
330 	tmp2 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
331 	zassert_not_null(tmp2, ASSERT_MSG_BUFFER_ALLOC_FAILED);
332 
333 	output = calloc(length, sizeof(float64_t));
334 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
335 
336 	/* Initialise contexts */
337 	input1 = (float64_t *)in_uptriangular_dpo;
338 	input2 = (float64_t *)in_rnda_dpo;
339 	mat_in1.pData = tmp1;
340 	mat_in2.pData = tmp2;
341 	mat_out.pData = output;
342 
343 	/* Iterate matrices */
344 	for (index = 0; index < ARRAY_SIZE(in_cholesky_dpo_dims); index++) {
345 		rows = columns = *dims++;
346 
347 		/* Initialise matrix dimensions */
348 		mat_in1.numRows = mat_in2.numRows = mat_out.numRows = rows;
349 		mat_in1.numCols = mat_in2.numCols = mat_out.numCols = columns;
350 
351 		/* Load matrix data */
352 		memcpy(mat_in1.pData, input1,
353 		       rows * columns * sizeof(float64_t));
354 
355 		memcpy(mat_in2.pData, input2,
356 		       rows * columns * sizeof(float64_t));
357 
358 		/* Run test function */
359 		status = arm_mat_solve_upper_triangular_f64(&mat_in1, &mat_in2,
360 							    &mat_out);
361 
362 		zassert_equal(status, ARM_MATH_SUCCESS,
363 			      ASSERT_MSG_INCORRECT_COMP_RESULT);
364 
365 		/* Increment output pointer */
366 		input1 += (rows * columns);
367 		input2 += (rows * columns);
368 		mat_out.pData += (rows * columns);
369 	}
370 
371 	/* Validate output */
372 	zassert_true(
373 		test_snr_error_f64(length, output,
374 			(float64_t *)ref_uptriangular_dpo,
375 			SNR_ERROR_THRESH),
376 		ASSERT_MSG_SNR_LIMIT_EXCEED);
377 
378 	zassert_true(
379 		test_close_error_f64(length, output,
380 			(float64_t *)ref_uptriangular_dpo,
381 			ABS_ERROR_THRESH, REL_ERROR_THRESH),
382 		ASSERT_MSG_ERROR_LIMIT_EXCEED);
383 
384 	/* Free buffers */
385 	free(tmp1);
386 	free(tmp2);
387 	free(output);
388 }
389 
ZTEST(matrix_unary_f64,test_arm_mat_solve_lower_triangular_f64)390 ZTEST(matrix_unary_f64, test_arm_mat_solve_lower_triangular_f64)
391 {
392 	size_t index;
393 	size_t length = ARRAY_SIZE(ref_lotriangular_dpo);
394 	const uint16_t *dims = in_cholesky_dpo_dims;
395 	float64_t *input1, *input2, *tmp1, *tmp2, *output;
396 	uint16_t rows, columns;
397 	arm_status status;
398 
399 	arm_matrix_instance_f64 mat_in1;
400 	arm_matrix_instance_f64 mat_in2;
401 	arm_matrix_instance_f64 mat_out;
402 
403 	/* Allocate buffers */
404 	tmp1 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
405 	zassert_not_null(tmp1, ASSERT_MSG_BUFFER_ALLOC_FAILED);
406 
407 	tmp2 = malloc(MAX_MATRIX_DIM * MAX_MATRIX_DIM * sizeof(float64_t));
408 	zassert_not_null(tmp2, ASSERT_MSG_BUFFER_ALLOC_FAILED);
409 
410 	output = calloc(length, sizeof(float64_t));
411 	zassert_not_null(output, ASSERT_MSG_BUFFER_ALLOC_FAILED);
412 
413 	/* Initialise contexts */
414 	input1 = (float64_t *)in_lotriangular_dpo;
415 	input2 = (float64_t *)in_rnda_dpo;
416 	mat_in1.pData = tmp1;
417 	mat_in2.pData = tmp2;
418 	mat_out.pData = output;
419 
420 	/* Iterate matrices */
421 	for (index = 0; index < ARRAY_SIZE(in_cholesky_dpo_dims); index++) {
422 		rows = columns = *dims++;
423 
424 		/* Initialise matrix dimensions */
425 		mat_in1.numRows = mat_in2.numRows = mat_out.numRows = rows;
426 		mat_in1.numCols = mat_in2.numCols = mat_out.numCols = columns;
427 
428 		/* Load matrix data */
429 		memcpy(mat_in1.pData, input1,
430 		       rows * columns * sizeof(float64_t));
431 
432 		memcpy(mat_in2.pData, input2,
433 		       rows * columns * sizeof(float64_t));
434 
435 		/* Run test function */
436 		status = arm_mat_solve_lower_triangular_f64(&mat_in1, &mat_in2,
437 							    &mat_out);
438 
439 		zassert_equal(status, ARM_MATH_SUCCESS,
440 			      ASSERT_MSG_INCORRECT_COMP_RESULT);
441 
442 		/* Increment output pointer */
443 		input1 += (rows * columns);
444 		input2 += (rows * columns);
445 		mat_out.pData += (rows * columns);
446 	}
447 
448 	/* Validate output */
449 	zassert_true(
450 		test_snr_error_f64(length, output,
451 			(float64_t *)ref_lotriangular_dpo,
452 			SNR_ERROR_THRESH),
453 		ASSERT_MSG_SNR_LIMIT_EXCEED);
454 
455 	zassert_true(
456 		test_close_error_f64(length, output,
457 			(float64_t *)ref_lotriangular_dpo,
458 			ABS_ERROR_THRESH, REL_ERROR_THRESH),
459 		ASSERT_MSG_ERROR_LIMIT_EXCEED);
460 
461 	/* Free buffers */
462 	free(tmp1);
463 	free(tmp2);
464 	free(output);
465 }
466 
467 /*
468  * NOTE: arm_mat_ldlt_f64 tests are not implemented for now because they
469  *       require on-device test pattern generation which defeats the purpose
470  *       of on-device testing. Add these tests when the upstream testsuite is
471  *       updated to use pre-generated test patterns.
472  */
473 
474 ZTEST_SUITE(matrix_unary_f64, NULL, NULL, NULL, NULL, NULL);
475