source: git/src/network.c @ 37c5191

stereo-2025
Last change on this file since 37c5191 was 37c5191, checked in by Olly Betts <olly@…>, 8 months ago

Dynamically size stacked network reductions

The number of link legs we need to store varies depending on the
reduction type, and is likely to vary more with some future reductions.

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