1 /* ----------------------------------------------------------------------
2 * Project: CMSIS DSP Library
3 * Title: arm_mat_inverse_f16.c
4 * Description: Floating-point matrix inverse
5 *
6 * $Date: 23 April 2021
7 * $Revision: V1.9.0
8 *
9 * Target Processor: Cortex-M and Cortex-A cores
10 * -------------------------------------------------------------------- */
11 /*
12 * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13 *
14 * SPDX-License-Identifier: Apache-2.0
15 *
16 * Licensed under the Apache License, Version 2.0 (the License); you may
17 * not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
19 *
20 * www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28
29 #include "dsp/matrix_functions_f16.h"
30 #include "dsp/matrix_utils.h"
31
32 #if defined(ARM_FLOAT16_SUPPORTED)
33
34
35 /**
36 @ingroup groupMatrix
37 */
38
39
40 /**
41 @addtogroup MatrixInv
42 @{
43 */
44
45 /**
46 @brief Floating-point matrix inverse.
47 @param[in] pSrc points to input matrix structure. The source matrix is modified by the function.
48 @param[out] pDst points to output matrix structure
49 @return execution status
50 - \ref ARM_MATH_SUCCESS : Operation successful
51 - \ref ARM_MATH_SIZE_MISMATCH : Matrix size check failed
52 - \ref ARM_MATH_SINGULAR : Input matrix is found to be singular (non-invertible)
53 */
arm_mat_inverse_f16(const arm_matrix_instance_f16 * pSrc,arm_matrix_instance_f16 * pDst)54 arm_status arm_mat_inverse_f16(
55 const arm_matrix_instance_f16 * pSrc,
56 arm_matrix_instance_f16 * pDst)
57 {
58 float16_t *pIn = pSrc->pData; /* input data matrix pointer */
59 float16_t *pOut = pDst->pData; /* output data matrix pointer */
60
61 float16_t *pTmp;
62 uint32_t numRows = pSrc->numRows; /* Number of rows in the matrix */
63 uint32_t numCols = pSrc->numCols; /* Number of Cols in the matrix */
64
65
66 float16_t pivot = 0.0f16, newPivot=0.0f16; /* Temporary input values */
67 uint32_t selectedRow,pivotRow,i, rowNb, rowCnt, flag = 0U, j,column; /* loop counters */
68 arm_status status; /* status of matrix inverse */
69
70 #ifdef ARM_MATH_MATRIX_CHECK
71
72 /* Check for matrix mismatch condition */
73 if ((pSrc->numRows != pSrc->numCols) ||
74 (pDst->numRows != pDst->numCols) ||
75 (pSrc->numRows != pDst->numRows) )
76 {
77 /* Set status as ARM_MATH_SIZE_MISMATCH */
78 status = ARM_MATH_SIZE_MISMATCH;
79 }
80 else
81
82 #endif /* #ifdef ARM_MATH_MATRIX_CHECK */
83
84 {
85 /*--------------------------------------------------------------------------------------------------------------
86 * Matrix Inverse can be solved using elementary row operations.
87 *
88 * Gauss-Jordan Method:
89 *
90 * 1. First combine the identity matrix and the input matrix separated by a bar to form an
91 * augmented matrix as follows:
92 * _ _ _ _
93 * | a11 a12 | 1 0 | | X11 X12 |
94 * | | | = | |
95 * |_ a21 a22 | 0 1 _| |_ X21 X21 _|
96 *
97 * 2. In our implementation, pDst Matrix is used as identity matrix.
98 *
99 * 3. Begin with the first row. Let i = 1.
100 *
101 * 4. Check to see if the pivot for row i is zero.
102 * The pivot is the element of the main diagonal that is on the current row.
103 * For instance, if working with row i, then the pivot element is aii.
104 * If the pivot is zero, exchange that row with a row below it that does not
105 * contain a zero in column i. If this is not possible, then an inverse
106 * to that matrix does not exist.
107 *
108 * 5. Divide every element of row i by the pivot.
109 *
110 * 6. For every row below and row i, replace that row with the sum of that row and
111 * a multiple of row i so that each new element in column i below row i is zero.
112 *
113 * 7. Move to the next row and column and repeat steps 2 through 5 until you have zeros
114 * for every element below and above the main diagonal.
115 *
116 * 8. Now an identical matrix is formed to the left of the bar(input matrix, pSrc).
117 * Therefore, the matrix to the right of the bar is our solution(pDst matrix, pDst).
118 *----------------------------------------------------------------------------------------------------------------*/
119
120 /* Working pointer for destination matrix */
121 pTmp = pOut;
122
123 /* Loop over the number of rows */
124 rowCnt = numRows;
125
126 /* Making the destination matrix as identity matrix */
127 while (rowCnt > 0U)
128 {
129 /* Writing all zeroes in lower triangle of the destination matrix */
130 j = numRows - rowCnt;
131 while (j > 0U)
132 {
133 *pTmp++ = 0.0f16;
134 j--;
135 }
136
137 /* Writing all ones in the diagonal of the destination matrix */
138 *pTmp++ = 1.0f16;
139
140 /* Writing all zeroes in upper triangle of the destination matrix */
141 j = rowCnt - 1U;
142 while (j > 0U)
143 {
144 *pTmp++ = 0.0f16;
145 j--;
146 }
147
148 /* Decrement loop counter */
149 rowCnt--;
150 }
151
152 /* Loop over the number of columns of the input matrix.
153 All the elements in each column are processed by the row operations */
154
155 /* Index modifier to navigate through the columns */
156 for(column = 0U; column < numCols; column++)
157 {
158 /* Check if the pivot element is zero..
159 * If it is zero then interchange the row with non zero row below.
160 * If there is no non zero element to replace in the rows below,
161 * then the matrix is Singular. */
162
163 pivotRow = column;
164
165 /* Temporary variable to hold the pivot value */
166 pTmp = ELEM(pSrc,column,column) ;
167 pivot = *pTmp;
168 selectedRow = column;
169
170
171 /* Loop over the number rows present below */
172
173 for (rowNb = column+1; rowNb < numRows; rowNb++)
174 {
175 /* Update the input and destination pointers */
176 pTmp = ELEM(pSrc,rowNb,column);
177 newPivot = *pTmp;
178 if (fabsf((float32_t)newPivot) > fabsf((float32_t)pivot))
179 {
180 selectedRow = rowNb;
181 pivot = newPivot;
182 }
183
184 }
185
186 /* Check if there is a non zero pivot element to
187 * replace in the rows below */
188 if (((_Float16)pivot != 0.0f16) && (selectedRow != column))
189 {
190 /* Loop over number of columns
191 * to the right of the pilot element */
192
193 SWAP_ROWS_F16(pSrc,column, pivotRow,selectedRow);
194 SWAP_ROWS_F16(pDst,0, pivotRow,selectedRow);
195
196
197 /* Flag to indicate whether exchange is done or not */
198 flag = 1U;
199
200 }
201
202
203 /* Update the status if the matrix is singular */
204 if ((flag != 1U) && ((_Float16)pivot == 0.0f16))
205 {
206 return ARM_MATH_SINGULAR;
207 }
208
209
210 /* Pivot element of the row */
211 pivot = 1.0f16 / (_Float16)pivot;
212
213 SCALE_ROW_F16(pSrc,column,pivot,pivotRow);
214 SCALE_ROW_F16(pDst,0,pivot,pivotRow);
215
216
217 /* Replace the rows with the sum of that row and a multiple of row i
218 * so that each new element in column i above row i is zero.*/
219
220 rowNb = 0;
221 for (;rowNb < pivotRow; rowNb++)
222 {
223 pTmp = ELEM(pSrc,rowNb,column) ;
224 pivot = *pTmp;
225
226 MAS_ROW_F16(column,pSrc,rowNb,pivot,pSrc,pivotRow);
227 MAS_ROW_F16(0 ,pDst,rowNb,pivot,pDst,pivotRow);
228
229
230 }
231
232 for (rowNb = pivotRow + 1; rowNb < numRows; rowNb++)
233 {
234 pTmp = ELEM(pSrc,rowNb,column) ;
235 pivot = *pTmp;
236
237 MAS_ROW_F16(column,pSrc,rowNb,pivot,pSrc,pivotRow);
238 MAS_ROW_F16(0 ,pDst,rowNb,pivot,pDst,pivotRow);
239
240 }
241
242 }
243
244 /* Set status as ARM_MATH_SUCCESS */
245 status = ARM_MATH_SUCCESS;
246
247 if ((flag != 1U) && ((_Float16)pivot == 0.0f16))
248 {
249 pIn = pSrc->pData;
250 for (i = 0; i < numRows * numCols; i++)
251 {
252 if ((_Float16)pIn[i] != 0.0f16)
253 break;
254 }
255
256 if (i == numRows * numCols)
257 status = ARM_MATH_SINGULAR;
258 }
259 }
260
261 /* Return to application */
262 return (status);
263 }
264 /**
265 @} end of MatrixInv group
266 */
267
268 #endif /* #if defined(ARM_FLOAT16_SUPPORTED) */
269
270