source: git/src/network.c @ e3f7ea7

stereo-2025
Last change on this file since e3f7ea7 was c77682a, checked in by Olly Betts <olly@…>, 4 months ago

Stop reporting node stats

These are kind of interesting, but since the advent of surveying with
Disto-X and similar devices which make it quick to shoot multiple
splay legs from each station the number of larger order nodes has
increased and this information is now quite verbose and any utility
it had has substantially declined.

If they're still wanted they could make a reappearance in the future in
aven, with splays excluded when counting the number of legs at each
station.

Fixes #86, reported by Wookey.

  • Property mode set to 100644
File size: 21.7 KB
Line 
1/* network.c
2 * Survex network reduction - find patterns and apply network reductions
3 * Copyright (C) 1991-2002,2005,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#if 0
21#define DEBUG_INVALID 1
22#define VALIDATE 1
23#define DUMP_NETWORK 1
24#endif
25
26#include <config.h>
27
28#include "validate.h"
29#include "debug.h"
30#include "cavern.h"
31#include "message.h"
32#include "netbits.h"
33#include "network.h"
34#include "out.h"
35
36typedef struct reduction {
37   struct reduction *next;
38   enum {
39       TYPE_PARALLEL,
40       TYPE_LOLLIPOP,
41       TYPE_DELTASTAR,
42   } type;
43   linkfor* join[];
44} reduction;
45
46#define allocate_reduction(N) osmalloc(sizeof(reduction) + (N) * sizeof(linkfor*))
47
48// Head of linked list of reductions.
49static reduction *reduction_stack;
50
51/* can be altered by -z<letters> on command line */
52unsigned long optimize = BITA('l') | BITA('p') | BITA('d');
53/* Lollipops, Parallel legs, Iterate mx, Delta* */
54
55extern void
56remove_subnets(void)
57{
58   node *stn, *stn2, *stn3, *stn4;
59   int dirn, dirn2, dirn3, dirn4;
60   reduction *trav;
61   linkfor *newleg, *newleg2;
62   bool fMore = true;
63
64   reduction_stack = NULL;
65
66   out_current_action(msg(/*Simplifying network*/129));
67
68   while (fMore) {
69      fMore = false;
70      if (optimize & BITA('l')) {
71#if PRINT_NETBITS
72         printf("replacing lollipops\n");
73#endif
74         /* NB can have non-fixed 0 nodes */
75         FOR_EACH_STN(stn, stnlist) {
76            if (three_node(stn)) {
77               dirn = -1;
78               if (stn->leg[1]->l.to == stn) dirn++;
79               if (stn->leg[0]->l.to == stn) dirn += 2;
80               if (dirn < 0) continue;
81
82               stn2 = stn->leg[dirn]->l.to;
83               if (fixed(stn2)) {
84                   /*    _
85                    *   ( )
86                    *    * stn
87                    *    |
88                    *    * stn2 (fixed)
89                    *    : (may have other connections)
90                    *
91                    * The leg forming the "stick" of the lollipop is
92                    * articulating so we can just fix stn with coordinates
93                    * calculated by adding or subtracting the leg's vector.
94                    */
95                   linkfor *leg = stn->leg[dirn];
96                   linkfor *rev_leg = reverse_leg(leg);
97                   leg->l.reverse |= FLAG_ARTICULATION;
98                   rev_leg->l.reverse |= FLAG_ARTICULATION;
99                   if (data_here(leg)) {
100                       subdd(&POSD(stn), &POSD(stn2), &leg->d);
101                   } else {
102                       adddd(&POSD(stn), &POSD(stn2), &rev_leg->d);
103                   }
104                   remove_stn_from_list(&stnlist, stn);
105                   add_stn_to_list(&fixedlist, stn);
106                   continue;
107               }
108
109               SVX_ASSERT(three_node(stn2));
110
111               /*        _
112                *       ( )
113                *        * stn
114                *        |
115                *        * stn2
116                *       / \
117                * stn4 *   * stn3  -->  stn4 *---* stn3
118                *      :   :                 :   :
119                */
120               dirn2 = reverse_leg_dirn(stn->leg[dirn]);
121               dirn2 = (dirn2 + 1) % 3;
122               stn3 = stn2->leg[dirn2]->l.to;
123               if (stn2 == stn3) continue; /* dumb-bell - leave alone */
124
125               dirn3 = reverse_leg_dirn(stn2->leg[dirn2]);
126
127               trav = allocate_reduction(2);
128               trav->type = TYPE_LOLLIPOP;
129
130               newleg2 = (linkfor*)osnew(linkcommon);
131
132               newleg = copy_link(stn3->leg[dirn3]);
133
134               dirn2 = (dirn2 + 1) % 3;
135               stn4 = stn2->leg[dirn2]->l.to;
136               dirn4 = reverse_leg_dirn(stn2->leg[dirn2]);
137#if 0
138               printf("Lollipop found with stn...stn4 = \n");
139               print_prefix(stn->name); putnl();
140               print_prefix(stn2->name); putnl();
141               print_prefix(stn3->name); putnl();
142               print_prefix(stn4->name); putnl();
143#endif
144
145               addto_link(newleg, stn2->leg[dirn2]);
146
147               /* remove stn and stn2 */
148               remove_stn_from_list(&stnlist, stn);
149               remove_stn_from_list(&stnlist, stn2);
150
151               /* stack lollipop and replace with a leg between stn3 and stn4 */
152               trav->join[0] = stn3->leg[dirn3];
153               newleg->l.to = stn4;
154               newleg->l.reverse = dirn4 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
155
156               trav->join[1] = stn4->leg[dirn4];
157               newleg2->l.to = stn3;
158               newleg2->l.reverse = dirn3 | FLAG_REPLACEMENTLEG;
159
160               stn3->leg[dirn3] = newleg;
161               stn4->leg[dirn4] = newleg2;
162
163               trav->next = reduction_stack;
164#if PRINT_NETBITS
165               printf("remove lollipop\n");
166#endif
167               reduction_stack = trav;
168               fMore = true;
169            }
170         }
171      }
172
173      if (optimize & BITA('p')) {
174#if PRINT_NETBITS
175         printf("replacing parallel legs\n");
176#endif
177         FOR_EACH_STN(stn, stnlist) {
178            /*
179             *  :            :
180             *  * stn3       * stn3
181             *  |            |
182             *  * stn        |
183             * ( )      -->  |
184             *  * stn2       |
185             *  |            |
186             *  * stn4       * stn4
187             *  :            :
188             */
189            if (three_node(stn)) {
190               stn2 = stn->leg[0]->l.to;
191               if (stn2 == stn->leg[1]->l.to) {
192                  dirn = 2;
193               } else if (stn2 == stn->leg[2]->l.to) {
194                  dirn = 1;
195               } else {
196                  if (stn->leg[1]->l.to != stn->leg[2]->l.to) continue;
197                  stn2 = stn->leg[1]->l.to;
198                  dirn = 0;
199               }
200
201               /* stn == stn2 => lollipop */
202               if (stn == stn2 || fixed(stn2)) continue;
203
204               SVX_ASSERT(three_node(stn2));
205
206               stn3 = stn->leg[dirn]->l.to;
207               /* 3 parallel legs (=> nothing else) so leave */
208               if (stn3 == stn2) continue;
209
210               dirn3 = reverse_leg_dirn(stn->leg[dirn]);
211               dirn2 = (0 + 1 + 2 - reverse_leg_dirn(stn->leg[(dirn + 1) % 3])
212                        - reverse_leg_dirn(stn->leg[(dirn + 2) % 3]));
213
214               stn4 = stn2->leg[dirn2]->l.to;
215               dirn4 = reverse_leg_dirn(stn2->leg[dirn2]);
216
217               trav = allocate_reduction(2);
218               trav->type = TYPE_PARALLEL;
219
220               newleg = copy_link(stn->leg[(dirn + 1) % 3]);
221               /* use newleg2 for scratch */
222               newleg2 = copy_link(stn->leg[(dirn + 2) % 3]);
223                 {
224#ifdef NO_COVARIANCES
225                    vars sum;
226                    var prod;
227                    delta temp, temp2;
228                    addss(&sum, &newleg->v, &newleg2->v);
229                    SVX_ASSERT2(!fZeros(&sum), "loop of zero variance found");
230                    mulss(&prod, &newleg->v, &newleg2->v);
231                    mulsd(&temp, &newleg2->v, &newleg->d);
232                    mulsd(&temp2, &newleg->v, &newleg2->d);
233                    adddd(&temp, &temp, &temp2);
234                    divds(&newleg->d, &temp, &sum);
235                    sdivvs(&newleg->v, &prod, &sum);
236#else
237                    svar inv1, inv2, sum;
238                    delta temp, temp2;
239                    /* if leg one is an equate, we can just ignore leg two
240                     * whatever it is */
241                    if (invert_svar(&inv1, &newleg->v)) {
242                       if (invert_svar(&inv2, &newleg2->v)) {
243                          addss(&sum, &inv1, &inv2);
244                          if (!invert_svar(&newleg->v, &sum)) {
245                             BUG("matrix singular in parallel legs replacement");
246                          }
247
248                          mulsd(&temp, &inv1, &newleg->d);
249                          mulsd(&temp2, &inv2, &newleg2->d);
250                          adddd(&temp, &temp, &temp2);
251                          mulsd(&newleg->d, &newleg->v, &temp);
252                       } else {
253                          /* leg two is an equate, so just ignore leg 1 */
254                          linkfor *tmpleg;
255                          tmpleg = newleg;
256                          newleg = newleg2;
257                          newleg2 = tmpleg;
258                       }
259                    }
260#endif
261                 }
262               osfree(newleg2);
263               newleg2 = (linkfor*)osnew(linkcommon);
264
265               addto_link(newleg, stn2->leg[dirn2]);
266               addto_link(newleg, stn3->leg[dirn3]);
267
268#if 0
269               printf("Parallel found with stn...stn4 = \n");
270               (dump_node)(stn); (dump_node)(stn2); (dump_node)(stn3); (dump_node)(stn4);
271               printf("dirns = %d %d %d %d\n", dirn, dirn2, dirn3, dirn4);
272#endif
273               SVX_ASSERT2(stn3->leg[dirn3]->l.to == stn, "stn3 end of || doesn't recip");
274               SVX_ASSERT2(stn4->leg[dirn4]->l.to == stn2, "stn4 end of || doesn't recip");
275               SVX_ASSERT2(stn->leg[(dirn+1)%3]->l.to == stn2 && stn->leg[(dirn + 2) % 3]->l.to == stn2, "|| legs aren't");
276
277               /* remove stn and stn2 (already discarded triple parallel) */
278               /* so stn!=stn4 <=> stn2!=stn3 */
279               remove_stn_from_list(&stnlist, stn);
280               remove_stn_from_list(&stnlist, stn2);
281
282               /* stack parallel and replace with a leg between stn3 and stn4 */
283               trav->join[0] = stn3->leg[dirn3];
284               newleg->l.to = stn4;
285               newleg->l.reverse = dirn4 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
286
287               trav->join[1] = stn4->leg[dirn4];
288               newleg2->l.to = stn3;
289               newleg2->l.reverse = dirn3 | FLAG_REPLACEMENTLEG;
290
291               stn3->leg[dirn3] = newleg;
292               stn4->leg[dirn4] = newleg2;
293
294               trav->next = reduction_stack;
295#if PRINT_NETBITS
296               printf("remove parallel\n");
297#endif
298               reduction_stack = trav;
299               fMore = true;
300            }
301         }
302      }
303
304      if (optimize & BITA('d')) {
305         node *stn5, *stn6;
306         int dirn5, dirn6;
307         linkfor *legAB, *legBC, *legCA;
308#if PRINT_NETBITS
309         printf("replacing deltas with stars\n");
310#endif
311         FOR_EACH_STN(stn, stnlist) {
312            /*    printf("*");*/
313            /*
314             *          :                     :
315             *          * stn5                * stn5
316             *          |                     |
317             *          * stn2                |
318             *         / \        -->         O stnZ
319             *        |   |                  / \
320             *    stn *---* stn3            /   \
321             *       /     \               /     \
322             * stn4 *       * stn6   stn4 *       * stn6
323             *      :       :             :       :
324             */
325            if (three_node(stn)) {
326               for (int dirn12 = 0; dirn12 <= 2; dirn12++) {
327                  stn2 = stn->leg[dirn12]->l.to;
328                  if (stn2 == stn || fixed(stn2)) continue;
329                  SVX_ASSERT(three_node(stn2));
330                  int dirn13 = (dirn12 + 1) % 3;
331                  stn3 = stn->leg[dirn13]->l.to;
332                  if (stn3 == stn || stn3 == stn2 || fixed(stn3)) continue;
333                  SVX_ASSERT(three_node(stn3));
334                  int dirn23 = reverse_leg_dirn(stn->leg[dirn12]);
335                  dirn23 = (dirn23 + 1) % 3;
336                  if (stn2->leg[dirn23]->l.to != stn3) {
337                      dirn23 = (dirn23 + 1) % 3;
338                      if (stn2->leg[dirn23]->l.to != stn3) {
339                          continue;
340                      }
341                  }
342                  legAB = copy_link(stn->leg[dirn12]);
343                  legBC = copy_link(stn2->leg[dirn23]);
344                  legCA = copy_link(stn3->leg[reverse_leg_dirn(stn->leg[dirn13])]);
345                  dirn = (0 + 1 + 2) - dirn12 - dirn13;
346                  dirn2 = (0 + 1 + 2) - dirn23 - reverse_leg_dirn(stn->leg[dirn12]);
347                  dirn3 = (0 + 1 + 2) - reverse_leg_dirn(stn->leg[dirn13]) - reverse_leg_dirn(stn2->leg[dirn23]);
348                  stn4 = stn->leg[dirn]->l.to;
349                  stn5 = stn2->leg[dirn2]->l.to;
350                  stn6 = stn3->leg[dirn3]->l.to;
351                  if (stn4 == stn2 || stn4 == stn3 || stn5 == stn3) continue;
352                  dirn4 = reverse_leg_dirn(stn->leg[dirn]);
353                  dirn5 = reverse_leg_dirn(stn2->leg[dirn2]);
354                  dirn6 = reverse_leg_dirn(stn3->leg[dirn3]);
355#if 0
356                  printf("delta-star, stn ... stn6 are:\n");
357                  (dump_node)(stn);
358                  (dump_node)(stn2);
359                  (dump_node)(stn3);
360                  (dump_node)(stn4);
361                  (dump_node)(stn5);
362                  (dump_node)(stn6);
363#endif
364                  SVX_ASSERT(stn4->leg[dirn4]->l.to == stn);
365                  SVX_ASSERT(stn5->leg[dirn5]->l.to == stn2);
366                  SVX_ASSERT(stn6->leg[dirn6]->l.to == stn3);
367
368                  trav = allocate_reduction(3);
369                  trav->type = TYPE_DELTASTAR;
370                  {
371                    linkfor *legAZ, *legBZ, *legCZ;
372                    node *stnZ;
373                    prefix *nameZ;
374                    svar invAB, invBC, invCA, tmp, sum, inv;
375                    var vtmp;
376                    svar sumAZBZ, sumBZCZ, sumCZAZ;
377                    delta temp, temp2;
378
379                    /* FIXME: ought to handle cases when some legs are
380                     * equates, but handle as a special case maybe? */
381                    if (!invert_svar(&invAB, &legAB->v)) break;
382                    if (!invert_svar(&invBC, &legBC->v)) break;
383                    if (!invert_svar(&invCA, &legCA->v)) break;
384
385                    addss(&sum, &legBC->v, &legCA->v);
386                    addss(&tmp, &sum, &legAB->v);
387                    if (!invert_svar(&inv, &tmp)) {
388                       /* impossible - loop of zero variance */
389                       BUG("loop of zero variance found");
390                    }
391
392                    legAZ = osnew(linkfor);
393                    legBZ = osnew(linkfor);
394                    legCZ = osnew(linkfor);
395
396                    /* AZBZ */
397                    /* done above: addvv(&sum, &legBC->v, &legCA->v); */
398                    mulss(&vtmp, &sum, &inv);
399                    smulvs(&sumAZBZ, &vtmp, &legAB->v);
400
401                    adddd(&temp, &legBC->d, &legCA->d);
402                    divds(&temp2, &temp, &sum);
403                    mulsd(&temp, &invAB, &legAB->d);
404                    subdd(&temp, &temp2, &temp);
405                    mulsd(&legBZ->d, &sumAZBZ, &temp);
406
407                    /* leg vectors after transform are determined up to
408                     * a constant addition, so arbitrarily fix AZ = 0 */
409                    legAZ->d[2] = legAZ->d[1] = legAZ->d[0] = 0;
410
411                    /* BZCZ */
412                    addss(&sum, &legCA->v, &legAB->v);
413                    mulss(&vtmp, &sum, &inv);
414                    smulvs(&sumBZCZ, &vtmp, &legBC->v);
415
416                    /* CZAZ */
417                    addss(&sum, &legAB->v, &legBC->v);
418                    mulss(&vtmp, &sum, &inv);
419                    smulvs(&sumCZAZ, &vtmp, &legCA->v);
420
421                    adddd(&temp, &legAB->d, &legBC->d);
422                    divds(&temp2, &temp, &sum);
423                    mulsd(&temp, &invCA, &legCA->d);
424                    /* NB: swapped arguments to negate answer for legCZ->d */
425                    subdd(&temp, &temp, &temp2);
426                    mulsd(&legCZ->d, &sumCZAZ, &temp);
427
428                    osfree(legAB);
429                    osfree(legBC);
430                    osfree(legCA);
431
432                    /* Now add two, subtract third, and scale by 0.5 */
433                    addss(&sum, &sumAZBZ, &sumCZAZ);
434                    subss(&sum, &sum, &sumBZCZ);
435                    mulsc(&legAZ->v, &sum, 0.5);
436
437                    addss(&sum, &sumBZCZ, &sumAZBZ);
438                    subss(&sum, &sum, &sumCZAZ);
439                    mulsc(&legBZ->v, &sum, 0.5);
440
441                    addss(&sum, &sumCZAZ, &sumBZCZ);
442                    subss(&sum, &sum, &sumAZBZ);
443                    mulsc(&legCZ->v, &sum, 0.5);
444
445                    nameZ = osnew(prefix);
446                    nameZ->pos = osnew(pos);
447                    nameZ->ident.p = NULL;
448                    stnZ = osnew(node);
449                    stnZ->name = nameZ;
450                    nameZ->stn = stnZ;
451                    nameZ->up = NULL;
452                    nameZ->min_export = nameZ->max_export = 0;
453                    nameZ->sflags = 0;
454                    unfix(stnZ);
455                    add_stn_to_list(&stnlist, stnZ);
456                    legAZ->l.to = stnZ;
457                    legAZ->l.reverse = 0 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
458                    legBZ->l.to = stnZ;
459                    legBZ->l.reverse = 1 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
460                    legCZ->l.to = stnZ;
461                    legCZ->l.reverse = 2 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
462                    stnZ->leg[0] = (linkfor*)osnew(linkcommon);
463                    stnZ->leg[1] = (linkfor*)osnew(linkcommon);
464                    stnZ->leg[2] = (linkfor*)osnew(linkcommon);
465                    stnZ->leg[0]->l.to = stn4;
466                    stnZ->leg[0]->l.reverse = dirn4;
467                    stnZ->leg[1]->l.to = stn5;
468                    stnZ->leg[1]->l.reverse = dirn5;
469                    stnZ->leg[2]->l.to = stn6;
470                    stnZ->leg[2]->l.reverse = dirn6;
471                    addto_link(legAZ, stn4->leg[dirn4]);
472                    addto_link(legBZ, stn5->leg[dirn5]);
473                    addto_link(legCZ, stn6->leg[dirn6]);
474                    /* stack stuff */
475                    trav->join[0] = stn4->leg[dirn4];
476                    trav->join[1] = stn5->leg[dirn5];
477                    trav->join[2] = stn6->leg[dirn6];
478                    trav->next = reduction_stack;
479#if PRINT_NETBITS
480                    printf("remove delta*\n");
481#endif
482                    reduction_stack = trav;
483                    fMore = true;
484
485                    remove_stn_from_list(&stnlist, stn);
486                    remove_stn_from_list(&stnlist, stn2);
487                    remove_stn_from_list(&stnlist, stn3);
488                    stn4->leg[dirn4] = legAZ;
489                    stn5->leg[dirn5] = legBZ;
490                    stn6->leg[dirn6] = legCZ;
491                  }
492                  break;
493               }
494            }
495         }
496      }
497
498   }
499}
500
501extern void
502replace_subnets(void)
503{
504   node *stn2, *stn3, *stn4;
505   int dirn2, dirn3, dirn4;
506
507   /* help to catch bad accesses */
508   stn2 = stn3 = stn4 = NULL;
509   dirn2 = dirn3 = dirn4 = 0;
510
511   out_current_action(msg(/*Calculating network*/130));
512
513   while (reduction_stack != NULL) {
514      /*  printf("replace_subnets() type %d\n", reduction_stack->type);*/
515
516#if PRINT_NETBITS
517      printf("replace_subnets\n");
518      if (reduction_stack->type == TYPE_LOLLIPOP) printf("islollipop\n");
519      if (reduction_stack->type == TYPE_PARALLEL) printf("isparallel\n");
520      if (reduction_stack->type == TYPE_DELTASTAR) printf("isdelta*\n");
521#endif
522
523      if (reduction_stack->type != TYPE_DELTASTAR) {
524         linkfor *leg;
525         leg = reduction_stack->join[0]; leg = reverse_leg(leg);
526         stn3 = leg->l.to; dirn3 = reverse_leg_dirn(leg);
527         leg = reduction_stack->join[1]; leg = reverse_leg(leg);
528         stn4 = leg->l.to; dirn4 = reverse_leg_dirn(leg);
529
530         if (!fixed(stn3) || !fixed(stn4)) {
531             SVX_ASSERT(!fixed(stn3) && !fixed(stn4));
532             goto skip;
533         }
534         SVX_ASSERT(data_here(stn3->leg[dirn3]));
535      }
536
537      if (reduction_stack->type == TYPE_LOLLIPOP) {
538         node *stn;
539         delta e;
540         linkfor *leg;
541         int zero;
542
543         leg = stn3->leg[dirn3];
544         stn2 = reduction_stack->join[0]->l.to;
545         dirn2 = reverse_leg_dirn(reduction_stack->join[0]);
546
547         zero = fZeros(&leg->v);
548         if (!zero) {
549            delta tmp;
550            subdd(&e, &POSD(stn4), &POSD(stn3));
551            subdd(&tmp, &e, &leg->d);
552            divds(&e, &tmp, &leg->v);
553         }
554         if (data_here(reduction_stack->join[0])) {
555            adddd(&POSD(stn2), &POSD(stn3), &reduction_stack->join[0]->d);
556            if (!zero) {
557               delta tmp;
558               mulsd(&tmp, &reduction_stack->join[0]->v, &e);
559               adddd(&POSD(stn2), &POSD(stn2), &tmp);
560            }
561         } else {
562            subdd(&POSD(stn2), &POSD(stn3), &stn2->leg[dirn2]->d);
563            if (!zero) {
564               delta tmp;
565               mulsd(&tmp, &stn2->leg[dirn2]->v, &e);
566               adddd(&POSD(stn2), &POSD(stn2), &tmp);
567            }
568         }
569         dirn2 = (dirn2 + 2) % 3; /* point back at stn again */
570         stn = stn2->leg[dirn2]->l.to;
571#if 0
572         printf("Replacing lollipop with stn...stn4 = \n");
573         print_prefix(stn->name); putnl();
574         print_prefix(stn2->name); putnl();
575         print_prefix(stn3->name); putnl();
576         print_prefix(stn4->name); putnl();
577#endif
578         if (data_here(stn2->leg[dirn2]))
579            adddd(&POSD(stn), &POSD(stn2), &stn2->leg[dirn2]->d);
580         else
581            subdd(&POSD(stn), &POSD(stn2), &reverse_leg(stn2->leg[dirn2])->d);
582
583         /* The "stick" of the lollipop is a new articulation. */
584         stn2->leg[dirn2]->l.reverse |= FLAG_ARTICULATION;
585         reverse_leg(stn2->leg[dirn2])->l.reverse |= FLAG_ARTICULATION;
586
587         add_stn_to_list(&fixedlist, stn);
588         add_stn_to_list(&fixedlist, stn2);
589
590         osfree(stn3->leg[dirn3]);
591         stn3->leg[dirn3] = reduction_stack->join[0];
592         osfree(stn4->leg[dirn4]);
593         stn4->leg[dirn4] = reduction_stack->join[1];
594      } else if (reduction_stack->type == TYPE_PARALLEL) {
595         /* parallel legs */
596         node *stn;
597         delta e, e2;
598         linkfor *leg;
599         int dirn;
600
601         stn = reduction_stack->join[0]->l.to;
602         stn2 = reduction_stack->join[1]->l.to;
603
604         dirn = reverse_leg_dirn(reduction_stack->join[0]);
605         dirn2 = reverse_leg_dirn(reduction_stack->join[1]);
606
607         leg = stn3->leg[dirn3];
608
609         if (leg->l.reverse & FLAG_ARTICULATION) {
610            reduction_stack->join[0]->l.reverse |= FLAG_ARTICULATION;
611            stn->leg[dirn]->l.reverse |= FLAG_ARTICULATION;
612            reduction_stack->join[1]->l.reverse |= FLAG_ARTICULATION;
613            stn2->leg[dirn2]->l.reverse |= FLAG_ARTICULATION;
614         }
615
616         if (fZeros(&leg->v))
617            e[0] = e[1] = e[2] = 0.0;
618         else {
619            delta tmp;
620            subdd(&e, &POSD(stn4), &POSD(stn3));
621            subdd(&tmp, &e, &leg->d);
622            divds(&e, &tmp, &leg->v);
623         }
624
625         if (data_here(reduction_stack->join[0])) {
626            leg = reduction_stack->join[0];
627            adddd(&POSD(stn), &POSD(stn3), &leg->d);
628         } else {
629            leg = stn->leg[dirn];
630            subdd(&POSD(stn), &POSD(stn3), &leg->d);
631         }
632         mulsd(&e2, &leg->v, &e);
633         adddd(&POSD(stn), &POSD(stn), &e2);
634
635         if (data_here(reduction_stack->join[1])) {
636            leg = reduction_stack->join[1];
637            adddd(&POSD(stn2), &POSD(stn4), &leg->d);
638         } else {
639            leg = stn2->leg[dirn2];
640            subdd(&POSD(stn2), &POSD(stn4), &leg->d);
641         }
642         mulsd(&e2, &leg->v, &e);
643         subdd(&POSD(stn2), &POSD(stn2), &e2);
644#if 0
645         printf("Replacing parallel with stn...stn4 = \n");
646         print_prefix(stn->name); putnl();
647         print_prefix(stn2->name); putnl();
648         print_prefix(stn3->name); putnl();
649         print_prefix(stn4->name); putnl();
650#endif
651
652         add_stn_to_list(&fixedlist, stn);
653         add_stn_to_list(&fixedlist, stn2);
654
655         osfree(stn3->leg[dirn3]);
656         stn3->leg[dirn3] = reduction_stack->join[0];
657         osfree(stn4->leg[dirn4]);
658         stn4->leg[dirn4] = reduction_stack->join[1];
659      } else if (reduction_stack->type == TYPE_DELTASTAR) {
660         node *stnZ;
661         node *stn[3];
662         int dirn[3];
663         int i;
664         linkfor *leg;
665
666         /* work out ends as we don't bother stacking them */
667         leg = reverse_leg(reduction_stack->join[0]);
668         stn[0] = leg->l.to;
669         dirn[0] = reverse_leg_dirn(leg);
670         stnZ = stn[0]->leg[dirn[0]]->l.to;
671         if (!fixed(stnZ)) {
672            SVX_ASSERT(!fixed(stn[0]));
673            goto skip;
674         }
675         stn[1] = stnZ->leg[1]->l.to;
676         dirn[1] = reverse_leg_dirn(stnZ->leg[1]);
677         stn[2] = stnZ->leg[2]->l.to;
678         dirn[2] = reverse_leg_dirn(stnZ->leg[2]);
679         /*print_prefix(stnZ->name);printf(" %p\n",(void*)stnZ);*/
680
681         for (i = 0; i < 3; i++) {
682            SVX_ASSERT2(fixed(stn[i]), "stn not fixed for D*");
683
684            leg = stn[i]->leg[dirn[i]];
685
686            SVX_ASSERT2(data_here(leg), "data not on leg for D*");
687            SVX_ASSERT2(leg->l.to == stnZ, "bad sub-network for D*");
688
689            stn2 = reduction_stack->join[i]->l.to;
690
691            if (data_here(reduction_stack->join[i])) {
692               adddd(&POSD(stn2), &POSD(stn[i]), &reduction_stack->join[i]->d);
693            } else {
694               subdd(&POSD(stn2), &POSD(stn[i]), &reverse_leg(reduction_stack->join[i])->d);
695            }
696
697            if (!fZeros(&leg->v)) {
698               delta e, tmp;
699               subdd(&e, &POSD(stnZ), &POSD(stn[i]));
700               subdd(&e, &e, &leg->d);
701               divds(&tmp, &e, &leg->v);
702               if (data_here(reduction_stack->join[i])) {
703                  mulsd(&e, &reduction_stack->join[i]->v, &tmp);
704               } else {
705                  mulsd(&e, &reverse_leg(reduction_stack->join[i])->v, &tmp);
706               }
707               adddd(&POSD(stn2), &POSD(stn2), &e);
708            }
709            add_stn_to_list(&fixedlist, stn2);
710            osfree(leg);
711            stn[i]->leg[dirn[i]] = reduction_stack->join[i];
712            /* transfer the articulation status of the radial legs */
713            if (stnZ->leg[i]->l.reverse & FLAG_ARTICULATION) {
714               reduction_stack->join[i]->l.reverse |= FLAG_ARTICULATION;
715               reverse_leg(reduction_stack->join[i])->l.reverse |= FLAG_ARTICULATION;
716            }
717            osfree(stnZ->leg[i]);
718            stnZ->leg[i] = NULL;
719         }
720/*printf("---%f %f %f\n",POS(stnZ, 0), POS(stnZ, 1), POS(stnZ, 2));*/
721         remove_stn_from_list(&fixedlist, stnZ);
722         osfree(stnZ->name);
723         osfree(stnZ);
724      } else {
725         BUG("reduction_stack has unknown type");
726      }
727
728skip:;
729      reduction *ptrOld = reduction_stack;
730      reduction_stack = reduction_stack->next;
731      osfree(ptrOld);
732   }
733}
Note: See TracBrowser for help on using the repository browser.