more firm_config.h includes removed
[libfirm] / ir / adt / gaussseidel.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <assert.h>
6 #include <math.h>
7 #include <string.h>
8 #include "xmalloc.h"
9 #include "gaussseidel.h"
10 #include "util.h"
11
12 #define MAX(x,y)   ((x) > (y) ? (x) : (y))
13 #define MIN(x,y)   ((x) < (y) ? (x) : (y))
14
15 /**
16  * The number of newly allocated rows (realloc)
17  * when there is no more room. Must be >= 1.
18  */
19 #define ROW_INCREASE_FACTOR 1.2
20
21 /**
22  * The number of newly allocated cols (realloc)
23  * when there is no more room. Must be >= 1.
24  */
25 #define COL_INCREASE 2
26
27 typedef struct _col_val_t {
28         double v;
29         int col_idx;
30 } col_val_t;
31
32 typedef struct _row_col_t {
33         int c_cols;
34         int n_cols;
35         double diag;
36         col_val_t *cols;
37 } row_col_t;
38
39 struct _gs_matrix_t {
40         int initial_col_increase;
41         int c_rows;
42         int n_zero_entries;           ///< Upper bound on number of entries equal to 0.0
43         row_col_t *rows;
44 };
45
46 static INLINE void alloc_cols(row_col_t *row, int c_cols) {
47         assert(c_cols > row->c_cols);
48         row->c_cols = c_cols;
49         row->cols   = XREALLOC(row->cols, col_val_t, c_cols);
50 }
51
52 static INLINE void alloc_rows(gs_matrix_t *m, int c_rows, int c_cols, int begin_init) {
53         int i;
54         assert(c_rows > m->c_rows);
55
56         m->c_rows = c_rows;
57         m->rows   = XREALLOC(m->rows, row_col_t, c_rows);
58
59         for (i = begin_init; i < c_rows; ++i) {
60                 m->rows[i].c_cols = 0;
61                 m->rows[i].n_cols = 0;
62                 m->rows[i].diag   = 0.0;
63                 m->rows[i].cols   = NULL;
64                 if (c_cols > 0)
65                         alloc_cols(&m->rows[i], c_cols);
66         }
67 }
68
69 gs_matrix_t *gs_new_matrix(int n_init_rows, int n_init_cols) {
70         gs_matrix_t *res = XMALLOCZ(gs_matrix_t);
71         if (n_init_rows < 16)
72                 n_init_rows = 16;
73         res->initial_col_increase = n_init_cols;
74         alloc_rows(res, n_init_rows, n_init_cols, 0);
75         return res;
76 }
77
78 void gs_delete_matrix(gs_matrix_t *m) {
79         int i;
80         for (i = 0; i < m->c_rows; ++i) {
81                 if (m->rows[i].c_cols)
82                         xfree(m->rows[i].cols);
83         }
84         if (m->c_rows)
85                 xfree(m->rows);
86         xfree(m);
87 }
88
89 unsigned gs_matrix_get_n_entries(const gs_matrix_t *m) {
90         int i;
91         unsigned n_entries = 0;
92
93         for (i = 0; i < m->c_rows; ++i) {
94                 n_entries += m->rows[i].n_cols;
95                 n_entries += (m->rows[i].diag != 0.0) ? 1 : 0;
96         }
97
98         return n_entries - m->n_zero_entries;
99 }
100
101 int gs_matrix_get_sizeof_allocated_memory(const gs_matrix_t *m) {
102         int i, n_col_val_ts = 0;
103         for (i = 0; i < m->c_rows; ++i)
104                 n_col_val_ts += m->rows[i].c_cols;
105
106         return n_col_val_ts * sizeof(col_val_t) + m->c_rows * sizeof(row_col_t) + sizeof(gs_matrix_t);
107 }
108
109 void gs_matrix_assure_row_capacity(gs_matrix_t *m, int row, int min_capacity) {
110         row_col_t *the_row = &m->rows[row];
111         if (the_row->c_cols < min_capacity)
112                 alloc_cols(the_row, min_capacity);
113 }
114
115 void gs_matrix_trim_row_capacities(gs_matrix_t *m) {
116         int i;
117         for (i = 0; i < m->c_rows; ++i) {
118                 row_col_t *the_row = &m->rows[i];
119                 if (the_row->c_cols) {
120                         the_row->c_cols    = the_row->n_cols;
121                         if (the_row->c_cols)
122                                 the_row->cols = XREALLOC(the_row->cols, col_val_t, the_row->c_cols);
123                         else
124                                 xfree(the_row->cols);
125                 }
126         }
127 }
128
129 void gs_matrix_delete_zero_entries(gs_matrix_t *m) {
130         int i, read_pos;
131         for (i = 0; i < m->c_rows; ++i) {
132                 row_col_t *the_row = &m->rows[i];
133                 int write_pos = 0;
134
135                 for (read_pos = 0; read_pos < the_row->n_cols; ++read_pos)
136                         if (the_row->cols[read_pos].v != 0.0 && read_pos != write_pos)
137                                 the_row->cols[write_pos++] = the_row->cols[read_pos];
138
139                 the_row->n_cols = write_pos;
140         }
141         m->n_zero_entries = 0;
142 }
143
144 void gs_matrix_set(gs_matrix_t *m, int row, int col, double val) {
145         row_col_t *the_row;
146         col_val_t *cols;
147         int min, max, c, i;
148
149         if (row >= m->c_rows) {
150                 int new_c_rows = (int)(ROW_INCREASE_FACTOR * row);
151                 alloc_rows(m, new_c_rows, m->initial_col_increase, m->c_rows);
152         }
153
154         the_row = &m->rows[row];
155
156         if (row == col) {
157                 /* Note that we store the diagonal inverted to turn divisions to mults in
158                  * matrix_gauss_seidel(). */
159                 assert(val != 0.0);
160                 the_row->diag = 1.0 / val;
161                 return;
162         }
163
164         // Search for correct column
165         cols = the_row->cols;
166         min  = 0;
167         max  = the_row->n_cols;
168         c    = (max+min)/2;
169         while (min < max) {
170                 int idx = cols[c].col_idx;
171                 if (idx < col)
172                         min = MAX(c, min+1);
173                 else if (idx > col)
174                         max = MIN(c, max-1);
175                 else
176                         break;
177                 c = (max+min)/2;
178         }
179
180         // Have we found the entry?
181         if (c < the_row->n_cols && the_row->cols[c].col_idx == col) {
182                 the_row->cols[c].v = val;
183                 if (val == 0.0)
184                         m->n_zero_entries++;
185                 return;
186         }
187
188         // We haven't found the entry, so we must create a new one.
189         // Is there enough space?
190         if (the_row->c_cols == the_row->n_cols)
191                 alloc_cols(the_row, the_row->c_cols + COL_INCREASE);
192
193         // Shift right-most entries to the right by one
194         for (i = the_row->n_cols; i > c; --i)
195                 the_row->cols[i] = the_row->cols[i-1];
196
197         // Finally insert the new entry
198         the_row->n_cols++;
199         the_row->cols[c].col_idx = col;
200         the_row->cols[c].v = val;
201
202         // Check that the entries are sorted
203         assert(c==0 || the_row->cols[c-1].col_idx < the_row->cols[c].col_idx);
204         assert(c>=the_row->n_cols-1 || the_row->cols[c].col_idx < the_row->cols[c+1].col_idx);
205 }
206
207 double gs_matrix_get(const gs_matrix_t *m, int row, int col) {
208         row_col_t *the_row;
209         int c;
210
211         if (row >= m->c_rows)
212                 return 0.0;
213
214         the_row = &m->rows[row];
215
216         if (row == col)
217                 return the_row->diag != 0.0 ? 1.0 / the_row->diag : 0.0;
218
219         // Search for correct column
220         for (c = 0; c < the_row->n_cols && the_row->cols[c].col_idx < col; ++c);
221
222         if (c >= the_row->n_cols || the_row->cols[c].col_idx > col)
223                 return 0.0;
224
225         assert(the_row->cols[c].col_idx == col);
226         return the_row->cols[c].v;
227 }
228
229 /* NOTE: You can slice out miss_rate and weights.
230  * This does ONE step of gauss_seidel. Termination must be checked outside!
231  * This solves m*x=0. You must add stuff for m*x=b. See wikipedia german and english article. Should be simple.
232  * param a is the number of rows in the matrix that should be considered.
233  *
234  * Note that the diagonal element is stored separately in this matrix implementation.
235  * */
236 double gs_matrix_gauss_seidel(const gs_matrix_t *m, double *x, int n) {
237         double res = 0.0;
238         int r;
239
240         assert(n <= m->c_rows);
241
242         for (r = 0; r < n; ++r) {
243                 row_col_t *row  = &m->rows[r];
244                 col_val_t *cols = row->cols;
245                 double sum, old, nw;
246                 int c;
247
248                 sum = 0.0;
249                 for (c = 0; c < row->n_cols; ++c) {
250                         int col_idx = cols[c].col_idx;
251                         sum += cols[c].v * x[col_idx];
252                 }
253
254                 old  = x[r];
255                 nw   = - sum * row->diag;
256                 // nw   = old - overdrive * (old + sum * row->diag);
257                 res += fabs(old - nw);
258                 x[r] = nw;
259         }
260
261         return res;
262 }
263
264 void gs_matrix_export(const gs_matrix_t *m, double *nw, int size)
265 {
266         int effective_rows = MIN(size, m->c_rows);
267         int c, r;
268
269         memset(nw, 0, size * size * sizeof(*nw));
270         for (r=0; r < effective_rows; ++r) {
271                 row_col_t *row = &m->rows[r];
272                 int base       = r * size;
273
274                 assert(row->diag != 0.0);
275                 nw[base + r] = 1.0 / row->diag;
276                 for (c = 0; c < row->n_cols; ++c) {
277                         int col_idx = row->cols[c].col_idx;
278                         nw[base + col_idx] = row->cols[c].v;
279                 }
280         }
281 }
282
283 void gs_matrix_dump(const gs_matrix_t *m, int a, int b, FILE *out) {
284         int effective_rows = MIN(a, m->c_rows);
285         int r, c, i;
286         double *elems = XMALLOCN(double, b);
287
288         // The rows which have some content
289         for (r=0; r < effective_rows; ++r) {
290                 row_col_t *row = &m->rows[r];
291
292                 memset(elems, 0, b * sizeof(*elems));
293
294                 for (c = 0; c < row->n_cols; ++c) {
295                         int col_idx = row->cols[c].col_idx;
296                         elems[col_idx] = row->cols[c].v;
297                 }
298                 elems[r] = row->diag != 0.0 ? 1.0 / row->diag : 0.0;
299
300                 for (i = 0; i < b; ++i)
301                         if (elems[i] != 0.0)
302                                 fprintf(out, "%+4.4f ", elems[i]);
303                         else
304                                 fprintf(out, "        ");
305                 fprintf(out, "\n");
306         }
307
308         // Append 0-rows to fit height of matrix
309         for (r=effective_rows; r < a; ++r) {
310                 for (c=0; c < b; ++c)
311                                 fprintf(out, "        ");
312                 fprintf(out, "\n");
313         }
314
315         xfree(elems);
316 }
317
318 void gs_matrix_self_test(int d) {
319         int i, o;
320         gs_matrix_t *m = gs_new_matrix(10, 10);
321
322         for (i=0; i<d; ++i)
323                 for (o=0; o<d; ++o)
324                         gs_matrix_set(m, i, o, i*o);
325
326         for (i=0; i<d; ++i)
327                 for (o=0; o<d; ++o)
328                         assert(gs_matrix_get(m, i, o) == i*o);
329         gs_delete_matrix(m);
330 }