arm_mat_inverse_f64.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. /* ----------------------------------------------------------------------
  2. * Project: CMSIS DSP Library
  3. * Title: arm_mat_inverse_f64.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. #include "dsp/matrix_functions.h"
  29. /**
  30. @ingroup groupMatrix
  31. */
  32. /**
  33. @addtogroup MatrixInv
  34. @{
  35. */
  36. /**
  37. @brief Floating-point (64 bit) matrix inverse.
  38. @param[in] pSrc points to input matrix structure. The source matrix is modified by the function.
  39. @param[out] pDst points to output matrix structure
  40. @return execution status
  41. - \ref ARM_MATH_SUCCESS : Operation successful
  42. - \ref ARM_MATH_SIZE_MISMATCH : Matrix size check failed
  43. - \ref ARM_MATH_SINGULAR : Input matrix is found to be singular (non-invertible)
  44. */
  45. arm_status arm_mat_inverse_f64(
  46. const arm_matrix_instance_f64 * pSrc,
  47. arm_matrix_instance_f64 * pDst)
  48. {
  49. float64_t *pIn = pSrc->pData; /* input data matrix pointer */
  50. float64_t *pOut = pDst->pData; /* output data matrix pointer */
  51. float64_t *pInT1, *pInT2; /* Temporary input data matrix pointer */
  52. float64_t *pOutT1, *pOutT2; /* Temporary output data matrix pointer */
  53. float64_t *pPivotRowIn, *pPRT_in, *pPivotRowDst, *pPRT_pDst; /* Temporary input and output data matrix pointer */
  54. uint32_t numRows = pSrc->numRows; /* Number of rows in the matrix */
  55. uint32_t numCols = pSrc->numCols; /* Number of Cols in the matrix */
  56. #if defined (ARM_MATH_DSP)
  57. float64_t Xchg, in = 0.0, in1; /* Temporary input values */
  58. uint32_t i, rowCnt, flag = 0U, j, loopCnt, k,l; /* loop counters */
  59. arm_status status; /* status of matrix inverse */
  60. #ifdef ARM_MATH_MATRIX_CHECK
  61. /* Check for matrix mismatch condition */
  62. if ((pSrc->numRows != pSrc->numCols) ||
  63. (pDst->numRows != pDst->numCols) ||
  64. (pSrc->numRows != pDst->numRows) )
  65. {
  66. /* Set status as ARM_MATH_SIZE_MISMATCH */
  67. status = ARM_MATH_SIZE_MISMATCH;
  68. }
  69. else
  70. #endif /* #ifdef ARM_MATH_MATRIX_CHECK */
  71. {
  72. /*--------------------------------------------------------------------------------------------------------------
  73. * Matrix Inverse can be solved using elementary row operations.
  74. *
  75. * Gauss-Jordan Method:
  76. *
  77. * 1. First combine the identity matrix and the input matrix separated by a bar to form an
  78. * augmented matrix as follows:
  79. * _ _ _ _
  80. * | a11 a12 | 1 0 | | X11 X12 |
  81. * | | | = | |
  82. * |_ a21 a22 | 0 1 _| |_ X21 X21 _|
  83. *
  84. * 2. In our implementation, pDst Matrix is used as identity matrix.
  85. *
  86. * 3. Begin with the first row. Let i = 1.
  87. *
  88. * 4. Check to see if the pivot for row i is zero.
  89. * The pivot is the element of the main diagonal that is on the current row.
  90. * For instance, if working with row i, then the pivot element is aii.
  91. * If the pivot is zero, exchange that row with a row below it that does not
  92. * contain a zero in column i. If this is not possible, then an inverse
  93. * to that matrix does not exist.
  94. *
  95. * 5. Divide every element of row i by the pivot.
  96. *
  97. * 6. For every row below and row i, replace that row with the sum of that row and
  98. * a multiple of row i so that each new element in column i below row i is zero.
  99. *
  100. * 7. Move to the next row and column and repeat steps 2 through 5 until you have zeros
  101. * for every element below and above the main diagonal.
  102. *
  103. * 8. Now an identical matrix is formed to the left of the bar(input matrix, pSrc).
  104. * Therefore, the matrix to the right of the bar is our solution(pDst matrix, pDst).
  105. *----------------------------------------------------------------------------------------------------------------*/
  106. /* Working pointer for destination matrix */
  107. pOutT1 = pOut;
  108. /* Loop over the number of rows */
  109. rowCnt = numRows;
  110. /* Making the destination matrix as identity matrix */
  111. while (rowCnt > 0U)
  112. {
  113. /* Writing all zeroes in lower triangle of the destination matrix */
  114. j = numRows - rowCnt;
  115. while (j > 0U)
  116. {
  117. *pOutT1++ = 0.0;
  118. j--;
  119. }
  120. /* Writing all ones in the diagonal of the destination matrix */
  121. *pOutT1++ = 1.0;
  122. /* Writing all zeroes in upper triangle of the destination matrix */
  123. j = rowCnt - 1U;
  124. while (j > 0U)
  125. {
  126. *pOutT1++ = 0.0;
  127. j--;
  128. }
  129. /* Decrement loop counter */
  130. rowCnt--;
  131. }
  132. /* Loop over the number of columns of the input matrix.
  133. All the elements in each column are processed by the row operations */
  134. loopCnt = numCols;
  135. /* Index modifier to navigate through the columns */
  136. l = 0U;
  137. while (loopCnt > 0U)
  138. {
  139. /* Check if the pivot element is zero..
  140. * If it is zero then interchange the row with non zero row below.
  141. * If there is no non zero element to replace in the rows below,
  142. * then the matrix is Singular. */
  143. /* Working pointer for the input matrix that points
  144. * to the pivot element of the particular row */
  145. pInT1 = pIn + (l * numCols);
  146. /* Working pointer for the destination matrix that points
  147. * to the pivot element of the particular row */
  148. pOutT1 = pOut + (l * numCols);
  149. /* Temporary variable to hold the pivot value */
  150. in = *pInT1;
  151. /* Check if the pivot element is zero */
  152. if (*pInT1 == 0.0)
  153. {
  154. /* Loop over the number rows present below */
  155. for (i = 1U; i < numRows - l; i++)
  156. {
  157. /* Update the input and destination pointers */
  158. pInT2 = pInT1 + (numCols * i);
  159. pOutT2 = pOutT1 + (numCols * i);
  160. /* Check if there is a non zero pivot element to
  161. * replace in the rows below */
  162. if (*pInT2 != 0.0)
  163. {
  164. /* Loop over number of columns
  165. * to the right of the pilot element */
  166. j = numCols - l;
  167. while (j > 0U)
  168. {
  169. /* Exchange the row elements of the input matrix */
  170. Xchg = *pInT2;
  171. *pInT2++ = *pInT1;
  172. *pInT1++ = Xchg;
  173. /* Decrement the loop counter */
  174. j--;
  175. }
  176. /* Loop over number of columns of the destination matrix */
  177. j = numCols;
  178. while (j > 0U)
  179. {
  180. /* Exchange the row elements of the destination matrix */
  181. Xchg = *pOutT2;
  182. *pOutT2++ = *pOutT1;
  183. *pOutT1++ = Xchg;
  184. /* Decrement loop counter */
  185. j--;
  186. }
  187. /* Flag to indicate whether exchange is done or not */
  188. flag = 1U;
  189. /* Break after exchange is done */
  190. break;
  191. }
  192. /* Decrement loop counter */
  193. }
  194. }
  195. /* Update the status if the matrix is singular */
  196. if ((flag != 1U) && (in == 0.0))
  197. {
  198. return ARM_MATH_SINGULAR;
  199. }
  200. /* Points to the pivot row of input and destination matrices */
  201. pPivotRowIn = pIn + (l * numCols);
  202. pPivotRowDst = pOut + (l * numCols);
  203. /* Temporary pointers to the pivot row pointers */
  204. pInT1 = pPivotRowIn;
  205. pInT2 = pPivotRowDst;
  206. /* Pivot element of the row */
  207. in = *pPivotRowIn;
  208. /* Loop over number of columns
  209. * to the right of the pilot element */
  210. j = (numCols - l);
  211. while (j > 0U)
  212. {
  213. /* Divide each element of the row of the input matrix
  214. * by the pivot element */
  215. in1 = *pInT1;
  216. *pInT1++ = in1 / in;
  217. /* Decrement the loop counter */
  218. j--;
  219. }
  220. /* Loop over number of columns of the destination matrix */
  221. j = numCols;
  222. while (j > 0U)
  223. {
  224. /* Divide each element of the row of the destination matrix
  225. * by the pivot element */
  226. in1 = *pInT2;
  227. *pInT2++ = in1 / in;
  228. /* Decrement the loop counter */
  229. j--;
  230. }
  231. /* Replace the rows with the sum of that row and a multiple of row i
  232. * so that each new element in column i above row i is zero.*/
  233. /* Temporary pointers for input and destination matrices */
  234. pInT1 = pIn;
  235. pInT2 = pOut;
  236. /* index used to check for pivot element */
  237. i = 0U;
  238. /* Loop over number of rows */
  239. /* to be replaced by the sum of that row and a multiple of row i */
  240. k = numRows;
  241. while (k > 0U)
  242. {
  243. /* Check for the pivot element */
  244. if (i == l)
  245. {
  246. /* If the processing element is the pivot element,
  247. only the columns to the right are to be processed */
  248. pInT1 += numCols - l;
  249. pInT2 += numCols;
  250. }
  251. else
  252. {
  253. /* Element of the reference row */
  254. in = *pInT1;
  255. /* Working pointers for input and destination pivot rows */
  256. pPRT_in = pPivotRowIn;
  257. pPRT_pDst = pPivotRowDst;
  258. /* Loop over the number of columns to the right of the pivot element,
  259. to replace the elements in the input matrix */
  260. j = (numCols - l);
  261. while (j > 0U)
  262. {
  263. /* Replace the element by the sum of that row
  264. and a multiple of the reference row */
  265. in1 = *pInT1;
  266. *pInT1++ = in1 - (in * *pPRT_in++);
  267. /* Decrement the loop counter */
  268. j--;
  269. }
  270. /* Loop over the number of columns to
  271. replace the elements in the destination matrix */
  272. j = numCols;
  273. while (j > 0U)
  274. {
  275. /* Replace the element by the sum of that row
  276. and a multiple of the reference row */
  277. in1 = *pInT2;
  278. *pInT2++ = in1 - (in * *pPRT_pDst++);
  279. /* Decrement loop counter */
  280. j--;
  281. }
  282. }
  283. /* Increment temporary input pointer */
  284. pInT1 = pInT1 + l;
  285. /* Decrement loop counter */
  286. k--;
  287. /* Increment pivot index */
  288. i++;
  289. }
  290. /* Increment the input pointer */
  291. pIn++;
  292. /* Decrement the loop counter */
  293. loopCnt--;
  294. /* Increment the index modifier */
  295. l++;
  296. }
  297. #else
  298. float64_t Xchg, in = 0.0; /* Temporary input values */
  299. uint32_t i, rowCnt, flag = 0U, j, loopCnt, l; /* loop counters */
  300. arm_status status; /* status of matrix inverse */
  301. #ifdef ARM_MATH_MATRIX_CHECK
  302. /* Check for matrix mismatch condition */
  303. if ((pSrc->numRows != pSrc->numCols) ||
  304. (pDst->numRows != pDst->numCols) ||
  305. (pSrc->numRows != pDst->numRows) )
  306. {
  307. /* Set status as ARM_MATH_SIZE_MISMATCH */
  308. status = ARM_MATH_SIZE_MISMATCH;
  309. }
  310. else
  311. #endif /* #ifdef ARM_MATH_MATRIX_CHECK */
  312. {
  313. /*--------------------------------------------------------------------------------------------------------------
  314. * Matrix Inverse can be solved using elementary row operations.
  315. *
  316. * Gauss-Jordan Method:
  317. *
  318. * 1. First combine the identity matrix and the input matrix separated by a bar to form an
  319. * augmented matrix as follows:
  320. * _ _ _ _ _ _ _ _
  321. * | | a11 a12 | | | 1 0 | | | X11 X12 |
  322. * | | | | | | | = | |
  323. * |_ |_ a21 a22 _| | |_0 1 _| _| |_ X21 X21 _|
  324. *
  325. * 2. In our implementation, pDst Matrix is used as identity matrix.
  326. *
  327. * 3. Begin with the first row. Let i = 1.
  328. *
  329. * 4. Check to see if the pivot for row i is zero.
  330. * The pivot is the element of the main diagonal that is on the current row.
  331. * For instance, if working with row i, then the pivot element is aii.
  332. * If the pivot is zero, exchange that row with a row below it that does not
  333. * contain a zero in column i. If this is not possible, then an inverse
  334. * to that matrix does not exist.
  335. *
  336. * 5. Divide every element of row i by the pivot.
  337. *
  338. * 6. For every row below and row i, replace that row with the sum of that row and
  339. * a multiple of row i so that each new element in column i below row i is zero.
  340. *
  341. * 7. Move to the next row and column and repeat steps 2 through 5 until you have zeros
  342. * for every element below and above the main diagonal.
  343. *
  344. * 8. Now an identical matrix is formed to the left of the bar(input matrix, src).
  345. * Therefore, the matrix to the right of the bar is our solution(dst matrix, dst).
  346. *----------------------------------------------------------------------------------------------------------------*/
  347. /* Working pointer for destination matrix */
  348. pOutT1 = pOut;
  349. /* Loop over the number of rows */
  350. rowCnt = numRows;
  351. /* Making the destination matrix as identity matrix */
  352. while (rowCnt > 0U)
  353. {
  354. /* Writing all zeroes in lower triangle of the destination matrix */
  355. j = numRows - rowCnt;
  356. while (j > 0U)
  357. {
  358. *pOutT1++ = 0.0;
  359. j--;
  360. }
  361. /* Writing all ones in the diagonal of the destination matrix */
  362. *pOutT1++ = 1.0;
  363. /* Writing all zeroes in upper triangle of the destination matrix */
  364. j = rowCnt - 1U;
  365. while (j > 0U)
  366. {
  367. *pOutT1++ = 0.0;
  368. j--;
  369. }
  370. /* Decrement loop counter */
  371. rowCnt--;
  372. }
  373. /* Loop over the number of columns of the input matrix.
  374. All the elements in each column are processed by the row operations */
  375. loopCnt = numCols;
  376. /* Index modifier to navigate through the columns */
  377. l = 0U;
  378. while (loopCnt > 0U)
  379. {
  380. /* Check if the pivot element is zero..
  381. * If it is zero then interchange the row with non zero row below.
  382. * If there is no non zero element to replace in the rows below,
  383. * then the matrix is Singular. */
  384. /* Working pointer for the input matrix that points
  385. * to the pivot element of the particular row */
  386. pInT1 = pIn + (l * numCols);
  387. /* Working pointer for the destination matrix that points
  388. * to the pivot element of the particular row */
  389. pOutT1 = pOut + (l * numCols);
  390. /* Temporary variable to hold the pivot value */
  391. in = *pInT1;
  392. /* Check if the pivot element is zero */
  393. if (*pInT1 == 0.0)
  394. {
  395. /* Loop over the number rows present below */
  396. for (i = 1U; i < numRows-l; i++)
  397. {
  398. /* Update the input and destination pointers */
  399. pInT2 = pInT1 + (numCols * i);
  400. pOutT2 = pOutT1 + (numCols * i);
  401. /* Check if there is a non zero pivot element to
  402. * replace in the rows below */
  403. if (*pInT2 != 0.0)
  404. {
  405. /* Loop over number of columns
  406. * to the right of the pilot element */
  407. for (j = 0U; j < (numCols - l); j++)
  408. {
  409. /* Exchange the row elements of the input matrix */
  410. Xchg = *pInT2;
  411. *pInT2++ = *pInT1;
  412. *pInT1++ = Xchg;
  413. }
  414. for (j = 0U; j < numCols; j++)
  415. {
  416. Xchg = *pOutT2;
  417. *pOutT2++ = *pOutT1;
  418. *pOutT1++ = Xchg;
  419. }
  420. /* Flag to indicate whether exchange is done or not */
  421. flag = 1U;
  422. /* Break after exchange is done */
  423. break;
  424. }
  425. }
  426. }
  427. /* Update the status if the matrix is singular */
  428. if ((flag != 1U) && (in == 0.0))
  429. {
  430. return ARM_MATH_SINGULAR;
  431. }
  432. /* Points to the pivot row of input and destination matrices */
  433. pPivotRowIn = pIn + (l * numCols);
  434. pPivotRowDst = pOut + (l * numCols);
  435. /* Temporary pointers to the pivot row pointers */
  436. pInT1 = pPivotRowIn;
  437. pOutT1 = pPivotRowDst;
  438. /* Pivot element of the row */
  439. in = *(pIn + (l * numCols));
  440. /* Loop over number of columns
  441. * to the right of the pilot element */
  442. for (j = 0U; j < (numCols - l); j++)
  443. {
  444. /* Divide each element of the row of the input matrix
  445. * by the pivot element */
  446. *pInT1 = *pInT1 / in;
  447. pInT1++;
  448. }
  449. for (j = 0U; j < numCols; j++)
  450. {
  451. /* Divide each element of the row of the destination matrix
  452. * by the pivot element */
  453. *pOutT1 = *pOutT1 / in;
  454. pOutT1++;
  455. }
  456. /* Replace the rows with the sum of that row and a multiple of row i
  457. * so that each new element in column i above row i is zero.*/
  458. /* Temporary pointers for input and destination matrices */
  459. pInT1 = pIn;
  460. pOutT1 = pOut;
  461. for (i = 0U; i < numRows; i++)
  462. {
  463. /* Check for the pivot element */
  464. if (i == l)
  465. {
  466. /* If the processing element is the pivot element,
  467. only the columns to the right are to be processed */
  468. pInT1 += numCols - l;
  469. pOutT1 += numCols;
  470. }
  471. else
  472. {
  473. /* Element of the reference row */
  474. in = *pInT1;
  475. /* Working pointers for input and destination pivot rows */
  476. pPRT_in = pPivotRowIn;
  477. pPRT_pDst = pPivotRowDst;
  478. /* Loop over the number of columns to the right of the pivot element,
  479. to replace the elements in the input matrix */
  480. for (j = 0U; j < (numCols - l); j++)
  481. {
  482. /* Replace the element by the sum of that row
  483. and a multiple of the reference row */
  484. *pInT1 = *pInT1 - (in * *pPRT_in++);
  485. pInT1++;
  486. }
  487. /* Loop over the number of columns to
  488. replace the elements in the destination matrix */
  489. for (j = 0U; j < numCols; j++)
  490. {
  491. /* Replace the element by the sum of that row
  492. and a multiple of the reference row */
  493. *pOutT1 = *pOutT1 - (in * *pPRT_pDst++);
  494. pOutT1++;
  495. }
  496. }
  497. /* Increment temporary input pointer */
  498. pInT1 = pInT1 + l;
  499. }
  500. /* Increment the input pointer */
  501. pIn++;
  502. /* Decrement the loop counter */
  503. loopCnt--;
  504. /* Increment the index modifier */
  505. l++;
  506. }
  507. #endif /* #if defined (ARM_MATH_DSP) */
  508. /* Set status as ARM_MATH_SUCCESS */
  509. status = ARM_MATH_SUCCESS;
  510. if ((flag != 1U) && (in == 0.0))
  511. {
  512. pIn = pSrc->pData;
  513. for (i = 0; i < numRows * numCols; i++)
  514. {
  515. if (pIn[i] != 0.0)
  516. break;
  517. }
  518. if (i == numRows * numCols)
  519. status = ARM_MATH_SINGULAR;
  520. }
  521. }
  522. /* Return to application */
  523. return (status);
  524. }
  525. /**
  526. @} end of MatrixInv group
  527. */