source: git/src/matrix.c @ 3b8b342

stereo-2025
Last change on this file since 3b8b342 was 3b8b342, checked in by Olly Betts <olly@…>, 12 months ago

Fix warnings in SOR code

This is some old experimental code to solve the matrix iteratively.
It still works if enabled (but seems to be much slower) but there
were some compiler warnings.

  • Property mode set to 100644
File size: 12.1 KB
RevLine 
[421b7d2]1/* matrix.c
[d1b1380]2 * Matrix building and solving routines
[a4adf09]3 * Copyright (C) 1993-2003,2010,2013 Olly Betts
[846746e]4 *
[89231c4]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.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]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
[ecbc6c18]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
[d1b1380]18 */
19
[2164fa4]20/*#define SOR 1*/
[702f518]21
[032ed06]22#if 0
23# define DEBUG_INVALID 1
24#endif
25
[4c83f84]26#include <config.h>
[d1b1380]27
28#include "debug.h"
[a420b49]29#include "cavern.h"
[c082b69]30#include "filename.h"
31#include "message.h"
[d1b1380]32#include "netbits.h"
33#include "matrix.h"
34#include "out.h"
35
36#undef PRINT_MATRICES
37#define PRINT_MATRICES 0
38
39#undef DEBUG_MATRIX_BUILD
40#define DEBUG_MATRIX_BUILD 0
41
42#undef DEBUG_MATRIX
43#define DEBUG_MATRIX 0
44
45#if PRINT_MATRICES
[9965b2b]46static void print_matrix(real *M, real *B, long n);
[d1b1380]47#endif
48
[9965b2b]49static void choleski(real *M, real *B, long n);
[3fde384f]50
[d1b1380]51#ifdef SOR
[9965b2b]52static void sor(real *M, real *B, long n);
[d1b1380]53#endif
54
[a420b49]55/* for M(row, col) col must be <= row, so Y <= X */
[9965b2b]56# define M(X, Y) ((real *)M)[((((OSSIZE_T)(X)) * ((X) + 1)) >> 1) + (Y)]
[421b7d2]57              /* +(Y>X?0*printf("row<col (line %d)\n",__LINE__):0) */
[9965b2b]58/*#define M_(X, Y) ((real *)M)[((((OSSIZE_T)(Y)) * ((Y) + 1)) >> 1) + (X)]*/
[d1b1380]59
[eb18f4d]60static void build_matrix(node *list);
[d1b1380]61
62static long n_stn_tab;
63
[c19f129]64static pos **stn_tab;
[d1b1380]65
[032ed06]66extern void
[d9b5db53]67solve_matrix(node *list)
[032ed06]68{
69   node *stn;
[702f518]70   long n = 0;
[d9b5db53]71   FOR_EACH_STN(stn, list) {
[103c026]72      if (!fixed(stn))
73          n++;
[032ed06]74   }
75   if (n == 0) return;
76
[86907b0]77   /* We need to allocate stn_tab with one entry per unfixed cluster of equated
78    * stations, but it's much simpler to count the number of unfixed nodes.
79    * This will over-count stations with more than 3 legs and equated stations
80    * but in a typical survey that's a small minority of stations.
[032ed06]81    */
[66de220]82   stn_tab = osmalloc((OSSIZE_T)(n * ossizeof(pos*)));
[4f613e0]83   n_stn_tab = 0;
[cb3d1e2]84
[103c026]85   /* We store the stn_tab index in stn->colour for quick and easy lookup in
86    * build_matrix().
87    */
[d9b5db53]88   FOR_EACH_STN(stn, list) {
[103c026]89      if (!fixed(stn)) {
90          int i;
91          pos *p = stn->name->pos;
92          for (i = 0; i < n_stn_tab; i++) {
93              if (stn_tab[i] == p)
94                  break;
95          }
96          if (i == n_stn_tab)
97              stn_tab[n_stn_tab++] = p;
98          stn->colour = i;
99      } else {
100          stn->colour = -1;
101      }
[032ed06]102   }
103
[eb18f4d]104   build_matrix(list);
[2c9c3ff]105#if DEBUG_MATRIX
[2164fa4]106   FOR_EACH_STN(stn, list) {
[2aa930f]107      printf("(%8.2f, %8.2f, %8.2f ) ", POS(stn, 0), POS(stn, 1), POS(stn, 2));
[2164fa4]108      print_prefix(stn->name);
[2aa930f]109      putnl();
[2164fa4]110   }
[2c9c3ff]111#endif
[4f613e0]112
113   osfree(stn_tab);
[032ed06]114}
[d1b1380]115
[3fde384f]116#ifdef NO_COVARIANCES
[702f518]117# define FACTOR 1
[3fde384f]118#else
[702f518]119# define FACTOR 3
[3fde384f]120#endif
121
[a420b49]122static void
[eb18f4d]123build_matrix(node *list)
[a420b49]124{
[3e36e2ef]125   SVX_ASSERT(n_stn_tab > 0);
[eb18f4d]126   /* (OSSIZE_T) cast may be needed if n_stn_tab>=181 */
[5bb3dc4]127   real *M = osmalloc((OSSIZE_T)((((OSSIZE_T)n_stn_tab * FACTOR * (n_stn_tab * FACTOR + 1)) >> 1)) * ossizeof(real));
128   real *B = osmalloc((OSSIZE_T)(n_stn_tab * FACTOR * ossizeof(real)));
[dbd68203]129
[647407d]130   if (!fQuiet) {
[a4adf09]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);
[dbd68203]135   }
136
[3fde384f]137#ifdef NO_COVARIANCES
[5bb3dc4]138   int dim = 2;
[3fde384f]139#else
[5bb3dc4]140   int dim = 0; /* fudge next loop for now */
[3fde384f]141#endif
[a420b49]142   for ( ; dim >= 0; dim--) {
[2164fa4]143      node *stn;
144      int row;
145
[907fe10]146      /* Initialise M and B to zero - zeroing "linearly" will minimise
[421b7d2]147       * paging when the matrix is large */
[66de220]148      {
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;
153      }
[dbd68203]154
[3c7ab9a]155      /* Construct matrix by going through the stn list.
[421b7d2]156       *
[907fe10]157       * All legs between two fixed stations can be ignored here.
[421b7d2]158       *
[3c7ab9a]159       * Other legs we want to add exactly once to M.  To achieve this we
160       * wan to:
161       *
162       * - add forward legs between two unfixed stations,
163       *
164       * - add legs from unfixed stations to fixed stations (we do them from
165       *   the unfixed end so we don't need to detect when we're at a fixed
166       *   point cut line and determine which side we're currently dealing
167       *   with).
168       *
169       * To implement this, we only look at legs from unfixed stations and add
170       * a leg if to a fixed station, or to an unfixed station and it's a
171       * forward leg.
172       */
[d9b5db53]173      FOR_EACH_STN(stn, list) {
[2164fa4]174#ifdef NO_COVARIANCES
175         real e;
176#else
[dac18d8]177         svar e;
[eb18f4d]178         delta a;
[2164fa4]179#endif
[b5d3988]180#if DEBUG_MATRIX_BUILD
[dbd68203]181         print_prefix(stn->name);
[b5d3988]182         printf(" used: %d colour %ld\n",
[a420b49]183                (!!stn->leg[2]) << 2 | (!!stn -> leg[1]) << 1 | (!!stn->leg[0]),
[b5d3988]184                stn->colour);
[3fde384f]185
[5bb3dc4]186         for (int dirn = 0; dirn <= 2 && stn->leg[dirn]; dirn++) {
[b5d3988]187#ifdef NO_COVARIANCES
[907fe10]188            printf("Leg %d, vx=%f, reverse=%d, to ", dirn,
189                   stn->leg[dirn]->v[0], stn->leg[dirn]->l.reverse);
[b5d3988]190#else
[907fe10]191            printf("Leg %d, vx=%f, reverse=%d, to ", dirn,
192                   stn->leg[dirn]->v[0][0], stn->leg[dirn]->l.reverse);
[b5d3988]193#endif
[907fe10]194            print_prefix(stn->leg[dirn]->l.to->name);
195            putnl();
196         }
[dbd68203]197         putnl();
[d1b1380]198#endif /* DEBUG_MATRIX_BUILD */
[b5d3988]199
[907fe10]200         if (!fixed(stn)) {
[103c026]201            int f = stn->colour;
[5bb3dc4]202            for (int dirn = 0; dirn <= 2 && stn->leg[dirn]; dirn++) {
[907fe10]203               linkfor *leg = stn->leg[dirn];
204               node *to = leg->l.to;
205               if (fixed(to)) {
206                  bool fRev = !data_here(leg);
207                  if (fRev) leg = reverse_leg(leg);
208                  /* Ignore equated nodes */
[3fde384f]209#ifdef NO_COVARIANCES
[907fe10]210                  e = leg->v[dim];
211                  if (e != (real)0.0) {
212                     e = ((real)1.0) / e;
213                     M(f,f) += e;
[f52dcc7]214                     B[f] += e * POS(to, dim);
[907fe10]215                     if (fRev) {
[f52dcc7]216                        B[f] += leg->d[dim];
[907fe10]217                     } else {
[f52dcc7]218                        B[f] -= leg->d[dim];
[564f471]219                     }
[907fe10]220                  }
[3fde384f]221#else
[907fe10]222                  if (invert_svar(&e, &leg->v)) {
223                     if (fRev) {
224                        adddd(&a, &POSD(to), &leg->d);
225                     } else {
226                        subdd(&a, &POSD(to), &leg->d);
227                     }
[5bb3dc4]228                     delta b;
[907fe10]229                     mulsd(&b, &e, &a);
[5bb3dc4]230                     for (int i = 0; i < 3; i++) {
[907fe10]231                        M(f * FACTOR + i, f * FACTOR + i) += e[i];
232                        B[f * FACTOR + i] += b[i];
[564f471]233                     }
[907fe10]234                     M(f * FACTOR + 1, f * FACTOR) += e[3];
235                     M(f * FACTOR + 2, f * FACTOR) += e[4];
236                     M(f * FACTOR + 2, f * FACTOR + 1) += e[5];
237                  }
[3fde384f]238#endif
[907fe10]239               } else if (data_here(leg)) {
240                  /* forward leg, unfixed -> unfixed */
[103c026]241                  int t = to->colour;
[d1b1380]242#if DEBUG_MATRIX
[907fe10]243                  printf("Leg %d to %d, var %f, delta %f\n", f, t, e,
244                         leg->d[dim]);
[d1b1380]245#endif
[907fe10]246                  /* Ignore equated nodes & lollipops */
[3fde384f]247#ifdef NO_COVARIANCES
[907fe10]248                  e = leg->v[dim];
249                  if (t != f && e != (real)0.0) {
250                     e = ((real)1.0) / e;
251                     M(f,f) += e;
252                     M(t,t) += e;
253                     if (f < t) M(t,f) -= e; else M(f,t) -= e;
[5bb3dc4]254                     real a = e * leg->d[dim];
[907fe10]255                     B[f] -= a;
256                     B[t] += a;
257                  }
[3fde384f]258#else
[907fe10]259                  if (t != f && invert_svar(&e, &leg->v)) {
260                     mulsd(&a, &e, &leg->d);
[5bb3dc4]261                     for (int i = 0; i < 3; i++) {
[907fe10]262                        M(f * FACTOR + i, f * FACTOR + i) += e[i];
263                        M(t * FACTOR + i, t * FACTOR + i) += e[i];
264                        if (f < t)
265                           M(t * FACTOR + i, f * FACTOR + i) -= e[i];
266                        else
267                           M(f * FACTOR + i, t * FACTOR + i) -= e[i];
268                        B[f * FACTOR + i] -= a[i];
269                        B[t * FACTOR + i] += a[i];
270                     }
271                     M(f * FACTOR + 1, f * FACTOR) += e[3];
272                     M(t * FACTOR + 1, t * FACTOR) += e[3];
273                     M(f * FACTOR + 2, f * FACTOR) += e[4];
274                     M(t * FACTOR + 2, t * FACTOR) += e[4];
275                     M(f * FACTOR + 2, f * FACTOR + 1) += e[5];
276                     M(t * FACTOR + 2, t * FACTOR + 1) += e[5];
277                     if (f < t) {
278                        M(t * FACTOR + 1, f * FACTOR) -= e[3];
279                        M(t * FACTOR, f * FACTOR + 1) -= e[3];
280                        M(t * FACTOR + 2, f * FACTOR) -= e[4];
281                        M(t * FACTOR, f * FACTOR + 2) -= e[4];
282                        M(t * FACTOR + 2, f * FACTOR + 1) -= e[5];
283                        M(t * FACTOR + 1, f * FACTOR + 2) -= e[5];
284                     } else {
285                        M(f * FACTOR + 1, t * FACTOR) -= e[3];
286                        M(f * FACTOR, t * FACTOR + 1) -= e[3];
287                        M(f * FACTOR + 2, t * FACTOR) -= e[4];
288                        M(f * FACTOR, t * FACTOR + 2) -= e[4];
289                        M(f * FACTOR + 2, t * FACTOR + 1) -= e[5];
290                        M(f * FACTOR + 1, t * FACTOR + 2) -= e[5];
[dbd68203]291                     }
292                  }
[907fe10]293#endif
[564f471]294               }
[907fe10]295            }
[dbd68203]296         }
[d1b1380]297      }
298
299#if PRINT_MATRICES
[eb18f4d]300      print_matrix(M, B, n_stn_tab * FACTOR); /* 'ave a look! */
[d1b1380]301#endif
302
303#ifdef SOR
[032ed06]304      /* defined in network.c, may be altered by -z<letters> on command line */
[a420b49]305      if (optimize & BITA('i'))
[eb18f4d]306         sor(M, B, n_stn_tab * FACTOR);
[dbd68203]307      else
[d1b1380]308#endif
[eb18f4d]309         choleski(M, B, n_stn_tab * FACTOR);
[d1b1380]310
[dbd68203]311      {
[5bb3dc4]312         for (int m = (int)(n_stn_tab - 1); m >= 0; m--) {
[3fde384f]313#ifdef NO_COVARIANCES
[c19f129]314            stn_tab[m]->p[dim] = B[m];
[032ed06]315            if (dim == 0) {
[4c07c51]316               SVX_ASSERT2(pos_fixed(stn_tab[m]),
[032ed06]317                       "setting station coordinates didn't mark pos as fixed");
318            }
[3fde384f]319#else
[5bb3dc4]320            for (int i = 0; i < 3; i++) {
[c19f129]321               stn_tab[m]->p[i] = B[m * FACTOR + i];
[702f518]322            }
[4c07c51]323            SVX_ASSERT2(pos_fixed(stn_tab[m]),
[032ed06]324                    "setting station coordinates didn't mark pos as fixed");
[3fde384f]325#endif
[a420b49]326         }
[d1b1380]327#if EXPLICIT_FIXED_FLAG
[5bb3dc4]328         for (int m = n_stn_tab - 1; m >= 0; m--) fixpos(stn_tab[m]);
[d1b1380]329#endif
[dbd68203]330      }
331   }
332   osfree(B);
333   osfree(M);
[d1b1380]334}
335
[702f518]336/* Solve MX=B for X by Choleski factorisation - modified Choleski actually
337 * since we factor into LDL' while Choleski is just LL'
338 */
[d1b1380]339/* Note M must be symmetric positive definite */
340/* routine is entitled to scribble on M and B if it wishes */
[a420b49]341static void
[9965b2b]342choleski(real *M, real *B, long n)
[a420b49]343{
[5bb3dc4]344   for (int j = 1; j < n; j++) {
[3fde384f]345      real V;
[5bb3dc4]346      for (int i = 0; i < j; i++) {
[421b7d2]347         V = (real)0.0;
[5bb3dc4]348         for (int k = 0; k < i; k++) V += M(i,k) * M(j,k) * M(k,k);
[a420b49]349         M(j,i) = (M(j,i) - V) / M(i,i);
[dbd68203]350      }
351      V = (real)0.0;
[5bb3dc4]352      for (int k = 0; k < j; k++) V += M(j,k) * M(j,k) * M(k,k);
[3fde384f]353      M(j,j) -= V; /* may be best to add M() last for numerical reasons too */
[dbd68203]354   }
[d1b1380]355
[dbd68203]356   /* Multiply x by L inverse */
[5bb3dc4]357   for (int i = 0; i < n - 1; i++) {
358      for (int j = i + 1; j < n; j++) {
[dbd68203]359         B[j] -= M(j,i) * B[i];
[3fde384f]360      }
[dbd68203]361   }
[d1b1380]362
[dbd68203]363   /* Multiply x by D inverse */
[5bb3dc4]364   for (int i = 0; i < n; i++) {
[dbd68203]365      B[i] /= M(i,i);
[3fde384f]366   }
367
368   /* Multiply x by (L transpose) inverse */
[5bb3dc4]369   for (int i = (int)(n - 1); i > 0; i--) {
370      for (int j = i - 1; j >= 0; j--) {
[421b7d2]371         B[j] -= M(i,j) * B[i];
[3fde384f]372      }
[dbd68203]373   }
[d1b1380]374
[dbd68203]375   /* printf("\n%ld/%ld\n\n",flops,flopsTot); */
[d1b1380]376}
377
378#ifdef SOR
379/* factor to use for SOR (must have 1 <= SOR_factor < 2) */
[702f518]380#define SOR_factor 1.93 /* 1.95 */
[d1b1380]381
382/* Solve MX=B for X by SOR of Gauss-Siedel */
383/* routine is entitled to scribble on M and B if it wishes */
[a420b49]384static void
[9965b2b]385sor(real *M, real *B, long n)
[a420b49]386{
[dbd68203]387   long it = 0;
[d1b1380]388
[5bb3dc4]389   real *X = osmalloc(n * ossizeof(real));
[d1b1380]390
[5bb3dc4]391   const real threshold = 0.00001;
[d1b1380]392
[647407d]393   printf("reciprocating diagonal\n"); /* TRANSLATE */
[d1b1380]394
[3fde384f]395   /* munge diagonal so we can multiply rather than divide */
[5bb3dc4]396   for (int row = n - 1; row >= 0; row--) {
[dbd68203]397      M(row,row) = 1 / M(row,row);
[702f518]398      X[row] = 0;
[dbd68203]399   }
[d1b1380]400
[647407d]401   printf("starting iteration\n"); /* TRANSLATE */
[d1b1380]402
[5bb3dc4]403   real t;
[dbd68203]404   do {
405      /*printf("*");*/
406      it++;
407      t = 0.0;
[5bb3dc4]408      for (int row = 0; row < n; row++) {
409         real x = B[row];
410         int col;
[a420b49]411         for (col = 0; col < row; col++) x -= M(row,col) * X[col];
412         for (col++; col < n; col++) x -= M(col,row) * X[col];
[dbd68203]413         x *= M(row,row);
[3b8b342]414         real sor_delta = (x - X[row]) * SOR_factor;
415         X[row] += sor_delta;
416         real t2 = fabs(sor_delta);
[dbd68203]417         if (t2 > t) t = t2;
418      }
[3b8b342]419      printf("% 6ld: %8.6f\n", it, t);
[dbd68203]420   } while (t >= threshold && it < 100000);
[d1b1380]421
[dbd68203]422   if (t >= threshold) {
423      fprintf(stderr, "*not* converged after %ld iterations\n", it);
424      BUG("iteration stinks");
425   }
[d1b1380]426
[647407d]427   printf("%ld iterations\n", it); /* TRANSLATE */
[d1b1380]428
429#if 0
[dbd68203]430   putnl();
[5bb3dc4]431   for (int row = n - 1; row >= 0; row--) {
[dbd68203]432      t = 0.0;
[5bb3dc4]433      for (int col = 0; col < row; col++) t += M(row, col) * X[col];
[a420b49]434      t += X[row] / M(row, row);
435      for (col = row + 1; col < n; col++)
436         t += M(col, row) * X[col];
[b5d3988]437      printf("[ %f %f ]\n", t, B[row]);
[dbd68203]438   }
[d1b1380]439#endif
440
[5bb3dc4]441   for (int row = n - 1; row >= 0; row--) B[row] = X[row];
[d1b1380]442
[dbd68203]443   osfree(X);
[647407d]444   printf("\ndone\n"); /* TRANSLATE */
[dbd68203]445}
[d1b1380]446#endif
447
448#if PRINT_MATRICES
[a420b49]449static void
[9965b2b]450print_matrix(real *M, real *B, long n)
[a420b49]451{
[dbd68203]452   printf("Matrix, M and vector, B:\n");
[5bb3dc4]453   for (long row = 0; row < n; row++) {
454      long col;
[a420b49]455      for (col = 0; col <= row; col++) printf("%6.2f\t", M(row, col));
456      for (; col <= n; col++) printf(" \t");
[dbd68203]457      printf("\t%6.2f\n", B[row]);
458   }
459   putnl();
460   return;
[d1b1380]461}
462#endif
Note: See TracBrowser for help on using the repository browser.