source: git/src/netbits.c @ 99d6dd9

RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernlogstereowalls-datawalls-data-hanging-as-warning
Last change on this file since 99d6dd9 was 55a0527, checked in by Olly Betts <olly@…>, 11 years ago

src/img.c,src/netbits.c: Fix comments in C code for portability
to pre-C99 compilers which don't support these as an extension.

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