GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
sparse_matrix.c
Go to the documentation of this file.
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 * SPDX-FileCopyrightText: 2010 GRASS Development Team
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 *
13 *****************************************************************************/
14
15#include <assert.h>
16#include <stdlib.h>
17#include <math.h>
18#include <grass/gmath.h>
19#include <grass/gis.h>
20
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 * */
33 int row)
34{
35 if (Asp != NULL) {
36 G_debug(5,
37 "Add sparse vector %p to the sparse linear equation system at "
38 "row %i\n",
39 (void *)spvector, row);
40 Asp[row] = spvector;
41 }
42 else {
43 return -1;
44 }
45
46 return 1;
47}
48
49/*!
50 * \brief Allocate memory for a sparse matrix
51 *
52 * \param rows int
53 * \return G_math_spvector **
54 *
55 * */
57{
59
60 G_debug(4, "Allocate memory for a sparse matrix with %i rows\n", rows);
61
62 spmatrix = (G_math_spvector **)G_calloc(rows, sizeof(G_math_spvector *));
63
64 return spmatrix;
65}
66
67/*!
68 * \brief Allocate memory for a sparse vector
69 *
70 * \param cols int
71 * \return G_math_spvector *
72 *
73 * */
75{
77
78 G_debug(4, "Allocate memory for a sparse vector with %i cols\n", cols);
79
81
82 spvector->cols = cols;
83 spvector->index = (unsigned int *)G_calloc(cols, sizeof(unsigned int));
84 spvector->values = (double *)G_calloc(cols, sizeof(double));
85
86 return spvector;
87}
88
89/*!
90 * \brief Release the memory of the sparse vector
91 *
92 * \param spvector G_math_spvector *
93 * \return void
94 *
95 * */
97{
98 if (spvector) {
99 if (spvector->values)
100 G_free(spvector->values);
101 if (spvector->index)
102 G_free(spvector->index);
104
105 spvector = NULL;
106 }
107
108 return;
109}
110
111/*!
112 * \brief Release the memory of the sparse matrix
113 *
114 * \param Asp G_math_spvector **
115 * \param rows int
116 * \return void
117 *
118 * */
120{
121 int i;
122
123 if (Asp) {
124 for (i = 0; i < rows; i++)
125 G_math_free_spvector(Asp[i]);
126
127 G_free(Asp);
128 Asp = NULL;
129 }
130
131 return;
132}
133
134/*!
135 *
136 * \brief print the sparse matrix Asp to stdout
137 *
138 *
139 * \param Asp (G_math_spvector **)
140 * \param rows (int)
141 * \return void
142 *
143 * */
145{
146 int i, j, out;
147 unsigned int k;
148
149 for (i = 0; i < rows; i++) {
150 for (j = 0; j < rows; j++) {
151 out = 0;
152 for (k = 0; k < Asp[i]->cols; k++) {
153 if (Asp[i]->index[k] == (unsigned int)j) {
154 fprintf(stdout, "%4.5f ", Asp[i]->values[k]);
155 out = 1;
156 }
157 }
158 if (!out)
159 fprintf(stdout, "%4.5f ", 0.0);
160 }
161 fprintf(stdout, "\n");
162 }
163
164 return;
165}
166
167/*!
168 * \brief Convert a sparse matrix into a quadratic matrix
169 *
170 * This function is multi-threaded with OpenMP. It creates its own parallel
171 * OpenMP region.
172 *
173 * \param Asp (G_math_spvector **)
174 * \param rows (int)
175 * \return (double **)
176 *
177 * */
178double **G_math_Asp_to_A(G_math_spvector **Asp, int rows)
179{
180 int i;
181 unsigned int j;
182
183 double **A = NULL;
184
185 A = G_alloc_matrix(rows, rows);
186
187#pragma omp parallel for schedule(static) private(i, j)
188 for (i = 0; i < rows; i++) {
189 for (j = 0; j < Asp[i]->cols; j++) {
190 A[i][Asp[i]->index[j]] = Asp[i]->values[j];
191 }
192 }
193 return A;
194}
195
196/*!
197 * \brief Convert a symmetric sparse matrix into a symmetric band matrix
198 *
199 \verbatim
200 Symmetric matrix with bandwidth of 3
201
202 5 2 1 0
203 2 5 2 1
204 1 2 5 2
205 0 1 2 5
206
207 will be converted into the band matrix
208
209 5 2 1
210 5 2 1
211 5 2 0
212 5 0 0
213
214 \endverbatim
215 * \param Asp (G_math_spvector **)
216 * \param rows (int)
217 * \param bandwidth (int)
218 * \return (double **) the resulting ymmetric band matrix [rows][bandwidth]
219 *
220 * */
222 int bandwidth)
223{
224 unsigned int i, j;
225
226 double **A = NULL;
227
228 assert(rows >= 0 && bandwidth >= 0);
229
230 A = G_alloc_matrix(rows, bandwidth);
231
232 for (i = 0; i < (unsigned int)rows; i++) {
233 for (j = 0; j < Asp[i]->cols; j++) {
234 if (Asp[i]->index[j] == i) {
235 A[i][0] = Asp[i]->values[j];
236 }
237 else if (Asp[i]->index[j] > i) {
238 A[i][Asp[i]->index[j] - i] = Asp[i]->values[j];
239 }
240 }
241 }
242 return A;
243}
244
245/*!
246 * \brief Convert a quadratic matrix into a sparse matrix
247 *
248 * This function is multi-threaded with OpenMP. It creates its own parallel
249 * OpenMP region.
250 *
251 * \param A (double **)
252 * \param rows (int)
253 * \param epsilon (double) -- non-zero values are greater then epsilon
254 * \return (G_math_spvector **)
255 *
256 * */
257G_math_spvector **G_math_A_to_Asp(double **A, int rows, double epsilon)
258{
259 int i, j;
260
261 int nonull, count = 0;
262
263 G_math_spvector **Asp = NULL;
264
265 Asp = G_math_alloc_spmatrix(rows);
266
267#pragma omp parallel for schedule(static) private(i, j, nonull, count)
268 for (i = 0; i < rows; i++) {
269 nonull = 0;
270 /*Count the number of non zero entries */
271 for (j = 0; j < rows; j++) {
272 if (A[i][j] > epsilon)
273 nonull++;
274 }
275 /*Allocate the sparse vector and insert values */
277
278 count = 0;
279 for (j = 0; j < rows; j++) {
280 if (A[i][j] > epsilon) {
281 v->index[count] = 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/*!
293 * \brief Convert a symmetric band matrix into a sparse matrix
294 *
295 * WARNING:
296 * This function is experimental, do not use.
297 * Only the upper triangle matrix of the band structure is copied.
298 *
299 * \param A (double **) the symmetric band matrix
300 * \param rows (int)
301 * \param bandwidth (int)
302 * \param epsilon (double) -- non-zero values are greater then epsilon
303 * \return (G_math_spvector **)
304 *
305 * */
307 int bandwidth, double epsilon)
308{
309 int i, j;
310
311 int nonull, count = 0;
312
313 G_math_spvector **Asp = NULL;
314
315 Asp = G_math_alloc_spmatrix(rows);
316
317 for (i = 0; i < rows; i++) {
318 nonull = 0;
319 /*Count the number of non zero entries */
320 for (j = 0; j < bandwidth; j++) {
321 if (A[i][j] > epsilon)
322 nonull++;
323 }
324
325 /*Allocate the sparse vector and insert values */
326
328
329 count = 0;
330 if (A[i][0] > epsilon) {
331 v->index[count] = i;
332 v->values[count] = A[i][0];
333 count++;
334 }
335
336 for (j = 1; j < bandwidth; j++) {
337 if (A[i][j] > epsilon && i + j < rows) {
338 v->index[count] = i + j;
339 v->values[count] = A[i][j];
340 count++;
341 }
342 }
343 /*Add vector to sparse matrix */
344 G_math_add_spvector(Asp, v, i);
345 }
346 return Asp;
347}
348
349/*!
350 * \brief Compute the matrix - vector product
351 * of sparse matrix **Asp and vector x.
352 *
353 * This function is multi-threaded with OpenMP and can be called within a
354 * parallel OpenMP region.
355 *
356 * y = A * x
357 *
358 *
359 * \param Asp (G_math_spvector **)
360 * \param x (double) *)
361 * \param y (double * )
362 * \param rows (int)
363 * \return (void)
364 *
365 * */
366void G_math_Ax_sparse(G_math_spvector **Asp, double *x, double *y, int rows)
367{
368 int i;
369 unsigned int j;
370
371 double tmp;
372
373#pragma omp for schedule(static) private(i, j, tmp)
374 for (i = 0; i < rows; i++) {
375 tmp = 0;
376 for (j = 0; j < Asp[i]->cols; j++) {
377 tmp += Asp[i]->values[j] * x[Asp[i]->index[j]];
378 }
379 y[i] = tmp;
380 }
381 return;
382}
#define NULL
Definition ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
#define G_calloc(m, n)
Definition defs/gis.h:137
int G_debug(int, const char *,...) __attribute__((format(printf
double ** G_alloc_matrix(int, int)
Matrix memory allocation.
Definition dalloc.c:55
int count
#define assert(condition)
Definition lz4.c:291
void G_math_Ax_sparse(G_math_spvector **Asp, double *x, double *y, int rows)
Compute the matrix - vector product of sparse matrix **Asp and vector x.
double ** G_math_Asp_to_sband_matrix(G_math_spvector **Asp, int rows, int bandwidth)
Convert a symmetric sparse matrix into a symmetric band matrix.
void G_math_print_spmatrix(G_math_spvector **Asp, int rows)
print the sparse matrix Asp to stdout
double ** G_math_Asp_to_A(G_math_spvector **Asp, int rows)
Convert a sparse matrix into a quadratic matrix.
G_math_spvector * G_math_alloc_spvector(int cols)
Allocate memory for a sparse vector.
void G_math_free_spvector(G_math_spvector *spvector)
Release the memory of the sparse vector.
void G_math_free_spmatrix(G_math_spvector **Asp, int rows)
Release the memory of the sparse matrix.
int G_math_add_spvector(G_math_spvector **Asp, G_math_spvector *spvector, int row)
Adds a sparse vector to a sparse matrix at position row.
G_math_spvector ** G_math_sband_matrix_to_Asp(double **A, int rows, int bandwidth, double epsilon)
Convert a symmetric band matrix into a sparse matrix.
G_math_spvector ** G_math_A_to_Asp(double **A, int rows, double epsilon)
Convert a quadratic matrix into a sparse matrix.
G_math_spvector ** G_math_alloc_spmatrix(int rows)
Allocate memory for a sparse matrix.
The row vector of the sparse matrix.
Definition gmath.h:54
double * values
Definition gmath.h:55
unsigned int cols
Definition gmath.h:56
unsigned int * index
Definition gmath.h:57
#define x