sparse_matrix.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /*****************************************************************************
  2. *
  3. * MODULE: Grass numerical math interface
  4. * AUTHOR(S): Soeren Gebbert, Berlin (GER) Dec 2006
  5. * soerengebbert <at> googlemail <dot> com
  6. *
  7. * PURPOSE: linear equation system solvers
  8. * part of the gmath library
  9. *
  10. * COPYRIGHT: (C) 2010 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #include <stdlib.h>
  18. #include <math.h>
  19. #include <grass/gmath.h>
  20. #include <grass/gis.h>
  21. /*!
  22. * \brief Adds a sparse vector to a sparse matrix at position row
  23. *
  24. * Return 1 for success and -1 for failure
  25. *
  26. * \param Asp G_math_spvector **
  27. * \param spvector G_math_spvector *
  28. * \param row int
  29. * \return int 1 success, -1 failure
  30. *
  31. * */
  32. int G_math_add_spvector(G_math_spvector ** Asp, G_math_spvector * spvector,
  33. int row)
  34. {
  35. if (Asp != NULL) {
  36. G_debug(5,
  37. "Add sparse vector %p to the sparse linear equation system at row %i\n",
  38. spvector, row);
  39. Asp[row] = spvector;
  40. }
  41. else {
  42. return -1;
  43. }
  44. return 1;
  45. }
  46. /*!
  47. * \brief Allocate memory for a sparse matrix
  48. *
  49. * \param rows int
  50. * \return G_math_spvector **
  51. *
  52. * */
  53. G_math_spvector **G_math_alloc_spmatrix(int rows)
  54. {
  55. G_math_spvector **spmatrix;
  56. G_debug(4, "Allocate memory for a sparse matrix with %i rows\n", rows);
  57. spmatrix = (G_math_spvector **) G_calloc(rows, sizeof(G_math_spvector *));
  58. return spmatrix;
  59. }
  60. /*!
  61. * \brief Allocate memory for a sparse vector
  62. *
  63. * \param cols int
  64. * \return G_math_spvector *
  65. *
  66. * */
  67. G_math_spvector *G_math_alloc_spvector(int cols)
  68. {
  69. G_math_spvector *spvector;
  70. G_debug(4, "Allocate memory for a sparse vector with %i cols\n", cols);
  71. spvector = (G_math_spvector *) G_calloc(1, sizeof(G_math_spvector));
  72. spvector->cols = cols;
  73. spvector->index = (unsigned int *)G_calloc(cols, sizeof(unsigned int));
  74. spvector->values = (double *)G_calloc(cols, sizeof(double));
  75. return spvector;
  76. }
  77. /*!
  78. * \brief Release the memory of the sparse vector
  79. *
  80. * \param spvector G_math_spvector *
  81. * \return void
  82. *
  83. * */
  84. void G_math_free_spvector(G_math_spvector * spvector)
  85. {
  86. if (spvector) {
  87. if (spvector->values)
  88. G_free(spvector->values);
  89. if (spvector->index)
  90. G_free(spvector->index);
  91. G_free(spvector);
  92. spvector = NULL;
  93. }
  94. return;
  95. }
  96. /*!
  97. * \brief Release the memory of the sparse matrix
  98. *
  99. * \param Asp G_math_spvector **
  100. * \param rows int
  101. * \return void
  102. *
  103. * */
  104. void G_math_free_spmatrix(G_math_spvector ** Asp, int rows)
  105. {
  106. int i;
  107. if (Asp) {
  108. for (i = 0; i < rows; i++)
  109. G_math_free_spvector(Asp[i]);
  110. G_free(Asp);
  111. Asp = NULL;
  112. }
  113. return;
  114. }
  115. /*!
  116. *
  117. * \brief print the sparse matrix Asp to stdout
  118. *
  119. *
  120. * \param Asp (G_math_spvector **)
  121. * \param rows (int)
  122. * \return void
  123. *
  124. * */
  125. void G_math_print_spmatrix(G_math_spvector ** Asp, int rows)
  126. {
  127. int i, j, k, out;
  128. for (i = 0; i < rows; i++) {
  129. for (j = 0; j < rows; j++) {
  130. out = 0;
  131. for (k = 0; k < Asp[i]->cols; k++) {
  132. if (Asp[i]->index[k] == j) {
  133. fprintf(stdout, "%4.5f ", Asp[i]->values[k]);
  134. out = 1;
  135. }
  136. }
  137. if (!out)
  138. fprintf(stdout, "%4.5f ", 0.0);
  139. }
  140. fprintf(stdout, "\n");
  141. }
  142. return;
  143. }
  144. /*!
  145. * \brief Convert a sparse matrix into a quadratic matrix
  146. *
  147. * This function is multi-threaded with OpenMP. It creates its own parallel OpenMP region.
  148. *
  149. * \param Asp (G_math_spvector **)
  150. * \param rows (int)
  151. * \return (double **)
  152. *
  153. * */
  154. double **G_math_Asp_to_A(G_math_spvector ** Asp, int rows)
  155. {
  156. int i, j;
  157. double **A = NULL;
  158. A = G_alloc_matrix(rows, rows);
  159. #pragma omp parallel for schedule (static) private(i, j)
  160. for (i = 0; i < rows; i++) {
  161. for (j = 0; j < Asp[i]->cols; j++) {
  162. A[i][Asp[i]->index[j]] = Asp[i]->values[j];
  163. }
  164. }
  165. return A;
  166. }
  167. /*!
  168. * \brief Convert a symmetric sparse matrix into a symmetric band matrix
  169. *
  170. \verbatim
  171. Symmetric matrix with bandwidth of 3
  172. 5 2 1 0
  173. 2 5 2 1
  174. 1 2 5 2
  175. 0 1 2 5
  176. will be converted into the band matrix
  177. 5 2 1
  178. 5 2 1
  179. 5 2 0
  180. 5 0 0
  181. \endverbatim
  182. * \param Asp (G_math_spvector **)
  183. * \param rows (int)
  184. * \param bandwidth (int)
  185. * \return (double **) the resulting ymmetric band matrix [rows][bandwidth]
  186. *
  187. * */
  188. double **G_math_Asp_to_sband_matrix(G_math_spvector ** Asp, int rows, int bandwidth)
  189. {
  190. int i, j;
  191. double **A = NULL;
  192. A = G_alloc_matrix(rows, bandwidth);
  193. for (i = 0; i < rows; i++) {
  194. for (j = 0; j < Asp[i]->cols; j++) {
  195. if(Asp[i]->index[j] == i) {
  196. A[i][0] = Asp[i]->values[j];
  197. } else if (Asp[i]->index[j] > i) {
  198. A[i][Asp[i]->index[j] - i] = Asp[i]->values[j];
  199. }
  200. }
  201. }
  202. return A;
  203. }
  204. /*!
  205. * \brief Convert a quadratic matrix into a sparse matrix
  206. *
  207. * This function is multi-threaded with OpenMP. It creates its own parallel OpenMP region.
  208. *
  209. * \param A (double **)
  210. * \param rows (int)
  211. * \param epsilon (double) -- non-zero values are greater then epsilon
  212. * \return (G_math_spvector **)
  213. *
  214. * */
  215. G_math_spvector **G_math_A_to_Asp(double **A, int rows, double epsilon)
  216. {
  217. int i, j;
  218. int nonull, count = 0;
  219. G_math_spvector **Asp = NULL;
  220. Asp = G_math_alloc_spmatrix(rows);
  221. #pragma omp parallel for schedule (static) private(i, j, nonull, count)
  222. for (i = 0; i < rows; i++) {
  223. nonull = 0;
  224. /*Count the number of non zero entries */
  225. for (j = 0; j < rows; j++) {
  226. if (A[i][j] > epsilon)
  227. nonull++;
  228. }
  229. /*Allocate the sparse vector and insert values */
  230. G_math_spvector *v = G_math_alloc_spvector(nonull);
  231. count = 0;
  232. for (j = 0; j < rows; j++) {
  233. if (A[i][j] > epsilon) {
  234. v->index[count] = j;
  235. v->values[count] = A[i][j];
  236. count++;
  237. }
  238. }
  239. /*Add vector to sparse matrix */
  240. G_math_add_spvector(Asp, v, i);
  241. }
  242. return Asp;
  243. }
  244. /*!
  245. * \brief Convert a symmetric band matrix into a sparse matrix
  246. *
  247. * WARNING:
  248. * This function is experimental, do not use.
  249. * Only the upper triangle matrix of the band strcuture is copied.
  250. *
  251. * \param A (double **) the symmetric band matrix
  252. * \param rows (int)
  253. * \param bandwidth (int)
  254. * \param epsilon (double) -- non-zero values are greater then epsilon
  255. * \return (G_math_spvector **)
  256. *
  257. * */
  258. G_math_spvector **G_math_sband_matrix_to_Asp(double **A, int rows, int bandwidth, double epsilon)
  259. {
  260. int i, j;
  261. int nonull, count = 0;
  262. G_math_spvector **Asp = NULL;
  263. Asp = G_math_alloc_spmatrix(rows);
  264. for (i = 0; i < rows; i++) {
  265. nonull = 0;
  266. /*Count the number of non zero entries */
  267. for (j = 0; j < bandwidth; j++) {
  268. if (A[i][j] > epsilon)
  269. nonull++;
  270. }
  271. /*Allocate the sparse vector and insert values */
  272. G_math_spvector *v = G_math_alloc_spvector(nonull);
  273. count = 0;
  274. if (A[i][0] > epsilon) {
  275. v->index[count] = i;
  276. v->values[count] = A[i][0];
  277. count++;
  278. }
  279. for (j = 1; j < bandwidth; j++) {
  280. if (A[i][j] > epsilon && i + j < rows) {
  281. v->index[count] = i + j;
  282. v->values[count] = A[i][j];
  283. count++;
  284. }
  285. }
  286. /*Add vector to sparse matrix */
  287. G_math_add_spvector(Asp, v, i);
  288. }
  289. return Asp;
  290. }
  291. /*!
  292. * \brief Compute the matrix - vector product
  293. * of sparse matrix **Asp and vector x.
  294. *
  295. * This function is multi-threaded with OpenMP and can be called within a parallel OpenMP region.
  296. *
  297. * y = A * x
  298. *
  299. *
  300. * \param Asp (G_math_spvector **)
  301. * \param x (double) *)
  302. * \param y (double * )
  303. * \param rows (int)
  304. * \return (void)
  305. *
  306. * */
  307. void G_math_Ax_sparse(G_math_spvector ** Asp, double *x, double *y, int rows)
  308. {
  309. int i, j;
  310. double tmp;
  311. #pragma omp for schedule (static) private(i, j, tmp)
  312. for (i = 0; i < rows; i++) {
  313. tmp = 0;
  314. for (j = 0; j < Asp[i]->cols; j++) {
  315. tmp += Asp[i]->values[j] * x[Asp[i]->index[j]];
  316. }
  317. y[i] = tmp;
  318. }
  319. return;
  320. }