source: git/src/network.c @ 5a2d346

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

Handle a lollipop with a fixed stick end specially

We can just calculate the position of the unfixed station by adding
vectors and solve the position of the unfixed point without having to
build and solve a single element matrix.

This will generally reduce the number of "Solving one equation..."
messages when solving a complex survey network.

  • Property mode set to 100644
File size: 21.7 KB
RevLine 
[ff6cfe1]1/* network.c
[5853657]2 * Survex network reduction - find patterns and apply network reductions
[37c5191]3 * Copyright (C) 1991-2002,2005,2024 Olly Betts
[846746e]4 *
[89231c4]5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
[ecbc6c18]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
[a420b49]18 */
19
[032ed06]20#if 0
[564f471]21#define DEBUG_INVALID 1
22#define VALIDATE 1
[5853657]23#define DUMP_NETWORK 1
[032ed06]24#endif
25
[4c83f84]26#include <config.h>
[d1b1380]27
28#include "validate.h"
29#include "debug.h"
[a420b49]30#include "cavern.h"
[4167edd]31#include "message.h"
[d1b1380]32#include "netbits.h"
33#include "network.h"
34#include "out.h"
35
[37c5191]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;
[4d695ce3]45
[37c5191]46#define allocate_reduction(N) osmalloc(sizeof(reduction) + (N) * sizeof(linkfor*))
[d1b1380]47
[37c5191]48// Head of linked list of reductions.
49static reduction *reduction_stack;
[d1b1380]50
[5853657]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* */
[a420b49]54
55extern void
56remove_subnets(void)
57{
58   node *stn, *stn2, *stn3, *stn4;
59   int dirn, dirn2, dirn3, dirn4;
[37c5191]60   reduction *trav;
[a420b49]61   linkfor *newleg, *newleg2;
[63d4f07]62   bool fMore = true;
[a420b49]63
[37c5191]64   reduction_stack = NULL;
[cb3d1e2]65
[a420b49]66   out_current_action(msg(/*Simplifying network*/129));
67
68   while (fMore) {
[63d4f07]69      fMore = false;
[a420b49]70      if (optimize & BITA('l')) {
[1e431a4e]71#if PRINT_NETBITS
72         printf("replacing lollipops\n");
73#endif
[a420b49]74         /* NB can have non-fixed 0 nodes */
[564f471]75         FOR_EACH_STN(stn, stnlist) {
[bf9faf6]76            if (three_node(stn)) {
[a420b49]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;
[f189010]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               }
[a420b49]108
[4c07c51]109               SVX_ASSERT(three_node(stn2));
[a420b49]110
[f189010]111               /*        _
112                *       ( )
113                *        * stn
114                *        |
115                *        * stn2
116                *       / \
117                * stn4 *   * stn3  -->  stn4 *---* stn3
118                *      :   :                 :   :
119                */
[a420b49]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
[37c5191]127               trav = allocate_reduction(2);
128               trav->type = TYPE_LOLLIPOP;
129
[a420b49]130               newleg2 = (linkfor*)osnew(linkrev);
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]);
[d1b1380]137#if 0
[37c5191]138               printf("Lollipop found with stn...stn4 = \n");
[a420b49]139               print_prefix(stn->name); putnl();
140               print_prefix(stn2->name); putnl();
141               print_prefix(stn3->name); putnl();
142               print_prefix(stn4->name); putnl();
[d1b1380]143#endif
144
[a420b49]145               addto_link(newleg, stn2->leg[dirn2]);
[d1b1380]146
[564f471]147               /* remove stn and stn2 */
148               remove_stn_from_list(&stnlist, stn);
149               remove_stn_from_list(&stnlist, stn2);
[d1b1380]150
[37c5191]151               /* stack lollipop and replace with a leg between stn3 and stn4 */
152               trav->join[0] = stn3->leg[dirn3];
[a420b49]153               newleg->l.to = stn4;
154               newleg->l.reverse = dirn4 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
[d1b1380]155
[37c5191]156               trav->join[1] = stn4->leg[dirn4];
[a420b49]157               newleg2->l.to = stn3;
158               newleg2->l.reverse = dirn3 | FLAG_REPLACEMENTLEG;
[d1b1380]159
[a420b49]160               stn3->leg[dirn3] = newleg;
161               stn4->leg[dirn4] = newleg2;
[d1b1380]162
[37c5191]163               trav->next = reduction_stack;
[032ed06]164#if PRINT_NETBITS
[37c5191]165               printf("remove lollipop\n");
[a420b49]166#endif
[37c5191]167               reduction_stack = trav;
[63d4f07]168               fMore = true;
[a420b49]169            }
170         }
[d1b1380]171      }
172
[a420b49]173      if (optimize & BITA('p')) {
[032ed06]174#if PRINT_NETBITS
175         printf("replacing parallel legs\n");
176#endif
[564f471]177         FOR_EACH_STN(stn, stnlist) {
[a420b49]178            /*
[5c05606]179             *  :            :
180             *  * stn3       * stn3
181             *  |            |
182             *  * stn        |
183             * ( )      -->  |
184             *  * stn2       |
185             *  |            |
186             *  * stn4       * stn4
187             *  :            :
[a420b49]188             */
[bf9faf6]189            if (three_node(stn)) {
[a420b49]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
[37c5191]201               /* stn == stn2 => lollipop */
[01d9c43b]202               if (stn == stn2 || fixed(stn2)) continue;
[a420b49]203
[4c07c51]204               SVX_ASSERT(three_node(stn2));
[a420b49]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
[37c5191]217               trav = allocate_reduction(2);
218               trav->type = TYPE_PARALLEL;
[a420b49]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                 {
[43d6ecfe]224#ifdef NO_COVARIANCES
[dac18d8]225                    vars sum;
226                    var prod;
[eb18f4d]227                    delta temp, temp2;
[dac18d8]228                    addss(&sum, &newleg->v, &newleg2->v);
[4c07c51]229                    SVX_ASSERT2(!fZeros(&sum), "loop of zero variance found");
[dac18d8]230                    mulss(&prod, &newleg->v, &newleg2->v);
231                    mulsd(&temp, &newleg2->v, &newleg->d);
232                    mulsd(&temp2, &newleg->v, &newleg2->d);
[a420b49]233                    adddd(&temp, &temp, &temp2);
[dac18d8]234                    divds(&newleg->d, &temp, &sum);
235                    sdivvs(&newleg->v, &prod, &sum);
[43d6ecfe]236#else
[59f2dbb]237                    svar inv1, inv2, sum;
[eb18f4d]238                    delta temp, temp2;
[43d6ecfe]239                    /* if leg one is an equate, we can just ignore leg two
240                     * whatever it is */
[dac18d8]241                    if (invert_svar(&inv1, &newleg->v)) {
242                       if (invert_svar(&inv2, &newleg2->v)) {
[59f2dbb]243                          addss(&sum, &inv1, &inv2);
[dac18d8]244                          if (!invert_svar(&newleg->v, &sum)) {
[2d3f65a]245                             BUG("matrix singular in parallel legs replacement");
[43d6ecfe]246                          }
[cb3d1e2]247
[59f2dbb]248                          mulsd(&temp, &inv1, &newleg->d);
249                          mulsd(&temp2, &inv2, &newleg2->d);
[43d6ecfe]250                          adddd(&temp, &temp, &temp2);
[59f2dbb]251                          mulsd(&newleg->d, &newleg->v, &temp);
[43d6ecfe]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
[a420b49]261                 }
262               osfree(newleg2);
263               newleg2 = (linkfor*)osnew(linkrev);
264
265               addto_link(newleg, stn2->leg[dirn2]);
266               addto_link(newleg, stn3->leg[dirn3]);
[d1b1380]267
268#if 0
[a420b49]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);
[d1b1380]272#endif
[4c07c51]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");
[a420b49]276
[564f471]277               /* remove stn and stn2 (already discarded triple parallel) */
[a420b49]278               /* so stn!=stn4 <=> stn2!=stn3 */
[564f471]279               remove_stn_from_list(&stnlist, stn);
280               remove_stn_from_list(&stnlist, stn2);
[a420b49]281
282               /* stack parallel and replace with a leg between stn3 and stn4 */
[37c5191]283               trav->join[0] = stn3->leg[dirn3];
[a420b49]284               newleg->l.to = stn4;
285               newleg->l.reverse = dirn4 | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
286
[37c5191]287               trav->join[1] = stn4->leg[dirn4];
[a420b49]288               newleg2->l.to = stn3;
289               newleg2->l.reverse = dirn3 | FLAG_REPLACEMENTLEG;
290
291               stn3->leg[dirn3] = newleg;
292               stn4->leg[dirn4] = newleg2;
293
[37c5191]294               trav->next = reduction_stack;
[032ed06]295#if PRINT_NETBITS
296               printf("remove parallel\n");
[a420b49]297#endif
[37c5191]298               reduction_stack = trav;
[63d4f07]299               fMore = true;
[a420b49]300            }
301         }
[d1b1380]302      }
303
[a420b49]304      if (optimize & BITA('d')) {
305         node *stn5, *stn6;
[66be513]306         int dirn5, dirn6;
[a420b49]307         linkfor *legAB, *legBC, *legCA;
[1e431a4e]308#if PRINT_NETBITS
309         printf("replacing deltas with stars\n");
310#endif
[564f471]311         FOR_EACH_STN(stn, stnlist) {
[a420b49]312            /*    printf("*");*/
313            /*
[5c05606]314             *          :                     :
315             *          * stn5                * stn5
316             *          |                     |
317             *          * stn2                |
318             *         / \        -->         O stnZ
319             *        |   |                  / \
320             *    stn *---* stn3            /   \
321             *       /     \               /     \
322             * stn4 *       * stn6   stn4 *       * stn6
323             *      :       :             :       :
[a420b49]324             */
[bf9faf6]325            if (three_node(stn)) {
[66be513]326               for (int dirn12 = 0; dirn12 <= 2; dirn12++) {
327                  stn2 = stn->leg[dirn12]->l.to;
[01d9c43b]328                  if (stn2 == stn || fixed(stn2)) continue;
[66be513]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                      }
[a420b49]341                  }
[66be513]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]);
[d1b1380]355#if 0
[66be513]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);
[d1b1380]363#endif
[66be513]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);
[a420b49]367
[37c5191]368                  trav = allocate_reduction(3);
369                  trav->type = TYPE_DELTASTAR;
[66be513]370                  {
[e322717]371                    linkfor *legAZ, *legBZ, *legCZ;
[a420b49]372                    node *stnZ;
373                    prefix *nameZ;
[59f2dbb]374                    svar invAB, invBC, invCA, tmp, sum, inv;
375                    var vtmp;
376                    svar sumAZBZ, sumBZCZ, sumCZAZ;
[eb18f4d]377                    delta temp, temp2;
[cb3d1e2]378
[43d6ecfe]379                    /* FIXME: ought to handle cases when some legs are
380                     * equates, but handle as a special case maybe? */
[dac18d8]381                    if (!invert_svar(&invAB, &legAB->v)) break;
382                    if (!invert_svar(&invBC, &legBC->v)) break;
383                    if (!invert_svar(&invCA, &legCA->v)) break;
[43d6ecfe]384
[59f2dbb]385                    addss(&sum, &legBC->v, &legCA->v);
386                    addss(&tmp, &sum, &legAB->v);
[dac18d8]387                    if (!invert_svar(&inv, &tmp)) {
[647407d]388                       /* impossible - loop of zero variance */
389                       BUG("loop of zero variance found");
390                    }
[cb3d1e2]391
[e322717]392                    legAZ = osnew(linkfor);
393                    legBZ = osnew(linkfor);
394                    legCZ = osnew(linkfor);
395
[43d6ecfe]396                    /* AZBZ */
[c861f75]397                    /* done above: addvv(&sum, &legBC->v, &legCA->v); */
[59f2dbb]398                    mulss(&vtmp, &sum, &inv);
399                    smulvs(&sumAZBZ, &vtmp, &legAB->v);
[43d6ecfe]400
401                    adddd(&temp, &legBC->d, &legCA->d);
[59f2dbb]402                    divds(&temp2, &temp, &sum);
403                    mulsd(&temp, &invAB, &legAB->d);
[c861f75]404                    subdd(&temp, &temp2, &temp);
[59f2dbb]405                    mulsd(&legBZ->d, &sumAZBZ, &temp);
[43d6ecfe]406
[c861f75]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;
[43d6ecfe]410
[c861f75]411                    /* BZCZ */
[59f2dbb]412                    addss(&sum, &legCA->v, &legAB->v);
413                    mulss(&vtmp, &sum, &inv);
414                    smulvs(&sumBZCZ, &vtmp, &legBC->v);
[43d6ecfe]415
416                    /* CZAZ */
[59f2dbb]417                    addss(&sum, &legAB->v, &legBC->v);
418                    mulss(&vtmp, &sum, &inv);
419                    smulvs(&sumCZAZ, &vtmp, &legCA->v);
[43d6ecfe]420
421                    adddd(&temp, &legAB->d, &legBC->d);
[59f2dbb]422                    divds(&temp2, &temp, &sum);
423                    mulsd(&temp, &invCA, &legCA->d);
[c861f75]424                    /* NB: swapped arguments to negate answer for legCZ->d */
425                    subdd(&temp, &temp, &temp2);
[59f2dbb]426                    mulsd(&legCZ->d, &sumCZAZ, &temp);
[43d6ecfe]427
[e322717]428                    osfree(legAB);
429                    osfree(legBC);
430                    osfree(legCA);
431
[43d6ecfe]432                    /* Now add two, subtract third, and scale by 0.5 */
[59f2dbb]433                    addss(&sum, &sumAZBZ, &sumCZAZ);
434                    subss(&sum, &sum, &sumBZCZ);
435                    mulsc(&legAZ->v, &sum, 0.5);
[43d6ecfe]436
[59f2dbb]437                    addss(&sum, &sumBZCZ, &sumAZBZ);
438                    subss(&sum, &sum, &sumCZAZ);
439                    mulsc(&legBZ->v, &sum, 0.5);
[43d6ecfe]440
[59f2dbb]441                    addss(&sum, &sumCZAZ, &sumBZCZ);
442                    subss(&sum, &sum, &sumAZBZ);
443                    mulsc(&legCZ->v, &sum, 0.5);
[43d6ecfe]444
[a420b49]445                    nameZ = osnew(prefix);
[be97baf]446                    nameZ->pos = osnew(pos);
[ba84079]447                    nameZ->ident.p = NULL;
[6adb88c]448                    nameZ->shape = 3;
[a420b49]449                    stnZ = osnew(node);
450                    stnZ->name = nameZ;
451                    nameZ->stn = stnZ;
452                    nameZ->up = NULL;
[932f7e9]453                    nameZ->min_export = nameZ->max_export = 0;
[a420b49]454                    unfix(stnZ);
[564f471]455                    add_stn_to_list(&stnlist, stnZ);
[a420b49]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(linkrev);
463                    stnZ->leg[1] = (linkfor*)osnew(linkrev);
464                    stnZ->leg[2] = (linkfor*)osnew(linkrev);
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;
[dbb4e19]471                    addto_link(legAZ, stn4->leg[dirn4]);
472                    addto_link(legBZ, stn5->leg[dirn5]);
473                    addto_link(legCZ, stn6->leg[dirn6]);
[a420b49]474                    /* stack stuff */
[37c5191]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;
[032ed06]479#if PRINT_NETBITS
480                    printf("remove delta*\n");
[a420b49]481#endif
[37c5191]482                    reduction_stack = trav;
[63d4f07]483                    fMore = true;
[cb3d1e2]484
[564f471]485                    remove_stn_from_list(&stnlist, stn);
486                    remove_stn_from_list(&stnlist, stn2);
487                    remove_stn_from_list(&stnlist, stn3);
[a420b49]488                    stn4->leg[dirn4] = legAZ;
489                    stn5->leg[dirn5] = legBZ;
490                    stn6->leg[dirn6] = legCZ;
[66be513]491                  }
492                  break;
493               }
[a420b49]494            }
495         }
496      }
[d1b1380]497
[a420b49]498   }
[d1b1380]499}
500
[5853657]501extern void
[a420b49]502replace_subnets(void)
503{
[eb18f4d]504   node *stn2, *stn3, *stn4;
505   int dirn2, dirn3, dirn4;
[4d695ce3]506
507   /* help to catch bad accesses */
[eb18f4d]508   stn2 = stn3 = stn4 = NULL;
509   dirn2 = dirn3 = dirn4 = 0;
[4d695ce3]510
[a420b49]511   out_current_action(msg(/*Calculating network*/130));
[4d695ce3]512
[37c5191]513   while (reduction_stack != NULL) {
514      /*  printf("replace_subnets() type %d\n", reduction_stack->type);*/
[032ed06]515
516#if PRINT_NETBITS
517      printf("replace_subnets\n");
[37c5191]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");
[032ed06]521#endif
522
[37c5191]523      if (reduction_stack->type != TYPE_DELTASTAR) {
[eb18f4d]524         linkfor *leg;
[37c5191]525         leg = reduction_stack->join[0]; leg = reverse_leg(leg);
[421b7d2]526         stn3 = leg->l.to; dirn3 = reverse_leg_dirn(leg);
[37c5191]527         leg = reduction_stack->join[1]; leg = reverse_leg(leg);
[421b7d2]528         stn4 = leg->l.to; dirn4 = reverse_leg_dirn(leg);
[cb3d1e2]529
[cfef352]530         if (!fixed(stn3) || !fixed(stn4)) {
531             SVX_ASSERT(!fixed(stn3) && !fixed(stn4));
532             goto skip;
533         }
[4c07c51]534         SVX_ASSERT(data_here(stn3->leg[dirn3]));
[4d695ce3]535      }
[d1b1380]536
[37c5191]537      if (reduction_stack->type == TYPE_LOLLIPOP) {
[eb18f4d]538         node *stn;
[421b7d2]539         delta e;
540         linkfor *leg;
[e6cfe52]541         int zero;
[43d6ecfe]542
[e6cfe52]543         leg = stn3->leg[dirn3];
[37c5191]544         stn2 = reduction_stack->join[0]->l.to;
545         dirn2 = reverse_leg_dirn(reduction_stack->join[0]);
[e6cfe52]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         }
[37c5191]554         if (data_here(reduction_stack->join[0])) {
555            adddd(&POSD(stn2), &POSD(stn3), &reduction_stack->join[0]->d);
[e6cfe52]556            if (!zero) {
[eb18f4d]557               delta tmp;
[37c5191]558               mulsd(&tmp, &reduction_stack->join[0]->v, &e);
[e6cfe52]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;
[d1b1380]571#if 0
[37c5191]572         printf("Replacing lollipop with stn...stn4 = \n");
[e6cfe52]573         print_prefix(stn->name); putnl();
574         print_prefix(stn2->name); putnl();
575         print_prefix(stn3->name); putnl();
576         print_prefix(stn4->name); putnl();
[d1b1380]577#endif
[e6cfe52]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
[37c5191]583         /* The "stick" of the lollipop is a new articulation. */
[e6cfe52]584         stn2->leg[dirn2]->l.reverse |= FLAG_ARTICULATION;
585         reverse_leg(stn2->leg[dirn2])->l.reverse |= FLAG_ARTICULATION;
586
[bf9faf6]587         add_stn_to_list(&fixedlist, stn);
588         add_stn_to_list(&fixedlist, stn2);
[d1b1380]589
[421b7d2]590         osfree(stn3->leg[dirn3]);
[37c5191]591         stn3->leg[dirn3] = reduction_stack->join[0];
[421b7d2]592         osfree(stn4->leg[dirn4]);
[37c5191]593         stn4->leg[dirn4] = reduction_stack->join[1];
594      } else if (reduction_stack->type == TYPE_PARALLEL) {
[421b7d2]595         /* parallel legs */
[eb18f4d]596         node *stn;
[421b7d2]597         delta e, e2;
598         linkfor *leg;
[e6cfe52]599         int dirn;
[421b7d2]600
[37c5191]601         stn = reduction_stack->join[0]->l.to;
602         stn2 = reduction_stack->join[1]->l.to;
[402c753]603
[37c5191]604         dirn = reverse_leg_dirn(reduction_stack->join[0]);
605         dirn2 = reverse_leg_dirn(reduction_stack->join[1]);
[e6cfe52]606
607         leg = stn3->leg[dirn3];
608
609         if (leg->l.reverse & FLAG_ARTICULATION) {
[37c5191]610            reduction_stack->join[0]->l.reverse |= FLAG_ARTICULATION;
[e6cfe52]611            stn->leg[dirn]->l.reverse |= FLAG_ARTICULATION;
[37c5191]612            reduction_stack->join[1]->l.reverse |= FLAG_ARTICULATION;
[e6cfe52]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
[37c5191]625         if (data_here(reduction_stack->join[0])) {
626            leg = reduction_stack->join[0];
[e6cfe52]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
[37c5191]635         if (data_here(reduction_stack->join[1])) {
636            leg = reduction_stack->join[1];
[e6cfe52]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);
[d1b1380]644#if 0
[e6cfe52]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();
[d1b1380]650#endif
[e6cfe52]651
[bf9faf6]652         add_stn_to_list(&fixedlist, stn);
653         add_stn_to_list(&fixedlist, stn2);
[cb3d1e2]654
[421b7d2]655         osfree(stn3->leg[dirn3]);
[37c5191]656         stn3->leg[dirn3] = reduction_stack->join[0];
[421b7d2]657         osfree(stn4->leg[dirn4]);
[37c5191]658         stn4->leg[dirn4] = reduction_stack->join[1];
659      } else if (reduction_stack->type == TYPE_DELTASTAR) {
[421b7d2]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 */
[37c5191]667         leg = reverse_leg(reduction_stack->join[0]);
[421b7d2]668         stn[0] = leg->l.to;
669         dirn[0] = reverse_leg_dirn(leg);
670         stnZ = stn[0]->leg[dirn[0]]->l.to;
[4c07c51]671         SVX_ASSERT(fixed(stnZ));
[cfef352]672         if (!fixed(stnZ)) {
673            SVX_ASSERT(!fixed(stn[0]));
674            goto skip;
675         }
[421b7d2]676         stn[1] = stnZ->leg[1]->l.to;
[a420b49]677         dirn[1] = reverse_leg_dirn(stnZ->leg[1]);
[421b7d2]678         stn[2] = stnZ->leg[2]->l.to;
[a420b49]679         dirn[2] = reverse_leg_dirn(stnZ->leg[2]);
[564f471]680         /*print_prefix(stnZ->name);printf(" %p\n",(void*)stnZ);*/
[4d695ce3]681
[e6cfe52]682         for (i = 0; i < 3; i++) {
[4c07c51]683            SVX_ASSERT2(fixed(stn[i]), "stn not fixed for D*");
[1e431a4e]684
[e6cfe52]685            leg = stn[i]->leg[dirn[i]];
[1e431a4e]686
[4c07c51]687            SVX_ASSERT2(data_here(leg), "data not on leg for D*");
688            SVX_ASSERT2(leg->l.to == stnZ, "bad sub-network for D*");
[1e431a4e]689
[37c5191]690            stn2 = reduction_stack->join[i]->l.to;
[1e431a4e]691
[37c5191]692            if (data_here(reduction_stack->join[i])) {
693               adddd(&POSD(stn2), &POSD(stn[i]), &reduction_stack->join[i]->d);
[1e431a4e]694            } else {
[37c5191]695               subdd(&POSD(stn2), &POSD(stn[i]), &reverse_leg(reduction_stack->join[i])->d);
[1e431a4e]696            }
697
[e6cfe52]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);
[37c5191]703               if (data_here(reduction_stack->join[i])) {
704                  mulsd(&e, &reduction_stack->join[i]->v, &tmp);
[1e431a4e]705               } else {
[37c5191]706                  mulsd(&e, &reverse_leg(reduction_stack->join[i])->v, &tmp);
[1e431a4e]707               }
[e6cfe52]708               adddd(&POSD(stn2), &POSD(stn2), &e);
709            }
[bf9faf6]710            add_stn_to_list(&fixedlist, stn2);
[e6cfe52]711            osfree(leg);
[37c5191]712            stn[i]->leg[dirn[i]] = reduction_stack->join[i];
[e6cfe52]713            /* transfer the articulation status of the radial legs */
714            if (stnZ->leg[i]->l.reverse & FLAG_ARTICULATION) {
[37c5191]715               reduction_stack->join[i]->l.reverse |= FLAG_ARTICULATION;
716               reverse_leg(reduction_stack->join[i])->l.reverse |= FLAG_ARTICULATION;
[e6cfe52]717            }
718            osfree(stnZ->leg[i]);
719            stnZ->leg[i] = NULL;
720         }
721/*printf("---%f %f %f\n",POS(stnZ, 0), POS(stnZ, 1), POS(stnZ, 2));*/
[bf9faf6]722         remove_stn_from_list(&fixedlist, stnZ);
[dbb4e19]723         osfree(stnZ->name);
724         osfree(stnZ);
[4d695ce3]725      } else {
[37c5191]726         BUG("reduction_stack has unknown type");
[4d695ce3]727      }
[d1b1380]728
[226342b]729skip:;
[37c5191]730      reduction *ptrOld = reduction_stack;
731      reduction_stack = reduction_stack->next;
[4d695ce3]732      osfree(ptrOld);
733   }
[d1b1380]734}
Note: See TracBrowser for help on using the repository browser.