arm_mat_inverse_f64.c 20 KB

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