source: git/src/netbits.c

walls-data-hanging-as-warning
Last change on this file was 4c83f84, checked in by Olly Betts <olly@…>, 12 days ago

Don't check HAVE_CONFIG_H in most cases

This check is only useful for img.c, which is intended to be usable
outside of Survex (and had fallbacks for functions which may not be
available which will get used if built in a non-autotools project).
For all the other source files it's just useless boilerplate.

  • Property mode set to 100644
File size: 22.2 KB
Line 
1/* netbits.c
2 * Miscellaneous primitive network routines for Survex
3 * Copyright (C) 1992-2024 Olly Betts
4 *
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.
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
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
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
18 */
19
20#include <config.h>
21
22#if 0
23# define DEBUG_INVALID 1
24#endif
25
26#include "debug.h"
27#include "cavern.h"
28#include "filename.h"
29#include "message.h"
30#include "netbits.h"
31#include "datain.h" /* for compile_error */
32#include "validate.h" /* for compile_error */
33#include <math.h>
34
35#define THRESHOLD (REAL_EPSILON * 1000) /* 100 was too small */
36
37node *stn_iter = NULL; /* for FOR_EACH_STN */
38
39static struct {
40   prefix * to_name;
41   prefix * fr_name;
42   linkfor * leg;
43   int n;
44} last_leg = { NULL, NULL, NULL, 0 };
45
46void clear_last_leg(void) {
47   last_leg.to_name = NULL;
48}
49
50static char freeleg(node **stnptr);
51
52#ifdef NO_COVARIANCES
53static void check_var(/*const*/ var *v) {
54   int bad = 0;
55   int i;
56
57   for (i = 0; i < 3; i++) {
58      if (isnan(v[i])
59         printf("*** NaN!!!\n"), bad = 1;
60   }
61   if (bad) print_var(v);
62   return;
63}
64#else
65#define V(A,B) ((*v)[A][B])
66static void check_var(/*const*/ var *v) {
67   int bad = 0;
68   int ok = 0;
69   int i, j;
70#if DEBUG_INVALID
71   real det = 0.0;
72#endif
73
74   for (i = 0; i < 3; i++) {
75      for (j = 0; j < 3; j++) {
76         if (isnan(V(i, j)))
77            printf("*** NaN!!!\n"), bad = 1, ok = 1;
78         if (V(i, j) != 0.0) ok = 1;
79      }
80   }
81   if (!ok) return; /* ignore all-zero matrices */
82
83#if DEBUG_INVALID
84   for (i = 0; i < 3; i++) {
85      det += V(i, 0) * (V((i + 1) % 3, 1) * V((i + 2) % 3, 2) -
86                        V((i + 1) % 3, 2) * V((i + 2) % 3, 1));
87   }
88
89   if (fabs(det) < THRESHOLD)
90      printf("*** Singular!!!\n"), bad = 1;
91#endif
92
93#if 0
94   /* don't check this - it isn't always the case! */
95   if (fabs(V(0,1) - V(1,0)) > THRESHOLD ||
96       fabs(V(0,2) - V(2,0)) > THRESHOLD ||
97       fabs(V(1,2) - V(2,1)) > THRESHOLD)
98      printf("*** Not symmetric!!!\n"), bad = 1;
99   if (V(0,0) <= 0.0 || V(1,1) <= 0.0 || V(2,2) <= 0.0)
100      printf("*** Not positive definite (diag <= 0)!!!\n"), bad = 1;
101   if (sqrd(V(0,1)) >= V(0,0)*V(1,1) || sqrd(V(0,2)) >= V(0,0)*V(2,2) ||
102       sqrd(V(1,0)) >= V(0,0)*V(1,1) || sqrd(V(2,0)) >= V(0,0)*V(2,2) ||
103       sqrd(V(1,2)) >= V(2,2)*V(1,1) || sqrd(V(2,1)) >= V(2,2)*V(1,1))
104      printf("*** Not positive definite (off diag^2 >= diag product)!!!\n"), bad = 1;
105#endif
106   if (bad) print_var(*v);
107}
108
109#define SN(V,A,B) ((*(V))[(A)==(B)?(A):2+(A)+(B)])
110#define S(A,B) SN(v,A,B)
111
112static void check_svar(/*const*/ svar *v) {
113   int bad = 0;
114   int ok = 0;
115   int i;
116#if DEBUG_INVALID
117   real det = 0.0;
118#endif
119
120   for (i = 0; i < 6; i++) {
121      if (isnan((*v)[i]))
122         printf("*** NaN!!!\n"), bad = 1, ok = 1;
123      if ((*v)[i] != 0.0) ok = 1;
124   }
125   if (!ok) return; /* ignore all-zero matrices */
126
127#if DEBUG_INVALID
128   for (i = 0; i < 3; i++) {
129      det += S(i, 0) * (S((i + 1) % 3, 1) * S((i + 2) % 3, 2) -
130                        S((i + 1) % 3, 2) * S((i + 2) % 3, 1));
131   }
132
133   if (fabs(det) < THRESHOLD)
134      printf("*** Singular!!!\n"), bad = 1;
135#endif
136
137#if 0
138   /* don't check this - it isn't always the case! */
139   if ((*v)[0] <= 0.0 || (*v)[1] <= 0.0 || (*v)[2] <= 0.0)
140      printf("*** Not positive definite (diag <= 0)!!!\n"), bad = 1;
141   if (sqrd((*v)[3]) >= (*v)[0]*(*v)[1] ||
142       sqrd((*v)[4]) >= (*v)[0]*(*v)[2] ||
143       sqrd((*v)[5]) >= (*v)[1]*(*v)[2])
144      printf("*** Not positive definite (off diag^2 >= diag product)!!!\n"), bad = 1;
145#endif
146   if (bad) print_svar(*v);
147}
148#endif
149
150static void check_d(/*const*/ delta *d) {
151   int bad = 0;
152   int i;
153
154   for (i = 0; i < 3; i++) {
155      if (isnan((*d)[i]))
156         printf("*** NaN!!!\n"), bad = 1;
157   }
158
159   if (bad) printf("(%4.2f,%4.2f,%4.2f)\n", (*d)[0], (*d)[1], (*d)[2]);
160}
161
162/* insert at head of double-linked list */
163void
164add_stn_to_list(node **list, node *stn) {
165   SVX_ASSERT(list);
166   SVX_ASSERT(stn);
167   SVX_ASSERT(stn_iter != stn); /* if it does, we're still on a list... */
168#if 0
169   printf("add_stn_to_list(%p, [%p] ", list, stn);
170   if (stn->name) print_prefix(stn->name);
171   printf(")\n");
172#endif
173   stn->next = *list;
174   stn->prev = NULL;
175   if (*list) (*list)->prev = stn;
176   *list = stn;
177}
178
179/* remove from double-linked list */
180void
181remove_stn_from_list(node **list, node *stn) {
182   SVX_ASSERT(list);
183   SVX_ASSERT(stn);
184#if 0
185   printf("remove_stn_from_list(%p, [%p] ", list, stn);
186   if (stn->name) print_prefix(stn->name);
187   printf(")\n");
188#endif
189#if DEBUG_INVALID
190     {
191        /* check station is actually in this list */
192        node *stn_to_remove_is_in_list = *list;
193        validate();
194        while (stn_to_remove_is_in_list != stn) {
195           SVX_ASSERT(stn_to_remove_is_in_list);
196           stn_to_remove_is_in_list = stn_to_remove_is_in_list->next;
197        }
198     }
199#endif
200   /* adjust the iterator if it points to the element we're deleting */
201   if (stn_iter == stn) stn_iter = stn_iter->next;
202   /* need a special case if we're removing the list head */
203   if (stn->prev == NULL) {
204      *list = stn->next;
205      if (*list) (*list)->prev = NULL;
206   } else {
207      stn->prev->next = stn->next;
208      if (stn->next) stn->next->prev = stn->prev;
209   }
210}
211
212/* Create (uses osmalloc) a forward leg containing the data in leg, or
213 * the reversed data in the reverse of leg, if leg doesn't hold data
214 */
215linkfor *
216copy_link(linkfor *leg)
217{
218   linkfor *legOut;
219   int d;
220   legOut = osnew(linkfor);
221   if (data_here(leg)) {
222      for (d = 2; d >= 0; d--) legOut->d[d] = leg->d[d];
223   } else {
224      leg = reverse_leg(leg);
225      SVX_ASSERT(data_here(leg));
226      for (d = 2; d >= 0; d--) legOut->d[d] = -leg->d[d];
227   }
228#if 1
229# ifndef NO_COVARIANCES
230   check_svar(&(leg->v));
231     {
232        int i;
233        for (i = 0; i < 6; i++) legOut->v[i] = leg->v[i];
234     }
235# else
236   for (d = 2; d >= 0; d--) legOut->v[d] = leg->v[d];
237# endif
238#else
239   memcpy(legOut->v, leg->v, sizeof(svar));
240#endif
241   legOut->meta = pcs->meta;
242   if (pcs->meta) ++pcs->meta->ref_count;
243   return legOut;
244}
245
246/* Adds to the forward leg “leg”, the data in leg2, or the reversed data
247 * in the reverse of leg2, if leg2 doesn't hold data
248 */
249linkfor *
250addto_link(linkfor *leg, const linkfor *leg2)
251{
252   if (data_here(leg2)) {
253      adddd(&leg->d, &leg->d, &((linkfor *)leg2)->d);
254   } else {
255      leg2 = reverse_leg(leg2);
256      SVX_ASSERT(data_here(leg2));
257      subdd(&leg->d, &leg->d, &((linkfor *)leg2)->d);
258   }
259   addss(&leg->v, &leg->v, &((linkfor *)leg2)->v);
260   return leg;
261}
262
263static linkfor *
264addleg_(node *fr, node *to,
265        real dx, real dy, real dz,
266        real vx, real vy, real vz,
267#ifndef NO_COVARIANCES
268        real cyz, real czx, real cxy,
269#endif
270        int leg_flags)
271{
272   int i, j;
273   linkfor *leg, *leg2;
274   /* we have been asked to add a leg with the same node at both ends
275    * - this should be trapped by the caller */
276   SVX_ASSERT(fr->name != to->name);
277
278   leg = osnew(linkfor);
279   leg2 = (linkfor*)osnew(linkrev);
280
281   i = freeleg(&fr);
282   j = freeleg(&to);
283
284   leg->l.to = to;
285   leg2->l.to = fr;
286   leg->d[0] = dx;
287   leg->d[1] = dy;
288   leg->d[2] = dz;
289#ifndef NO_COVARIANCES
290   leg->v[0] = vx;
291   leg->v[1] = vy;
292   leg->v[2] = vz;
293   leg->v[3] = cxy;
294   leg->v[4] = czx;
295   leg->v[5] = cyz;
296   check_svar(&(leg->v));
297#else
298   leg->v[0] = vx;
299   leg->v[1] = vy;
300   leg->v[2] = vz;
301#endif
302   leg2->l.reverse = i;
303   leg->l.reverse = j | FLAG_DATAHERE | leg_flags;
304
305   leg->l.flags = pcs->flags | (pcs->recorded_style << FLAGS_STYLE_BIT0);
306   leg->meta = pcs->meta;
307   if (pcs->meta) ++pcs->meta->ref_count;
308
309   fr->leg[i] = leg;
310   to->leg[j] = leg2;
311
312   ++fr->name->shape;
313   ++to->name->shape;
314
315   return leg;
316}
317
318/* Add a leg between names *fr_name and *to_name
319 * If either is a three node, then it is split into two
320 * and the data structure adjusted as necessary.
321 */
322void
323addlegbyname(prefix *fr_name, prefix *to_name, bool fToFirst,
324             real dx, real dy, real dz,
325             real vx, real vy, real vz
326#ifndef NO_COVARIANCES
327             , real cyz, real czx, real cxy
328#endif
329             )
330{
331   node *to, *fr;
332   if (to_name == fr_name) {
333      /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
334       * "survey stations".
335       *
336       * %s is replaced by the name of the station. */
337      compile_diagnostic(DIAG_ERR, /*Survey leg with same station (“%s”) at both ends - typing error?*/50,
338                         sprint_prefix(to_name));
339      return;
340   }
341   if (fToFirst) {
342      to = StnFromPfx(to_name);
343      fr = StnFromPfx(fr_name);
344   } else {
345      fr = StnFromPfx(fr_name);
346      to = StnFromPfx(to_name);
347   }
348   if (last_leg.to_name) {
349      if (last_leg.to_name == to_name && last_leg.fr_name == fr_name) {
350         /* FIXME: Not the right way to average... */
351         linkfor * leg = last_leg.leg;
352         int n = last_leg.n++;
353         leg->d[0] = (leg->d[0] * n + dx) / (n + 1);
354         leg->d[1] = (leg->d[1] * n + dy) / (n + 1);
355         leg->d[2] = (leg->d[2] * n + dz) / (n + 1);
356#ifndef NO_COVARIANCES
357         leg->v[0] = (leg->v[0] * n + vx) / (n + 1);
358         leg->v[1] = (leg->v[1] * n + vy) / (n + 1);
359         leg->v[2] = (leg->v[2] * n + vz) / (n + 1);
360         leg->v[3] = (leg->v[3] * n + cxy) / (n + 1);
361         leg->v[4] = (leg->v[4] * n + czx) / (n + 1);
362         leg->v[5] = (leg->v[5] * n + cyz) / (n + 1);
363         check_svar(&(leg->v));
364#else
365         leg->v[0] = (leg->v[0] * n + vx) / (n + 1);
366         leg->v[1] = (leg->v[1] * n + vy) / (n + 1);
367         leg->v[2] = (leg->v[2] * n + vz) / (n + 1);
368#endif
369         return;
370      }
371   }
372   cLegs++;
373
374   last_leg.to_name = to_name;
375   last_leg.fr_name = fr_name;
376   last_leg.n = 1;
377   last_leg.leg = addleg_(fr, to, dx, dy, dz, vx, vy, vz,
378#ifndef NO_COVARIANCES
379                          cyz, czx, cxy,
380#endif
381                          0);
382}
383
384/* helper function for replace_pfx */
385static void
386replace_pfx_(node *stn, node *from, pos *pos_replace, pos *pos_with)
387{
388   int d;
389   stn->name->pos = pos_with;
390   for (d = 0; d < 3; d++) {
391      linkfor *leg = stn->leg[d];
392      node *to;
393      if (!leg) break;
394      to = leg->l.to;
395      if (to == from) continue;
396
397      if (fZeros(data_here(leg) ? &leg->v : &reverse_leg(leg)->v))
398         replace_pfx_(to, stn, pos_replace, pos_with);
399   }
400}
401
402/* We used to iterate over the whole station list (inefficient) - now we
403 * just look at any neighbouring nodes to see if they are equated */
404static void
405replace_pfx(const prefix *pfx_replace, const prefix *pfx_with)
406{
407   pos *pos_replace;
408   SVX_ASSERT(pfx_replace);
409   SVX_ASSERT(pfx_with);
410   pos_replace = pfx_replace->pos;
411   SVX_ASSERT(pos_replace != pfx_with->pos);
412
413   replace_pfx_(pfx_replace->stn, NULL, pos_replace, pfx_with->pos);
414
415#if DEBUG_INVALID
416   {
417      node *stn;
418      FOR_EACH_STN(stn, stnlist) {
419         SVX_ASSERT(stn->name->pos != pos_replace);
420      }
421   }
422#endif
423
424   /* free the (now-unused) old pos */
425   osfree(pos_replace);
426}
427
428/* Add an equating leg between existing stations *fr and *to (whose names are
429 * name1 and name2).
430 */
431void
432process_equate(prefix *name1, prefix *name2)
433{
434   node *stn1, *stn2;
435   clear_last_leg();
436   if (name1 == name2) {
437      /* catch something like *equate "fred fred" */
438      /* TRANSLATORS: Here "station" is a survey station, not a train station.
439       */
440      compile_diagnostic(DIAG_WARN, /*Station “%s” equated to itself*/13,
441                         sprint_prefix(name1));
442      return;
443   }
444   stn1 = StnFromPfx(name1);
445   stn2 = StnFromPfx(name2);
446   /* equate nodes if not already equated */
447   if (name1->pos != name2->pos) {
448      if (pfx_fixed(name1)) {
449         if (pfx_fixed(name2)) {
450            /* both are fixed, but let them off iff their coordinates match */
451            char *s = osstrdup(sprint_prefix(name1));
452            int d;
453            for (d = 2; d >= 0; d--) {
454               if (name1->pos->p[d] != name2->pos->p[d]) {
455                  compile_diagnostic(DIAG_ERR, /*Tried to equate two non-equal fixed stations: “%s” and “%s”*/52,
456                                     s, sprint_prefix(name2));
457                  osfree(s);
458                  return;
459               }
460            }
461            /* TRANSLATORS: "equal" as in:
462             *
463             * *fix a 1 2 3
464             * *fix b 1 2 3
465             * *equate a b */
466            compile_diagnostic(DIAG_WARN, /*Equating two equal fixed points: “%s” and “%s”*/53,
467                               s, sprint_prefix(name2));
468            osfree(s);
469         }
470
471         /* name1 is fixed, so replace all refs to name2's pos with name1's */
472         replace_pfx(name2, name1);
473      } else {
474         /* name1 isn't fixed, so replace all refs to its pos with name2's */
475         replace_pfx(name1, name2);
476      }
477
478      /* count equates as legs for now... */
479      cLegs++;
480      addleg_(stn1, stn2,
481              (real)0.0, (real)0.0, (real)0.0,
482              (real)0.0, (real)0.0, (real)0.0,
483#ifndef NO_COVARIANCES
484              (real)0.0, (real)0.0, (real)0.0,
485#endif
486              FLAG_FAKE);
487   }
488}
489
490/* Add a 'fake' leg (not counted) between existing stations *fr and *to
491 * (which *must* be different)
492 * If either node is a three node, then it is split into two
493 * and the data structure adjusted as necessary
494 */
495void
496addfakeleg(node *fr, node *to,
497           real dx, real dy, real dz,
498           real vx, real vy, real vz
499#ifndef NO_COVARIANCES
500           , real cyz, real czx, real cxy
501#endif
502           )
503{
504   clear_last_leg();
505   addleg_(fr, to, dx, dy, dz, vx, vy, vz,
506#ifndef NO_COVARIANCES
507           cyz, czx, cxy,
508#endif
509           FLAG_FAKE);
510}
511
512static char
513freeleg(node **stnptr)
514{
515   node *stn, *oldstn;
516   linkfor *leg, *leg2;
517#ifndef NO_COVARIANCES
518   int i;
519#endif
520
521   stn = *stnptr;
522
523   if (stn->leg[0] == NULL) return 0; /* leg[0] unused */
524   if (stn->leg[1] == NULL) return 1; /* leg[1] unused */
525   if (stn->leg[2] == NULL) return 2; /* leg[2] unused */
526
527   /* All legs used, so split node in two */
528   oldstn = stn;
529   stn = osnew(node);
530   leg = osnew(linkfor);
531   leg2 = (linkfor*)osnew(linkrev);
532
533   *stnptr = stn;
534
535   add_stn_to_list(&stnlist, stn);
536   stn->name = oldstn->name;
537
538   leg->l.to = stn;
539   leg->d[0] = leg->d[1] = leg->d[2] = (real)0.0;
540
541#ifndef NO_COVARIANCES
542   for (i = 0; i < 6; i++) leg->v[i] = (real)0.0;
543#else
544   leg->v[0] = leg->v[1] = leg->v[2] = (real)0.0;
545#endif
546   leg->l.reverse = 1 | FLAG_DATAHERE | FLAG_FAKE;
547   leg->l.flags = pcs->flags | (pcs->recorded_style << FLAGS_STYLE_BIT0);
548
549   leg2->l.to = oldstn;
550   leg2->l.reverse = 0;
551
552   /* NB this preserves pos->stn->leg[0] to point to the "real" fixed point
553    * for stations fixed with error estimates
554    */
555   stn->leg[0] = oldstn->leg[0];
556   /* correct reverse leg */
557   reverse_leg(stn->leg[0])->l.to = stn;
558   stn->leg[1] = leg2;
559
560   oldstn->leg[0] = leg;
561
562   stn->leg[2] = NULL; /* needed as stn->leg[dirn]==NULL indicates unused */
563
564   return(2); /* leg[2] unused */
565}
566
567node *
568StnFromPfx(prefix *name)
569{
570   node *stn;
571   if (name->stn != NULL) return (name->stn);
572   stn = osnew(node);
573   stn->name = name;
574   if (name->pos == NULL) {
575      name->pos = osnew(pos);
576      unfix(stn);
577   }
578   stn->leg[0] = stn->leg[1] = stn->leg[2] = NULL;
579   add_stn_to_list(&stnlist, stn);
580   name->stn = stn;
581   cStns++;
582   return stn;
583}
584
585extern void
586fprint_prefix(FILE *fh, const prefix *ptr)
587{
588   SVX_ASSERT(ptr);
589   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
590      /* We release the stations, so ptr->stn is NULL late on, so we can't
591       * use that to print "anonymous station surveyed from somesurvey.12"
592       * here.  FIXME */
593      fputs("anonymous station", fh);
594      /* FIXME: if ident is set, show it? */
595      return;
596   }
597   if (ptr->up != NULL) {
598      fprint_prefix(fh, ptr->up);
599      if (ptr->up->up != NULL) fputc(output_separator, fh);
600      SVX_ASSERT(ptr->ident);
601      fputs(ptr->ident, fh);
602   }
603}
604
605static char *buffer = NULL;
606static OSSIZE_T buffer_len = 256;
607
608static OSSIZE_T
609sprint_prefix_(const prefix *ptr)
610{
611   OSSIZE_T len = 1;
612   if (ptr->up != NULL) {
613      SVX_ASSERT(ptr->ident);
614      len = sprint_prefix_(ptr->up);
615      OSSIZE_T end = len - 1;
616      if (ptr->up->up != NULL) len++;
617      len += strlen(ptr->ident);
618      if (len > buffer_len) {
619         buffer = osrealloc(buffer, len);
620         buffer_len = len;
621      }
622      char *p = buffer + end;
623      if (ptr->up->up != NULL) *p++ = output_separator;
624      strcpy(p, ptr->ident);
625   }
626   return len;
627}
628
629extern char *
630sprint_prefix(const prefix *ptr)
631{
632   SVX_ASSERT(ptr);
633   if (!buffer) buffer = osmalloc(buffer_len);
634   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
635      /* We release the stations, so ptr->stn is NULL late on, so we can't
636       * use that to print "anonymous station surveyed from somesurvey.12"
637       * here.  FIXME */
638      strcpy(buffer, "anonymous station");
639      /* FIXME: if ident is set, show it? */
640      return buffer;
641   }
642   *buffer = '\0';
643   sprint_prefix_(ptr);
644   return buffer;
645}
646
647/* r = ab ; r,a,b are variance matrices */
648void
649mulss(var *r, /*const*/ svar *a, /*const*/ svar *b)
650{
651#ifdef NO_COVARIANCES
652   /* variance-only version */
653   (*r)[0] = (*a)[0] * (*b)[0];
654   (*r)[1] = (*a)[1] * (*b)[1];
655   (*r)[2] = (*a)[2] * (*b)[2];
656#else
657   int i, j, k;
658   real tot;
659
660#if 0
661   SVX_ASSERT((/*const*/ var *)r != a);
662   SVX_ASSERT((/*const*/ var *)r != b);
663#endif
664
665   check_svar(a);
666   check_svar(b);
667
668   for (i = 0; i < 3; i++) {
669      for (j = 0; j < 3; j++) {
670         tot = 0;
671         for (k = 0; k < 3; k++) {
672            tot += SN(a,i,k) * SN(b,k,j);
673         }
674         (*r)[i][j] = tot;
675      }
676   }
677   check_var(r);
678#endif
679}
680
681#ifndef NO_COVARIANCES
682/* r = ab ; r,a,b are variance matrices */
683void
684smulvs(svar *r, /*const*/ var *a, /*const*/ svar *b)
685{
686   int i, j, k;
687   real tot;
688
689#if 0
690   SVX_ASSERT((/*const*/ var *)r != a);
691#endif
692   SVX_ASSERT((/*const*/ svar *)r != b);
693
694   check_var(a);
695   check_svar(b);
696
697   (*r)[3]=(*r)[4]=(*r)[5]=-999;
698   for (i = 0; i < 3; i++) {
699      for (j = 0; j < 3; j++) {
700         tot = 0;
701         for (k = 0; k < 3; k++) {
702            tot += (*a)[i][k] * SN(b,k,j);
703         }
704         if (i <= j)
705            SN(r,i,j) = tot;
706         else if (fabs(SN(r,j,i) - tot) > THRESHOLD) {
707            printf("not sym - %d,%d = %f, %d,%d was %f\n",
708                   i,j,tot,j,i,SN(r,j,i));
709            BUG("smulvs didn't produce a sym mx\n");
710         }
711      }
712   }
713   check_svar(r);
714}
715#endif
716
717/* r = vb ; r,b delta vectors; a variance matrix */
718void
719mulsd(delta *r, /*const*/ svar *v, /*const*/ delta *b)
720{
721#ifdef NO_COVARIANCES
722   /* variance-only version */
723   (*r)[0] = (*v)[0] * (*b)[0];
724   (*r)[1] = (*v)[1] * (*b)[1];
725   (*r)[2] = (*v)[2] * (*b)[2];
726#else
727   int i, j;
728   real tot;
729
730   SVX_ASSERT((/*const*/ delta*)r != b);
731   check_svar(v);
732   check_d(b);
733
734   for (i = 0; i < 3; i++) {
735      tot = 0;
736      for (j = 0; j < 3; j++) tot += S(i,j) * (*b)[j];
737      (*r)[i] = tot;
738   }
739   check_d(r);
740#endif
741}
742
743/* r = ca ; r,a variance matrices; c real scaling factor  */
744void
745mulsc(svar *r, /*const*/ svar *a, real c)
746{
747#ifdef NO_COVARIANCES
748   /* variance-only version */
749   (*r)[0] = (*a)[0] * c;
750   (*r)[1] = (*a)[1] * c;
751   (*r)[2] = (*a)[2] * c;
752#else
753   int i;
754
755   check_svar(a);
756   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] * c;
757   check_svar(r);
758#endif
759}
760
761/* r = a + b ; r,a,b delta vectors */
762void
763adddd(delta *r, /*const*/ delta *a, /*const*/ delta *b)
764{
765   check_d(a);
766   check_d(b);
767   (*r)[0] = (*a)[0] + (*b)[0];
768   (*r)[1] = (*a)[1] + (*b)[1];
769   (*r)[2] = (*a)[2] + (*b)[2];
770   check_d(r);
771}
772
773/* r = a - b ; r,a,b delta vectors */
774void
775subdd(delta *r, /*const*/ delta *a, /*const*/ delta *b) {
776   check_d(a);
777   check_d(b);
778   (*r)[0] = (*a)[0] - (*b)[0];
779   (*r)[1] = (*a)[1] - (*b)[1];
780   (*r)[2] = (*a)[2] - (*b)[2];
781   check_d(r);
782}
783
784/* r = a + b ; r,a,b variance matrices */
785void
786addss(svar *r, /*const*/ svar *a, /*const*/ svar *b)
787{
788#ifdef NO_COVARIANCES
789   /* variance-only version */
790   (*r)[0] = (*a)[0] + (*b)[0];
791   (*r)[1] = (*a)[1] + (*b)[1];
792   (*r)[2] = (*a)[2] + (*b)[2];
793#else
794   int i;
795
796   check_svar(a);
797   check_svar(b);
798   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] + (*b)[i];
799   check_svar(r);
800#endif
801}
802
803/* r = a - b ; r,a,b variance matrices */
804void
805subss(svar *r, /*const*/ svar *a, /*const*/ svar *b)
806{
807#ifdef NO_COVARIANCES
808   /* variance-only version */
809   (*r)[0] = (*a)[0] - (*b)[0];
810   (*r)[1] = (*a)[1] - (*b)[1];
811   (*r)[2] = (*a)[2] - (*b)[2];
812#else
813   int i;
814
815   check_svar(a);
816   check_svar(b);
817   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] - (*b)[i];
818   check_svar(r);
819#endif
820}
821
822/* inv = v^-1 ; inv,v variance matrices */
823extern int
824invert_svar(svar *inv, /*const*/ svar *v)
825{
826#ifdef NO_COVARIANCES
827   int i;
828   for (i = 0; i < 3; i++) {
829      if ((*v)[i] == 0.0) return 0; /* matrix is singular */
830      (*inv)[i] = 1.0 / (*v)[i];
831   }
832#else
833   real det, a, b, c, d, e, f, bcff, efcd, dfbe;
834
835#if 0
836   SVX_ASSERT((/*const*/ var *)inv != v);
837#endif
838
839   check_svar(v);
840   /* a d e
841    * d b f
842    * e f c
843    */
844   a = (*v)[0], b = (*v)[1], c = (*v)[2];
845   d = (*v)[3], e = (*v)[4], f = (*v)[5];
846   bcff = b * c - f * f;
847   efcd = e * f - c * d;
848   dfbe = d * f - b * e;
849   det = a * bcff + d * efcd + e * dfbe;
850
851   if (det == 0.0) {
852      /* printf("det=%.20f\n", det); */
853      return 0; /* matrix is singular */
854   }
855
856   det = 1 / det;
857
858   (*inv)[0] = det * bcff;
859   (*inv)[1] = det * (c * a - e * e);
860   (*inv)[2] = det * (a * b - d * d);
861   (*inv)[3] = det * efcd;
862   (*inv)[4] = det * dfbe;
863   (*inv)[5] = det * (e * d - a * f);
864
865#if 0
866   /* This test fires very occasionally, and there's not much point in
867    * it anyhow - the matrix inversion algorithm is simple enough that
868    * we can be confident it's correctly implemented, so we might as
869    * well save the cycles and not perform this check.
870    */
871     { /* check that original * inverse = identity matrix */
872        int i;
873        var p;
874        real D = 0;
875        mulss(&p, v, inv);
876        for (i = 0; i < 3; i++) {
877           int j;
878           for (j = 0; j < 3; j++) D += fabs(p[i][j] - (real)(i==j));
879        }
880        if (D > THRESHOLD) {
881           printf("original * inverse=\n");
882           print_svar(*v);
883           printf("*\n");
884           print_svar(*inv);
885           printf("=\n");
886           print_var(p);
887           BUG("matrix didn't invert");
888        }
889        check_svar(inv);
890     }
891#endif
892#endif
893   return 1;
894}
895
896/* r = (b^-1)a ; r,a delta vectors; b variance matrix */
897#ifndef NO_COVARIANCES
898void
899divds(delta *r, /*const*/ delta *a, /*const*/ svar *b)
900{
901#ifdef NO_COVARIANCES
902   /* variance-only version */
903   (*r)[0] = (*a)[0] / (*b)[0];
904   (*r)[1] = (*a)[1] / (*b)[1];
905   (*r)[2] = (*a)[2] / (*b)[2];
906#else
907   svar b_inv;
908   if (!invert_svar(&b_inv, b)) {
909      print_svar(*b);
910      BUG("covariance matrix is singular");
911   }
912   mulsd(r, &b_inv, a);
913#endif
914}
915#endif
916
917bool
918fZeros(/*const*/ svar *v) {
919#ifdef NO_COVARIANCES
920   /* variance-only version */
921   return ((*v)[0] == 0.0 && (*v)[1] == 0.0 && (*v)[2] == 0.0);
922#else
923   int i;
924
925   check_svar(v);
926   for (i = 0; i < 6; i++) if ((*v)[i] != 0.0) return false;
927
928   return true;
929#endif
930}
Note: See TracBrowser for help on using the repository browser.