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
21 #define DEBUG_INVALID 1
23 #define DUMP_NETWORK 1
36 typedef struct reduction
{
37 struct reduction
*next
;
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* */
58 node
*stn
, *stn2
, *stn3
, *stn4
;
59 int dirn
, dirn2
, dirn3
, dirn4
;
61 linkfor
*newleg
, *newleg2
;
64 reduction_stack
= NULL
;
66 out_current_action(msg(/*Simplifying network*/129));
70 if (optimize
& BITA('l')) {
72 printf("replacing lollipops\n");
74 /* NB can have non-fixed 0 nodes */
75 FOR_EACH_STN(stn
, stnlist
) {
76 if (three_node(stn
)) {
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
;
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
;
100 subdd(&POSD(stn
), &POSD(stn2
), &leg
->d
);
102 adddd(&POSD(stn
), &POSD(stn2
), &rev_leg
->d
);
104 remove_stn_from_list(&stnlist
, stn
);
105 add_stn_to_list(&fixedlist
, stn
);
109 SVX_ASSERT(three_node(stn2
));
117 * stn4 * * stn3 --> stn4 *---* stn3
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
]);
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();
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
];
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
;
165 printf("remove lollipop\n");
167 reduction_stack
= trav
;
173 if (optimize
& BITA('p')) {
175 printf("replacing parallel legs\n");
177 FOR_EACH_STN(stn
, stnlist
) {
189 if (three_node(stn
)) {
190 stn2
= stn
->leg
[0]->l
.to
;
191 if (stn2
== stn
->leg
[1]->l
.to
) {
193 } else if (stn2
== stn
->leg
[2]->l
.to
) {
196 if (stn
->leg
[1]->l
.to
!= stn
->leg
[2]->l
.to
) continue;
197 stn2
= stn
->leg
[1]->l
.to
;
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
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
);
237 svar inv1
, inv2
, sum
;
239 /* if leg one is an equate, we can just ignore leg two
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
);
253 /* leg two is an equate, so just ignore leg 1 */
263 newleg2
= (linkfor
*)osnew(linkcommon
);
265 addto_link(newleg
, stn2
->leg
[dirn2
]);
266 addto_link(newleg
, stn3
->leg
[dirn3
]);
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
);
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
];
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
;
296 printf("remove parallel\n");
298 reduction_stack
= trav
;
304 if (optimize
& BITA('d')) {
307 linkfor
*legAB
, *legBC
, *legCA
;
309 printf("replacing deltas with stars\n");
311 FOR_EACH_STN(stn
, stnlist
) {
322 * stn4 * * stn6 stn4 * * stn6
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
) {
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
]);
356 printf("delta-star, stn ... stn6 are:\n");
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
;
374 svar invAB
, invBC
, invCA
, tmp
, sum
, inv
;
376 svar sumAZBZ
, sumBZCZ
, sumCZAZ
;
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
);
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;
412 addss(&sum
, &legCA
->v
, &legAB
->v
);
413 mulss(&vtmp
, &sum
, &inv
);
414 smulvs(&sumBZCZ
, &vtmp
, &legBC
->v
);
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
);
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
;
453 nameZ
->min_export
= nameZ
->max_export
= 0;
456 add_stn_to_list(&stnlist
, stnZ
);
458 legAZ
->l
.reverse
= 0 | FLAG_DATAHERE
| FLAG_REPLACEMENTLEG
;
460 legBZ
->l
.reverse
= 1 | FLAG_DATAHERE
| FLAG_REPLACEMENTLEG
;
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
]);
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
;
481 printf("remove delta*\n");
483 reduction_stack
= trav
;
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
;
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);*/
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");
524 if (reduction_stack
->type
!= TYPE_DELTASTAR
) {
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
));
535 SVX_ASSERT(data_here(stn3
->leg
[dirn3
]));
538 if (reduction_stack
->type
== TYPE_LOLLIPOP
) {
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
);
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
);
559 mulsd(&tmp
, &reduction_stack
->join
[0]->v
, &e
);
560 adddd(&POSD(stn2
), &POSD(stn2
), &tmp
);
563 subdd(&POSD(stn2
), &POSD(stn3
), &stn2
->leg
[dirn2
]->d
);
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
;
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();
579 if (data_here(stn2
->leg
[dirn2
]))
580 adddd(&POSD(stn
), &POSD(stn2
), &stn2
->leg
[dirn2
]->d
);
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
) {
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
;
618 e
[0] = e
[1] = e
[2] = 0.0;
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
);
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
);
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
);
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();
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
) {
667 /* work out ends as we don't bother stacking them */
668 leg
= reverse_leg(reduction_stack
->join
[0]);
670 dirn
[0] = reverse_leg_dirn(leg
);
671 stnZ
= stn
[0]->leg
[dirn
[0]]->l
.to
;
673 SVX_ASSERT(!fixed(stn
[0]));
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
);
695 subdd(&POSD(stn2
), &POSD(stn
[i
]), &reverse_leg(reduction_stack
->join
[i
])->d
);
698 if (!fZeros(&leg
->v
)) {
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
);
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
);
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
]);
721 /*printf("---%f %f %f\n",POS(stnZ, 0), POS(stnZ, 1), POS(stnZ, 2));*/
722 remove_stn_from_list(&fixedlist
, stnZ
);
726 BUG("reduction_stack has unknown type");
730 reduction
*ptrOld
= reduction_stack
;
731 reduction_stack
= reduction_stack
->next
;