Fix message references for inches and feet
[survex.git] / src / network.c
blobeafa892b7a0abaec869e4ba525ea7e234a7c7f59
1 /* network.c
2 * Survex network reduction - find patterns and apply network reductions
3 * Copyright (C) 1991-2002,2005,2024 Olly Betts
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.
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.
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
20 #if 0
21 #define DEBUG_INVALID 1
22 #define VALIDATE 1
23 #define DUMP_NETWORK 1
24 #endif
26 #include <config.h>
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"
36 typedef struct reduction {
37 struct reduction *next;
38 enum {
39 TYPE_PARALLEL,
40 TYPE_LOLLIPOP,
41 TYPE_DELTASTAR,
42 } type;
43 linkfor* join[];
44 } reduction;
46 #define allocate_reduction(N) osmalloc(sizeof(reduction) + (N) * sizeof(linkfor*))
48 // Head of linked list of reductions.
49 static reduction *reduction_stack;
51 /* can be altered by -z<letters> on command line */
52 unsigned long optimize = BITA('l') | BITA('p') | BITA('d');
53 /* Lollipops, Parallel legs, Iterate mx, Delta* */
55 extern void
56 remove_subnets(void)
58 node *stn, *stn2, *stn3, *stn4;
59 int dirn, dirn2, dirn3, dirn4;
60 reduction *trav;
61 linkfor *newleg, *newleg2;
62 bool fMore = true;
64 reduction_stack = NULL;
66 out_current_action(msg(/*Simplifying network*/129));
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;
82 stn2 = stn->leg[dirn]->l.to;
83 if (fixed(stn2)) {
84 /* _
85 * ( )
86 * * stn
87 * |
88 * * stn2 (fixed)
89 * : (may have other connections)
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.
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);
104 remove_stn_from_list(&stnlist, stn);
105 add_stn_to_list(&fixedlist, stn);
106 continue;
109 SVX_ASSERT(three_node(stn2));
111 /* _
112 * ( )
113 * * stn
115 * * stn2
116 * / \
117 * stn4 * * stn3 --> stn4 *---* stn3
118 * : : : :
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 */
125 dirn3 = reverse_leg_dirn(stn2->leg[dirn2]);
127 trav = allocate_reduction(2);
128 trav->type = TYPE_LOLLIPOP;
130 newleg2 = (linkfor*)osnew(linkcommon);
132 newleg = copy_link(stn3->leg[dirn3]);
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
145 addto_link(newleg, stn2->leg[dirn2]);
147 /* remove stn and stn2 */
148 remove_stn_from_list(&stnlist, stn);
149 remove_stn_from_list(&stnlist, stn2);
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;
156 trav->join[1] = stn4->leg[dirn4];
157 newleg2->l.to = stn3;
158 newleg2->l.reverse = dirn3 | FLAG_REPLACEMENTLEG;
160 stn3->leg[dirn3] = newleg;
161 stn4->leg[dirn4] = newleg2;
163 trav->next = reduction_stack;
164 #if PRINT_NETBITS
165 printf("remove lollipop\n");
166 #endif
167 reduction_stack = trav;
168 fMore = true;
173 if (optimize & BITA('p')) {
174 #if PRINT_NETBITS
175 printf("replacing parallel legs\n");
176 #endif
177 FOR_EACH_STN(stn, stnlist) {
179 * : :
180 * * stn3 * stn3
181 * | |
182 * * stn |
183 * ( ) --> |
184 * * stn2 |
185 * | |
186 * * stn4 * stn4
187 * : :
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;
201 /* stn == stn2 => lollipop */
202 if (stn == stn2 || fixed(stn2)) continue;
204 SVX_ASSERT(three_node(stn2));
206 stn3 = stn->leg[dirn]->l.to;
207 /* 3 parallel legs (=> nothing else) so leave */
208 if (stn3 == stn2) continue;
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]));
214 stn4 = stn2->leg[dirn2]->l.to;
215 dirn4 = reverse_leg_dirn(stn2->leg[dirn2]);
217 trav = allocate_reduction(2);
218 trav->type = TYPE_PARALLEL;
220 newleg = copy_link(stn->leg[(dirn + 1) % 3]);
221 /* use newleg2 for scratch */
222 newleg2 = copy_link(stn->leg[(dirn + 2) % 3]);
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");
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;
260 #endif
262 osfree(newleg2);
263 newleg2 = (linkfor*)osnew(linkcommon);
265 addto_link(newleg, stn2->leg[dirn2]);
266 addto_link(newleg, stn3->leg[dirn3]);
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");
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);
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;
287 trav->join[1] = stn4->leg[dirn4];
288 newleg2->l.to = stn3;
289 newleg2->l.reverse = dirn3 | FLAG_REPLACEMENTLEG;
291 stn3->leg[dirn3] = newleg;
292 stn4->leg[dirn4] = newleg2;
294 trav->next = reduction_stack;
295 #if PRINT_NETBITS
296 printf("remove parallel\n");
297 #endif
298 reduction_stack = trav;
299 fMore = true;
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("*");*/
314 * : :
315 * * stn5 * stn5
316 * | |
317 * * stn2 |
318 * / \ --> O stnZ
319 * | | / \
320 * stn *---* stn3 / \
321 * / \ / \
322 * stn4 * * stn6 stn4 * * stn6
323 * : : : :
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;
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);
368 trav = allocate_reduction(3);
369 trav->type = TYPE_DELTASTAR;
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;
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;
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");
392 legAZ = osnew(linkfor);
393 legBZ = osnew(linkfor);
394 legCZ = osnew(linkfor);
396 /* AZBZ */
397 /* done above: addvv(&sum, &legBC->v, &legCA->v); */
398 mulss(&vtmp, &sum, &inv);
399 smulvs(&sumAZBZ, &vtmp, &legAB->v);
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);
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;
411 /* BZCZ */
412 addss(&sum, &legCA->v, &legAB->v);
413 mulss(&vtmp, &sum, &inv);
414 smulvs(&sumBZCZ, &vtmp, &legBC->v);
416 /* CZAZ */
417 addss(&sum, &legAB->v, &legBC->v);
418 mulss(&vtmp, &sum, &inv);
419 smulvs(&sumCZAZ, &vtmp, &legCA->v);
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);
428 osfree(legAB);
429 osfree(legBC);
430 osfree(legCA);
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);
437 addss(&sum, &sumBZCZ, &sumAZBZ);
438 subss(&sum, &sum, &sumCZAZ);
439 mulsc(&legBZ->v, &sum, 0.5);
441 addss(&sum, &sumCZAZ, &sumBZCZ);
442 subss(&sum, &sum, &sumAZBZ);
443 mulsc(&legCZ->v, &sum, 0.5);
445 nameZ = osnew(prefix);
446 nameZ->pos = osnew(pos);
447 nameZ->ident.p = NULL;
448 nameZ->shape = 3;
449 stnZ = osnew(node);
450 stnZ->name = nameZ;
451 nameZ->stn = stnZ;
452 nameZ->up = NULL;
453 nameZ->min_export = nameZ->max_export = 0;
454 nameZ->sflags = 0;
455 unfix(stnZ);
456 add_stn_to_list(&stnlist, stnZ);
457 legAZ->l.to = stnZ;
458 legAZ->l.reverse = 0 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
459 legBZ->l.to = stnZ;
460 legBZ->l.reverse = 1 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
461 legCZ->l.to = stnZ;
462 legCZ->l.reverse = 2 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
463 stnZ->leg[0] = (linkfor*)osnew(linkcommon);
464 stnZ->leg[1] = (linkfor*)osnew(linkcommon);
465 stnZ->leg[2] = (linkfor*)osnew(linkcommon);
466 stnZ->leg[0]->l.to = stn4;
467 stnZ->leg[0]->l.reverse = dirn4;
468 stnZ->leg[1]->l.to = stn5;
469 stnZ->leg[1]->l.reverse = dirn5;
470 stnZ->leg[2]->l.to = stn6;
471 stnZ->leg[2]->l.reverse = dirn6;
472 addto_link(legAZ, stn4->leg[dirn4]);
473 addto_link(legBZ, stn5->leg[dirn5]);
474 addto_link(legCZ, stn6->leg[dirn6]);
475 /* stack stuff */
476 trav->join[0] = stn4->leg[dirn4];
477 trav->join[1] = stn5->leg[dirn5];
478 trav->join[2] = stn6->leg[dirn6];
479 trav->next = reduction_stack;
480 #if PRINT_NETBITS
481 printf("remove delta*\n");
482 #endif
483 reduction_stack = trav;
484 fMore = true;
486 remove_stn_from_list(&stnlist, stn);
487 remove_stn_from_list(&stnlist, stn2);
488 remove_stn_from_list(&stnlist, stn3);
489 stn4->leg[dirn4] = legAZ;
490 stn5->leg[dirn5] = legBZ;
491 stn6->leg[dirn6] = legCZ;
493 break;
502 extern void
503 replace_subnets(void)
505 node *stn2, *stn3, *stn4;
506 int dirn2, dirn3, dirn4;
508 /* help to catch bad accesses */
509 stn2 = stn3 = stn4 = NULL;
510 dirn2 = dirn3 = dirn4 = 0;
512 out_current_action(msg(/*Calculating network*/130));
514 while (reduction_stack != NULL) {
515 /* printf("replace_subnets() type %d\n", reduction_stack->type);*/
517 #if PRINT_NETBITS
518 printf("replace_subnets\n");
519 if (reduction_stack->type == TYPE_LOLLIPOP) printf("islollipop\n");
520 if (reduction_stack->type == TYPE_PARALLEL) printf("isparallel\n");
521 if (reduction_stack->type == TYPE_DELTASTAR) printf("isdelta*\n");
522 #endif
524 if (reduction_stack->type != TYPE_DELTASTAR) {
525 linkfor *leg;
526 leg = reduction_stack->join[0]; leg = reverse_leg(leg);
527 stn3 = leg->l.to; dirn3 = reverse_leg_dirn(leg);
528 leg = reduction_stack->join[1]; leg = reverse_leg(leg);
529 stn4 = leg->l.to; dirn4 = reverse_leg_dirn(leg);
531 if (!fixed(stn3) || !fixed(stn4)) {
532 SVX_ASSERT(!fixed(stn3) && !fixed(stn4));
533 goto skip;
535 SVX_ASSERT(data_here(stn3->leg[dirn3]));
538 if (reduction_stack->type == TYPE_LOLLIPOP) {
539 node *stn;
540 delta e;
541 linkfor *leg;
542 int zero;
544 leg = stn3->leg[dirn3];
545 stn2 = reduction_stack->join[0]->l.to;
546 dirn2 = reverse_leg_dirn(reduction_stack->join[0]);
548 zero = fZeros(&leg->v);
549 if (!zero) {
550 delta tmp;
551 subdd(&e, &POSD(stn4), &POSD(stn3));
552 subdd(&tmp, &e, &leg->d);
553 divds(&e, &tmp, &leg->v);
555 if (data_here(reduction_stack->join[0])) {
556 adddd(&POSD(stn2), &POSD(stn3), &reduction_stack->join[0]->d);
557 if (!zero) {
558 delta tmp;
559 mulsd(&tmp, &reduction_stack->join[0]->v, &e);
560 adddd(&POSD(stn2), &POSD(stn2), &tmp);
562 } else {
563 subdd(&POSD(stn2), &POSD(stn3), &stn2->leg[dirn2]->d);
564 if (!zero) {
565 delta tmp;
566 mulsd(&tmp, &stn2->leg[dirn2]->v, &e);
567 adddd(&POSD(stn2), &POSD(stn2), &tmp);
570 dirn2 = (dirn2 + 2) % 3; /* point back at stn again */
571 stn = stn2->leg[dirn2]->l.to;
572 #if 0
573 printf("Replacing lollipop with stn...stn4 = \n");
574 print_prefix(stn->name); putnl();
575 print_prefix(stn2->name); putnl();
576 print_prefix(stn3->name); putnl();
577 print_prefix(stn4->name); putnl();
578 #endif
579 if (data_here(stn2->leg[dirn2]))
580 adddd(&POSD(stn), &POSD(stn2), &stn2->leg[dirn2]->d);
581 else
582 subdd(&POSD(stn), &POSD(stn2), &reverse_leg(stn2->leg[dirn2])->d);
584 /* The "stick" of the lollipop is a new articulation. */
585 stn2->leg[dirn2]->l.reverse |= FLAG_ARTICULATION;
586 reverse_leg(stn2->leg[dirn2])->l.reverse |= FLAG_ARTICULATION;
588 add_stn_to_list(&fixedlist, stn);
589 add_stn_to_list(&fixedlist, stn2);
591 osfree(stn3->leg[dirn3]);
592 stn3->leg[dirn3] = reduction_stack->join[0];
593 osfree(stn4->leg[dirn4]);
594 stn4->leg[dirn4] = reduction_stack->join[1];
595 } else if (reduction_stack->type == TYPE_PARALLEL) {
596 /* parallel legs */
597 node *stn;
598 delta e, e2;
599 linkfor *leg;
600 int dirn;
602 stn = reduction_stack->join[0]->l.to;
603 stn2 = reduction_stack->join[1]->l.to;
605 dirn = reverse_leg_dirn(reduction_stack->join[0]);
606 dirn2 = reverse_leg_dirn(reduction_stack->join[1]);
608 leg = stn3->leg[dirn3];
610 if (leg->l.reverse & FLAG_ARTICULATION) {
611 reduction_stack->join[0]->l.reverse |= FLAG_ARTICULATION;
612 stn->leg[dirn]->l.reverse |= FLAG_ARTICULATION;
613 reduction_stack->join[1]->l.reverse |= FLAG_ARTICULATION;
614 stn2->leg[dirn2]->l.reverse |= FLAG_ARTICULATION;
617 if (fZeros(&leg->v))
618 e[0] = e[1] = e[2] = 0.0;
619 else {
620 delta tmp;
621 subdd(&e, &POSD(stn4), &POSD(stn3));
622 subdd(&tmp, &e, &leg->d);
623 divds(&e, &tmp, &leg->v);
626 if (data_here(reduction_stack->join[0])) {
627 leg = reduction_stack->join[0];
628 adddd(&POSD(stn), &POSD(stn3), &leg->d);
629 } else {
630 leg = stn->leg[dirn];
631 subdd(&POSD(stn), &POSD(stn3), &leg->d);
633 mulsd(&e2, &leg->v, &e);
634 adddd(&POSD(stn), &POSD(stn), &e2);
636 if (data_here(reduction_stack->join[1])) {
637 leg = reduction_stack->join[1];
638 adddd(&POSD(stn2), &POSD(stn4), &leg->d);
639 } else {
640 leg = stn2->leg[dirn2];
641 subdd(&POSD(stn2), &POSD(stn4), &leg->d);
643 mulsd(&e2, &leg->v, &e);
644 subdd(&POSD(stn2), &POSD(stn2), &e2);
645 #if 0
646 printf("Replacing parallel with stn...stn4 = \n");
647 print_prefix(stn->name); putnl();
648 print_prefix(stn2->name); putnl();
649 print_prefix(stn3->name); putnl();
650 print_prefix(stn4->name); putnl();
651 #endif
653 add_stn_to_list(&fixedlist, stn);
654 add_stn_to_list(&fixedlist, stn2);
656 osfree(stn3->leg[dirn3]);
657 stn3->leg[dirn3] = reduction_stack->join[0];
658 osfree(stn4->leg[dirn4]);
659 stn4->leg[dirn4] = reduction_stack->join[1];
660 } else if (reduction_stack->type == TYPE_DELTASTAR) {
661 node *stnZ;
662 node *stn[3];
663 int dirn[3];
664 int i;
665 linkfor *leg;
667 /* work out ends as we don't bother stacking them */
668 leg = reverse_leg(reduction_stack->join[0]);
669 stn[0] = leg->l.to;
670 dirn[0] = reverse_leg_dirn(leg);
671 stnZ = stn[0]->leg[dirn[0]]->l.to;
672 if (!fixed(stnZ)) {
673 SVX_ASSERT(!fixed(stn[0]));
674 goto skip;
676 stn[1] = stnZ->leg[1]->l.to;
677 dirn[1] = reverse_leg_dirn(stnZ->leg[1]);
678 stn[2] = stnZ->leg[2]->l.to;
679 dirn[2] = reverse_leg_dirn(stnZ->leg[2]);
680 /*print_prefix(stnZ->name);printf(" %p\n",(void*)stnZ);*/
682 for (i = 0; i < 3; i++) {
683 SVX_ASSERT2(fixed(stn[i]), "stn not fixed for D*");
685 leg = stn[i]->leg[dirn[i]];
687 SVX_ASSERT2(data_here(leg), "data not on leg for D*");
688 SVX_ASSERT2(leg->l.to == stnZ, "bad sub-network for D*");
690 stn2 = reduction_stack->join[i]->l.to;
692 if (data_here(reduction_stack->join[i])) {
693 adddd(&POSD(stn2), &POSD(stn[i]), &reduction_stack->join[i]->d);
694 } else {
695 subdd(&POSD(stn2), &POSD(stn[i]), &reverse_leg(reduction_stack->join[i])->d);
698 if (!fZeros(&leg->v)) {
699 delta e, tmp;
700 subdd(&e, &POSD(stnZ), &POSD(stn[i]));
701 subdd(&e, &e, &leg->d);
702 divds(&tmp, &e, &leg->v);
703 if (data_here(reduction_stack->join[i])) {
704 mulsd(&e, &reduction_stack->join[i]->v, &tmp);
705 } else {
706 mulsd(&e, &reverse_leg(reduction_stack->join[i])->v, &tmp);
708 adddd(&POSD(stn2), &POSD(stn2), &e);
710 add_stn_to_list(&fixedlist, stn2);
711 osfree(leg);
712 stn[i]->leg[dirn[i]] = reduction_stack->join[i];
713 /* transfer the articulation status of the radial legs */
714 if (stnZ->leg[i]->l.reverse & FLAG_ARTICULATION) {
715 reduction_stack->join[i]->l.reverse |= FLAG_ARTICULATION;
716 reverse_leg(reduction_stack->join[i])->l.reverse |= FLAG_ARTICULATION;
718 osfree(stnZ->leg[i]);
719 stnZ->leg[i] = NULL;
721 /*printf("---%f %f %f\n",POS(stnZ, 0), POS(stnZ, 1), POS(stnZ, 2));*/
722 remove_stn_from_list(&fixedlist, stnZ);
723 osfree(stnZ->name);
724 osfree(stnZ);
725 } else {
726 BUG("reduction_stack has unknown type");
729 skip:;
730 reduction *ptrOld = reduction_stack;
731 reduction_stack = reduction_stack->next;
732 osfree(ptrOld);