source: git/src/netbits.c @ ce04943

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectstereostereo-2025walls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since ce04943 was b4fe9fb, checked in by Olly Betts <olly@…>, 22 years ago

Merged changes with 1.0 branch.

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@2437 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 25.4 KB
Line 
1/* netbits.c
2 * Miscellaneous primitive network routines for Survex
3 * Copyright (C) 1992-2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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#ifdef CHASM3DX
37#include <stddef.h> /* for offsetof */
38#endif
39
40#define THRESHOLD (REAL_EPSILON * 1000) /* 100 was too small */
41
42node *stn_iter = NULL; /* for FOR_EACH_STN */
43
44#ifdef NO_COVARIANCES
45static void check_var(/*const*/ var *v) {
46   int bad = 0;
47   int i;
48
49   for (i = 0; i < 3; i++) {
50      char buf[32];
51      sprintf(buf, "%6.3f", v[i]);
52      if (strstr(buf, "NaN") || strstr(buf, "nan"))
53         printf("*** NaN!!!\n"), bad = 1;
54   }
55   if (bad) print_var(v);
56   return;
57}
58#else
59#define V(A,B) ((*v)[A][B])
60static void check_var(/*const*/ var *v) {
61   int bad = 0;
62   int ok = 0;
63   int i, j;
64#if DEBUG_INVALID
65   real det = 0.0;
66#endif
67
68   for (i = 0; i < 3; i++) {
69      for (j = 0; j < 3; j++) {
70         char buf[32];
71         sprintf(buf, "%6.3f", V(i, j));
72         if (strstr(buf, "NaN") || strstr(buf, "nan"))
73            printf("*** NaN!!!\n"), bad = 1, ok = 1;
74         if (V(i, j) != 0.0) ok = 1;
75      }
76   }
77   if (!ok) return; /* ignore all-zero matrices */
78
79#if DEBUG_INVALID
80   for (i = 0; i < 3; i++) {
81      det += V(i, 0) * (V((i + 1) % 3, 1) * V((i + 2) % 3, 2) -
82                        V((i + 1) % 3, 2) * V((i + 2) % 3, 1));
83   }
84
85   if (fabs(det) < THRESHOLD)
86      printf("*** Singular!!!\n"), bad = 1;
87#endif
88
89#if 0
90   /* don't check this - it isn't always the case! */
91   if (fabs(V(0,1) - V(1,0)) > THRESHOLD ||
92       fabs(V(0,2) - V(2,0)) > THRESHOLD ||
93       fabs(V(1,2) - V(2,1)) > THRESHOLD)
94      printf("*** Not symmetric!!!\n"), bad = 1;
95   if (V(0,0) <= 0.0 || V(1,1) <= 0.0 || V(2,2) <= 0.0)
96      printf("*** Not positive definite (diag <= 0)!!!\n"), bad = 1;
97   if (sqrd(V(0,1)) >= V(0,0)*V(1,1) || sqrd(V(0,2)) >= V(0,0)*V(2,2) ||
98       sqrd(V(1,0)) >= V(0,0)*V(1,1) || sqrd(V(2,0)) >= V(0,0)*V(2,2) ||
99       sqrd(V(1,2)) >= V(2,2)*V(1,1) || sqrd(V(2,1)) >= V(2,2)*V(1,1))
100      printf("*** Not positive definite (off diag^2 >= diag product)!!!\n"), bad = 1;
101#endif
102   if (bad) print_var(*v);
103}
104
105#define SN(V,A,B) ((*(V))[(A)==(B)?(A):2+(A)+(B)])
106#define S(A,B) SN(v,A,B)
107
108static void check_svar(/*const*/ svar *v) {
109   int bad = 0;
110   int ok = 0;
111   int i;
112#if DEBUG_INVALID
113   real det = 0.0;
114#endif
115
116   for (i = 0; i < 6; i++) {
117      char buf[32];
118      sprintf(buf, "%6.3f", (*v)[i]);
119      if (strstr(buf, "NaN") || strstr(buf, "nan"))
120         printf("*** NaN!!!\n"), bad = 1, ok = 1;
121      if ((*v)[i] != 0.0) ok = 1;
122   }
123   if (!ok) return; /* ignore all-zero matrices */
124
125#if DEBUG_INVALID
126   for (i = 0; i < 3; i++) {
127      det += S(i, 0) * (S((i + 1) % 3, 1) * S((i + 2) % 3, 2) -
128                        S((i + 1) % 3, 2) * S((i + 2) % 3, 1));
129   }
130
131   if (fabs(det) < THRESHOLD)
132      printf("*** Singular!!!\n"), bad = 1;
133#endif
134
135#if 0
136   /* don't check this - it isn't always the case! */
137   if ((*v)[0] <= 0.0 || (*v)[1] <= 0.0 || (*v)[2] <= 0.0)
138      printf("*** Not positive definite (diag <= 0)!!!\n"), bad = 1;
139   if (sqrd((*v)[3]) >= (*v)[0]*(*v)[1] ||
140       sqrd((*v)[4]) >= (*v)[0]*(*v)[2] ||
141       sqrd((*v)[5]) >= (*v)[1]*(*v)[2])
142      printf("*** Not positive definite (off diag^2 >= diag product)!!!\n"), bad = 1;
143#endif
144   if (bad) print_svar(*v);
145}
146#endif
147
148static void check_d(/*const*/ delta *d) {
149   int bad = 0;
150   int i;
151
152   for (i = 0; i < 3; i++) {
153      char buf[32];
154      sprintf(buf, "%6.3f", (*d)[i]);
155      if (strstr(buf, "NaN") || strstr(buf, "nan"))
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 void
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   int shape;
275   /* we have been asked to add a leg with the same node at both ends
276    * - this should be trapped by the caller */
277   SVX_ASSERT(fr->name != to->name);
278
279   leg = osnew(linkfor);
280   leg2 = (linkfor*)osnew(linkrev);
281
282   i = freeleg(&fr);
283   j = freeleg(&to);
284
285   leg->l.to = to;
286   leg2->l.to = fr;
287   leg->d[0] = dx;
288   leg->d[1] = dy;
289   leg->d[2] = dz;
290#ifndef NO_COVARIANCES
291   leg->v[0] = vx;
292   leg->v[1] = vy;
293   leg->v[2] = vz;
294   leg->v[3] = cxy;
295   leg->v[4] = czx;
296   leg->v[5] = cyz;
297   check_svar(&(leg->v));
298#else
299   leg->v[0] = vx;
300   leg->v[1] = vy;
301   leg->v[2] = vz;
302#endif
303   leg2->l.reverse = i;
304   leg->l.reverse = j | FLAG_DATAHERE | leg_flags;
305
306   leg->l.flags = pcs->flags;
307   leg->meta = pcs->meta;
308   if (pcs->meta) ++pcs->meta->ref_count;
309
310   fr->leg[i] = leg;
311   to->leg[j] = leg2;
312
313   shape = fr->name->shape + 1;
314   if (shape < 1) shape = 1 - shape;
315   fr->name->shape = shape;
316
317   shape = to->name->shape + 1;
318   if (shape < 1) shape = 1 - shape;
319   to->name->shape = shape;
320}
321
322/* Add a leg between names *fr_name and *to_name
323 * If either is a three node, then it is split into two
324 * and the data structure adjusted as necessary.
325 */
326void
327addlegbyname(prefix *fr_name, prefix *to_name, bool fToFirst,
328             real dx, real dy, real dz,
329             real vx, real vy, real vz
330#ifndef NO_COVARIANCES
331             , real cyz, real czx, real cxy
332#endif
333             )
334{
335   node *to, *fr;
336   if (to_name == fr_name) {
337      compile_error(/*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   cLegs++; /* increment count (first as compiler may do tail recursion) */
349   addleg_(fr, to, dx, dy, dz, vx, vy, vz,
350#ifndef NO_COVARIANCES
351           cyz, czx, cxy,
352#endif
353           0);
354}
355
356/* helper function for replace_pfx */
357static void
358replace_pfx_(node *stn, node *from, pos *pos_replace, pos *pos_with)
359{
360   int d;
361   stn->name->pos = pos_with;
362   for (d = 0; d < 3; d++) {
363      linkfor *leg = stn->leg[d];
364      node *to;
365      if (!leg) break;
366      to = leg->l.to;
367      if (to == from) continue;
368
369      if (fZeros(data_here(leg) ? &leg->v : &reverse_leg(leg)->v))
370         replace_pfx_(to, stn, pos_replace, pos_with);
371   }
372}
373
374/* We used to iterate over the whole station list (inefficient) - now we
375 * just look at any neighbouring nodes to see if they are equated */
376static void
377replace_pfx(const prefix *pfx_replace, const prefix *pfx_with)
378{
379   pos *pos_replace;
380   SVX_ASSERT(pfx_replace);
381   SVX_ASSERT(pfx_with);
382   pos_replace = pfx_replace->pos;
383   SVX_ASSERT(pos_replace != pfx_with->pos);
384
385   replace_pfx_(pfx_replace->stn, NULL, pos_replace, pfx_with->pos);
386
387#if DEBUG_INVALID
388   {
389      node *stn;
390      FOR_EACH_STN(stn, stnlist) {
391         SVX_ASSERT(stn->name->pos != pos_replace);
392      }
393   }
394#endif
395
396   /* free the (now-unused) old pos */
397   osfree(pos_replace);
398}
399
400/* Add an equating leg between existing stations *fr and *to (whose names are
401 * name1 and name2).
402 */
403void
404process_equate(prefix *name1, prefix *name2)
405{
406   node *stn1, *stn2;
407   if (name1 == name2) {
408      /* catch something like *equate "fred fred" */
409      compile_warning(/*Station `%s' equated to itself*/13,
410                      sprint_prefix(name1));
411      return;
412   }
413   stn1 = StnFromPfx(name1);
414   stn2 = StnFromPfx(name2);
415   /* equate nodes if not already equated */
416   if (name1->pos != name2->pos) {
417      if (pfx_fixed(name1)) {
418         if (pfx_fixed(name2)) {
419            /* both are fixed, but let them off iff their coordinates match */
420            char *s = osstrdup(sprint_prefix(name1));
421            int d;
422            for (d = 2; d >= 0; d--) {
423               if (name1->pos->p[d] != name2->pos->p[d]) {
424                  compile_error(/*Tried to equate two non-equal fixed stations: `%s' and `%s'*/52,
425                                s, sprint_prefix(name2));
426                  osfree(s);
427                  return;
428               }
429            }
430            compile_warning(/*Equating two equal fixed points: `%s' and `%s'*/53,
431                            s, sprint_prefix(name2));
432            osfree(s);
433         }
434
435         /* name1 is fixed, so replace all refs to name2's pos with name1's */
436         replace_pfx(name2, name1);
437      } else {
438         /* name1 isn't fixed, so replace all refs to its pos with name2's */
439         replace_pfx(name1, name2);
440      }
441
442      /* count equates as legs for now... */
443      cLegs++;
444      addleg_(stn1, stn2,
445              (real)0.0, (real)0.0, (real)0.0,
446              (real)0.0, (real)0.0, (real)0.0,
447#ifndef NO_COVARIANCES
448              (real)0.0, (real)0.0, (real)0.0,
449#endif
450              FLAG_FAKE);
451   }
452}
453
454/* Add a 'fake' leg (not counted) between existing stations *fr and *to
455 * (which *must* be different)
456 * If either node is a three node, then it is split into two
457 * and the data structure adjusted as necessary
458 */
459void
460addfakeleg(node *fr, node *to,
461           real dx, real dy, real dz,
462           real vx, real vy, real vz
463#ifndef NO_COVARIANCES
464           , real cyz, real czx, real cxy
465#endif
466           )
467{
468   addleg_(fr, to, dx, dy, dz, vx, vy, vz,
469#ifndef NO_COVARIANCES
470           cyz, czx, cxy,
471#endif
472           FLAG_FAKE);
473}
474
475char
476freeleg(node **stnptr)
477{
478   node *stn, *oldstn;
479   linkfor *leg, *leg2;
480#ifndef NO_COVARIANCES
481   int i;
482#endif
483
484   stn = *stnptr;
485
486   if (stn->leg[0] == NULL) return 0; /* leg[0] unused */
487   if (stn->leg[1] == NULL) return 1; /* leg[1] unused */
488   if (stn->leg[2] == NULL) return 2; /* leg[2] unused */
489
490   /* All legs used, so split node in two */
491   oldstn = stn;
492   stn = osnew(node);
493   leg = osnew(linkfor);
494   leg2 = (linkfor*)osnew(linkrev);
495
496   *stnptr = stn;
497
498   add_stn_to_list(&stnlist, stn);
499   stn->name = oldstn->name;
500
501   leg->l.to = stn;
502   leg->d[0] = leg->d[1] = leg->d[2] = (real)0.0;
503
504#ifndef NO_COVARIANCES
505   for (i = 0; i < 6; i++) leg->v[i] = (real)0.0;
506#else
507   leg->v[0] = leg->v[1] = leg->v[2] = (real)0.0;
508#endif
509   leg->l.reverse = 1 | FLAG_DATAHERE | FLAG_FAKE;
510   leg->l.flags = pcs->flags;
511
512   leg2->l.to = oldstn;
513   leg2->l.reverse = 0;
514
515   /* NB this preserves pos->stn->leg[0] to point to the "real" fixed point
516    * for stations fixed with error estimates
517    */
518   stn->leg[0] = oldstn->leg[0];
519   /* correct reverse leg */
520   reverse_leg(stn->leg[0])->l.to = stn;
521   stn->leg[1] = leg2;
522
523   oldstn->leg[0] = leg;
524
525   stn->leg[2] = NULL; /* needed as stn->leg[dirn]==NULL indicates unused */
526
527   return(2); /* leg[2] unused */
528}
529
530node *
531StnFromPfx(prefix *name)
532{
533   node *stn;
534   if (name->stn != NULL) return (name->stn);
535   stn = osnew(node);
536   stn->name = name;
537   if (name->pos == NULL) {
538#ifdef CHASM3DX
539      if (fUseNewFormat) {
540         name->pos = osnew(pos);
541         name->pos->id = 0;
542      } else {
543         /* only allocate the part of the structure we need... */
544         name->pos = (pos *)osmalloc(offsetof(pos, id));
545      }
546#else
547      name->pos = osnew(pos);
548#endif
549      unfix(stn);
550   }
551   stn->leg[0] = stn->leg[1] = stn->leg[2] = NULL;
552   add_stn_to_list(&stnlist, stn);
553   name->stn = stn;
554   cStns++;
555   return stn;
556}
557
558extern void
559fprint_prefix(FILE *fh, const prefix *ptr)
560{
561   SVX_ASSERT(ptr);
562   if (ptr->up != NULL) {
563      fprint_prefix(fh, ptr->up);
564      if (ptr->up->up != NULL) fputc('.', fh);
565      SVX_ASSERT(ptr->ident);
566      fputs(ptr->ident, fh);
567   }
568}
569
570static char *buffer = NULL;
571static OSSIZE_T buffer_len = 256;
572
573static OSSIZE_T
574sprint_prefix_(const prefix *ptr)
575{
576   OSSIZE_T len = 1;
577   if (ptr->up != NULL) {
578      SVX_ASSERT(ptr->ident);
579      len = sprint_prefix_(ptr->up) + strlen(ptr->ident);
580      if (ptr->up->up != NULL) len++;
581      if (len > buffer_len) {
582         buffer = osrealloc(buffer, len);
583         buffer_len = len;
584      }
585      if (ptr->up->up != NULL) strcat(buffer, ".");
586      strcat(buffer, ptr->ident);
587   }
588   return len;
589}
590
591extern char *
592sprint_prefix(const prefix *ptr)
593{
594   SVX_ASSERT(ptr);
595   if (!buffer) buffer = osmalloc(buffer_len);
596   *buffer = '\0';
597   sprint_prefix_(ptr);
598   return buffer;
599}
600
601/* r = ab ; r,a,b are variance matrices */
602void
603mulvv(var *r, /*const*/ var *a, /*const*/ var *b)
604{
605#ifdef NO_COVARIANCES
606   /* variance-only version */
607   (*r)[0] = (*a)[0] * (*b)[0];
608   (*r)[1] = (*a)[1] * (*b)[1];
609   (*r)[2] = (*a)[2] * (*b)[2];
610#else
611   int i, j, k;
612   real tot;
613
614   SVX_ASSERT((/*const*/ var *)r != a);
615   SVX_ASSERT((/*const*/ var *)r != b);
616
617   check_var(a);
618   check_var(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 += (*a)[i][k] * (*b)[k][j];
625         }
626         (*r)[i][j] = tot;
627      }
628   }
629   check_var(r);
630#endif
631}
632
633/* r = ab ; r,a,b are variance matrices */
634void
635mulss(var *r, /*const*/ svar *a, /*const*/ svar *b)
636{
637#ifdef NO_COVARIANCES
638   /* variance-only version */
639   (*r)[0] = (*a)[0] * (*b)[0];
640   (*r)[1] = (*a)[1] * (*b)[1];
641   (*r)[2] = (*a)[2] * (*b)[2];
642#else
643   int i, j, k;
644   real tot;
645
646#if 0
647   SVX_ASSERT((/*const*/ var *)r != a);
648   SVX_ASSERT((/*const*/ var *)r != b);
649#endif
650
651   check_svar(a);
652   check_svar(b);
653
654   for (i = 0; i < 3; i++) {
655      for (j = 0; j < 3; j++) {
656         tot = 0;
657         for (k = 0; k < 3; k++) {
658            tot += SN(a,i,k) * SN(b,k,j);
659         }
660         (*r)[i][j] = tot;
661      }
662   }
663   check_var(r);
664#endif
665}
666
667/* r = ab ; r,a,b are variance matrices */
668void
669smulvs(svar *r, /*const*/ var *a, /*const*/ svar *b)
670{
671#ifdef NO_COVARIANCES
672   /* variance-only version */
673   (*r)[0] = (*a)[0] * (*b)[0];
674   (*r)[1] = (*a)[1] * (*b)[1];
675   (*r)[2] = (*a)[2] * (*b)[2];
676#else
677   int i, j, k;
678   real tot;
679
680#if 0
681   SVX_ASSERT((/*const*/ var *)r != a);
682#endif
683   SVX_ASSERT((/*const*/ svar *)r != b);
684
685   check_var(a);
686   check_svar(b);
687
688   (*r)[3]=(*r)[4]=(*r)[5]=-999;
689   for (i = 0; i < 3; i++) {
690      for (j = 0; j < 3; j++) {
691         tot = 0;
692         for (k = 0; k < 3; k++) {
693            tot += (*a)[i][k] * SN(b,k,j);
694         }
695         if (i <= j)
696            SN(r,i,j) = tot;
697         else if (fabs(SN(r,j,i) - tot) > THRESHOLD) {
698            printf("not sym - %d,%d = %f, %d,%d was %f\n",
699                   i,j,tot,j,i,SN(r,j,i));
700            BUG("smulvs didn't produce a sym mx\n");
701         }
702      }
703   }
704   check_svar(r);
705#endif
706}
707
708/* r = ab ; r,b delta vectors; a variance matrix */
709void
710mulvd(delta *r, /*const*/ var *a, /*const*/ delta *b)
711{
712#ifdef NO_COVARIANCES
713   /* variance-only version */
714   (*r)[0] = (*a)[0] * (*b)[0];
715   (*r)[1] = (*a)[1] * (*b)[1];
716   (*r)[2] = (*a)[2] * (*b)[2];
717#else
718   int i, k;
719   real tot;
720
721   SVX_ASSERT((/*const*/ delta*)r != b);
722   check_var(a);
723   check_d(b);
724
725   for (i = 0; i < 3; i++) {
726      tot = 0;
727      for (k = 0; k < 3; k++) tot += (*a)[i][k] * (*b)[k];
728      (*r)[i] = tot;
729   }
730   check_d(r);
731#endif
732}
733
734/* r = vb ; r,b delta vectors; a variance matrix */
735void
736mulsd(delta *r, /*const*/ svar *v, /*const*/ delta *b)
737{
738#ifdef NO_COVARIANCES
739   /* variance-only version */
740   (*r)[0] = (*v)[0] * (*b)[0];
741   (*r)[1] = (*v)[1] * (*b)[1];
742   (*r)[2] = (*v)[2] * (*b)[2];
743#else
744   int i, j;
745   real tot;
746
747   SVX_ASSERT((/*const*/ delta*)r != b);
748   check_svar(v);
749   check_d(b);
750
751   for (i = 0; i < 3; i++) {
752      tot = 0;
753      for (j = 0; j < 3; j++) tot += S(i,j) * (*b)[j];
754      (*r)[i] = tot;
755   }
756   check_d(r);
757#endif
758}
759
760/* r = ca ; r,a delta vectors; c real scaling factor  */
761void
762muldc(delta *r, /*const*/ delta *a, real c) {
763   check_d(a);
764   (*r)[0] = (*a)[0] * c;
765   (*r)[1] = (*a)[1] * c;
766   (*r)[2] = (*a)[2] * c;
767   check_d(r);
768}
769
770/* r = ca ; r,a variance matrices; c real scaling factor  */
771void
772mulvc(var *r, /*const*/ var *a, real c)
773{
774#ifdef NO_COVARIANCES
775   /* variance-only version */
776   (*r)[0] = (*a)[0] * c;
777   (*r)[1] = (*a)[1] * c;
778   (*r)[2] = (*a)[2] * c;
779#else
780   int i, j;
781
782   check_var(a);
783   for (i = 0; i < 3; i++) {
784      for (j = 0; j < 3; j++) (*r)[i][j] = (*a)[i][j] * c;
785   }
786   check_var(r);
787#endif
788}
789
790/* r = ca ; r,a variance matrices; c real scaling factor  */
791void
792mulsc(svar *r, /*const*/ svar *a, real c)
793{
794#ifdef NO_COVARIANCES
795   /* variance-only version */
796   (*r)[0] = (*a)[0] * c;
797   (*r)[1] = (*a)[1] * c;
798   (*r)[2] = (*a)[2] * c;
799#else
800   int i;
801
802   check_svar(a);
803   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] * c;
804   check_svar(r);
805#endif
806}
807
808/* r = a + b ; r,a,b delta vectors */
809void
810adddd(delta *r, /*const*/ delta *a, /*const*/ delta *b)
811{
812   check_d(a);
813   check_d(b);
814   (*r)[0] = (*a)[0] + (*b)[0];
815   (*r)[1] = (*a)[1] + (*b)[1];
816   (*r)[2] = (*a)[2] + (*b)[2];
817   check_d(r);
818}
819
820/* r = a - b ; r,a,b delta vectors */
821void
822subdd(delta *r, /*const*/ delta *a, /*const*/ delta *b) {
823   check_d(a);
824   check_d(b);
825   (*r)[0] = (*a)[0] - (*b)[0];
826   (*r)[1] = (*a)[1] - (*b)[1];
827   (*r)[2] = (*a)[2] - (*b)[2];
828   check_d(r);
829}
830
831/* r = a + b ; r,a,b variance matrices */
832void
833addvv(var *r, /*const*/ var *a, /*const*/ var *b)
834{
835#ifdef NO_COVARIANCES
836   /* variance-only version */
837   (*r)[0] = (*a)[0] + (*b)[0];
838   (*r)[1] = (*a)[1] + (*b)[1];
839   (*r)[2] = (*a)[2] + (*b)[2];
840#else
841   int i, j;
842
843   check_var(a);
844   check_var(b);
845   for (i = 0; i < 3; i++) {
846      for (j = 0; j < 3; j++) (*r)[i][j] = (*a)[i][j] + (*b)[i][j];
847   }
848   check_var(r);
849#endif
850}
851
852/* r = a + b ; r,a,b variance matrices */
853void
854addss(svar *r, /*const*/ svar *a, /*const*/ svar *b)
855{
856#ifdef NO_COVARIANCES
857   /* variance-only version */
858   (*r)[0] = (*a)[0] + (*b)[0];
859   (*r)[1] = (*a)[1] + (*b)[1];
860   (*r)[2] = (*a)[2] + (*b)[2];
861#else
862   int i;
863
864   check_svar(a);
865   check_svar(b);
866   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] + (*b)[i];
867   check_svar(r);
868#endif
869}
870
871/* r = a - b ; r,a,b variance matrices */
872void
873subvv(var *r, /*const*/ var *a, /*const*/ var *b)
874{
875#ifdef NO_COVARIANCES
876   /* variance-only version */
877   (*r)[0] = (*a)[0] - (*b)[0];
878   (*r)[1] = (*a)[1] - (*b)[1];
879   (*r)[2] = (*a)[2] - (*b)[2];
880#else
881   int i, j;
882
883   check_var(a);
884   check_var(b);
885   for (i = 0; i < 3; i++) {
886      for (j = 0; j < 3; j++) (*r)[i][j] = (*a)[i][j] - (*b)[i][j];
887   }
888   check_var(r);
889#endif
890}
891
892/* r = a - b ; r,a,b variance matrices */
893void
894subss(svar *r, /*const*/ svar *a, /*const*/ svar *b)
895{
896#ifdef NO_COVARIANCES
897   /* variance-only version */
898   (*r)[0] = (*a)[0] - (*b)[0];
899   (*r)[1] = (*a)[1] - (*b)[1];
900   (*r)[2] = (*a)[2] - (*b)[2];
901#else
902   int i;
903
904   check_svar(a);
905   check_svar(b);
906   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] - (*b)[i];
907   check_svar(r);
908#endif
909}
910
911/* inv = v^-1 ; inv,v variance matrices */
912#ifdef NO_COVARIANCES
913extern int
914invert_var(var *inv, /*const*/ var *v)
915{
916   int i;
917   for (i = 0; i < 3; i++) {
918      if ((*v)[i] == 0.0) return 0; /* matrix is singular */
919      (*inv)[i] = 1.0 / (*v)[i];
920   }
921   return 1;
922}
923#else
924extern int
925invert_var(var *inv, /*const*/ var *v)
926{
927   int i, j;
928   real det = 0;
929
930   SVX_ASSERT((/*const*/ var *)inv != v);
931
932   check_var(v);
933   for (i = 0; i < 3; i++) {
934      det += V(i, 0) * (V((i + 1) % 3, 1) * V((i + 2) % 3, 2) -
935                        V((i + 1) % 3, 2) * V((i + 2) % 3, 1));
936   }
937
938   if (det == 0.0) {
939      /* printf("det=%.20f\n", det); */
940      return 0; /* matrix is singular */
941   }
942
943   det = 1 / det;
944
945#define B(I,J) ((*v)[(J)%3][(I)%3])
946   for (i = 0; i < 3; i++) {
947      for (j = 0; j < 3; j++) {
948         (*inv)[i][j] = det * (B(i+1,j+1)*B(i+2,j+2) - B(i+2,j+1)*B(i+1,j+2));
949      }
950   }
951#undef B
952
953#if 0
954   /* This test fires very occasionally, and there's not much point in
955    * it anyhow - the matrix inversion algorithm is simple enough that
956    * we can be confident it's correctly implemented, so we might as
957    * well save the cycles and not perform this check.
958    */
959     { /* check that original * inverse = identity matrix */
960        var p;
961        real d = 0;
962        mulvv(&p, v, inv);
963        for (i = 0; i < 3; i++) {
964           for (j = 0; j < 3; j++) d += fabs(p[i][j] - (real)(i==j));
965        }
966        if (d > THRESHOLD) {
967           printf("original * inverse=\n");
968           print_var(*v);
969           printf("*\n");
970           print_var(*inv);
971           printf("=\n");
972           print_var(p);
973           BUG("matrix didn't invert");
974        }
975        check_var(inv);
976     }
977#endif
978
979   return 1;
980}
981#endif
982
983/* inv = v^-1 ; inv,v variance matrices */
984#ifndef NO_COVARIANCES
985extern int
986invert_svar(svar *inv, /*const*/ svar *v)
987{
988   real det, a, b, c, d, e, f, bcff, efcd, dfbe;
989
990#if 0
991   SVX_ASSERT((/*const*/ var *)inv != v);
992#endif
993
994   check_svar(v);
995   /* a d e
996    * d b f
997    * e f c
998    */
999   a = (*v)[0], b = (*v)[1], c = (*v)[2];
1000   d = (*v)[3], e = (*v)[4], f = (*v)[5];
1001   bcff = b * c - f * f;
1002   efcd = e * f - c * d;
1003   dfbe = d * f - b * e;
1004   det = a * bcff + d * efcd + e * dfbe;
1005
1006   if (det == 0.0) {
1007      /* printf("det=%.20f\n", det); */
1008      return 0; /* matrix is singular */
1009   }
1010
1011   det = 1 / det;
1012
1013   (*inv)[0] = det * bcff;
1014   (*inv)[1] = det * (c * a - e * e);
1015   (*inv)[2] = det * (a * b - d * d);
1016   (*inv)[3] = det * efcd;
1017   (*inv)[4] = det * dfbe;
1018   (*inv)[5] = det * (e * d - a * f);
1019
1020#if 0
1021   /* This test fires very occasionally, and there's not much point in
1022    * it anyhow - the matrix inversion algorithm is simple enough that
1023    * we can be confident it's correctly implemented, so we might as
1024    * well save the cycles and not perform this check.
1025    */
1026     { /* check that original * inverse = identity matrix */
1027        int i;
1028        var p;
1029        real D = 0;
1030        mulss(&p, v, inv);
1031        for (i = 0; i < 3; i++) {
1032           int j;
1033           for (j = 0; j < 3; j++) D += fabs(p[i][j] - (real)(i==j));
1034        }
1035        if (D > THRESHOLD) {
1036           printf("original * inverse=\n");
1037           print_svar(*v);
1038           printf("*\n");
1039           print_svar(*inv);
1040           printf("=\n");
1041           print_var(p);
1042           BUG("matrix didn't invert");
1043        }
1044        check_svar(inv);
1045     }
1046#endif
1047   return 1;
1048}
1049#endif
1050
1051/* r = (b^-1)a ; r,a delta vectors; b variance matrix */
1052void
1053divdv(delta *r, /*const*/ delta *a, /*const*/ var *b)
1054{
1055#ifdef NO_COVARIANCES
1056   /* variance-only version */
1057   (*r)[0] = (*a)[0] / (*b)[0];
1058   (*r)[1] = (*a)[1] / (*b)[1];
1059   (*r)[2] = (*a)[2] / (*b)[2];
1060#else
1061   var b_inv;
1062   if (!invert_var(&b_inv, b)) {
1063      print_var(*b);
1064      BUG("covariance matrix is singular");
1065   }
1066   mulvd(r, &b_inv, a);
1067#endif
1068}
1069
1070/* r = (b^-1)a ; r,a delta vectors; b variance matrix */
1071#ifndef NO_COVARIANCES
1072void
1073divds(delta *r, /*const*/ delta *a, /*const*/ svar *b)
1074{
1075   svar b_inv;
1076   if (!invert_svar(&b_inv, b)) {
1077      print_svar(*b);
1078      BUG("covariance matrix is singular");
1079   }
1080   mulsd(r, &b_inv, a);
1081}
1082#endif
1083
1084/* f = a(b^-1) ; r,a,b variance matrices */
1085void
1086divvv(var *r, /*const*/ var *a, /*const*/ var *b)
1087{
1088#ifdef NO_COVARIANCES
1089   /* variance-only version */
1090   (*r)[0] = (*a)[0] / (*b)[0];
1091   (*r)[1] = (*a)[1] / (*b)[1];
1092   (*r)[2] = (*a)[2] / (*b)[2];
1093#else
1094   var b_inv;
1095   check_var(a);
1096   check_var(b);
1097   if (!invert_var(&b_inv, b)) {
1098      print_var(*b);
1099      BUG("covariance matrix is singular");
1100   }
1101   mulvv(r, a, &b_inv);
1102   check_var(r);
1103#endif
1104}
1105
1106bool
1107fZeros(/*const*/ svar *v) {
1108#ifdef NO_COVARIANCES
1109   /* variance-only version */
1110   return ((*v)[0] == 0.0 && (*v)[1] == 0.0 && (*v)[2] == 0.0);
1111#else
1112   int i;
1113
1114   check_svar(v);
1115   for (i = 0; i < 6; i++) if ((*v)[i] != 0.0) return fFalse;
1116
1117   return fTrue;
1118#endif
1119}
Note: See TracBrowser for help on using the repository browser.