Fix coding style
[survex.git] / src / matrix.c
blob13dffd99810b8b282d61fa94d715739e322275b0
1 /* matrix.c
2 * Matrix building and solving routines
3 * Copyright (C) 1993-2003,2010,2013 Olly Betts
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 /*#define SOR 1*/
22 #if 0
23 # define DEBUG_INVALID 1
24 #endif
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include "debug.h"
31 #include "cavern.h"
32 #include "filename.h"
33 #include "message.h"
34 #include "netbits.h"
35 #include "matrix.h"
36 #include "out.h"
38 #undef PRINT_MATRICES
39 #define PRINT_MATRICES 0
41 #undef DEBUG_MATRIX_BUILD
42 #define DEBUG_MATRIX_BUILD 0
44 #undef DEBUG_MATRIX
45 #define DEBUG_MATRIX 0
47 #if PRINT_MATRICES
48 static void print_matrix(real *M, real *B, long n);
49 #endif
51 static void choleski(real *M, real *B, long n);
53 #ifdef SOR
54 static void sor(real *M, real *B, long n);
55 #endif
57 /* for M(row, col) col must be <= row, so Y <= X */
58 # define M(X, Y) ((real *)M)[((((OSSIZE_T)(X)) * ((X) + 1)) >> 1) + (Y)]
59 /* +(Y>X?0*printf("row<col (line %d)\n",__LINE__):0) */
60 /*#define M_(X, Y) ((real *)M)[((((OSSIZE_T)(Y)) * ((Y) + 1)) >> 1) + (X)]*/
62 static int find_stn_in_tab(node *stn);
63 static int add_stn_to_tab(node *stn);
64 static void build_matrix(node *list);
66 static long n_stn_tab;
68 static pos **stn_tab;
70 extern void
71 solve_matrix(node *list)
73 node *stn;
74 long n = 0;
75 FOR_EACH_STN(stn, list) {
76 if (!fixed(stn)) n++;
78 if (n == 0) return;
80 /* we just need n to be a reasonable estimate >= the number
81 * of stations left after reduction. If memory is
82 * plentiful, we can be crass.
84 stn_tab = osmalloc((OSSIZE_T)(n * ossizeof(pos*)));
85 n_stn_tab = 0;
87 FOR_EACH_STN(stn, list) {
88 if (!fixed(stn)) add_stn_to_tab(stn);
91 if (n_stn_tab < n) {
92 /* release unused entries in stn_tab */
93 stn_tab = osrealloc(stn_tab, n_stn_tab * ossizeof(pos*));
96 build_matrix(list);
97 #if DEBUG_MATRIX
98 FOR_EACH_STN(stn, list) {
99 printf("(%8.2f, %8.2f, %8.2f ) ", POS(stn, 0), POS(stn, 1), POS(stn, 2));
100 print_prefix(stn->name);
101 putnl();
103 #endif
105 osfree(stn_tab);
108 #ifdef NO_COVARIANCES
109 # define FACTOR 1
110 #else
111 # define FACTOR 3
112 #endif
114 static void
115 build_matrix(node *list)
117 real *M;
118 real *B;
119 int dim;
121 if (n_stn_tab == 0) {
122 if (!fQuiet)
123 puts(msg(/*Network solved by reduction - no simultaneous equations to solve.*/74));
124 return;
126 /* (OSSIZE_T) cast may be needed if n_stn_tab>=181 */
127 M = osmalloc((OSSIZE_T)((((OSSIZE_T)n_stn_tab * FACTOR * (n_stn_tab * FACTOR + 1)) >> 1)) * ossizeof(real));
128 B = osmalloc((OSSIZE_T)(n_stn_tab * FACTOR * ossizeof(real)));
130 if (!fQuiet) {
131 if (n_stn_tab == 1)
132 out_current_action(msg(/*Solving one equation*/78));
133 else
134 out_current_action1(msg(/*Solving %d simultaneous equations*/75), n_stn_tab);
137 #ifdef NO_COVARIANCES
138 dim = 2;
139 #else
140 dim = 0; /* fudge next loop for now */
141 #endif
142 for ( ; dim >= 0; dim--) {
143 node *stn;
144 int row;
146 /* Initialise M and B to zero - zeroing "linearly" will minimise
147 * paging when the matrix is large */
149 int end = n_stn_tab * FACTOR;
150 for (row = 0; row < end; row++) B[row] = (real)0.0;
151 end = ((OSSIZE_T)n_stn_tab * FACTOR * (n_stn_tab * FACTOR + 1)) >> 1;
152 for (row = 0; row < end; row++) M[row] = (real)0.0;
155 /* Construct matrix - Go thru' stn list & add all forward legs between
156 * two unfixed stations to M (so each leg goes on exactly once).
158 * All legs between two fixed stations can be ignored here.
160 * All legs between a fixed and an unfixed station are then considered
161 * from the unfixed end (if we consider them from the fixed end we'd
162 * need to somehow detect when we're at a fixed point cut line and work
163 * out which side we're dealing with at this time. */
164 FOR_EACH_STN(stn, list) {
165 #ifdef NO_COVARIANCES
166 real e;
167 #else
168 svar e;
169 delta a;
170 #endif
171 int f, t;
172 int dirn;
173 #if DEBUG_MATRIX_BUILD
174 print_prefix(stn->name);
175 printf(" used: %d colour %ld\n",
176 (!!stn->leg[2]) << 2 | (!!stn -> leg[1]) << 1 | (!!stn->leg[0]),
177 stn->colour);
179 for (dirn = 0; dirn <= 2 && stn->leg[dirn]; dirn++) {
180 #ifdef NO_COVARIANCES
181 printf("Leg %d, vx=%f, reverse=%d, to ", dirn,
182 stn->leg[dirn]->v[0], stn->leg[dirn]->l.reverse);
183 #else
184 printf("Leg %d, vx=%f, reverse=%d, to ", dirn,
185 stn->leg[dirn]->v[0][0], stn->leg[dirn]->l.reverse);
186 #endif
187 print_prefix(stn->leg[dirn]->l.to->name);
188 putnl();
190 putnl();
191 #endif /* DEBUG_MATRIX_BUILD */
193 if (!fixed(stn)) {
194 f = find_stn_in_tab(stn);
195 for (dirn = 0; dirn <= 2 && stn->leg[dirn]; dirn++) {
196 linkfor *leg = stn->leg[dirn];
197 node *to = leg->l.to;
198 if (fixed(to)) {
199 bool fRev = !data_here(leg);
200 if (fRev) leg = reverse_leg(leg);
201 /* Ignore equated nodes */
202 #ifdef NO_COVARIANCES
203 e = leg->v[dim];
204 if (e != (real)0.0) {
205 e = ((real)1.0) / e;
206 M(f,f) += e;
207 B[f] += e * POS(to, dim);
208 if (fRev) {
209 B[f] += leg->d[dim];
210 } else {
211 B[f] -= leg->d[dim];
214 #else
215 if (invert_svar(&e, &leg->v)) {
216 delta b;
217 int i;
218 if (fRev) {
219 adddd(&a, &POSD(to), &leg->d);
220 } else {
221 subdd(&a, &POSD(to), &leg->d);
223 mulsd(&b, &e, &a);
224 for (i = 0; i < 3; i++) {
225 M(f * FACTOR + i, f * FACTOR + i) += e[i];
226 B[f * FACTOR + i] += b[i];
228 M(f * FACTOR + 1, f * FACTOR) += e[3];
229 M(f * FACTOR + 2, f * FACTOR) += e[4];
230 M(f * FACTOR + 2, f * FACTOR + 1) += e[5];
232 #endif
233 } else if (data_here(leg)) {
234 /* forward leg, unfixed -> unfixed */
235 t = find_stn_in_tab(to);
236 #if DEBUG_MATRIX
237 printf("Leg %d to %d, var %f, delta %f\n", f, t, e,
238 leg->d[dim]);
239 #endif
240 /* Ignore equated nodes & lollipops */
241 #ifdef NO_COVARIANCES
242 e = leg->v[dim];
243 if (t != f && e != (real)0.0) {
244 real a;
245 e = ((real)1.0) / e;
246 M(f,f) += e;
247 M(t,t) += e;
248 if (f < t) M(t,f) -= e; else M(f,t) -= e;
249 a = e * leg->d[dim];
250 B[f] -= a;
251 B[t] += a;
253 #else
254 if (t != f && invert_svar(&e, &leg->v)) {
255 int i;
256 mulsd(&a, &e, &leg->d);
257 for (i = 0; i < 3; i++) {
258 M(f * FACTOR + i, f * FACTOR + i) += e[i];
259 M(t * FACTOR + i, t * FACTOR + i) += e[i];
260 if (f < t)
261 M(t * FACTOR + i, f * FACTOR + i) -= e[i];
262 else
263 M(f * FACTOR + i, t * FACTOR + i) -= e[i];
264 B[f * FACTOR + i] -= a[i];
265 B[t * FACTOR + i] += a[i];
267 M(f * FACTOR + 1, f * FACTOR) += e[3];
268 M(t * FACTOR + 1, t * FACTOR) += e[3];
269 M(f * FACTOR + 2, f * FACTOR) += e[4];
270 M(t * FACTOR + 2, t * FACTOR) += e[4];
271 M(f * FACTOR + 2, f * FACTOR + 1) += e[5];
272 M(t * FACTOR + 2, t * FACTOR + 1) += e[5];
273 if (f < t) {
274 M(t * FACTOR + 1, f * FACTOR) -= e[3];
275 M(t * FACTOR, f * FACTOR + 1) -= e[3];
276 M(t * FACTOR + 2, f * FACTOR) -= e[4];
277 M(t * FACTOR, f * FACTOR + 2) -= e[4];
278 M(t * FACTOR + 2, f * FACTOR + 1) -= e[5];
279 M(t * FACTOR + 1, f * FACTOR + 2) -= e[5];
280 } else {
281 M(f * FACTOR + 1, t * FACTOR) -= e[3];
282 M(f * FACTOR, t * FACTOR + 1) -= e[3];
283 M(f * FACTOR + 2, t * FACTOR) -= e[4];
284 M(f * FACTOR, t * FACTOR + 2) -= e[4];
285 M(f * FACTOR + 2, t * FACTOR + 1) -= e[5];
286 M(f * FACTOR + 1, t * FACTOR + 2) -= e[5];
289 #endif
295 #if PRINT_MATRICES
296 print_matrix(M, B, n_stn_tab * FACTOR); /* 'ave a look! */
297 #endif
299 #ifdef SOR
300 /* defined in network.c, may be altered by -z<letters> on command line */
301 if (optimize & BITA('i'))
302 sor(M, B, n_stn_tab * FACTOR);
303 else
304 #endif
305 choleski(M, B, n_stn_tab * FACTOR);
308 int m;
309 for (m = (int)(n_stn_tab - 1); m >= 0; m--) {
310 #ifdef NO_COVARIANCES
311 stn_tab[m]->p[dim] = B[m];
312 if (dim == 0) {
313 SVX_ASSERT2(pos_fixed(stn_tab[m]),
314 "setting station coordinates didn't mark pos as fixed");
316 #else
317 int i;
318 for (i = 0; i < 3; i++) {
319 stn_tab[m]->p[i] = B[m * FACTOR + i];
321 SVX_ASSERT2(pos_fixed(stn_tab[m]),
322 "setting station coordinates didn't mark pos as fixed");
323 #endif
325 #if EXPLICIT_FIXED_FLAG
326 for (m = n_stn_tab - 1; m >= 0; m--) fixpos(stn_tab[m]);
327 #endif
330 osfree(B);
331 osfree(M);
334 static int
335 find_stn_in_tab(node *stn)
337 int i = 0;
338 pos *p = stn->name->pos;
339 while (stn_tab[i] != p)
340 if (++i == n_stn_tab) {
341 #if DEBUG_INVALID
342 fputs("Station ", stderr);
343 fprint_prefix(stderr, stn->name);
344 fputs(" not in table\n\n", stderr);
345 #endif
346 #if 0
347 print_prefix(stn->name);
348 printf(" used: %d colour %d\n",
349 (!!stn->leg[2])<<2 | (!!stn->leg[1])<<1 | (!!stn->leg[0]),
350 stn->colour);
351 #endif
352 fatalerror(/*Bug in program detected! Please report this to the authors*/11);
354 return i;
357 static int
358 add_stn_to_tab(node *stn)
360 int i;
361 pos *p = stn->name->pos;
362 for (i = 0; i < n_stn_tab; i++) {
363 if (stn_tab[i] == p) return i;
365 stn_tab[n_stn_tab++] = p;
366 return i;
369 /* Solve MX=B for X by Choleski factorisation - modified Choleski actually
370 * since we factor into LDL' while Choleski is just LL'
372 /* Note M must be symmetric positive definite */
373 /* routine is entitled to scribble on M and B if it wishes */
374 static void
375 choleski(real *M, real *B, long n)
377 int i, j, k;
379 for (j = 1; j < n; j++) {
380 real V;
381 for (i = 0; i < j; i++) {
382 V = (real)0.0;
383 for (k = 0; k < i; k++) V += M(i,k) * M(j,k) * M(k,k);
384 M(j,i) = (M(j,i) - V) / M(i,i);
386 V = (real)0.0;
387 for (k = 0; k < j; k++) V += M(j,k) * M(j,k) * M(k,k);
388 M(j,j) -= V; /* may be best to add M() last for numerical reasons too */
391 /* Multiply x by L inverse */
392 for (i = 0; i < n - 1; i++) {
393 for (j = i + 1; j < n; j++) {
394 B[j] -= M(j,i) * B[i];
398 /* Multiply x by D inverse */
399 for (i = 0; i < n; i++) {
400 B[i] /= M(i,i);
403 /* Multiply x by (L transpose) inverse */
404 for (i = (int)(n - 1); i > 0; i--) {
405 for (j = i - 1; j >= 0; j--) {
406 B[j] -= M(i,j) * B[i];
410 /* printf("\n%ld/%ld\n\n",flops,flopsTot); */
413 #ifdef SOR
414 /* factor to use for SOR (must have 1 <= SOR_factor < 2) */
415 #define SOR_factor 1.93 /* 1.95 */
417 /* Solve MX=B for X by SOR of Gauss-Siedel */
418 /* routine is entitled to scribble on M and B if it wishes */
419 static void
420 sor(real *M, real *B, long n)
422 real t, x, delta, threshold, t2;
423 int row, col;
424 real *X;
425 long it = 0;
427 X = osmalloc(n * ossizeof(real));
429 threshold = 0.00001;
431 printf("reciprocating diagonal\n"); /* TRANSLATE */
433 /* munge diagonal so we can multiply rather than divide */
434 for (row = n - 1; row >= 0; row--) {
435 M(row,row) = 1 / M(row,row);
436 X[row] = 0;
439 printf("starting iteration\n"); /* TRANSLATE */
441 do {
442 /*printf("*");*/
443 it++;
444 t = 0.0;
445 for (row = 0; row < n; row++) {
446 x = B[row];
447 for (col = 0; col < row; col++) x -= M(row,col) * X[col];
448 for (col++; col < n; col++) x -= M(col,row) * X[col];
449 x *= M(row,row);
450 delta = (x - X[row]) * SOR_factor;
451 X[row] += delta;
452 t2 = fabs(delta);
453 if (t2 > t) t = t2;
455 printf("% 6d: %8.6f\n", it, t);
456 } while (t >= threshold && it < 100000);
458 if (t >= threshold) {
459 fprintf(stderr, "*not* converged after %ld iterations\n", it);
460 BUG("iteration stinks");
463 printf("%ld iterations\n", it); /* TRANSLATE */
465 #if 0
466 putnl();
467 for (row = n - 1; row >= 0; row--) {
468 t = 0.0;
469 for (col = 0; col < row; col++) t += M(row, col) * X[col];
470 t += X[row] / M(row, row);
471 for (col = row + 1; col < n; col++)
472 t += M(col, row) * X[col];
473 printf("[ %f %f ]\n", t, B[row]);
475 #endif
477 for (row = n - 1; row >= 0; row--) B[row] = X[row];
479 osfree(X);
480 printf("\ndone\n"); /* TRANSLATE */
482 #endif
484 #if PRINT_MATRICES
485 static void
486 print_matrix(real *M, real *B, long n)
488 long row, col;
489 printf("Matrix, M and vector, B:\n");
490 for (row = 0; row < n; row++) {
491 for (col = 0; col <= row; col++) printf("%6.2f\t", M(row, col));
492 for (; col <= n; col++) printf(" \t");
493 printf("\t%6.2f\n", B[row]);
495 putnl();
496 return;
498 #endif