solvers_direct_cholesky_band.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <grass/gis.h>
  5. #include <grass/gmath.h>
  6. #include <grass/glocale.h>
  7. /**
  8. * \brief Cholesky decomposition of a symmetric band matrix
  9. *
  10. * \param A (double**) the input symmetric band matrix
  11. * \param T (double**) the resulting lower tringular sband matrix
  12. * \param rows (int) number of rows
  13. * \param bandwidth (int) the bandwidth of the symmetric band matrix
  14. *
  15. * */
  16. void G_math_cholesky_sband_decomposition(double **A, double **T, int rows, int bandwidth)
  17. {
  18. int i, j, k, end;
  19. double sum;
  20. G_debug(2, "G_math_cholesky_sband_decomposition(): n=%d bandwidth=%d", rows, bandwidth);
  21. for (i = 0; i < rows; i++) {
  22. G_percent(i, rows, 2);
  23. for (j = 0; j < bandwidth; j++) {
  24. sum = A[i][j];
  25. /* start = 1 */
  26. /* end = bandwidth - j or i + 1 */
  27. end = ((bandwidth - j) < (i + 1) ? (bandwidth - j) : (i + 1));
  28. for (k = 1; k < end; k++)
  29. sum -= T[i - k][k] * T[i - k][j + k];
  30. if (j == 0) {
  31. if (sum <= 0.0)
  32. G_fatal_error(_("Decomposition failed at row %i and col %i"), i, j);
  33. T[i][0] = sqrt(sum);
  34. }
  35. else
  36. T[i][j] = sum / T[i][0];
  37. }
  38. }
  39. G_percent(i, rows, 2);
  40. return;
  41. }
  42. /**
  43. * \brief Cholesky symmetric band matrix solver for linear equation systems of type Ax = b
  44. *
  45. * \param A (double**) the input symmetric band matrix
  46. * \param x (double*) the resulting vector, result is written in here
  47. * \param b (double*) the right hand side of Ax = b
  48. * \param rows (int) number of rows
  49. * \param bandwidth (int) the bandwidth of the symmetric band matrix
  50. *
  51. * */
  52. void G_math_solver_cholesky_sband(double **A, double *x, double *b, int rows, int bandwidth)
  53. {
  54. double **T;
  55. T = G_alloc_matrix(rows, bandwidth);
  56. G_math_cholesky_sband_decomposition(A, T, rows, bandwidth); /* T computation */
  57. G_math_cholesky_sband_substitution(T, x, b, rows, bandwidth);
  58. G_free_matrix(T);
  59. return;
  60. }
  61. /**
  62. * \brief Forward and backward substitution of a lower tringular symmetric band matrix of A from system Ax = b
  63. *
  64. * \param T (double**) the lower triangle symmetric band matrix
  65. * \param x (double*) the resulting vector
  66. * \param b (double*) the right hand side of Ax = b
  67. * \param rows (int) number of rows
  68. * \param bandwidth (int) the bandwidth of the symmetric band matrix
  69. *
  70. * */
  71. void G_math_cholesky_sband_substitution(double **T, double *x, double *b, int rows, int bandwidth)
  72. {
  73. int i, j, start, end;
  74. /* Forward substitution */
  75. x[0] = b[0] / T[0][0];
  76. for (i = 1; i < rows; i++) {
  77. x[i] = b[i];
  78. /* start = 0 or i - bandwidth + 1 */
  79. start = ((i - bandwidth + 1) < 0 ? 0 : (i - bandwidth + 1));
  80. /* end = i */
  81. for (j = start; j < i; j++)
  82. x[i] -= T[j][i - j] * x[j];
  83. x[i] = x[i] / T[i][0];
  84. }
  85. /* Backward substitution */
  86. x[rows - 1] = x[rows - 1] / T[rows - 1][0];
  87. for (i = rows - 2; i >= 0; i--) {
  88. /* start = i + 1 */
  89. /* end = rows or bandwidth + i */
  90. end = (rows < (bandwidth + i) ? rows : (bandwidth + i));
  91. for (j = i + 1; j < end; j++)
  92. x[i] -= T[i][j - i] * x[j];
  93. x[i] = x[i] / T[i][0];
  94. }
  95. return;
  96. }
  97. /*--------------------------------------------------------------------------------------*/
  98. /* Tcholetsky matrix invertion */
  99. void G_math_cholesky_sband_invert(double **A, double *invAdiag, int rows, int bandwidth)
  100. {
  101. double **T = NULL;
  102. double *vect = NULL;
  103. int i, j, k, start;
  104. double sum;
  105. T = G_alloc_matrix(rows, bandwidth);
  106. vect = G_alloc_vector(rows);
  107. /* T computation */
  108. G_math_cholesky_sband_decomposition(A, T, rows, bandwidth);
  109. /* T Diagonal invertion */
  110. for (i = 0; i < rows; i++) {
  111. T[i][0] = 1.0 / T[i][0];
  112. }
  113. /* A Diagonal invertion */
  114. for (i = 0; i < rows; i++) {
  115. vect[0] = T[i][0];
  116. invAdiag[i] = vect[0] * vect[0];
  117. for (j = i + 1; j < rows; j++) {
  118. sum = 0.0;
  119. /* start = i or j - bandwidth + 1 */
  120. start = ((j - bandwidth + 1) < i ? i : (j - bandwidth + 1));
  121. /* end = j */
  122. for (k = start; k < j; k++) {
  123. sum -= vect[k - i] * T[k][j - k];
  124. }
  125. vect[j - i] = sum * T[j][0];
  126. invAdiag[i] += vect[j - i] * vect[j - i];
  127. }
  128. }
  129. G_free_matrix(T);
  130. G_free_vector(vect);
  131. return;
  132. }
  133. /*--------------------------------------------------------------------------------------*/
  134. /* Tcholetsky matrix solution and invertion */
  135. void G_math_solver_cholesky_sband_invert(double **A, double *x, double *b, double *invAdiag,
  136. int rows, int bandwidth)
  137. {
  138. double **T = NULL;
  139. double *vect = NULL;
  140. int i, j, k, start;
  141. double sum;
  142. T = G_alloc_matrix(rows, bandwidth);
  143. vect = G_alloc_vector(rows);
  144. /* T computation */
  145. G_math_cholesky_sband_decomposition(A, T, rows, bandwidth);
  146. G_math_cholesky_sband_substitution(T, x, b, rows, bandwidth);
  147. /* T Diagonal invertion */
  148. for (i = 0; i < rows; i++) {
  149. T[i][0] = 1.0 / T[i][0];
  150. }
  151. /* A Diagonal invertion */
  152. for (i = 0; i < rows; i++) {
  153. vect[0] = T[i][0];
  154. invAdiag[i] = vect[0] * vect[0];
  155. for (j = i + 1; j < rows; j++) {
  156. sum = 0.0;
  157. /* start = i or j - bandwidth + 1 */
  158. start = ((j - bandwidth + 1) < i ? i : (j - bandwidth + 1));
  159. /* end = j */
  160. for (k = start; k < j; k++) {
  161. sum -= vect[k - i] * T[k][j - k];
  162. }
  163. vect[j - i] = sum * T[j][0];
  164. invAdiag[i] += vect[j - i] * vect[j - i];
  165. }
  166. }
  167. G_free_matrix(T);
  168. G_free_vector(vect);
  169. return;
  170. }