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
23 # define DEBUG_INVALID 1
37 #define PRINT_MATRICES 0
39 #undef DEBUG_MATRIX_BUILD
40 #define DEBUG_MATRIX_BUILD 0
43 #define DEBUG_MATRIX 0
46 static void print_matrix(real
*M
, real
*B
, long n
);
49 static void choleski(real
*M
, real
*B
, long n
);
52 static void sor(real
*M
, real
*B
, long n
);
55 /* for M(row, col) col must be <= row, so Y <= X */
56 # define M(X, Y) ((real *)M)[((((OSSIZE_T)(X)) * ((X) + 1)) >> 1) + (Y)]
57 /* +(Y>X?0*printf("row<col (line %d)\n",__LINE__):0) */
58 /*#define M_(X, Y) ((real *)M)[((((OSSIZE_T)(Y)) * ((Y) + 1)) >> 1) + (X)]*/
60 static int find_stn_in_tab(node
*stn
);
61 static int add_stn_to_tab(node
*stn
);
62 static void build_matrix(node
*list
);
64 static long n_stn_tab
;
69 solve_matrix(node
*list
)
73 FOR_EACH_STN(stn
, list
) {
78 /* we just need n to be a reasonable estimate >= the number
79 * of stations left after reduction. If memory is
80 * plentiful, we can be crass.
82 stn_tab
= osmalloc((OSSIZE_T
)(n
* ossizeof(pos
*)));
85 FOR_EACH_STN(stn
, list
) {
86 if (!fixed(stn
)) add_stn_to_tab(stn
);
90 /* release unused entries in stn_tab */
91 stn_tab
= osrealloc(stn_tab
, n_stn_tab
* ossizeof(pos
*));
96 FOR_EACH_STN(stn
, list
) {
97 printf("(%8.2f, %8.2f, %8.2f ) ", POS(stn
, 0), POS(stn
, 1), POS(stn
, 2));
98 print_prefix(stn
->name
);
106 #ifdef NO_COVARIANCES
113 build_matrix(node
*list
)
119 if (n_stn_tab
== 0) {
121 puts(msg(/*Network solved by reduction - no simultaneous equations to solve.*/74));
124 /* (OSSIZE_T) cast may be needed if n_stn_tab>=181 */
125 M
= osmalloc((OSSIZE_T
)((((OSSIZE_T
)n_stn_tab
* FACTOR
* (n_stn_tab
* FACTOR
+ 1)) >> 1)) * ossizeof(real
));
126 B
= osmalloc((OSSIZE_T
)(n_stn_tab
* FACTOR
* ossizeof(real
)));
130 out_current_action(msg(/*Solving one equation*/78));
132 out_current_action1(msg(/*Solving %d simultaneous equations*/75), n_stn_tab
);
135 #ifdef NO_COVARIANCES
138 dim
= 0; /* fudge next loop for now */
140 for ( ; dim
>= 0; dim
--) {
144 /* Initialise M and B to zero - zeroing "linearly" will minimise
145 * paging when the matrix is large */
147 int end
= n_stn_tab
* FACTOR
;
148 for (row
= 0; row
< end
; row
++) B
[row
] = (real
)0.0;
149 end
= ((OSSIZE_T
)n_stn_tab
* FACTOR
* (n_stn_tab
* FACTOR
+ 1)) >> 1;
150 for (row
= 0; row
< end
; row
++) M
[row
] = (real
)0.0;
153 /* Construct matrix - Go thru' stn list & add all forward legs between
154 * two unfixed stations to M (so each leg goes on exactly once).
156 * All legs between two fixed stations can be ignored here.
158 * All legs between a fixed and an unfixed station are then considered
159 * from the unfixed end (if we consider them from the fixed end we'd
160 * need to somehow detect when we're at a fixed point cut line and work
161 * out which side we're dealing with at this time. */
162 FOR_EACH_STN(stn
, list
) {
163 #ifdef NO_COVARIANCES
171 #if DEBUG_MATRIX_BUILD
172 print_prefix(stn
->name
);
173 printf(" used: %d colour %ld\n",
174 (!!stn
->leg
[2]) << 2 | (!!stn
-> leg
[1]) << 1 | (!!stn
->leg
[0]),
177 for (dirn
= 0; dirn
<= 2 && stn
->leg
[dirn
]; dirn
++) {
178 #ifdef NO_COVARIANCES
179 printf("Leg %d, vx=%f, reverse=%d, to ", dirn
,
180 stn
->leg
[dirn
]->v
[0], stn
->leg
[dirn
]->l
.reverse
);
182 printf("Leg %d, vx=%f, reverse=%d, to ", dirn
,
183 stn
->leg
[dirn
]->v
[0][0], stn
->leg
[dirn
]->l
.reverse
);
185 print_prefix(stn
->leg
[dirn
]->l
.to
->name
);
189 #endif /* DEBUG_MATRIX_BUILD */
192 f
= find_stn_in_tab(stn
);
193 for (dirn
= 0; dirn
<= 2 && stn
->leg
[dirn
]; dirn
++) {
194 linkfor
*leg
= stn
->leg
[dirn
];
195 node
*to
= leg
->l
.to
;
197 bool fRev
= !data_here(leg
);
198 if (fRev
) leg
= reverse_leg(leg
);
199 /* Ignore equated nodes */
200 #ifdef NO_COVARIANCES
202 if (e
!= (real
)0.0) {
205 B
[f
] += e
* POS(to
, dim
);
213 if (invert_svar(&e
, &leg
->v
)) {
217 adddd(&a
, &POSD(to
), &leg
->d
);
219 subdd(&a
, &POSD(to
), &leg
->d
);
222 for (i
= 0; i
< 3; i
++) {
223 M(f
* FACTOR
+ i
, f
* FACTOR
+ i
) += e
[i
];
224 B
[f
* FACTOR
+ i
] += b
[i
];
226 M(f
* FACTOR
+ 1, f
* FACTOR
) += e
[3];
227 M(f
* FACTOR
+ 2, f
* FACTOR
) += e
[4];
228 M(f
* FACTOR
+ 2, f
* FACTOR
+ 1) += e
[5];
231 } else if (data_here(leg
)) {
232 /* forward leg, unfixed -> unfixed */
233 t
= find_stn_in_tab(to
);
235 printf("Leg %d to %d, var %f, delta %f\n", f
, t
, e
,
238 /* Ignore equated nodes & lollipops */
239 #ifdef NO_COVARIANCES
241 if (t
!= f
&& e
!= (real
)0.0) {
246 if (f
< t
) M(t
,f
) -= e
; else M(f
,t
) -= e
;
252 if (t
!= f
&& invert_svar(&e
, &leg
->v
)) {
254 mulsd(&a
, &e
, &leg
->d
);
255 for (i
= 0; i
< 3; i
++) {
256 M(f
* FACTOR
+ i
, f
* FACTOR
+ i
) += e
[i
];
257 M(t
* FACTOR
+ i
, t
* FACTOR
+ i
) += e
[i
];
259 M(t
* FACTOR
+ i
, f
* FACTOR
+ i
) -= e
[i
];
261 M(f
* FACTOR
+ i
, t
* FACTOR
+ i
) -= e
[i
];
262 B
[f
* FACTOR
+ i
] -= a
[i
];
263 B
[t
* FACTOR
+ i
] += a
[i
];
265 M(f
* FACTOR
+ 1, f
* FACTOR
) += e
[3];
266 M(t
* FACTOR
+ 1, t
* FACTOR
) += e
[3];
267 M(f
* FACTOR
+ 2, f
* FACTOR
) += e
[4];
268 M(t
* FACTOR
+ 2, t
* FACTOR
) += e
[4];
269 M(f
* FACTOR
+ 2, f
* FACTOR
+ 1) += e
[5];
270 M(t
* FACTOR
+ 2, t
* FACTOR
+ 1) += e
[5];
272 M(t
* FACTOR
+ 1, f
* FACTOR
) -= e
[3];
273 M(t
* FACTOR
, f
* FACTOR
+ 1) -= e
[3];
274 M(t
* FACTOR
+ 2, f
* FACTOR
) -= e
[4];
275 M(t
* FACTOR
, f
* FACTOR
+ 2) -= e
[4];
276 M(t
* FACTOR
+ 2, f
* FACTOR
+ 1) -= e
[5];
277 M(t
* FACTOR
+ 1, f
* FACTOR
+ 2) -= e
[5];
279 M(f
* FACTOR
+ 1, t
* FACTOR
) -= e
[3];
280 M(f
* FACTOR
, t
* FACTOR
+ 1) -= e
[3];
281 M(f
* FACTOR
+ 2, t
* FACTOR
) -= e
[4];
282 M(f
* FACTOR
, t
* FACTOR
+ 2) -= e
[4];
283 M(f
* FACTOR
+ 2, t
* FACTOR
+ 1) -= e
[5];
284 M(f
* FACTOR
+ 1, t
* FACTOR
+ 2) -= e
[5];
294 print_matrix(M
, B
, n_stn_tab
* FACTOR
); /* 'ave a look! */
298 /* defined in network.c, may be altered by -z<letters> on command line */
299 if (optimize
& BITA('i'))
300 sor(M
, B
, n_stn_tab
* FACTOR
);
303 choleski(M
, B
, n_stn_tab
* FACTOR
);
307 for (m
= (int)(n_stn_tab
- 1); m
>= 0; m
--) {
308 #ifdef NO_COVARIANCES
309 stn_tab
[m
]->p
[dim
] = B
[m
];
311 SVX_ASSERT2(pos_fixed(stn_tab
[m
]),
312 "setting station coordinates didn't mark pos as fixed");
316 for (i
= 0; i
< 3; i
++) {
317 stn_tab
[m
]->p
[i
] = B
[m
* FACTOR
+ i
];
319 SVX_ASSERT2(pos_fixed(stn_tab
[m
]),
320 "setting station coordinates didn't mark pos as fixed");
323 #if EXPLICIT_FIXED_FLAG
324 for (m
= n_stn_tab
- 1; m
>= 0; m
--) fixpos(stn_tab
[m
]);
333 find_stn_in_tab(node
*stn
)
336 pos
*p
= stn
->name
->pos
;
337 while (stn_tab
[i
] != p
)
338 if (++i
== n_stn_tab
) {
340 fputs("Station ", stderr
);
341 fprint_prefix(stderr
, stn
->name
);
342 fputs(" not in table\n\n", stderr
);
345 print_prefix(stn
->name
);
346 printf(" used: %d colour %d\n",
347 (!!stn
->leg
[2])<<2 | (!!stn
->leg
[1])<<1 | (!!stn
->leg
[0]),
350 fatalerror(/*Bug in program detected! Please report this to the authors*/11);
356 add_stn_to_tab(node
*stn
)
359 pos
*p
= stn
->name
->pos
;
360 for (i
= 0; i
< n_stn_tab
; i
++) {
361 if (stn_tab
[i
] == p
) return i
;
363 stn_tab
[n_stn_tab
++] = p
;
367 /* Solve MX=B for X by Choleski factorisation - modified Choleski actually
368 * since we factor into LDL' while Choleski is just LL'
370 /* Note M must be symmetric positive definite */
371 /* routine is entitled to scribble on M and B if it wishes */
373 choleski(real
*M
, real
*B
, long n
)
377 for (j
= 1; j
< n
; j
++) {
379 for (i
= 0; i
< j
; i
++) {
381 for (k
= 0; k
< i
; k
++) V
+= M(i
,k
) * M(j
,k
) * M(k
,k
);
382 M(j
,i
) = (M(j
,i
) - V
) / M(i
,i
);
385 for (k
= 0; k
< j
; k
++) V
+= M(j
,k
) * M(j
,k
) * M(k
,k
);
386 M(j
,j
) -= V
; /* may be best to add M() last for numerical reasons too */
389 /* Multiply x by L inverse */
390 for (i
= 0; i
< n
- 1; i
++) {
391 for (j
= i
+ 1; j
< n
; j
++) {
392 B
[j
] -= M(j
,i
) * B
[i
];
396 /* Multiply x by D inverse */
397 for (i
= 0; i
< n
; i
++) {
401 /* Multiply x by (L transpose) inverse */
402 for (i
= (int)(n
- 1); i
> 0; i
--) {
403 for (j
= i
- 1; j
>= 0; j
--) {
404 B
[j
] -= M(i
,j
) * B
[i
];
408 /* printf("\n%ld/%ld\n\n",flops,flopsTot); */
412 /* factor to use for SOR (must have 1 <= SOR_factor < 2) */
413 #define SOR_factor 1.93 /* 1.95 */
415 /* Solve MX=B for X by SOR of Gauss-Siedel */
416 /* routine is entitled to scribble on M and B if it wishes */
418 sor(real
*M
, real
*B
, long n
)
420 real t
, x
, delta
, threshold
, t2
;
425 X
= osmalloc(n
* ossizeof(real
));
429 printf("reciprocating diagonal\n"); /* TRANSLATE */
431 /* munge diagonal so we can multiply rather than divide */
432 for (row
= n
- 1; row
>= 0; row
--) {
433 M(row
,row
) = 1 / M(row
,row
);
437 printf("starting iteration\n"); /* TRANSLATE */
443 for (row
= 0; row
< n
; row
++) {
445 for (col
= 0; col
< row
; col
++) x
-= M(row
,col
) * X
[col
];
446 for (col
++; col
< n
; col
++) x
-= M(col
,row
) * X
[col
];
448 delta
= (x
- X
[row
]) * SOR_factor
;
453 printf("% 6d: %8.6f\n", it
, t
);
454 } while (t
>= threshold
&& it
< 100000);
456 if (t
>= threshold
) {
457 fprintf(stderr
, "*not* converged after %ld iterations\n", it
);
458 BUG("iteration stinks");
461 printf("%ld iterations\n", it
); /* TRANSLATE */
465 for (row
= n
- 1; row
>= 0; row
--) {
467 for (col
= 0; col
< row
; col
++) t
+= M(row
, col
) * X
[col
];
468 t
+= X
[row
] / M(row
, row
);
469 for (col
= row
+ 1; col
< n
; col
++)
470 t
+= M(col
, row
) * X
[col
];
471 printf("[ %f %f ]\n", t
, B
[row
]);
475 for (row
= n
- 1; row
>= 0; row
--) B
[row
] = X
[row
];
478 printf("\ndone\n"); /* TRANSLATE */
484 print_matrix(real
*M
, real
*B
, long n
)
487 printf("Matrix, M and vector, B:\n");
488 for (row
= 0; row
< n
; row
++) {
489 for (col
= 0; col
<= row
; col
++) printf("%6.2f\t", M(row
, col
));
490 for (; col
<= n
; col
++) printf(" \t");
491 printf("\t%6.2f\n", B
[row
]);