arm_mat_inverse_f64.c 21 KB

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