source: git/src/netbits.c @ 7f4a756

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 7f4a756 was a4ae909, checked in by Olly Betts <olly@…>, 20 years ago

Removed support for writing Chasm's 3dx format.

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

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